feat: completely support for all site-wide management settings in resource_setting_mgmt (#54)

* feat: completely support for all site-wide management settings in resource_setting_mgmt

* require controller version minimum 7.3 for debug_tools_enabled
This commit is contained in:
Mateusz Filipowicz
2025-03-15 10:47:14 +01:00
committed by GitHub
parent fbb6296e9e
commit 8b6ff55a18
4 changed files with 713 additions and 20 deletions

View File

@@ -1,24 +1,33 @@
package acctest
import (
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"sync"
"testing"
pt "github.com/filipowm/terraform-provider-unifi/internal/provider/testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
)
var settingMgmtLock = sync.Mutex{}
const testSettingMgmtResourceName = "unifi_setting_mgmt.test"
func TestAccSettingMgmt_basic(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
Lock: &settingMgmtLock,
Steps: []resource.TestStep{
{
Config: testAccSettingMgmtConfig_basic(),
Check: resource.ComposeTestCheckFunc(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "site", "default"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "true"),
),
ConfigPlanChecks: pt.CheckResourceActions(testSettingMgmtResourceName, plancheck.ResourceActionCreate),
},
pt.ImportStepWithSite("unifi_setting_mgmt.test"),
pt.ImportStepWithSite(testSettingMgmtResourceName),
},
})
}
@@ -29,9 +38,14 @@ func TestAccSettingMgmt_site(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccSettingMgmtConfig_site(),
Check: resource.ComposeTestCheckFunc(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttrPair(testSettingMgmtResourceName, "site", "unifi_site.test", "name"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "true"),
),
ConfigPlanChecks: pt.CheckResourceActions(testSettingMgmtResourceName, plancheck.ResourceActionCreate),
},
pt.ImportStepWithSite("unifi_setting_mgmt.test"),
pt.ImportStepWithSite(testSettingMgmtResourceName),
},
})
}
@@ -42,9 +56,298 @@ func TestAccSettingMgmt_sshKeys(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccSettingMgmtConfig_sshKeys(),
Check: resource.ComposeTestCheckFunc(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttrPair(testSettingMgmtResourceName, "site", "unifi_site.test", "name"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "1"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.name", "Test key"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.type", "ssh-rsa"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.comment", "test@example.com"),
),
ConfigPlanChecks: pt.CheckResourceActions(testSettingMgmtResourceName, plancheck.ResourceActionCreate),
},
pt.ImportStepWithSite("unifi_setting_mgmt.test"),
pt.ImportStepWithSite(testSettingMgmtResourceName),
},
})
}
func TestAccSettingMgmt_fullConfig(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
VersionConstraint: ">= 7.3",
Lock: &settingMgmtLock,
Steps: []resource.TestStep{
{
Config: testAccSettingMgmtConfig_fullConfig(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "site", "default"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade_hour", "3"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "advanced_feature_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "alert_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "boot_sound", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "debug_tools_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "direct_connect_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "led_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "outdoor_mode_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "unifi_idp_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "wifiman_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_bind_wildcard", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_username", "admin"),
),
ConfigPlanChecks: pt.CheckResourceActions(testSettingMgmtResourceName, plancheck.ResourceActionCreate),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
},
})
}
func TestAccSettingMgmt_update(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
Lock: &settingMgmtLock,
Steps: []resource.TestStep{
{
Config: testAccSettingMgmtConfig_initialConfig(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade_hour", "3"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "led_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
Config: testAccSettingMgmtConfig_updatedConfig(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade_hour", "5"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "led_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "false"),
),
},
},
})
}
func TestAccSettingMgmt_sshCredentials(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
Lock: &settingMgmtLock,
Steps: []resource.TestStep{
{
Config: testAccSettingMgmtConfig_sshCredentials(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_username", "admin"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_password", "securepassword"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
},
})
}
func TestAccSettingMgmt_cornerCases(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
Lock: &settingMgmtLock,
Steps: []resource.TestStep{
{
// Initial configuration with specific values
Config: testAccSettingMgmtConfig_cornerCasesInitial(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "site", "default"),
// Boolean attributes - initial values
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "alert_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "boot_sound", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "direct_connect_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "led_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "outdoor_mode_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "unifi_idp_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "wifiman_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_bind_wildcard", "true"),
// Numeric values - initial
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade_hour", "3"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Toggle all boolean values and change numeric values
Config: testAccSettingMgmtConfig_cornerCasesToggled(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
// Boolean attributes - toggled values
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "alert_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "boot_sound", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "direct_connect_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "led_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "outdoor_mode_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "unifi_idp_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "wifiman_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_bind_wildcard", "false"),
// Numeric values - changed
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade_hour", "23"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Test boundary values for numeric fields and mixed boolean values
Config: testAccSettingMgmtConfig_cornerCasesBoundary(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
// Mixed boolean values
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "alert_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "boot_sound", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "direct_connect_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "led_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "outdoor_mode_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "unifi_idp_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "wifiman_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_bind_wildcard", "true"),
// Boundary value for auto_upgrade_hour (1 - minimum value)
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "auto_upgrade_hour", "0"),
),
},
},
})
}
func TestAccSettingMgmt_sshKeyManagement(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
Lock: &settingMgmtLock,
Steps: []resource.TestStep{
{
// Initial configuration with one SSH key
Config: testAccSettingMgmtConfig_sshKeyManagementInitial(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "1"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.name", "Initial key"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.type", "ssh-rsa"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.key", "AAAAB3NzaC1yc2EAAAADAQABAAABAQC0"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.comment", "initial@example.com"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Add a second SSH key and modify the first one
Config: testAccSettingMgmtConfig_sshKeyManagementModified(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "2"),
// First key is modified
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.name", "Modified key"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.type", "ssh-rsa"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.key", "AAAAB3NzaC1yc2EAAAADAQABAAABAQC1"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.comment", "modified@example.com"),
// Second key is added
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.1.name", "Additional key"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.1.type", "ssh-ed25519"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.1.key", "AAAAC3NzaC1lZDI1NTE5AAAAIG"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.1.comment", "additional@example.com"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Remove the first key, keep the second key
Config: testAccSettingMgmtConfig_sshKeyManagementRemoved(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "1"),
// Only the second key remains
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.name", "Additional key"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.type", "ssh-ed25519"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.key", "AAAAC3NzaC1lZDI1NTE5AAAAIG"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.comment", "additional@example.com"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Remove all SSH keys
Config: testAccSettingMgmtConfig_sshKeyManagementNoKeys(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "0"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
},
})
}
func TestAccSettingMgmt_sshAuthModes(t *testing.T) {
AcceptanceTest(t, AcceptanceTestCase{
Lock: &settingMgmtLock,
Steps: []resource.TestStep{
{
// Initial configuration with SSH password authentication enabled
Config: testAccSettingMgmtConfig_sshAuthModesPasswordOnly(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_username", "admin"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_password", "password123"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "0"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Switch to SSH key authentication only
Config: testAccSettingMgmtConfig_sshAuthModesKeyOnly(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "false"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "1"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.name", "Auth key"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.type", "ssh-rsa"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Enable both authentication methods
Config: testAccSettingMgmtConfig_sshAuthModesBoth(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_auth_password_enabled", "true"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_username", "admin"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_password", "newpassword"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.#", "1"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.name", "Auth key"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_key.0.type", "ssh-rsa"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
{
// Disable SSH entirely
Config: testAccSettingMgmtConfig_sshAuthModesDisabled(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(testSettingMgmtResourceName, "id"),
resource.TestCheckResourceAttr(testSettingMgmtResourceName, "ssh_enabled", "false"),
),
},
pt.ImportStepWithSite(testSettingMgmtResourceName),
},
})
}
@@ -88,3 +391,222 @@ resource "unifi_setting_mgmt" "test" {
}
`
}
func testAccSettingMgmtConfig_fullConfig() string {
return `
resource "unifi_setting_mgmt" "test" {
auto_upgrade = true
auto_upgrade_hour = 3
advanced_feature_enabled = true
alert_enabled = true
boot_sound = false
debug_tools_enabled = true
direct_connect_enabled = false
led_enabled = true
outdoor_mode_enabled = false
unifi_idp_enabled = false
wifiman_enabled = true
ssh_enabled = true
ssh_auth_password_enabled = true
ssh_bind_wildcard = false
ssh_username = "admin"
}
`
}
func testAccSettingMgmtConfig_initialConfig() string {
return `
resource "unifi_setting_mgmt" "test" {
auto_upgrade = true
auto_upgrade_hour = 3
led_enabled = true
ssh_enabled = true
}
`
}
func testAccSettingMgmtConfig_updatedConfig() string {
return `
resource "unifi_setting_mgmt" "test" {
auto_upgrade = false
auto_upgrade_hour = 5
led_enabled = false
ssh_enabled = false
}
`
}
func testAccSettingMgmtConfig_sshCredentials() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
ssh_auth_password_enabled = true
ssh_username = "admin"
ssh_password = "securepassword"
}
`
}
func testAccSettingMgmtConfig_cornerCasesInitial() string {
return `
resource "unifi_setting_mgmt" "test" {
auto_upgrade = true
auto_upgrade_hour = 3
alert_enabled = true
boot_sound = true
direct_connect_enabled = false
led_enabled = true
outdoor_mode_enabled = true
unifi_idp_enabled = false
wifiman_enabled = true
ssh_enabled = true
ssh_auth_password_enabled = true
ssh_bind_wildcard = true
}
`
}
func testAccSettingMgmtConfig_cornerCasesToggled() string {
return `
resource "unifi_setting_mgmt" "test" {
auto_upgrade = false
auto_upgrade_hour = 23
alert_enabled = false
boot_sound = false
direct_connect_enabled = false
led_enabled = false
outdoor_mode_enabled = false
unifi_idp_enabled = false
wifiman_enabled = false
ssh_enabled = false
ssh_auth_password_enabled = false
ssh_bind_wildcard = false
}
`
}
func testAccSettingMgmtConfig_cornerCasesBoundary() string {
return `
resource "unifi_setting_mgmt" "test" {
auto_upgrade = true
auto_upgrade_hour = 0
alert_enabled = true
boot_sound = false
direct_connect_enabled = false
led_enabled = true
outdoor_mode_enabled = false
unifi_idp_enabled = false
wifiman_enabled = true
ssh_enabled = true
ssh_auth_password_enabled = false
ssh_bind_wildcard = true
}
`
}
func testAccSettingMgmtConfig_sshKeyManagementInitial() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
ssh_key {
name = "Initial key"
type = "ssh-rsa"
key = "AAAAB3NzaC1yc2EAAAADAQABAAABAQC0"
comment = "initial@example.com"
}
}
`
}
func testAccSettingMgmtConfig_sshKeyManagementModified() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
ssh_key {
name = "Modified key"
type = "ssh-rsa"
key = "AAAAB3NzaC1yc2EAAAADAQABAAABAQC1"
comment = "modified@example.com"
}
ssh_key {
name = "Additional key"
type = "ssh-ed25519"
key = "AAAAC3NzaC1lZDI1NTE5AAAAIG"
comment = "additional@example.com"
}
}
`
}
func testAccSettingMgmtConfig_sshKeyManagementRemoved() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
ssh_key {
name = "Additional key"
type = "ssh-ed25519"
key = "AAAAC3NzaC1lZDI1NTE5AAAAIG"
comment = "additional@example.com"
}
}
`
}
func testAccSettingMgmtConfig_sshKeyManagementNoKeys() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
}
`
}
func testAccSettingMgmtConfig_sshAuthModesPasswordOnly() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
ssh_auth_password_enabled = true
ssh_username = "admin"
ssh_password = "password123"
}
`
}
func testAccSettingMgmtConfig_sshAuthModesKeyOnly() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
ssh_auth_password_enabled = false
ssh_key {
name = "Auth key"
type = "ssh-rsa"
key = "AAAAB3NzaC1yc2EAAAADAQABAAABAQC0"
comment = "auth@example.com"
}
}
`
}
func testAccSettingMgmtConfig_sshAuthModesBoth() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = true
ssh_auth_password_enabled = true
ssh_username = "admin"
ssh_password = "newpassword"
ssh_key {
name = "Auth key"
type = "ssh-rsa"
key = "AAAAB3NzaC1yc2EAAAADAQABAAABAQC0"
comment = "auth@example.com"
}
}
`
}
func testAccSettingMgmtConfig_sshAuthModesDisabled() string {
return `
resource "unifi_setting_mgmt" "test" {
ssh_enabled = false
}
`
}

View File

@@ -3,6 +3,9 @@ package settings
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
"github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
@@ -12,6 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -37,9 +41,23 @@ func (m *SshKeyModel) AttributeTypes() map[string]attr.Type {
// mgmtModel represents the data model for management settings.
type mgmtModel struct {
base.Model
AutoUpgrade types.Bool `tfsdk:"auto_upgrade"`
SshEnabled types.Bool `tfsdk:"ssh_enabled"`
SshKeys types.List `tfsdk:"ssh_key"`
AdvancedFeatureEnabled types.Bool `tfsdk:"advanced_feature_enabled"`
AlertEnabled types.Bool `tfsdk:"alert_enabled"`
AutoUpgrade types.Bool `tfsdk:"auto_upgrade"`
AutoUpgradeHour types.Int32 `tfsdk:"auto_upgrade_hour"`
BootSound types.Bool `tfsdk:"boot_sound"`
DebugToolsEnabled types.Bool `tfsdk:"debug_tools_enabled"`
DirectConnectEnabled types.Bool `tfsdk:"direct_connect_enabled"`
LedEnabled types.Bool `tfsdk:"led_enabled"`
OutdoorModeEnabled types.Bool `tfsdk:"outdoor_mode_enabled"`
UnifiIdpEnabled types.Bool `tfsdk:"unifi_idp_enabled"`
WifimanEnabled types.Bool `tfsdk:"wifiman_enabled"`
SshAuthPasswordEnabled types.Bool `tfsdk:"ssh_auth_password_enabled"`
SshBindWildcard types.Bool `tfsdk:"ssh_bind_wildcard"`
SshKeys types.List `tfsdk:"ssh_key"`
SshPassword types.String `tfsdk:"ssh_password"`
SshEnabled types.Bool `tfsdk:"ssh_enabled"`
SshUsername types.String `tfsdk:"ssh_username"`
}
func (m *mgmtModel) AsUnifiModel(ctx context.Context) (interface{}, diag.Diagnostics) {
@@ -52,11 +70,25 @@ func (m *mgmtModel) AsUnifiModel(ctx context.Context) (interface{}, diag.Diagnos
}
return &unifi.SettingMgmt{
ID: m.ID.ValueString(),
Key: unifi.SettingMgmtKey,
AutoUpgrade: m.AutoUpgrade.ValueBool(),
XSshEnabled: m.SshEnabled.ValueBool(),
XSshKeys: sshKeys,
ID: m.ID.ValueString(),
Key: unifi.SettingMgmtKey,
AutoUpgrade: m.AutoUpgrade.ValueBool(),
AutoUpgradeHour: int(m.AutoUpgradeHour.ValueInt32()),
AdvancedFeatureEnabled: m.AdvancedFeatureEnabled.ValueBool(),
AlertEnabled: m.AlertEnabled.ValueBool(),
BootSound: m.BootSound.ValueBool(),
DebugToolsEnabled: m.DebugToolsEnabled.ValueBool(),
DirectConnectEnabled: m.DirectConnectEnabled.ValueBool(),
LedEnabled: m.LedEnabled.ValueBool(),
OutdoorModeEnabled: m.OutdoorModeEnabled.ValueBool(),
UnifiIDpEnabled: m.UnifiIdpEnabled.ValueBool(),
WifimanEnabled: m.WifimanEnabled.ValueBool(),
XSshEnabled: m.SshEnabled.ValueBool(),
XSshAuthPasswordEnabled: m.SshAuthPasswordEnabled.ValueBool(),
XSshBindWildcard: m.SshBindWildcard.ValueBool(),
XSshUsername: m.SshUsername.ValueString(),
XSshPassword: m.SshPassword.ValueString(),
XSshKeys: sshKeys,
}, diags
}
@@ -96,7 +128,21 @@ func (m *mgmtModel) Merge(ctx context.Context, other interface{}) diag.Diagnosti
m.ID = types.StringValue(resp.ID)
m.AutoUpgrade = types.BoolValue(resp.AutoUpgrade)
m.AutoUpgradeHour = types.Int32Value(int32(resp.AutoUpgradeHour))
m.AdvancedFeatureEnabled = types.BoolValue(resp.AdvancedFeatureEnabled)
m.AlertEnabled = types.BoolValue(resp.AlertEnabled)
m.BootSound = types.BoolValue(resp.BootSound)
m.DebugToolsEnabled = types.BoolValue(resp.DebugToolsEnabled)
m.DirectConnectEnabled = types.BoolValue(resp.DirectConnectEnabled)
m.LedEnabled = types.BoolValue(resp.LedEnabled)
m.OutdoorModeEnabled = types.BoolValue(resp.OutdoorModeEnabled)
m.UnifiIdpEnabled = types.BoolValue(resp.UnifiIDpEnabled)
m.WifimanEnabled = types.BoolValue(resp.WifimanEnabled)
m.SshEnabled = types.BoolValue(resp.XSshEnabled)
m.SshAuthPasswordEnabled = types.BoolValue(resp.XSshAuthPasswordEnabled)
m.SshBindWildcard = types.BoolValue(resp.XSshBindWildcard)
m.SshUsername = types.StringValue(resp.XSshUsername)
m.SshPassword = types.StringValue(resp.XSshPassword)
// Convert SSH keys
if len(resp.XSshKeys) > 0 {
@@ -138,15 +184,20 @@ func NewMgmtResource() resource.Resource {
}
var (
_ base.ResourceModel = &mgmtModel{}
_ resource.Resource = &mgmtResource{}
_ resource.ResourceWithConfigure = &mgmtResource{}
_ base.ResourceModel = &mgmtModel{}
_ resource.Resource = &mgmtResource{}
_ resource.ResourceWithConfigure = &mgmtResource{}
_ resource.ResourceWithModifyPlan = &mgmtResource{}
)
type mgmtResource struct {
*base.GenericResource[*mgmtModel]
}
func (r *mgmtResource) ModifyPlan(_ context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
resp.Diagnostics.Append(r.RequireMinVersionForPath("7.3", path.Root("debug_tools_enabled"), req.Config)...)
}
func (r *mgmtResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "The `unifi_setting_mgmt` resource manages site-wide management settings in the UniFi controller.\n\n" +
@@ -166,6 +217,90 @@ func (r *mgmtResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
MarkdownDescription: "Enable automatic firmware upgrades for all UniFi devices at this site. When enabled, devices will automatically " +
"update to the latest stable firmware version approved for your controller version.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"auto_upgrade_hour": schema.Int32Attribute{
MarkdownDescription: "The hour of the day (0-23) when automatic firmware upgrades will occur.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Int32{
int32planmodifier.UseStateForUnknown(),
},
Validators: []validator.Int32{
int32validator.Between(0, 23),
},
},
"advanced_feature_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable advanced features for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"alert_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable alerts for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"boot_sound": schema.BoolAttribute{
MarkdownDescription: "Enable the boot sound for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"debug_tools_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable debug tools for UniFi devices at this site. Requires controller version 7.3 or later.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"direct_connect_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable direct connect for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"led_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable the LED light for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"outdoor_mode_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable outdoor mode for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"unifi_idp_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable UniFi IDP for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"wifiman_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable WiFiman for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
@@ -174,10 +309,44 @@ func (r *mgmtResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
MarkdownDescription: "Enable SSH access to UniFi devices at this site. When enabled, you can connect to devices using SSH for advanced " +
"configuration and troubleshooting. It's recommended to only enable this temporarily when needed.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"ssh_auth_password_enabled": schema.BoolAttribute{
MarkdownDescription: "Enable SSH password authentication for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"ssh_bind_wildcard": schema.BoolAttribute{
MarkdownDescription: "Enable SSH bind wildcard for UniFi devices at this site.",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Bool{
boolplanmodifier.UseStateForUnknown(),
},
},
"ssh_username": schema.StringAttribute{
MarkdownDescription: "The SSH username for UniFi devices at this site.",
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
"ssh_password": schema.StringAttribute{
MarkdownDescription: "The SSH password for UniFi devices at this site.",
Optional: true,
Computed: true,
Sensitive: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
},
Blocks: map[string]schema.Block{
"ssh_key": schema.ListNestedBlock{