Skip to content

Commit

Permalink
feat: Support for ip/services (#195)
Browse files Browse the repository at this point in the history
* feat: Support for ip/services (#182)

* fix: Fix examples, broken tests, non-empty plan
  • Loading branch information
vaerh committed May 1, 2023
1 parent f413b88 commit 591096d
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 0 deletions.
3 changes: 3 additions & 0 deletions examples/resources/routeros_ip_service/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#The ID can be found via API or the terminal
#The command for the terminal is -> :put [/ip/service get [print show-ids]]
terraform import routeros_ip_service.www_ssl www-ssl
40 changes: 40 additions & 0 deletions examples/resources/routeros_ip_service/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
locals {
tls_service = {"api-ssl" = 8729, "www-ssl" = 443}
disable_service = {"api" = 8728, "ftp" = 21, "telnet" = 23, "www" = 80}
enable_service = {"ssh" = 22, "winbox" = 8291}
}

resource "routeros_system_certificate" "tls_cert" {
name = "tls-cert"
common_name = "Mikrotik Router"
days_valid = 3650
key_usage = ["key-cert-sign", "crl-sign", "digital-signature", "key-agreement", "tls-server"]
key_size = "prime256v1"
sign {
}
}

# terraform state rm 'routeros_ip_service.tls["www-ssl"]'
# terraform import 'routeros_ip_service.tls["www-ssl"]' www-ssl
resource "routeros_ip_service" "tls" {
for_each = local.tls_service
numbers = each.key
port = each.value
certificate = routeros_system_certificate.tls_cert.name
tls_version = "only-1.2"
disabled = false
}

resource "routeros_ip_service" "disabled" {
for_each = local.disable_service
numbers = each.key
port = each.value
disabled = true
}

resource "routeros_ip_service" "enabled" {
for_each = local.enable_service
numbers = each.key
port = each.value
disabled = false
}
1 change: 1 addition & 0 deletions routeros/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func Provider() *schema.Provider {
"routeros_ip_route": ResourceIPRoute(),
"routeros_ip_dns": ResourceDns(),
"routeros_ip_dns_record": ResourceDnsRecord(),
"routeros_ip_service": ResourceIpService(),
"routeros_ipv6_address": ResourceIPv6Address(),
"routeros_ipv6_firewall_filter": ResourceIPv6FirewallFilter(),
"routeros_ipv6_route": ResourceIPv6Route(),
Expand Down
125 changes: 125 additions & 0 deletions routeros/resource_ip_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package routeros

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

/*
{
".id": "*0",
"address": "",
"disabled": "false",
"invalid": "false",
"name": "telnet",
"port": "23",
"vrf": "main"
},
{
".id": "*6",
"address": "",
"certificate": "https-cert",
"disabled": "false",
"invalid": "false",
"name": "www-ssl",
"port": "443",
"tls-version": "any",
"vrf": "main"
},
*/

// https://help.mikrotik.com/docs/display/ROS/Services
func ResourceIpService() *schema.Resource {
resSchema := map[string]*schema.Schema{
MetaResourcePath: PropResourcePath("/ip/service"),
MetaId: PropId(Name),

"address": {
Type: schema.TypeString,
Optional: true,
Default: "",
Description: "List of IP/IPv6 prefixes from which the service is accessible.",
DiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool {
if oldValue == "" && newValue == "0.0.0.0/0" {
return false
}
return oldValue == newValue
},
},
"certificate": {
Type: schema.TypeString,
Optional: true,
Description: "The name of the certificate used by a particular service. Applicable only for services " +
"that depend on certificates ( www-ssl, api-ssl ).",
},
KeyDisabled: PropDisabledRw,
KeyInvalid: PropInvalidRo,
"name": {
Type: schema.TypeString,
Computed: true,
Description: "Service name.",
},
"numbers": {
Type: schema.TypeString,
Required: true,
Description: "The name of the service whose settings will be changed ( api, api-ssl, ftp, ssh, telnet, " +
"winbox, www, www-ssl ).",
ValidateDiagFunc: ValidationMultiValInSlice([]string{"api", "api-ssl", "ftp", "ssh", "telnet", "winbox",
"www", "www-ssl"}, false, false),
},
"port": {
Type: schema.TypeInt,
Required: true,
Description: "The port particular service listens on.",
ValidateFunc: validation.IntBetween(1, 65535),
},
"tls_version": {
Type: schema.TypeString,
Optional: true,
Description: "Specifies which TLS versions to allow by a particular service.",
ValidateFunc: validation.StringInSlice([]string{"any", "only-1.2"}, false),
},
"vrf": {
Type: schema.TypeString,
Optional: true,
Default: "main",
Description: "Specify which VRF instance to use by a particular service.",
},
}

resCreateUpdate := func(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
item, metadata := TerraformResourceDataToMikrotik(resSchema, d)

d.SetId(d.Get("numbers").(string))

var resUrl string
if m.(Client).GetTransport() == TransportREST {
// https://router/rest/system/identity/set
// https://router/rest/caps-man/manager/set
resUrl = "/set"
}

err := m.(Client).SendRequest(crudPost, &URL{Path: metadata.Path + resUrl}, item, nil)
if err != nil {
return diag.FromErr(err)
}

return ResourceRead(ctx, resSchema, d, m)
}

return &schema.Resource{
CreateContext: resCreateUpdate,
ReadContext: DefaultRead(resSchema),
UpdateContext: resCreateUpdate,
DeleteContext: DefaultSystemDelete(resSchema),

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: resSchema,
}
}
60 changes: 60 additions & 0 deletions routeros/resource_ip_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package routeros

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)

const testIpServiceAddress = "routeros_ip_service.telnet"

func TestAccIpServiceTest_basic(t *testing.T) {
for _, name := range testNames {
t.Run(name, func(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testSetTransportEnv(t, name)
},
ProviderFactories: testAccProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccIpServiceConfig(),
Check: resource.ComposeTestCheckFunc(
testAccCheckIpServiceExists(testIpServiceAddress),
resource.TestCheckResourceAttr(testIpServiceAddress, "name", "telnet"),
),
},
},
})
})
}
}

func testAccCheckIpServiceExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("not found: %s", name)
}

if rs.Primary.ID == "" {
return fmt.Errorf("no id is set")
}

return nil
}
}

func testAccIpServiceConfig() string {
return providerConfig + `
resource "routeros_ip_service" "telnet" {
numbers = "telnet"
disabled = true
port = 23
}
`
}

0 comments on commit 591096d

Please sign in to comment.