diff --git a/examples/resources/routeros_user_manager_advanced/import.sh b/examples/resources/routeros_user_manager_advanced/import.sh new file mode 100644 index 00000000..2515ff26 --- /dev/null +++ b/examples/resources/routeros_user_manager_advanced/import.sh @@ -0,0 +1 @@ +terraform import routeros_user_manager_advanced.settings . diff --git a/examples/resources/routeros_user_manager_advanced/resource.tf b/examples/resources/routeros_user_manager_advanced/resource.tf new file mode 100644 index 00000000..8753acd5 --- /dev/null +++ b/examples/resources/routeros_user_manager_advanced/resource.tf @@ -0,0 +1,4 @@ +resource "routeros_user_manager_advanced" "settings" { + web_private_password = "password" + web_private_username = "admin" +} diff --git a/examples/resources/routeros_user_manager_attribute/import.sh b/examples/resources/routeros_user_manager_attribute/import.sh new file mode 100644 index 00000000..3b073ddb --- /dev/null +++ b/examples/resources/routeros_user_manager_attribute/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/attribute get [print show-ids]] +terraform routeros_user_manager_attribute.mikrotik_wireless_comment '*1' diff --git a/examples/resources/routeros_user_manager_attribute/resource.tf b/examples/resources/routeros_user_manager_attribute/resource.tf new file mode 100644 index 00000000..e4f10c69 --- /dev/null +++ b/examples/resources/routeros_user_manager_attribute/resource.tf @@ -0,0 +1,6 @@ +resource "routeros_user_manager_attribute" "mikrotik_wireless_comment" { + name = "Mikrotik-Wireless-Comment" + packet_types = ["access-accept"] + type_id = 21 + value_type = "string" +} diff --git a/examples/resources/routeros_user_manager_database/import.sh b/examples/resources/routeros_user_manager_database/import.sh new file mode 100644 index 00000000..45935324 --- /dev/null +++ b/examples/resources/routeros_user_manager_database/import.sh @@ -0,0 +1 @@ +terraform import routeros_user_manager_database.settings . diff --git a/examples/resources/routeros_user_manager_database/resource.tf b/examples/resources/routeros_user_manager_database/resource.tf new file mode 100644 index 00000000..03467516 --- /dev/null +++ b/examples/resources/routeros_user_manager_database/resource.tf @@ -0,0 +1,3 @@ +resource "routeros_user_manager_database" "settings" { + db_path = "/flash/user-manager5" +} diff --git a/examples/resources/routeros_user_manager_limitation/import.sh b/examples/resources/routeros_user_manager_limitation/import.sh new file mode 100644 index 00000000..78368cfe --- /dev/null +++ b/examples/resources/routeros_user_manager_limitation/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/limitation get [print show-ids]] +terraform import routeros_user_manager_limitation.test '*1' diff --git a/examples/resources/routeros_user_manager_limitation/resource.tf b/examples/resources/routeros_user_manager_limitation/resource.tf new file mode 100644 index 00000000..1ce602ed --- /dev/null +++ b/examples/resources/routeros_user_manager_limitation/resource.tf @@ -0,0 +1,6 @@ +resource "routeros_user_manager_limitation" "test" { + name = "test" + download_limit = 1024 + upload_limit = 1024 + uptime_limit = "10d" +} diff --git a/examples/resources/routeros_user_manager_profile/import.sh b/examples/resources/routeros_user_manager_profile/import.sh new file mode 100644 index 00000000..e65c2328 --- /dev/null +++ b/examples/resources/routeros_user_manager_profile/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/profile get [print show-ids]] +terraform import routeros_user_manager_profile.test '*1' diff --git a/examples/resources/routeros_user_manager_profile/resource.tf b/examples/resources/routeros_user_manager_profile/resource.tf new file mode 100644 index 00000000..897f7318 --- /dev/null +++ b/examples/resources/routeros_user_manager_profile/resource.tf @@ -0,0 +1,5 @@ +resource "routeros_user_manager_profile" "test" { + name = "test" + name_for_users = "Test" + price = 0.02 +} diff --git a/examples/resources/routeros_user_manager_profile_limitation/import.sh b/examples/resources/routeros_user_manager_profile_limitation/import.sh new file mode 100644 index 00000000..7239de15 --- /dev/null +++ b/examples/resources/routeros_user_manager_profile_limitation/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/profile-limitation get [print show-ids]] +terraform import routeros_user_manager_profile_limitation.weekend_night '*1' diff --git a/examples/resources/routeros_user_manager_profile_limitation/resource.tf b/examples/resources/routeros_user_manager_profile_limitation/resource.tf new file mode 100644 index 00000000..1dabd236 --- /dev/null +++ b/examples/resources/routeros_user_manager_profile_limitation/resource.tf @@ -0,0 +1,23 @@ +resource "routeros_user_manager_limitation" "test" { + name = "test" + download_limit = 1024 + upload_limit = 1024 + uptime_limit = "10d" +} + +resource "routeros_user_manager_profile" "test" { + name = "test" + name_for_users = "Test" + price = 0.02 +} + +resource "routeros_user_manager_profile_limitation" "weekend_night" { + limitation = routeros_user_manager_limitation.test.name + profile = routeros_user_manager_profile.test.name + from_time = "0s" + till_time = "6h" + weekdays = [ + "sunday", + "saturday", + ] +} diff --git a/examples/resources/routeros_user_manager_router/import.sh b/examples/resources/routeros_user_manager_router/import.sh new file mode 100644 index 00000000..deb3346d --- /dev/null +++ b/examples/resources/routeros_user_manager_router/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/router get [print show-ids]] +terraform import routeros_user_manager_router.test '*1' diff --git a/examples/resources/routeros_user_manager_router/resource.tf b/examples/resources/routeros_user_manager_router/resource.tf new file mode 100644 index 00000000..94df679c --- /dev/null +++ b/examples/resources/routeros_user_manager_router/resource.tf @@ -0,0 +1,5 @@ +resource "routeros_user_manager_router" "test" { + address = "127.0.0.1" + name = "test" + shared_secret = "password" +} diff --git a/examples/resources/routeros_user_manager_settings/import.sh b/examples/resources/routeros_user_manager_settings/import.sh new file mode 100644 index 00000000..dcda0d23 --- /dev/null +++ b/examples/resources/routeros_user_manager_settings/import.sh @@ -0,0 +1 @@ +terraform import routeros_user_manager_settings.settings . diff --git a/examples/resources/routeros_user_manager_settings/resource.tf b/examples/resources/routeros_user_manager_settings/resource.tf new file mode 100644 index 00000000..74e13cbe --- /dev/null +++ b/examples/resources/routeros_user_manager_settings/resource.tf @@ -0,0 +1,3 @@ +resource "routeros_user_manager_settings" "settings" { + enabled = true +} diff --git a/examples/resources/routeros_user_manager_user/import.sh b/examples/resources/routeros_user_manager_user/import.sh new file mode 100644 index 00000000..56d65858 --- /dev/null +++ b/examples/resources/routeros_user_manager_user/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/user get [print show-ids]] +terraform import routeros_user_manager_user.test '*1' diff --git a/examples/resources/routeros_user_manager_user/resource.tf b/examples/resources/routeros_user_manager_user/resource.tf new file mode 100644 index 00000000..b5e5b72d --- /dev/null +++ b/examples/resources/routeros_user_manager_user/resource.tf @@ -0,0 +1,25 @@ +resource "routeros_user_manager_attribute" "mikrotik_wireless_comment" { + name = "Mikrotik-Wireless-Comment" + type_id = 21 + value_type = "string" +} + +resource "routeros_user_manager_attribute" "mikrotik_wireless_vlanid" { + name = "Mikrotik-Wireless-VLANID" + type_id = 26 + value_type = "uint32" +} + +resource "routeros_user_manager_user_group" "test" { + name = "test" +} + +resource "routeros_user_manager_user" "test" { + attributes = [ + "${routeros_user_manager_attribute.mikrotik_wireless_comment.name}:Test Group", + "${routeros_user_manager_attribute.mikrotik_wireless_vlanid.name}:100", + ] + group = routeros_user_manager_user_group.test.name + name = "test" + password = "password" +} diff --git a/examples/resources/routeros_user_manager_user_group/import.sh b/examples/resources/routeros_user_manager_user_group/import.sh new file mode 100644 index 00000000..ce667285 --- /dev/null +++ b/examples/resources/routeros_user_manager_user_group/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/user/group get [print show-ids]] +terraform import routeros_user_manager_user_group.test '*1' diff --git a/examples/resources/routeros_user_manager_user_group/resource.tf b/examples/resources/routeros_user_manager_user_group/resource.tf new file mode 100644 index 00000000..27857e3a --- /dev/null +++ b/examples/resources/routeros_user_manager_user_group/resource.tf @@ -0,0 +1,27 @@ +resource "routeros_user_manager_attribute" "mikrotik_wireless_comment" { + name = "Mikrotik-Wireless-Comment" + type_id = 21 + value_type = "string" +} + +resource "routeros_user_manager_attribute" "mikrotik_wireless_vlanid" { + name = "Mikrotik-Wireless-VLANID" + type_id = 26 + value_type = "uint32" +} + +resource "routeros_user_manager_user_group" "test" { + name = "test" + attributes = [ + "${routeros_user_manager_attribute.mikrotik_wireless_comment.name}:Test Group", + "${routeros_user_manager_attribute.mikrotik_wireless_vlanid.name}:100", + ] + inner_auths = [ + "ttls-chap", + "ttls-pap", + ] + outer_auths = [ + "chap", + "pap", + ] +} diff --git a/examples/resources/routeros_user_manager_user_profile/import.sh b/examples/resources/routeros_user_manager_user_profile/import.sh new file mode 100644 index 00000000..e5049760 --- /dev/null +++ b/examples/resources/routeros_user_manager_user_profile/import.sh @@ -0,0 +1,3 @@ +#The ID can be found via API or the terminal +#The command for the terminal is -> :put [/user-manager/user-profile get [print show-ids]] +terraform import routeros_user_manager_user_profile.test '*1' diff --git a/examples/resources/routeros_user_manager_user_profile/resource.tf b/examples/resources/routeros_user_manager_user_profile/resource.tf new file mode 100644 index 00000000..9b80e38e --- /dev/null +++ b/examples/resources/routeros_user_manager_user_profile/resource.tf @@ -0,0 +1,12 @@ +resource "routeros_user_manager_profile" "test" { + name = "test" +} + +resource "routeros_user_manager_user" "test" { + name = "test" +} + +resource "routeros_user_manager_user_profile" "test" { + profile = routeros_user_manager_profile.test.name + user = routeros_user_manager_user.test.name +} diff --git a/routeros/mikrotik_serialize.go b/routeros/mikrotik_serialize.go index 965bfcdf..b4b8b26b 100644 --- a/routeros/mikrotik_serialize.go +++ b/routeros/mikrotik_serialize.go @@ -47,7 +47,7 @@ func isEmpty(propName string, schemaProp *schema.Schema, d *schema.ResourceData, return v.(string) == "" && schemaProp.Default.(string) == "" } return v.(string) == "" && confValue.IsNull() - case schema.TypeInt: + case schema.TypeFloat, schema.TypeInt: return confValue.IsNull() && schemaProp.Default == nil case schema.TypeBool: // If true, it is always not empty: @@ -195,6 +195,8 @@ func TerraformResourceDataToMikrotik(s map[string]*schema.Schema, d *schema.Reso switch terraformMetadata.Type { case schema.TypeString: item[mikrotikKebabName] = value.(string) + case schema.TypeFloat: + item[mikrotikKebabName] = strconv.FormatFloat(value.(float64), 'f', -1, 64) case schema.TypeInt: item[mikrotikKebabName] = strconv.Itoa(value.(int)) case schema.TypeBool: @@ -360,10 +362,18 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch case schema.TypeString: err = d.Set(terraformSnakeName, mikrotikValue) + case schema.TypeFloat: + f, e := strconv.ParseFloat(mikrotikValue, 64) + if e != nil { + diags = diag.Errorf("%v for '%v' field", e, terraformSnakeName) + break + } + err = d.Set(terraformSnakeName, f) + case schema.TypeInt: i, e := strconv.Atoi(mikrotikValue) if e != nil { - diags = diag.Errorf("%v for '%v' field", err, terraformSnakeName) + diags = diag.Errorf("%v for '%v' field", e, terraformSnakeName) break } err = d.Set(terraformSnakeName, i) @@ -391,15 +401,24 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch // Flat Lists & Sets: if _, ok := s[terraformSnakeName].Elem.(*schema.Schema); mikrotikValue != "" && ok { for _, v := range strings.Split(mikrotikValue, ",") { - if s[terraformSnakeName].Elem.(*schema.Schema).Type == schema.TypeInt { - i, err := strconv.Atoi(v) + switch s[terraformSnakeName].Elem.(*schema.Schema).Type { + case schema.TypeFloat: + f, err := strconv.ParseFloat(v, 64) if err != nil { diags = diag.Errorf("%v for '%v' field", err, terraformSnakeName) continue } + l = append(l, f) + case schema.TypeInt: + i, err := strconv.Atoi(v) + if err != nil { + diags = diag.Errorf("%v for '%v' field", err, terraformSnakeName) + continue + } l = append(l, i) - } else { + + default: l = append(l, v) } } @@ -429,6 +448,11 @@ func MikrotikResourceDataToTerraform(item MikrotikItem, s map[string]*schema.Sch switch s[terraformSnakeName].Elem.(*schema.Resource).Schema[subFieldSnakeName].Type { case schema.TypeString: v = mikrotikValue + case schema.TypeFloat: + v, err = strconv.ParseFloat(mikrotikValue, 64) + if err != nil { + diags = diag.Errorf("%v for '%v.%v' field", err, terraformSnakeName, subFieldSnakeName) + } case schema.TypeInt: v, err = strconv.Atoi(mikrotikValue) if err != nil { @@ -572,6 +596,14 @@ func MikrotikResourceDataToTerraformDatasource(items *[]MikrotikItem, resourceDa case schema.TypeString: propValue = mikrotikValue + case schema.TypeFloat: + f, err := strconv.ParseFloat(mikrotikValue, 64) + if err != nil { + diags = append(diags, diag.Errorf("%v for '%v' field", err, terraformSnakeName)...) + continue + } + propValue = f + case schema.TypeInt: i, err := strconv.Atoi(mikrotikValue) if err != nil { diff --git a/routeros/mikrotik_serialize_test.go b/routeros/mikrotik_serialize_test.go index 8676fcbe..8b09de80 100644 --- a/routeros/mikrotik_serialize_test.go +++ b/routeros/mikrotik_serialize_test.go @@ -15,6 +15,9 @@ var ( "string": { Type: schema.TypeString, }, + "float": { + Type: schema.TypeFloat, + }, "int": { Type: schema.TypeInt, }, @@ -40,6 +43,9 @@ var ( "string": { Type: schema.TypeString, }, + "float": { + Type: schema.TypeFloat, + }, "int": { Type: schema.TypeInt, }, @@ -55,10 +61,10 @@ var ( func Test_mikrotikResourceDataToTerraform(t *testing.T) { - testItem := MikrotikItem{".id": "*39", "string": "string12345", "int": "10", "bool": "true"} + testItem := MikrotikItem{".id": "*39", "string": "string12345", "float": "0.01", "int": "10", "bool": "true"} testResourceData := testResource.TestResourceData() - expectedRes := map[string]interface{}{"string": "string12345", "int": 10, "bool": true} + expectedRes := map[string]interface{}{"string": "string12345", "float": 0.01, "int": 10, "bool": true} err := MikrotikResourceDataToTerraform(testItem, testResource.Schema, testResourceData) if err != nil { @@ -77,11 +83,12 @@ func Test_mikrotikResourceDataToTerraform(t *testing.T) { func Test_terraformResourceDataToMikrotik(t *testing.T) { - expected := MikrotikItem{"string": "string12345", "int": "10", "bool": "yes"} + expected := MikrotikItem{"string": "string12345", "float": "0.01", "int": "10", "bool": "yes"} testResourceData := testResource.TestResourceData() testResourceData.SetId("*39") testResourceData.Set("string", "string12345") + testResourceData.Set("float", 0.01) testResourceData.Set("int", 10) testResourceData.Set("bool", true) @@ -94,14 +101,14 @@ func Test_terraformResourceDataToMikrotik(t *testing.T) { func Test_mikrotikResourceDataToTerraformDatasource(t *testing.T) { testItems := []MikrotikItem{ - {"string": "string12345", "int": "10", "bool": "yes"}, - {"string": "12345string", "int": "20", "bool": "no"}, + {"string": "string12345", "float": "0.01", "int": "10", "bool": "yes"}, + {"string": "12345string", "float": "0.02", "int": "20", "bool": "no"}, } testResourceData := testDatasource.TestResourceData() expectedRes := []map[string]interface{}{ - {MetaResourcePath: "", MetaId: 0, "string": "string12345", "int": 10, "bool": true}, - {MetaResourcePath: "", MetaId: 0, "string": "12345string", "int": 20, "bool": false}, + {MetaResourcePath: "", MetaId: 0, "string": "string12345", "float": 0.01, "int": 10, "bool": true}, + {MetaResourcePath: "", MetaId: 0, "string": "12345string", "float": 0.02, "int": 20, "bool": false}, } err := MikrotikResourceDataToTerraformDatasource(&testItems, "test_name", testDatasource.Schema, testResourceData) diff --git a/routeros/provider.go b/routeros/provider.go index 98d42cef..ac16b5f6 100644 --- a/routeros/provider.go +++ b/routeros/provider.go @@ -189,6 +189,19 @@ func Provider() *schema.Provider { // Helpers "routeros_wireguard_keys": ResourceWireguardKeys(), + + // User Manager + "routeros_user_manager_advanced": ResourceUserManagerAdvanced(), + "routeros_user_manager_attribute": ResourceUserManagerAttribute(), + "routeros_user_manager_database": ResourceUserManagerDatabase(), + "routeros_user_manager_limitation": ResourceUserManagerLimitation(), + "routeros_user_manager_profile": ResourceUserManagerProfile(), + "routeros_user_manager_profile_limitation": ResourceUserManagerProfileLimitation(), + "routeros_user_manager_router": ResourceUserManagerRouter(), + "routeros_user_manager_settings": ResourceUserManagerSettings(), + "routeros_user_manager_user": ResourceUserManagerUser(), + "routeros_user_manager_user_group": ResourceUserManagerUserGroup(), + "routeros_user_manager_user_profile": ResourceUserManagerUserProfile(), }, DataSourcesMap: map[string]*schema.Resource{ "routeros_firewall": DatasourceFirewall(), diff --git a/routeros/provider_schema_helpers.go b/routeros/provider_schema_helpers.go index f4cf3861..ce84427a 100644 --- a/routeros/provider_schema_helpers.go +++ b/routeros/provider_schema_helpers.go @@ -530,6 +530,10 @@ var ( // Prevents the need of hardcode values for default values, as those are harder to track over time/versions of // routeros AlwaysPresentNotUserProvided = func(k, old, new string, d *schema.ResourceData) bool { + // For lists and sets, the key will look like `something.12345` or `something.#`. + // But in the raw config it will be just `something`. + k = strings.Split(k, ".")[0] + if old != "" && d.GetRawConfig().GetAttr(k).IsNull() { return true } diff --git a/routeros/resource_user_manager_advanced.go b/routeros/resource_user_manager_advanced.go new file mode 100644 index 00000000..613344e2 --- /dev/null +++ b/routeros/resource_user_manager_advanced.go @@ -0,0 +1,83 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +/* +{ + "paypal-allow": "false", + "paypal-currency": "USD", + "paypal-password": "", + "paypal-signature": "", + "paypal-use-sandbox": "false", + "paypal-user": "", + "web-private-password": "", + "web-private-username": "" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Advanced +func ResourceUserManagerAdvanced() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/advanced"), + MetaId: PropId(Id), + + "paypal_allow": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "An option whether to enable PayPal functionality for User Manager.", + }, + "paypal_currency": { + Type: schema.TypeString, + Optional: true, + Default: "USD", + Description: "The currency related to price setting in which users will be billed.", + }, + "paypal_password": { + Type: schema.TypeString, + Optional: true, + Description: "The password of the PayPal API account.", + }, + "paypal_signature": { + Type: schema.TypeString, + Optional: true, + Description: "The signature of the PayPal API account.", + }, + "paypal_use_sandbox": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "An option whether to use PayPal's sandbox environment for testing purposes.", + }, + "paypal_user": { + Type: schema.TypeString, + Optional: true, + Description: "The username of the PayPal API account.", + }, + "web_private_password": { + Type: schema.TypeString, + Optional: true, + Description: "The password for accessing `/um/PRIVATE/` section over HTTP.", + }, + "web_private_username": { + Type: schema.TypeString, + Optional: true, + Description: "The username for accessing `/um/PRIVATE/` section over HTTP.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultSystemCreate(resSchema), + ReadContext: DefaultSystemRead(resSchema), + UpdateContext: DefaultSystemUpdate(resSchema), + DeleteContext: DefaultSystemDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_attribute.go b/routeros/resource_user_manager_attribute.go new file mode 100644 index 00000000..2d670c78 --- /dev/null +++ b/routeros/resource_user_manager_attribute.go @@ -0,0 +1,84 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +{ + ".id": "*1", + "default": "true", + "default-name": "Framed-IP-Address", + "name": "Framed-IP-Address", + "packet-types": "access-accept", + "standard-name": "Framed-IP-Address", + "type-id": "8", + "value-type": "ip-address", + "vendor-id": "standard" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Attributes +func ResourceUserManagerAttribute() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/attribute"), + MetaId: PropId(Id), + + "default": { + Type: schema.TypeBool, + Computed: true, + }, + "default_name": { + Type: schema.TypeString, + Computed: true, + Description: "The attribute's default name.", + }, + KeyName: PropName("The attribute's name."), + "packet_types": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"access-accept", "access-challenge"}, false), + }, + Description: "A set of `access-accept` and `access-challenge`.", + DiffSuppressFunc: AlwaysPresentNotUserProvided, + }, + "standard_name": { + Type: schema.TypeString, + Computed: true, + }, + "type_id": { + Type: schema.TypeInt, + Required: true, + Description: "Attribute identification number from the specific vendor's attribute database.", + }, + "value_type": { + Type: schema.TypeString, + Optional: true, + Default: "hex", + Description: "The attribute's value type.", + ValidateFunc: validation.StringInSlice([]string{"hex", "ip-address", "ip6-prefix", "macro", "string", "uint32"}, false), + }, + "vendor_id": { + Type: schema.TypeString, + Optional: true, + Default: "standard", + Description: "IANA allocated a specific enterprise identification number.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_database.go b/routeros/resource_user_manager_database.go new file mode 100644 index 00000000..8bb73486 --- /dev/null +++ b/routeros/resource_user_manager_database.go @@ -0,0 +1,41 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +/* +{ + "db-path": "/flash/user-manager5", + "db-size": "78176", + "free-disk-space": "3248128" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Database +func ResourceUserManagerDatabase() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/database"), + MetaId: PropId(Id), + MetaSkipFields: PropSkipFields(`"db_size","free_disk_space"`), + + "db_path": { + Type: schema.TypeString, + Required: true, + Description: "Path to the location where database files will be stored.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultSystemCreate(resSchema), + ReadContext: DefaultSystemRead(resSchema), + UpdateContext: DefaultSystemUpdate(resSchema), + DeleteContext: DefaultSystemDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_limitation.go b/routeros/resource_user_manager_limitation.go new file mode 100644 index 00000000..184ef1a0 --- /dev/null +++ b/routeros/resource_user_manager_limitation.go @@ -0,0 +1,160 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +{ + ".id": "*1", + "download-limit": "0", + "name": "test", + "rate-limit-burst-rx": "0", + "rate-limit-burst-threshold-rx": "0", + "rate-limit-burst-threshold-tx": "0", + "rate-limit-burst-time-rx": "0s", + "rate-limit-burst-time-tx": "0s", + "rate-limit-burst-tx": "0", + "rate-limit-min-rx": "0", + "rate-limit-min-tx": "0", + "rate-limit-priority": "0", + "rate-limit-rx": "10", + "rate-limit-tx": "10", + "reset-counters-interval": "disabled", + "reset-counters-start-time": "1970-01-01 00:00:00", + "transfer-limit": "0", + "upload-limit": "0", + "uptime-limit": "0s" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Limitations +func ResourceUserManagerLimitation() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/limitation"), + MetaId: PropId(Id), + + "download_limit": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + Description: "The total amount of traffic a user can download in bytes.", + ValidateFunc: validation.IntAtLeast(0), + }, + KeyName: PropName("Unique name of the limitation."), + "rate_limit_burst_rx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_burst_tx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_burst_threshold_rx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_burst_threshold_tx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_burst_time_rx": { + Type: schema.TypeString, + Optional: true, + Default: "0s", + DiffSuppressFunc: TimeEquall, + }, + "rate_limit_burst_time_tx": { + Type: schema.TypeString, + Optional: true, + Default: "0s", + DiffSuppressFunc: TimeEquall, + }, + "rate_limit_min_rx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_min_tx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_priority": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_rx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "rate_limit_tx": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntAtLeast(0), + }, + "reset_counters_interval": { + Type: schema.TypeString, + Optional: true, + Default: "disabled", + Description: "The interval from `reset_counters_start_time` when all associated user statistics are cleared.", + ValidateFunc: validation.StringInSlice([]string{"disabled", "hourly", "daily", "weekly", "monthly"}, false), + }, + "reset_counters_start_time": { + Type: schema.TypeString, + Optional: true, + Default: "1970-01-01 00:00:00", + Description: "Static date and time value from which `reset_counters_interval` is calculated.", + }, + "transfer_limit": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + Description: "The total amount of aggregated (download+upload) traffic in bytes.", + ValidateFunc: validation.IntAtLeast(0), + }, + "upload_limit": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + Description: "The total amount of traffic a user can upload in bytes.", + ValidateFunc: validation.IntAtLeast(0), + }, + "uptime_limit": { + Type: schema.TypeString, + Optional: true, + Default: "0s", + Description: "The total amount of uptime a user can stay active.", + DiffSuppressFunc: TimeEquall, + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_profile.go b/routeros/resource_user_manager_profile.go new file mode 100644 index 00000000..5a39adc1 --- /dev/null +++ b/routeros/resource_user_manager_profile.go @@ -0,0 +1,73 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +{ + ".id": "*1", + "name": "test", + "name-for-users": "test", + "override-shared-users": "off", + "price": "0", + "starts-when": "assigned", + "validity": "unlimited" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Profiles +func ResourceUserManagerProfile() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/profile"), + MetaId: PropId(Id), + + KeyName: PropName("Unique name of the profile."), + "name_for_users": { + Type: schema.TypeString, + Optional: true, + Description: "The name that will be shown to users in the web interface.", + DiffSuppressFunc: AlwaysPresentNotUserProvided, + }, + "override_shared_users": { + Type: schema.TypeString, + Optional: true, + Default: "off", + Description: "An option whether to allow multiple sessions with the same user name.", + }, + "price": { + Type: schema.TypeFloat, + Optional: true, + Default: .0, + Description: "The price of the profile.", + ValidateFunc: validation.FloatAtLeast(.0), + }, + "starts_when": { + Type: schema.TypeString, + Optional: true, + Default: "assigned", + Description: "The time when the profile becomes active (`assigned` - immediately when the profile entry is created, `first-auth` - upon first authentication request).", + ValidateFunc: validation.StringInSlice([]string{"assigned", "first-auth"}, false), + }, + "validity": { + Type: schema.TypeString, + Optional: true, + Default: "unlimited", + Description: "The total amount of time a user can use this profile.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_profile_limitation.go b/routeros/resource_user_manager_profile_limitation.go new file mode 100644 index 00000000..ec1f9afb --- /dev/null +++ b/routeros/resource_user_manager_profile_limitation.go @@ -0,0 +1,73 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +{ + ".id": "*1", + "from-time": "0s", + "limitation": "test", + "profile": "test", + "till-time": "23h59m59s", + "weekdays": "sunday,monday,tuesday,wednesday,thursday,friday,saturday" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-ProfileLimitations +func ResourceUserManagerProfileLimitation() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/profile-limitation"), + MetaId: PropId(Id), + + "from_time": { + Type: schema.TypeString, + Optional: true, + Default: "0s", + Description: "Time of the day when the limitation should take place.", + DiffSuppressFunc: TimeEquall, + }, + "limitation": { + Type: schema.TypeString, + Required: true, + Description: "The limitation name.", + }, + "profile": { + Type: schema.TypeString, + Required: true, + Description: "The profile name.", + }, + "till_time": { + Type: schema.TypeString, + Optional: true, + Default: "23h59m59s", + Description: "Time of the day when the limitation should end.", + DiffSuppressFunc: TimeEquall, + }, + "weekdays": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"}, false), + }, + Description: "Days of the week when the limitation is active.", + DiffSuppressFunc: AlwaysPresentNotUserProvided, + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_router.go b/routeros/resource_user_manager_router.go new file mode 100644 index 00000000..f8710175 --- /dev/null +++ b/routeros/resource_user_manager_router.go @@ -0,0 +1,60 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +{ + ".id": "*1", + "address": "127.0.0.1", + "coa-port": "3799", + "disabled": "false", + "name": "test", + "shared-secret": "password" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Routers +func ResourceUserManagerRouter() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/router"), + MetaId: PropId(Id), + + "address": { + Type: schema.TypeString, + Required: true, + Description: "IP address of the RADIUS client.", + ValidateFunc: validation.IsIPAddress, + }, + "coa_port": { + Type: schema.TypeInt, + Optional: true, + Default: 3799, + Description: "Port number of CoA (Change of Authorization) communication.", + ValidateFunc: validation.IntBetween(0, 65535), + }, + KeyDisabled: PropDisabledRw, + KeyName: PropName("Unique name of the RADIUS client."), + "shared_secret": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "The shared secret to secure communication.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_settings.go b/routeros/resource_user_manager_settings.go new file mode 100644 index 00000000..f84ced5c --- /dev/null +++ b/routeros/resource_user_manager_settings.go @@ -0,0 +1,70 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +{ + "accounting-port": "1813", + "authentication-port": "1812", + "certificate": "*0", + "enabled": "true", + "use-profiles": "false" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Settings +func ResourceUserManagerSettings() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager"), + MetaId: PropId(Id), + + "accounting_port": { + Type: schema.TypeInt, + Optional: true, + Default: 1813, + Description: "Port to listen for RADIUS accounting requests.", + ValidateFunc: validation.IntBetween(1, 65535), + }, + "authentication_port": { + Type: schema.TypeInt, + Optional: true, + Default: 1812, + Description: "Port to listen for RADIUS authentication requests.", + ValidateFunc: validation.IntBetween(1, 65535), + }, + "certificate": { + Type: schema.TypeString, + Optional: true, + Default: "none", + Description: "Certificate for use in EAP TLS-type authentication methods.", + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "An option whether the User Manager functionality is enabled.", + }, + "use_profiles": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "An option whether to use Profiles and Limitations. When set to `false`, only User configuration is required to run User Manager.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultSystemCreate(resSchema), + ReadContext: DefaultSystemRead(resSchema), + UpdateContext: DefaultSystemUpdate(resSchema), + DeleteContext: DefaultSystemDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_user.go b/routeros/resource_user_manager_user.go new file mode 100644 index 00000000..4008135f --- /dev/null +++ b/routeros/resource_user_manager_user.go @@ -0,0 +1,78 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +/* +{ + ".id": "*1", + "attributes": "", + "caller-id": "bind", + "comment": "test", + "disabled": "false", + "group": "test", + "name": "test", + "otp-secret": "", + "password": "password", + "shared-users": "1" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-Users +func ResourceUserManagerUser() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/user"), + MetaId: PropId(Id), + + "attributes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "A custom set of colon-separated attributes with their values will be added to `Access-Accept` messages for users in this group.", + }, + "caller_id": { + Type: schema.TypeString, + Optional: true, + Description: "Allow user's authentication with a specific Calling-Station-Id value.", + }, + KeyComment: PropCommentRw, + KeyDisabled: PropDisabledRw, + "group": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the group the user is associated with.", + DiffSuppressFunc: AlwaysPresentNotUserProvided, + }, + KeyName: PropName("Username for session authentication."), + "otp_secret": { + Type: schema.TypeString, + Optional: true, + Description: "A token of a one-time code that will be attached to the password.", + }, + "password": { + Type: schema.TypeString, + Optional: true, + Description: "The password of the user for session authentication.", + }, + "shared_users": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + Description: "The total amount of sessions the user can simultaneously establish.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_user_group.go b/routeros/resource_user_manager_user_group.go new file mode 100644 index 00000000..fb2ecd27 --- /dev/null +++ b/routeros/resource_user_manager_user_group.go @@ -0,0 +1,74 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +/* +{ + ".id": "*1", + "attributes": "Mikrotik-Wireless-Comment:Test Group,Mikrotik-Wireless-VLANID:100", + "default": "false", + "default-name": "", + "inner-auths": "ttls-pap,ttls-chap,ttls-mschap1,ttls-mschap2,peap-mschap2", + "name": "test", + "outer-auths": "pap,chap,mschap1,mschap2,eap-tls,eap-ttls,eap-peap,eap-mschap2" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-UserGroups +func ResourceUserManagerUserGroup() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/user/group"), + MetaId: PropId(Id), + + "attributes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "A custom set of colon-separated attributes with their values will be added to `Access-Accept` messages for users in this group.", + }, + "default": { + Type: schema.TypeBool, + Computed: true, + }, + "default_name": { + Type: schema.TypeString, + Computed: true, + Description: "The default name of the group.", + }, + "inner_auths": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"ttls-pap", "ttls-chap", "ttls-mschap1", "ttls-mschap2", "peap-mschap2"}, false), + }, + Description: "A set of allowed authentication methods for tunneled authentication methods (`ttls-pap`, `ttls-chap`, `ttls-mschap1`, `ttls-mschap2`, `peap-mschap2`).", + }, + KeyName: PropName("Unique name of the group."), + "outer_auths": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"pap", "chap", "mschap1", "mschap2", "eap-tls", "eap-ttls", "eap-peap", "eap-mschap2"}, false), + }, + Description: "A set of allowed authentication methods (`pap`, `chap`, `mschap1`, `mschap2`, `eap-tls`, `eap-ttls`, `eap-peap`, `eap-mschap2`).", + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +} diff --git a/routeros/resource_user_manager_user_profile.go b/routeros/resource_user_manager_user_profile.go new file mode 100644 index 00000000..8c61d55e --- /dev/null +++ b/routeros/resource_user_manager_user_profile.go @@ -0,0 +1,48 @@ +package routeros + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +/* +{ + ".id": "*1", + "end-time": "unlimited", + "profile": "test", + "state": "running", + "user": "test" +} +*/ + +// https://help.mikrotik.com/docs/display/ROS/User+Manager#UserManager-UserProfiles +func ResourceUserManagerUserProfile() *schema.Resource { + resSchema := map[string]*schema.Schema{ + MetaResourcePath: PropResourcePath("/user-manager/user-profile"), + MetaId: PropId(Id), + MetaSkipFields: PropSkipFields(`"end_time","state"`), + + "profile": { + Type: schema.TypeString, + Required: true, + Description: "Name of the profile to assign to the user.", + }, + "user": { + Type: schema.TypeString, + Required: true, + Description: "Name of the user to use the specified profile.", + }, + } + + return &schema.Resource{ + CreateContext: DefaultCreate(resSchema), + ReadContext: DefaultRead(resSchema), + UpdateContext: DefaultUpdate(resSchema), + DeleteContext: DefaultDelete(resSchema), + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: resSchema, + } +}