diff --git a/docs/data-sources/tenancy_contact_role.md b/docs/data-sources/tenancy_contact_role.md new file mode 100644 index 000000000..db18755ed --- /dev/null +++ b/docs/data-sources/tenancy_contact_role.md @@ -0,0 +1,21 @@ +# netbox\_tenancy\_contact\_role Data Source + +Get info about tenancy contact roles from netbox. + +## Example Usage + +```hcl +data "netbox_tenancy_contact_role" "contact_role_test" { + slug = "TestContactGroup" +} +``` + +## Argument Reference + +The following arguments are supported: +* ``slug`` - (Required) The slug of the tenancy contact roles. + +## Attributes Reference + +In addition to the above arguments, the following attributes are exported: +* ``id`` - The id (ref in Netbox) of this object. diff --git a/docs/resources/tenancy_contact_role.md b/docs/resources/tenancy_contact_role.md new file mode 100644 index 000000000..2a5edcbc8 --- /dev/null +++ b/docs/resources/tenancy_contact_role.md @@ -0,0 +1,89 @@ +# netbox\_tenancy\_contact\_role Resource + +Manage a contact role within Netbox. + +## Example Usage + +```hcl +resource "netbox_tenancy_contact_role" "contact_role_test" { + description = "Contact role created by terraform" + name = "TestContactRole" + slug = "TestContactRole" + + tag { + name = "tag1" + slug = "tag1" + } + + custom_field { + name = "cf_boolean" + type = "boolean" + value = "true" + } + + custom_field { + name = "cf_date" + type = "date" + value = "2020-12-25" + } + + custom_field { + name = "cf_text" + type = "text" + value = "some text" + } + + custom_field { + name = "cf_integer" + type = "integer" + value = "10" + } + + custom_field { + name = "cf_selection" + type = "selection" + value = "1" + } + + custom_field { + name = "cf_url" + type = "url" + value = "https://github.com" + } + + custom_field { + name = "cf_multiple_selection" + type = "multiple" + value = "0,1" + } +} +``` + +## Argument Reference + +The following arguments are supported: +* ``description`` - (Optional) Description for this object. +* ``name`` - (Required) The name for this object. +* ``slug`` - (Required) The slug for this object. + +The ``custom_field`` block (optional) supports: +* ``name`` - (Required) Name of the existing custom resource to associate with this resource. +* ``type`` - (Required) Type of the existing custom resource to associate with this resource (text, integer, boolean, url, selection, multiple). +* ``value`` - (Required) Value of the existing custom resource to associate with this resource. + +The ``tag`` block (optional) supports: +* ``name`` - (Required) Name of the existing tag to associate with this resource. +* ``slug`` - (Required) Slug of the existing tag to associate with this resource. + +## Attributes Reference + +In addition to the above arguments, the following attributes are exported: +* ``id`` - The id (ref in Netbox) of this object. + +## Import + +Contact roles can be imported by `id` e.g. + +``` +$ terraform import netbox_tenancy_contact_role.contact_role_test id +``` diff --git a/examples/main.tf b/examples/main.tf index 5011ac868..58c03320b 100644 --- a/examples/main.tf +++ b/examples/main.tf @@ -600,3 +600,61 @@ resource "netbox_tenancy_contact_group" "contact_group_02" { description = "Another contact group" parent_id = netbox_tenancy_contact_group.contact_group_01.id } + +resource "netbox_tenancy_contact_role" "contact_role_01" { + name = "A contact role" + slug = "cr01" + description = "A contact role" + + tag { + name = "tag1" + slug = "tag1" + } + + tag { + name = "tag2" + slug = "tag2" + } + + custom_field { + name = "cf_boolean" + type = "boolean" + value = "true" + } + + custom_field { + name = "cf_date" + type = "date" + value = "2020-12-25" + } + + custom_field { + name = "cf_text" + type = "text" + value = "some text" + } + + custom_field { + name = "cf_integer" + type = "integer" + value = "10" + } + + custom_field { + name = "cf_selection" + type = "selection" + value = "1" + } + + custom_field { + name = "cf_url" + type = "url" + value = "https://github.com" + } + + custom_field { + name = "cf_multiple_selection" + type = "multiple" + value = "0,1" + } +} diff --git a/netbox/data_netbox_tenancy_tenant_role.go b/netbox/data_netbox_tenancy_tenant_role.go new file mode 100644 index 000000000..214ec5d7c --- /dev/null +++ b/netbox/data_netbox_tenancy_tenant_role.go @@ -0,0 +1,55 @@ +package netbox + +import ( + "fmt" + "regexp" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + netboxclient "github.com/smutel/go-netbox/netbox/client" + "github.com/smutel/go-netbox/netbox/client/tenancy" +) + +func dataNetboxTenancyContactRole() *schema.Resource { + return &schema.Resource{ + Read: dataNetboxTenancyContactRoleRead, + + Schema: map[string]*schema.Schema{ + "slug": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^[-a-zA-Z0-9_]{1,50}$"), + "Must be like ^[-a-zA-Z0-9_]{1,50}$"), + }, + }, + } +} + +func dataNetboxTenancyContactRoleRead(d *schema.ResourceData, + m interface{}) error { + + client := m.(*netboxclient.NetBoxAPI) + + slug := d.Get("slug").(string) + + p := tenancy.NewTenancyContactRolesListParams().WithSlug(&slug) + + list, err := client.Tenancy.TenancyContactRolesList(p, nil) + if err != nil { + return err + } + + if *list.Payload.Count < 1 { + return fmt.Errorf("Your query returned no results. " + + "Please change your search criteria and try again.") + } else if *list.Payload.Count > 1 { + return fmt.Errorf("Your query returned more than one result. " + + "Please try a more specific search criteria.") + } + + d.SetId(strconv.FormatInt(list.Payload.Results[0].ID, 10)) + + return nil +} diff --git a/netbox/provider.go b/netbox/provider.go index 205211ae0..d8c003316 100644 --- a/netbox/provider.go +++ b/netbox/provider.go @@ -131,6 +131,7 @@ func Provider() *schema.Provider { "netbox_ipam_vlan_group": dataNetboxIpamVlanGroup(), "netbox_tenancy_contact": dataNetboxTenancyContact(), "netbox_tenancy_contact_group": dataNetboxTenancyContactGroup(), + "netbox_tenancy_contact_role": dataNetboxTenancyContactRole(), "netbox_tenancy_tenant": dataNetboxTenancyTenant(), "netbox_tenancy_tenant_group": dataNetboxTenancyTenantGroup(), "netbox_virtualization_cluster": dataNetboxVirtualizationCluster(), @@ -144,6 +145,7 @@ func Provider() *schema.Provider { "netbox_ipam_vlan_group": resourceNetboxIpamVlanGroup(), "netbox_tenancy_contact": resourceNetboxTenancyContact(), "netbox_tenancy_contact_group": resourceNetboxTenancyContactGroup(), + "netbox_tenancy_contact_role": resourceNetboxTenancyContactRole(), "netbox_tenancy_tenant": resourceNetboxTenancyTenant(), "netbox_tenancy_tenant_group": resourceNetboxTenancyTenantGroup(), "netbox_virtualization_interface": resourceNetboxVirtualizationInterface(), diff --git a/netbox/resource_netbox_tenancy_contact_role.go b/netbox/resource_netbox_tenancy_contact_role.go new file mode 100644 index 000000000..e2c0abb7f --- /dev/null +++ b/netbox/resource_netbox_tenancy_contact_role.go @@ -0,0 +1,261 @@ +package netbox + +import ( + "fmt" + "regexp" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + netboxclient "github.com/smutel/go-netbox/netbox/client" + "github.com/smutel/go-netbox/netbox/client/tenancy" + "github.com/smutel/go-netbox/netbox/models" +) + +func resourceNetboxTenancyContactRole() *schema.Resource { + return &schema.Resource{ + Create: resourceNetboxTenancyContactRoleCreate, + Read: resourceNetboxTenancyContactRoleRead, + Update: resourceNetboxTenancyContactRoleUpdate, + Delete: resourceNetboxTenancyContactRoleDelete, + Exists: resourceNetboxTenancyContactRoleExists, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "custom_field": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"text", "integer", "boolean", + "date", "url", "selection", "multiple"}, false), + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Default: nil, + ValidateFunc: validation.StringLenBetween(1, 100), + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), + }, + "slug": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch( + regexp.MustCompile("^[-a-zA-Z0-9_]{1,50}$"), + "Must be like ^[-a-zA-Z0-9_]{1,50}$"), + }, + "tag": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "slug": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } +} + +func resourceNetboxTenancyContactRoleCreate(d *schema.ResourceData, + m interface{}) error { + client := m.(*netboxclient.NetBoxAPI) + + resourceCustomFields := d.Get("custom_field").(*schema.Set).List() + customFields := convertCustomFieldsFromTerraformToAPI(nil, resourceCustomFields) + description := d.Get("description").(string) + name := d.Get("name").(string) + slug := d.Get("slug").(string) + tags := d.Get("tag").(*schema.Set).List() + + newResource := &models.ContactRole{ + CustomFields: &customFields, + Description: description, + Name: &name, + Slug: &slug, + Tags: convertTagsToNestedTags(tags), + } + + resource := tenancy.NewTenancyContactRolesCreateParams().WithData(newResource) + + resourceCreated, err := client.Tenancy.TenancyContactRolesCreate(resource, nil) + if err != nil { + return err + } + + d.SetId(strconv.FormatInt(resourceCreated.Payload.ID, 10)) + + return resourceNetboxTenancyContactRoleRead(d, m) +} + +func resourceNetboxTenancyContactRoleRead(d *schema.ResourceData, + m interface{}) error { + client := m.(*netboxclient.NetBoxAPI) + + resourceID := d.Id() + params := tenancy.NewTenancyContactRolesListParams().WithID(&resourceID) + resources, err := client.Tenancy.TenancyContactRolesList(params, nil) + if err != nil { + return err + } + + for _, resource := range resources.Payload.Results { + if strconv.FormatInt(resource.ID, 10) == d.Id() { + resourceCustomFields := d.Get("custom_field").(*schema.Set).List() + customFields := updateCustomFieldsFromAPI(resourceCustomFields, resource.CustomFields) + + if err = d.Set("custom_field", customFields); err != nil { + return err + } + + var description interface{} + if resource.Description == "" { + description = nil + } else { + description = resource.Description + } + + if err = d.Set("description", description); err != nil { + return err + } + + if err = d.Set("name", resource.Name); err != nil { + return err + } + + if err = d.Set("slug", resource.Slug); err != nil { + return err + } + + if err = d.Set("tag", convertNestedTagsToTags(resource.Tags)); err != nil { + return err + } + + return nil + } + } + + d.SetId("") + return nil +} + +func resourceNetboxTenancyContactRoleUpdate(d *schema.ResourceData, + m interface{}) error { + client := m.(*netboxclient.NetBoxAPI) + params := &models.ContactRole{} + + // Required parameters + name := d.Get("name").(string) + params.Name = &name + + slug := d.Get("slug").(string) + params.Slug = &slug + + if d.HasChange("custom_field") { + stateCustomFields, resourceCustomFields := d.GetChange("custom_field") + customFields := convertCustomFieldsFromTerraformToAPI(stateCustomFields.(*schema.Set).List(), resourceCustomFields.(*schema.Set).List()) + params.CustomFields = &customFields + } + + if d.HasChange("description") { + if description, exist := d.GetOk("description"); exist { + params.Description = description.(string) + } else { + params.Description = " " + } + } + + tags := d.Get("tag").(*schema.Set).List() + params.Tags = convertTagsToNestedTags(tags) + + resource := tenancy.NewTenancyContactRolesPartialUpdateParams().WithData(params) + + resourceID, err := strconv.ParseInt(d.Id(), 10, 64) + if err != nil { + return fmt.Errorf("Unable to convert ID into int64") + } + + resource.SetID(resourceID) + + _, err = client.Tenancy.TenancyContactRolesPartialUpdate(resource, nil) + if err != nil { + return err + } + + return resourceNetboxTenancyContactRoleRead(d, m) +} + +func resourceNetboxTenancyContactRoleDelete(d *schema.ResourceData, + m interface{}) error { + client := m.(*netboxclient.NetBoxAPI) + + resourceExists, err := resourceNetboxTenancyContactRoleExists(d, m) + if err != nil { + return err + } + + if !resourceExists { + return nil + } + + id, err := strconv.ParseInt(d.Id(), 10, 64) + if err != nil { + return fmt.Errorf("Unable to convert ID into int64") + } + + p := tenancy.NewTenancyContactRolesDeleteParams().WithID(id) + if _, err := client.Tenancy.TenancyContactRolesDelete(p, nil); err != nil { + return err + } + + return nil +} + +func resourceNetboxTenancyContactRoleExists(d *schema.ResourceData, + m interface{}) (b bool, + e error) { + client := m.(*netboxclient.NetBoxAPI) + resourceExist := false + + resourceID := d.Id() + params := tenancy.NewTenancyContactRolesListParams().WithID(&resourceID) + resources, err := client.Tenancy.TenancyContactRolesList(params, nil) + if err != nil { + return resourceExist, err + } + + for _, resource := range resources.Payload.Results { + if strconv.FormatInt(resource.ID, 10) == d.Id() { + resourceExist = true + } + } + + return resourceExist, nil +}