From 49a3ea73337aa6b31f4aa0f8633dad38b7998890 Mon Sep 17 00:00:00 2001 From: anita-1372 Date: Mon, 20 May 2024 12:41:06 +0530 Subject: [PATCH 1/6] cron and its threshold support in terraform --- api/constants.go | 1 + api/endpoints/fake/cron_monitors.go | 60 +++++ api/endpoints/monitors/cron_impl.go | 103 ++++++++ api/endpoints/monitors/cron_impl_test.go | 152 ++++++++++++ api/monitor_types.go | 53 ++++ api/types.go | 9 + docs/resources/cron_monitor.md | 135 ++++++++++ examples/cron_monitor_us.tf | 144 +++++++++++ fake/client.go | 7 + provider/provider.go | 1 + site24x7/client.go | 6 + site24x7/monitors/cron.go | 286 ++++++++++++++++++++++ site24x7/monitors/cron_test.go | 257 +++++++++++++++++++ site24x7/threshold_profile.go | 59 +++++ site24x7/threshold_profile_data_source.go | 17 ++ 15 files changed, 1290 insertions(+) create mode 100644 api/endpoints/fake/cron_monitors.go create mode 100644 api/endpoints/monitors/cron_impl.go create mode 100644 api/endpoints/monitors/cron_impl_test.go create mode 100644 docs/resources/cron_monitor.md create mode 100644 examples/cron_monitor_us.tf create mode 100644 site24x7/monitors/cron.go create mode 100644 site24x7/monitors/cron_test.go diff --git a/api/constants.go b/api/constants.go index d1771fa..6c3c37e 100644 --- a/api/constants.go +++ b/api/constants.go @@ -24,6 +24,7 @@ const ( RESTAPISEQ MonitorType = "RESTAPISEQ" AMAZON MonitorType = "AMAZON" SERVER MonitorType = "SERVER" + CRON MonitorType = "CRON" HEARTBEAT MonitorType = "HEARTBEAT" DNS MonitorType = "DNS" DOMAINEXPIRY MonitorType = "DOMAINEXPIRY" diff --git a/api/endpoints/fake/cron_monitors.go b/api/endpoints/fake/cron_monitors.go new file mode 100644 index 0000000..884a795 --- /dev/null +++ b/api/endpoints/fake/cron_monitors.go @@ -0,0 +1,60 @@ +package fake + +import ( + "github.com/site24x7/terraform-provider-site24x7/api" + "github.com/site24x7/terraform-provider-site24x7/api/endpoints/monitors" + "github.com/stretchr/testify/mock" +) + +var _ monitors.CronMonitors = &CronMonitors{} + +type CronMonitors struct { + mock.Mock +} + +func (e *CronMonitors) Get(monitorID string) (*api.CronMonitor, error) { + args := e.Called(monitorID) + if obj, ok := args.Get(0).(*api.CronMonitor); ok { + return obj, args.Error(1) + } + return nil, args.Error(1) +} + +func (e *CronMonitors) Create(monitor *api.CronMonitor) (*api.CronMonitor, error) { + args := e.Called(monitor) + if obj, ok := args.Get(0).(*api.CronMonitor); ok { + return obj, args.Error(1) + } + return nil, args.Error(1) +} + +func (e *CronMonitors) Update(monitor *api.CronMonitor) (*api.CronMonitor, error) { + args := e.Called(monitor) + if obj, ok := args.Get(0).(*api.CronMonitor); ok { + return obj, args.Error(1) + } + return nil, args.Error(1) +} + +func (e *CronMonitors) Delete(monitorID string) error { + args := e.Called(monitorID) + return args.Error(0) +} + +func (e *CronMonitors) List() ([]*api.CronMonitor, error) { + args := e.Called() + if obj, ok := args.Get(0).([]*api.CronMonitor); ok { + return obj, args.Error(1) + } + return nil, args.Error(1) +} + +func (e *CronMonitors) Activate(monitorID string) error { + args := e.Called(monitorID) + return args.Error(0) +} + +func (e *CronMonitors) Suspend(monitorID string) error { + args := e.Called(monitorID) + return args.Error(0) +} diff --git a/api/endpoints/monitors/cron_impl.go b/api/endpoints/monitors/cron_impl.go new file mode 100644 index 0000000..2f950c7 --- /dev/null +++ b/api/endpoints/monitors/cron_impl.go @@ -0,0 +1,103 @@ +package monitors + +import ( + "github.com/site24x7/terraform-provider-site24x7/api" + "github.com/site24x7/terraform-provider-site24x7/rest" +) + +type CronMonitors interface { + Get(monitorID string) (*api.CronMonitor, error) + Create(monitor *api.CronMonitor) (*api.CronMonitor, error) + Update(monitor *api.CronMonitor) (*api.CronMonitor, error) + Delete(monitorID string) error + List() ([]*api.CronMonitor, error) + Activate(monitorID string) error + Suspend(monitorID string) error +} + +type cronMonitors struct { + client rest.Client +} + +func NewCronMonitors(client rest.Client) CronMonitors { + return &cronMonitors{ + client: client, + } +} + +func (c *cronMonitors) Get(monitorID string) (*api.CronMonitor, error) { + monitor := &api.CronMonitor{} + err := c.client. + Get(). + Resource("monitors"). + ResourceID(monitorID). + Do(). + Parse(monitor) + + return monitor, err +} + +func (c *cronMonitors) Create(monitor *api.CronMonitor) (*api.CronMonitor, error) { + newMonitor := &api.CronMonitor{} + err := c.client. + Post(). + Resource("monitors"). + AddHeader("Content-Type", "application/json;charset=UTF-8"). + Body(monitor). + Do(). + Parse(newMonitor) + + return newMonitor, err +} + +func (c *cronMonitors) Update(monitor *api.CronMonitor) (*api.CronMonitor, error) { + updatedMonitor := &api.CronMonitor{} + err := c.client. + Put(). + Resource("monitors"). + ResourceID(monitor.MonitorID). + AddHeader("Content-Type", "application/json;charset=UTF-8"). + Body(monitor). + Do(). + Parse(updatedMonitor) + + return updatedMonitor, err +} + +func (c *cronMonitors) Delete(monitorID string) error { + return c.client. + Delete(). + Resource("monitors"). + ResourceID(monitorID). + Do(). + Err() +} + +func (c *cronMonitors) List() ([]*api.CronMonitor, error) { + cronMonitors := []*api.CronMonitor{} + err := c.client. + Get(). + Resource("monitors"). + Do(). + Parse(&cronMonitors) + + return cronMonitors, err +} + +func (c *cronMonitors) Activate(monitorID string) error { + return c.client. + Put(). + Resource("monitors/activate"). + ResourceID(monitorID). + Do(). + Err() +} + +func (c *cronMonitors) Suspend(monitorID string) error { + return c.client. + Put(). + Resource("monitors/suspend"). + ResourceID(monitorID). + Do(). + Err() +} diff --git a/api/endpoints/monitors/cron_impl_test.go b/api/endpoints/monitors/cron_impl_test.go new file mode 100644 index 0000000..3a86311 --- /dev/null +++ b/api/endpoints/monitors/cron_impl_test.go @@ -0,0 +1,152 @@ +package monitors + +import ( + "testing" + + "github.com/site24x7/terraform-provider-site24x7/api" + "github.com/site24x7/terraform-provider-site24x7/rest" + "github.com/site24x7/terraform-provider-site24x7/validation" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCronMonitors(t *testing.T) { + validation.RunTests(t, []*validation.EndpointTest{ + { + Name: "create cron monitor", + ExpectedVerb: "POST", + ExpectedPath: "/monitors", + ExpectedBody: validation.Fixture(t, "requests/create_cron_monitor.json"), + StatusCode: 200, + ResponseBody: validation.JsonAPIResponseBody(t, nil), + Fn: func(t *testing.T, c rest.Client) { + cronMonitor := &api.CronMonitor{ + DisplayName: "foo", + CronExpression: "* * * * *", + CronTz: "IST", + WaitTime: 30, + Type: "CRON", + ThresholdProfileID: "012", + NotificationProfileID: "789", + MonitorGroups: []string{"234", "567"}, + UserGroupIDs: []string{"123", "456"}, + TagIDs: []string{"123"}, + ThirdPartyServiceIDs: []string{"123", "456"}, + OnCallScheduleID: "1244", + } + + _, err := NewCronMonitors(c).Create(cronMonitor) + require.NoError(t, err) + }, + }, + { + Name: "get cron monitor", + ExpectedVerb: "GET", + ExpectedPath: "/monitors/897654345678", + StatusCode: 200, + ResponseBody: validation.Fixture(t, "responses/get_cron_monitor.json"), + Fn: func(t *testing.T, c rest.Client) { + cronMonitor, err := NewCronMonitors(c).Get("897654345678") + require.NoError(t, err) + + expected := &api.CronMonitor{ + MonitorID: "897654345678", + DisplayName: "foo", + CronExpression: "* * * * *", + CronTz: "IST", + WaitTime: 30, + Type: "CRON", + ThresholdProfileID: "012", + NotificationProfileID: "789", + MonitorGroups: []string{"234", "567"}, + UserGroupIDs: []string{"123", "456"}, + ThirdPartyServiceIDs: []string{"123", "456"}, + OnCallScheduleID: "1244", + } + + assert.Equal(t, expected, cronMonitor) + }, + }, + { + Name: "list cron monitors", + ExpectedVerb: "GET", + ExpectedPath: "/monitors", + StatusCode: 200, + ResponseBody: validation.Fixture(t, "responses/list_cron_monitors.json"), + Fn: func(t *testing.T, c rest.Client) { + cronMonitors, err := NewCronMonitors(c).List() + require.NoError(t, err) + + expected := []*api.CronMonitor{ + { + MonitorID: "897654345678", + DisplayName: "foo", + CronExpression: "* * * * *", + CronTz: "IST", + WaitTime: 30, + Type: "CRON", + ThresholdProfileID: "012", + NotificationProfileID: "789", + MonitorGroups: []string{"234", "567"}, + UserGroupIDs: []string{"123", "456"}, + ThirdPartyServiceIDs: []string{"123", "456"}, + OnCallScheduleID: "1244", + }, + { + MonitorID: "933654345678", + DisplayName: "foo", + CronExpression: "* * * * *", + CronTz: "IST", + WaitTime: 30, + Type: "CRON", + ThresholdProfileID: "012", + NotificationProfileID: "789", + MonitorGroups: []string{"234", "567"}, + UserGroupIDs: []string{"123", "456"}, + ThirdPartyServiceIDs: []string{"123", "456"}, + OnCallScheduleID: "1244", + }, + } + + assert.Equal(t, expected, cronMonitors) + }, + }, + { + Name: "update cron monitor", + ExpectedVerb: "PUT", + ExpectedPath: "/monitors/123", + ExpectedBody: validation.Fixture(t, "requests/update_cron_monitor.json"), + StatusCode: 200, + ResponseBody: validation.JsonAPIResponseBody(t, nil), + Fn: func(t *testing.T, c rest.Client) { + cronMonitor := &api.CronMonitor{ + MonitorID: "123", + DisplayName: "foo", + CronExpression: "* * * * *", + CronTz: "IST", + WaitTime: 30, + Type: "CRON", + ThresholdProfileID: "012", + NotificationProfileID: "789", + MonitorGroups: []string{"234", "567"}, + UserGroupIDs: []string{"123", "456"}, + TagIDs: []string{"123"}, + ThirdPartyServiceIDs: []string{"123", "456"}, + OnCallScheduleID: "1244", + } + + _, err := NewCronMonitors(c).Update(cronMonitor) + require.NoError(t, err) + }, + }, + { + Name: "delete cron monitor", + ExpectedVerb: "DELETE", + ExpectedPath: "/monitors/123", + StatusCode: 200, + Fn: func(t *testing.T, c rest.Client) { + require.NoError(t, NewCronMonitors(c).Delete("123")) + }, + }, + }) +} diff --git a/api/monitor_types.go b/api/monitor_types.go index 32bd84c..190847a 100644 --- a/api/monitor_types.go +++ b/api/monitor_types.go @@ -923,6 +923,59 @@ func (serverMonitor *ServerMonitor) String() string { return ToString(serverMonitor) } +//Cron Monitor resource in Site24x7 +type CronMonitor struct { + _ struct{} `type:"structure"` // Enforces key based initialization. + MonitorID string `json:"monitor_id,omitempty"` + DisplayName string `json:"display_name"` + CronExpression string `json:"cron_expression"` + CronTz string `json:"cron_tz"` + WaitTime int `json:"wait_time"` + Type string `json:"type"` + ThresholdProfileID string `json:"threshold_profile_id"` + NotificationProfileID string `json:"notification_profile_id"` + MonitorGroups []string `json:"monitor_groups,omitempty"` + TagIDs []string `json:"tag_ids,omitempty"` + ThirdPartyServiceIDs []string `json:"third_party_services,omitempty"` + UserGroupIDs []string `json:"user_group_ids,omitempty"` + OnCallScheduleID string `json:"on_call_schedule_id,omitempty"` +} + +func (cronMonitor *CronMonitor) SetLocationProfileID(locationProfileID string) { +} + +func (cronMonitor *CronMonitor) GetLocationProfileID() string { + return "" +} + +func (cronMonitor *CronMonitor) SetNotificationProfileID(notificationProfileID string) { + cronMonitor.NotificationProfileID = notificationProfileID +} + +func (cronMonitor *CronMonitor) GetNotificationProfileID() string { + return cronMonitor.NotificationProfileID +} + +func (cronMonitor *CronMonitor) SetUserGroupIDs(userGroupIDs []string) { + cronMonitor.UserGroupIDs = userGroupIDs +} + +func (cronMonitor *CronMonitor) GetUserGroupIDs() []string { + return cronMonitor.UserGroupIDs +} + +func (cronMonitor *CronMonitor) SetTagIDs(tagIDs []string) { + cronMonitor.TagIDs = tagIDs +} + +func (cronMonitor *CronMonitor) GetTagIDs() []string { + return cronMonitor.TagIDs +} + +func (cronMonitor *CronMonitor) String() string { + return ToString(cronMonitor) +} + // Denotes the Heartbeat monitor resource in Site24x7. type HeartbeatMonitor struct { _ struct{} `type:"structure"` // Enforces key based initialization. diff --git a/api/types.go b/api/types.go index a0d4417..c72f08c 100644 --- a/api/types.go +++ b/api/types.go @@ -203,6 +203,11 @@ type ThresholdProfile struct { // SSL_CERT attributes SSLCertificateFingerprintModified map[string]interface{} `json:"ssl_fingerprint_modified,omitempty"` SSLCertificateDaysUntilExpiry []map[string]interface{} `json:"days_until_expiry,omitempty"` + + // CRON attributes + CronNoRunAlert map[string]interface{} `json:"cron_no_run_alert,omitempty"` + CronDurationAlert map[string]interface{} `json:"cron_duration_alert,omitempty"` + // HEARTBEAT attributes TroubleIfNotPingedMoreThan map[string]interface{} `json:"hb_availability1,omitempty"` DownIfNotPingedMoreThan map[string]interface{} `json:"hb_availability2,omitempty"` @@ -254,6 +259,10 @@ func (thresholdProfile *ThresholdProfile) UnmarshalJSON(rawValue []byte) error { thresholdProfile.ResponseTimeThreshold = v.(map[string]interface{}) } else if k == "read_time_out" { thresholdProfile.ReadTimeOut = v.(map[string]interface{}) + } else if k == "cron_no_run_alert" { + thresholdProfile.CronNoRunAlert = v.(map[string]interface{}) + } else if k == "cron_duration_alert" { + thresholdProfile.CronDurationAlert = v.(map[string]interface{}) } } return nil diff --git a/docs/resources/cron_monitor.md b/docs/resources/cron_monitor.md new file mode 100644 index 0000000..ee9eae0 --- /dev/null +++ b/docs/resources/cron_monitor.md @@ -0,0 +1,135 @@ +--- +layout: "site24x7" +page_title: "Site24x7: site24x7_cron_monitor" +sidebar_current: "docs-site24x7-resource-cron-monitor" +description: |- + Create and manage a Cron monitor in Site24x7. +--- + +# Resource: site24x7\_cron\_monitor + +Use this resource to create, update and delete a Cron monitor in Site24x7. + +## Example Usage + +```hcl + +// Site24x7 Cron Monitor API doc - https://www.site24x7.com/help/api/#cron +resource "site24x7_cron_monitor" "cron_monitor_basic" { + // (Required) Display name for the monitor + display_name = "Sample test" + + // (Required) Cron expression to denote the job schedule. + cron_expression = "* * * * *" + + // (Required) Timezone of the server where job runs. + cron_tz = "IST" + + // (Required) Provide an extended period of time (seconds) to define when your alerts should be triggered. This is basically to avoid false alerts. + wait_time = 30 +} + +// Site24x7 Cron Monitor API doc - https://www.site24x7.com/help/api/#cron +resource "site24x7_cron_monitor" "cron_monitor_all_attributes" { + // (Required) Display name for the monitor + display_name = "Sample test" + + // (Required) Cron expression to denote the job schedule. + cron_expression = "* * * * *" + + // (Required) Timezone of the server where job runs. + cron_tz = "IST" + + // (Required) Provide an extended period of time (seconds) to define when your alerts should be triggered. This is basically to avoid false alerts. + wait_time = 30 + + // (Optional) Threshold profile to be associated with the monitor. If + // omitted, the first profile returned by the /api/threshold_profiles + // endpoint for the CRON monitor type (https://www.site24x7.com/help/api/#list-threshold-profiles) will + // be used. + threshold_profile_id = "123" + + // (Optional) Notification profile to be associated with the monitor. If + // omitted, the first profile returned by the /api/notification_profiles + // endpoint (https://www.site24x7.com/help/api/#list-notification-profiles) + // will be used. + notification_profile_id = "123" + + // (Optional) Name of the notification profile that has to be associated with the monitor. + // Profile name matching works for both exact and partial match. + // Either specify notification_profile_id or notification_profile_name. + // If notification_profile_id and notification_profile_name are omitted, + // the first profile returned by the /api/notification_profiles endpoint + // (https://www.site24x7.com/help/api/#list-notification-profiles) will be + // used. + notification_profile_name = "Terraform Profile" + + // (Optional) List of monitor group IDs to associate the monitor to. + monitor_groups = [ + "123", + "456" + ] + + // (Optional) List if user group IDs to be notified on down. + // Either specify user_group_ids or user_group_names. If omitted, the + // first user group returned by the /api/user_groups endpoint + // (https://www.site24x7.com/help/api/#list-of-all-user-groups) will be used. + user_group_ids = [ + "123", + ] + + // (Optional) List if user group names to be notified on down. + // Either specify user_group_ids or user_group_names. If omitted, the + // first user group returned by the /api/user_groups endpoint + // (https://www.site24x7.com/help/api/#list-of-all-user-groups) will be used. + user_group_names = [ + "Terraform", + "Network", + "Admin", + ] + + // (Optional) List if tag IDs to be associated to the monitor. + tag_ids = [ + "123", + ] + + // (Optional) List of tag names to be associated to the monitor. Tag name matching works for both exact and + // partial match. Either specify tag_ids or tag_names. + tag_names = [ + "Terraform", + "Server", + ] + + // (Optional) List of Third Party Service IDs to be associated to the monitor. + third_party_service_ids = [ + "4567" + ] + + // (Optional) Mandatory, if the user group ID is not given. On-Call Schedule ID of your choice. + on_call_schedule_id = "3455" +} + +``` + +## Attributes Reference + +### Required + +* `display_name` (String) Display Name for the monitor. +* `name_in_ping_url` (String) Unique name to be used in the ping URL. + +### Optional + +* `id` (String) The ID of this resource. +* `threshold_profile_id` (String) Threshold profile to be associated with the monitor. +* `notification_profile_id` (String) Notification profile to be associated with the monitor. Either specify notification_profile_id or notification_profile_name. If notification_profile_id and notification_profile_name are omitted, the first profile returned by the /api/notification_profiles endpoint will be used. +* `notification_profile_name` (String) Name of the notification profile to be associated with the monitor. Profile name matching works for both exact and partial match. +* `monitor_groups` (List of String) List of monitor groups to which the monitor has to be associated. +* `user_group_ids` (List of String) List of user groups to be notified when the monitor is down. Either specify user_group_ids or user_group_names. If omitted, the first user group returned by the /api/user_groups endpoint will be used. +* `user_group_names` (List of String) List of user group names to be notified when the monitor is down. Either specify user_group_ids or user_group_names. If omitted, the first user group returned by the /api/user_groups endpoint will be used. +* `tag_ids` (List of String) List of tags IDs to be associated to the monitor. Either specify tag_ids or tag_names. +* `tag_names` (List of String) List of tag names to be associated to the monitor. Tag name matching works for both exact and partial match. Either specify tag_ids or tag_names. +* `third_party_service_ids` (List of String) List of Third Party Service IDs to be associated to the monitor. +* `on_call_schedule_id` (String) Mandatory, if the user group ID is not given. On-Call Schedule ID of your choice. + +Refer [API documentation](https://www.site24x7.com/help/api/#cron) for more information about attributes. diff --git a/examples/cron_monitor_us.tf b/examples/cron_monitor_us.tf new file mode 100644 index 0000000..d3c767e --- /dev/null +++ b/examples/cron_monitor_us.tf @@ -0,0 +1,144 @@ +terraform { + # Require Terraform version 0.15.x (recommended) + required_version = "~> 0.13.0" + + required_providers { + site24x7 = { + source = "site24x7/site24x7" + # Update the latest version from https://registry.terraform.io/providers/site24x7/site24x7/latest + + } + } +} + +// Authentication API doc - https://www.site24x7.com/help/api/#authentication +provider "site24x7" { + // (Security recommendation - It is always best practice to store your credentials in a Vault of your choice.) + // (Required) The client ID will be looked up in the SITE24X7_OAUTH2_CLIENT_ID + // environment variable if the attribute is empty or omitted. + oauth2_client_id = "" + + // (Security recommendation - It is always best practice to store your credentials in a Vault of your choice.) + // (Required) The client secret will be looked up in the SITE24X7_OAUTH2_CLIENT_SECRET + // environment variable if the attribute is empty or omitted. + oauth2_client_secret = "" + + // (Security recommendation - It is always best practice to store your credentials in a Vault of your choice.) + // (Required) The refresh token will be looked up in the SITE24X7_OAUTH2_REFRESH_TOKEN + // environment variable if the attribute is empty or omitted. + oauth2_refresh_token = "" + + // (Required) Specify the data center from which you have obtained your + // OAuth client credentials and refresh token. It can be (US/EU/IN/AU/CN/JP/CA). + data_center = "US" + + // (Optional) ZAAID of the customer under a MSP or BU + zaaid = "1234" + + // (Optional) The minimum time to wait in seconds before retrying failed Site24x7 API requests. + retry_min_wait = 1 + + // (Optional) The maximum time to wait in seconds before retrying failed Site24x7 API + // requests. This is the upper limit for the wait duration with exponential + // backoff. + retry_max_wait = 30 + + // (Optional) Maximum number of Site24x7 API request retries to perform until giving up. + max_retries = 4 + + } + +// Site24x7 Cron Monitor API doc - https://www.site24x7.com/help/api/#cron +resource "site24x7_cron_monitor" "cron_monitor_basic" { + // (Required) Display name for the monitor + display_name = "Sample test" + + // (Required) Cron expression to denote the job schedule. + cron_expression = "* * * * *" + + // (Required) Timezone of the server where job runs. + cron_tz = "IST" + + // (Required) Provide an extended period of time (seconds) to define when your alerts should be triggered. This is basically to avoid false alerts. + wait_time = 30 +} + +// Site24x7 Cron Monitor API doc - https://www.site24x7.com/help/api/#cron +resource "site24x7_cron_monitor" "cron_monitor_all_attributes" { + // (Required) Display name for the monitor + display_name = "Sample test" + + // (Required) Cron expression to denote the job schedule. + cron_expression = "* * * * *" + + // (Required) Timezone of the server where job runs. + cron_tz = "IST" + + // (Required) Provide an extended period of time (seconds) to define when your alerts should be triggered. This is basically to avoid false alerts. + wait_time = 30 + + // (Optional) Threshold profile to be associated with the monitor. If + // omitted, the first profile returned by the /api/threshold_profiles + // endpoint for the CRON monitor type (https://www.site24x7.com/help/api/#list-threshold-profiles) will + // be used. + threshold_profile_id = "123" + + // (Optional) Notification profile to be associated with the monitor. If + // omitted, the first profile returned by the /api/notification_profiles + // endpoint (https://www.site24x7.com/help/api/#list-notification-profiles) + // will be used. + notification_profile_id = "123" + + // (Optional) Name of the notification profile that has to be associated with the monitor. + // Profile name matching works for both exact and partial match. + // Either specify notification_profile_id or notification_profile_name. + // If notification_profile_id and notification_profile_name are omitted, + // the first profile returned by the /api/notification_profiles endpoint + // (https://www.site24x7.com/help/api/#list-notification-profiles) will be + // used. + notification_profile_name = "Terraform Profile" + + // (Optional) List of monitor group IDs to associate the monitor to. + monitor_groups = [ + "123", + "456" + ] + + // (Optional) List if user group IDs to be notified on down. + // Either specify user_group_ids or user_group_names. If omitted, the + // first user group returned by the /api/user_groups endpoint + // (https://www.site24x7.com/help/api/#list-of-all-user-groups) will be used. + user_group_ids = [ + "123", + ] + + // (Optional) List if user group names to be notified on down. + // Either specify user_group_ids or user_group_names. If omitted, the + // first user group returned by the /api/user_groups endpoint + // (https://www.site24x7.com/help/api/#list-of-all-user-groups) will be used. + user_group_names = [ + "Terraform", + "Network", + "Admin", + ] + + // (Optional) List if tag IDs to be associated to the monitor. + tag_ids = [ + "123", + ] + + // (Optional) List of tag names to be associated to the monitor. Tag name matching works for both exact and + // partial match. Either specify tag_ids or tag_names. + tag_names = [ + "Terraform", + "Server", + ] + + // (Optional) List of Third Party Service IDs to be associated to the monitor. + third_party_service_ids = [ + "4567" + ] + + // (Optional) Mandatory, if the user group ID is not given. On-Call Schedule ID of your choice. + on_call_schedule_id = "3455" +} \ No newline at end of file diff --git a/fake/client.go b/fake/client.go index 8e8db59..e77383e 100644 --- a/fake/client.go +++ b/fake/client.go @@ -22,6 +22,7 @@ type Client struct { FakeWebsiteMonitors *fake.WebsiteMonitors FakeWebPageSpeedMonitors *fake.WebPageSpeedMonitors FakeSSLMonitors *fake.SSLMonitors + FakeCronMonitors *fake.CronMonitors FakeHeartbeatMonitors *fake.HeartbeatMonitors FakeDomainExpiryMonitors *fake.DomainExpiryMonitors FakeWebTransactionBrowserMonitors *fake.WebTransactionBrowserMonitors @@ -62,6 +63,7 @@ func NewClient() *Client { FakeTags: &fake.Tags{}, FakeAmazonMonitors: &fake.AmazonMonitors{}, FakeSSLMonitors: &fake.SSLMonitors{}, + FakeCronMonitors: &fake.CronMonitors{}, FakeHeartbeatMonitors: &fake.HeartbeatMonitors{}, FakeServerMonitors: &fake.ServerMonitors{}, FakeWebsiteMonitors: &fake.WebsiteMonitors{}, @@ -133,6 +135,11 @@ func (c *Client) SSLMonitors() monitors.SSLMonitors { return c.FakeSSLMonitors } +// CronMonitors implements Client. +func (c *Client) CronMonitors() monitors.CronMonitors { + return c.FakeCronMonitors +} + // HeartbeatMonitors implements Client. func (c *Client) HeartbeatMonitors() monitors.HeartbeatMonitors { return c.FakeHeartbeatMonitors diff --git a/provider/provider.go b/provider/provider.go index c79f049..5a177f7 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -85,6 +85,7 @@ func Provider() terraform.ResourceProvider { "site24x7_rest_api_monitor": monitors.ResourceSite24x7RestApiMonitor(), "site24x7_rest_api_transaction_monitor": monitors.ResourceSite24x7RestApiTransactionMonitor(), "site24x7_server_monitor": monitors.ResourceSite24x7ServerMonitor(), + "site24x7_cron_monitor": monitors.ResourceSite24x7CronMonitor(), "site24x7_heartbeat_monitor": monitors.ResourceSite24x7HeartbeatMonitor(), "site24x7_dns_server_monitor": monitors.ResourceSite24x7DNSServerMonitor(), "site24x7_domain_expiry_monitor": monitors.ResourceSite24x7DomainExpiryMonitor(), diff --git a/site24x7/client.go b/site24x7/client.go index 17c4a65..ca4da21 100644 --- a/site24x7/client.go +++ b/site24x7/client.go @@ -88,6 +88,7 @@ type Client interface { DNSServerMonitors() monitors.DNSServerMonitors WebPageSpeedMonitors() monitors.WebPageSpeedMonitors SSLMonitors() monitors.SSLMonitors + CronMonitors() monitors.CronMonitors HeartbeatMonitors() monitors.HeartbeatMonitors ServerMonitors() monitors.ServerMonitors DomainExpiryMonitors() monitors.DomainExpiryMonitors @@ -215,6 +216,11 @@ func (c *client) PortMonitors() monitors.PortMonitors { return monitors.NewPortMonitors(c.restClient) } +// CronMonitors implements Client. +func (c *client) CronMonitors() monitors.CronMonitors { + return monitors.NewCronMonitors(c.restClient) +} + // HeartbeatMonitors implements Client. func (c *client) HeartbeatMonitors() monitors.HeartbeatMonitors { return monitors.NewHeartbeatMonitors(c.restClient) diff --git a/site24x7/monitors/cron.go b/site24x7/monitors/cron.go new file mode 100644 index 0000000..b148175 --- /dev/null +++ b/site24x7/monitors/cron.go @@ -0,0 +1,286 @@ +package monitors + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/site24x7/terraform-provider-site24x7/api" + apierrors "github.com/site24x7/terraform-provider-site24x7/api/errors" + "github.com/site24x7/terraform-provider-site24x7/site24x7" +) + +var CronMonitorSchema = map[string]*schema.Schema{ + "display_name": { + Type: schema.TypeString, + Required: true, + Description: "Display Name for the monitor.", + }, + "cron_expression": { + Type: schema.TypeString, + Required: true, + Description: "Cron expression to denote the job schedule.", + }, + "cron_tz": { + Type: schema.TypeString, + Required: true, + Description: "Timezone of the server where job runs.", + }, + "wait_time": { + Type: schema.TypeInt, + Required: true, + Description: "Provide an extended period of time (seconds) to define when your alerts should be triggered. This is basically to avoid false alerts.", + }, + "threshold_profile_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Threshold profile to be associated with the monitor.", + }, + "notification_profile_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Notification profile to be associated with the monitor.", + }, + "notification_profile_name": { + Type: schema.TypeString, + Optional: true, + Description: "Name of the notification profile to be associated with the monitor.", + }, + "monitor_groups": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "List of monitor groups to which the monitor has to be associated.", + }, + "user_group_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Computed: true, + Description: "List of user groups to be notified when the monitor is down.", + }, + "user_group_names": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "Name of the user groups to be associated with the monitor.", + }, + "tag_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Computed: true, + Description: "List of tag IDs to be associated to the monitor.", + }, + "tag_names": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "List of tag names to be associated to the monitor.", + }, + "third_party_service_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "List of Third Party Service IDs to be associated to the monitor.", + }, + "on_call_schedule_id": { + Type: schema.TypeString, + Optional: true, + Description: "Mandatory, if the user group ID is not given. On-Call Schedule ID of your choice.", + }, +} + +func ResourceSite24x7CronMonitor() *schema.Resource { + return &schema.Resource{ + Create: cronMonitorCreate, + Read: cronMonitorRead, + Update: cronMonitorUpdate, + Delete: cronMonitorDelete, + Exists: cronMonitorExists, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: CronMonitorSchema, + } +} + +func cronMonitorCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(site24x7.Client) + + cronMonitor, err := resourceDataToCronMonitor(d, client) + if err != nil { + return err + } + + cronMonitor, err = client.CronMonitors().Create(cronMonitor) + if err != nil { + return err + } + + d.SetId(cronMonitor.MonitorID) + + return nil +} + +func cronMonitorRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(site24x7.Client) + + cronMonitor, err := client.CronMonitors().Get(d.Id()) + if err != nil { + return err + } + + updateCronMonitorResourceData(d, cronMonitor) + + return nil +} + +func cronMonitorUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(site24x7.Client) + + cronMonitor, err := resourceDataToCronMonitor(d, client) + if err != nil { + return err + } + + cronMonitor, err = client.CronMonitors().Update(cronMonitor) + if err != nil { + return err + } + + d.SetId(cronMonitor.MonitorID) + + // return cronMonitorRead(d, meta) + return nil +} + +func cronMonitorDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(site24x7.Client) + + err := client.CronMonitors().Delete(d.Id()) + if apierrors.IsNotFound(err) { + return nil + } + + return err +} + +func cronMonitorExists(d *schema.ResourceData, meta interface{}) (bool, error) { + client := meta.(site24x7.Client) + + _, err := client.CronMonitors().Get(d.Id()) + if apierrors.IsNotFound(err) { + return false, nil + } + + if err != nil { + return false, err + } + + return true, nil +} + +func resourceDataToCronMonitor(d *schema.ResourceData, client site24x7.Client) (*api.CronMonitor, error) { + + var monitorGroups []string + for _, group := range d.Get("monitor_groups").(*schema.Set).List() { + if group != nil { + monitorGroups = append(monitorGroups, group.(string)) + } + } + + var userGroupIDs []string + for _, id := range d.Get("user_group_ids").(*schema.Set).List() { + if id != nil { + userGroupIDs = append(userGroupIDs, id.(string)) + } + } + + var tagIDs []string + for _, id := range d.Get("tag_ids").(*schema.Set).List() { + if id != nil { + tagIDs = append(tagIDs, id.(string)) + } + } + + var thirdPartyServiceIDs []string + for _, id := range d.Get("third_party_service_ids").(*schema.Set).List() { + if id != nil { + thirdPartyServiceIDs = append(thirdPartyServiceIDs, id.(string)) + } + } + + cronMonitor := &api.CronMonitor{ + MonitorID: d.Id(), + DisplayName: d.Get("display_name").(string), + CronExpression: d.Get("cron_expression").(string), + CronTz: d.Get("cron_tz").(string), + WaitTime: d.Get("wait_time").(int), + Type: string(api.CRON), + ThresholdProfileID: d.Get("threshold_profile_id").(string), + NotificationProfileID: d.Get("notification_profile_id").(string), + MonitorGroups: monitorGroups, + UserGroupIDs: userGroupIDs, + TagIDs: tagIDs, + ThirdPartyServiceIDs: thirdPartyServiceIDs, + OnCallScheduleID: d.Get("on_call_schedule_id").(string), + } + + // Notification Profile + _, notificationProfileErr := site24x7.SetNotificationProfile(client, d, cronMonitor) + if notificationProfileErr != nil { + return nil, notificationProfileErr + } + + // User Alert Groups + _, userAlertGroupErr := site24x7.SetUserGroup(client, d, cronMonitor) + if userAlertGroupErr != nil { + return nil, userAlertGroupErr + } + + // Tags + _, tagsErr := site24x7.SetTags(client, d, cronMonitor) + if tagsErr != nil { + return nil, tagsErr + } + + // Threshold profile + if cronMonitor.ThresholdProfileID == "" { + profile, err := site24x7.DefaultThresholdProfile(client, api.CRON) + if err != nil { + return nil, err + } + cronMonitor.ThresholdProfileID = profile.ProfileID + d.Set("threshold_profile_id", profile) + } + + return cronMonitor, nil +} + +func updateCronMonitorResourceData(d *schema.ResourceData, monitor *api.CronMonitor) { + d.Set("display_name", monitor.DisplayName) + d.Set("type", monitor.Type) + d.Set("cron_expression", monitor.CronExpression) + d.Set("cron_tz", monitor.CronTz) + d.Set("wait_time", monitor.WaitTime) + d.Set("threshold_profile_id", monitor.ThresholdProfileID) + d.Set("notification_profile_id", monitor.NotificationProfileID) + d.Set("monitor_groups", monitor.MonitorGroups) + d.Set("user_group_ids", monitor.UserGroupIDs) + d.Set("tag_ids", monitor.TagIDs) + d.Set("third_party_service_ids", monitor.ThirdPartyServiceIDs) + d.Set("on_call_schedule_id", monitor.OnCallScheduleID) +} diff --git a/site24x7/monitors/cron_test.go b/site24x7/monitors/cron_test.go new file mode 100644 index 0000000..b293ef9 --- /dev/null +++ b/site24x7/monitors/cron_test.go @@ -0,0 +1,257 @@ +package monitors + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/site24x7/terraform-provider-site24x7/api" + apierrors "github.com/site24x7/terraform-provider-site24x7/api/errors" + "github.com/site24x7/terraform-provider-site24x7/fake" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCronMonitorCreate(t *testing.T) { + d := cronTestResourceData(t) + + c := fake.NewClient() + + a := &api.CronMonitor{ + DisplayName: "foo", + CronExpression: "* * * * *", + CronTz: "IST", + WaitTime: 30, + Type: "CRON", + ThresholdProfileID: "012", + NotificationProfileID: "789", + MonitorGroups: []string{"234", "567"}, + UserGroupIDs: []string{"456", "123"}, + TagIDs: []string{"123"}, + ThirdPartyServiceIDs: []string{"456", "123"}, + OnCallScheduleID: "1244", + } + + notificationProfiles := []*api.NotificationProfile{ + { + ProfileID: "123", + ProfileName: "Notifi Profile", + RcaNeeded: true, + }, + { + ProfileID: "456", + ProfileName: "TEST", + RcaNeeded: false, + }, + } + c.FakeNotificationProfiles.On("List").Return(notificationProfiles, nil) + + userGroups := []*api.UserGroup{ + { + DisplayName: "Admin Group", + Users: []string{"123", "456"}, + AttributeGroupID: "789", + ProductID: 0, + }, + { + DisplayName: "Network Group", + Users: []string{"123", "456"}, + AttributeGroupID: "345", + ProductID: 0, + }, + } + c.FakeUserGroups.On("List").Return(userGroups, nil) + + tags := []*api.Tag{ + { + TagID: "123", + TagName: "aws tag", + TagValue: "baz", + TagColor: "#B7DA9E", + }, + { + TagID: "456", + TagName: "website tag", + TagValue: "baz 1", + TagColor: "#B7DA9E", + }, + } + c.FakeTags.On("List").Return(tags, nil) + + c.FakeCronMonitors.On("Create", a).Return(a, nil).Once() + + require.NoError(t, cronMonitorCreate(d, c)) + + c.FakeCronMonitors.On("Create", a).Return(a, apierrors.NewStatusError(500, "error")).Once() + + err := cronMonitorCreate(d, c) + + assert.Equal(t, apierrors.NewStatusError(500, "error"), err) +} + +func TestCronMonitorUpdate(t *testing.T) { + d := cronTestResourceData(t) + d.SetId("123") + + c := fake.NewClient() + + a := &api.CronMonitor{ + MonitorID: "123", + DisplayName: "foo", + CronExpression: "* * * * *", + CronTz: "IST", + WaitTime: 30, + Type: "CRON", + ThresholdProfileID: "012", + NotificationProfileID: "789", + MonitorGroups: []string{"234", "567"}, + UserGroupIDs: []string{"456", "123"}, + TagIDs: []string{"123"}, + ThirdPartyServiceIDs: []string{"456", "123"}, + OnCallScheduleID: "1244", + } + + notificationProfiles := []*api.NotificationProfile{ + { + ProfileID: "123", + ProfileName: "Notifi Profile", + RcaNeeded: true, + }, + { + ProfileID: "456", + ProfileName: "TEST", + RcaNeeded: false, + }, + } + c.FakeNotificationProfiles.On("List").Return(notificationProfiles, nil) + + userGroups := []*api.UserGroup{ + { + DisplayName: "Admin Group", + Users: []string{"123", "456"}, + AttributeGroupID: "789", + ProductID: 0, + }, + { + DisplayName: "Network Group", + Users: []string{"123", "456"}, + AttributeGroupID: "345", + ProductID: 0, + }, + } + c.FakeUserGroups.On("List").Return(userGroups, nil) + + tags := []*api.Tag{ + { + TagID: "123", + TagName: "aws tag", + TagValue: "baz", + TagColor: "#B7DA9E", + }, + { + TagID: "456", + TagName: "website tag", + TagValue: "baz 1", + TagColor: "#B7DA9E", + }, + } + c.FakeTags.On("List").Return(tags, nil) + + c.FakeCronMonitors.On("Update", a).Return(a, nil).Once() + + require.NoError(t, cronMonitorUpdate(d, c)) + + c.FakeCronMonitors.On("Update", a).Return(a, apierrors.NewStatusError(500, "error")).Once() + + err := cronMonitorUpdate(d, c) + + assert.Equal(t, apierrors.NewStatusError(500, "error"), err) +} + +func TestCronMonitorRead(t *testing.T) { + d := cronTestResourceData(t) + d.SetId("123") + + c := fake.NewClient() + + c.FakeCronMonitors.On("Get", "123").Return(&api.CronMonitor{}, nil).Once() + + require.NoError(t, cronMonitorRead(d, c)) + + c.FakeCronMonitors.On("Get", "123").Return(nil, apierrors.NewStatusError(500, "error")).Once() + + err := cronMonitorRead(d, c) + + assert.Equal(t, apierrors.NewStatusError(500, "error"), err) +} + +func TestCronMonitorDelete(t *testing.T) { + d := cronTestResourceData(t) + d.SetId("123") + + c := fake.NewClient() + + c.FakeCronMonitors.On("Delete", "123").Return(nil).Once() + + require.NoError(t, cronMonitorDelete(d, c)) + + c.FakeCronMonitors.On("Delete", "123").Return(apierrors.NewStatusError(404, "not found")).Once() + + require.NoError(t, cronMonitorDelete(d, c)) +} + +func TestCronMonitorExists(t *testing.T) { + d := cronTestResourceData(t) + d.SetId("123") + + c := fake.NewClient() + + c.FakeCronMonitors.On("Get", "123").Return(&api.CronMonitor{}, nil).Once() + + exists, err := cronMonitorExists(d, c) + + require.NoError(t, err) + assert.True(t, exists) + + c.FakeCronMonitors.On("Get", "123").Return(nil, apierrors.NewStatusError(404, "not found")).Once() + + exists, err = cronMonitorExists(d, c) + + require.NoError(t, err) + assert.False(t, exists) + + c.FakeCronMonitors.On("Get", "123").Return(nil, apierrors.NewStatusError(500, "error")).Once() + + exists, err = cronMonitorExists(d, c) + + require.Equal(t, apierrors.NewStatusError(500, "error"), err) + assert.False(t, exists) +} + +func cronTestResourceData(t *testing.T) *schema.ResourceData { + return schema.TestResourceDataRaw(t, CronMonitorSchema, map[string]interface{}{ + "display_name": "foo", + "type": "CRON", + "cron_expression": "* * * * *", + "cron_tz": "IST", + "wait_time": 30, + "threshold_profile_id": "012", + "notification_profile_id": "789", + "monitor_groups": []interface{}{ + "234", + "567", + }, + "dependency_resource_ids": []interface{}{ + "234", + "567", + }, + "user_group_ids": []interface{}{ + "123", + "456", + }, + "third_party_service_ids": []interface{}{ + "123", + "456", + }, + "on_call_schedule_id": "1244", + }) +} diff --git a/site24x7/threshold_profile.go b/site24x7/threshold_profile.go index 1a4a581..47194c1 100644 --- a/site24x7/threshold_profile.go +++ b/site24x7/threshold_profile.go @@ -326,6 +326,39 @@ var ThresholdProfileSchema = map[string]*schema.Schema{ }, Description: "Triggers critical alert before the SSL certificate expires within the configured number of days.", }, + // CRON monitor type attributes + "cron_no_run_alert": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "severity": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntInSlice([]int{2}), // Trouble + }, + "value": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + Description: "Triggers Alert, if job does not start on schedule", + }, + "cron_duration_alert": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "trouble": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + Description: "Generate Down Alert if not pinged for more than x mins.", + }, + // HEARTBEAT monitor type attributes "trouble_if_not_pinged_more_than": { Type: schema.TypeInt, @@ -442,6 +475,8 @@ func resourceDataToThresholdProfile(d *schema.ResourceData) *api.ThresholdProfil setSSLCertificateAttributes(d, thresholdProfileToReturn) } else if monitorType == string(api.HEARTBEAT) { setHeartBeatAttributes(d, thresholdProfileToReturn) + } else if monitorType == string(api.CRON) { + setCronAttributes(d, thresholdProfileToReturn) } else { setCommonAttributes(d, thresholdProfileToReturn) } @@ -461,6 +496,8 @@ func updateThresholdProfileResourceData(d *schema.ResourceData, thresholdProfile setSSLCertificateResourceData(d, thresholdProfile) } else if monitorType == string(api.HEARTBEAT) { setHeartBeatResourceData(d, thresholdProfile) + } else if monitorType == string(api.CRON) { + setCronResourceData(d, thresholdProfile) } else { setCommonResourceData(d, thresholdProfile) } @@ -510,6 +547,28 @@ func setSSLCertificateResourceData(d *schema.ResourceData, thresholdProfile *api } } +func setCronAttributes(d *schema.ResourceData, thresholdProfile *api.ThresholdProfile) { + + if cronNoRunAlert, ok := d.GetOk("cron_no_run_alert"); ok { + thresholdProfile.CronNoRunAlert = cronNoRunAlert.(map[string]interface{}) + } + + if cronDurationAlert, ok := d.GetOk("cron_duration_alert"); ok { + thresholdProfile.CronDurationAlert = cronDurationAlert.(map[string]interface{}) + } +} + +func setCronResourceData(d *schema.ResourceData, thresholdProfile *api.ThresholdProfile) { + cronNoRunAlertMap := make(map[string]interface{}) + cronNoRunAlertMap["severity"] = int(thresholdProfile.CronNoRunAlert["severity"].(float64)) + cronNoRunAlertMap["value"] = thresholdProfile.CronNoRunAlert["value"].(bool) + d.Set("cron_no_run_alert", cronNoRunAlertMap) + + cronDurationAlertMap := make(map[string]interface{}) + cronDurationAlertMap["trouble"] = int(thresholdProfile.CronDurationAlert["trouble"].(float64)) + d.Set("cron_duration_alert", cronDurationAlertMap) +} + func setHeartBeatAttributes(d *schema.ResourceData, thresholdProfile *api.ThresholdProfile) { troubleIfNotPingedMoreThanMap := make(map[string]interface{}) if troubleIfNotPingedMoreThan, ok := d.GetOk("trouble_if_not_pinged_more_than"); ok { diff --git a/site24x7/threshold_profile_data_source.go b/site24x7/threshold_profile_data_source.go index 1e896fa..946993e 100644 --- a/site24x7/threshold_profile_data_source.go +++ b/site24x7/threshold_profile_data_source.go @@ -52,6 +52,18 @@ var thresholdProfileDataSourceSchema = map[string]*schema.Schema{ Computed: true, Description: "Triggers alert when the website content is modified.", }, + + "cron_no_run_alert": { + Type: schema.TypeMap, + Computed: true, + Description: "Triggers alert when the website content is modified.", + }, + + "cron_duration_alert": { + Type: schema.TypeMap, + Computed: true, + Description: "Triggers alert when the website content is modified.", + }, } func DataSourceSite24x7ThresholdProfile() *schema.Resource { @@ -88,6 +100,8 @@ func thresholdProfileDataSourceRead(d *schema.ResourceData, meta interface{}) er thresholdProfile.ProfileType = profileInfo.ProfileType thresholdProfile.DownLocationThreshold = profileInfo.DownLocationThreshold thresholdProfile.WebsiteContentModified = profileInfo.WebsiteContentModified + thresholdProfile.CronNoRunAlert = profileInfo.CronDurationAlert + thresholdProfile.CronDurationAlert = profileInfo.CronDurationAlert matchingThresholdProfileIDs = append(matchingThresholdProfileIDs, profileInfo.ProfileID) matchingThresholdProfileIDsAndNames = append(matchingThresholdProfileIDsAndNames, profileInfo.ProfileID+"__"+profileInfo.ProfileName) } else if thresholdProfile != nil && nameRegexPattern.MatchString(profileInfo.ProfileName) { @@ -118,4 +132,7 @@ func updateThresholdProfileDataSourceResourceData(d *schema.ResourceData, thresh d.Set("profile_type", thresholdProfile.ProfileType) d.Set("down_location_threshold", thresholdProfile.DownLocationThreshold) d.Set("website_content_modified", thresholdProfile.WebsiteContentModified) + + d.Set("cron_no_run_alert", thresholdProfile.CronNoRunAlert) + d.Set("cron_duration_alert", thresholdProfile.CronDurationAlert) } From d102cbcfb887d11026c395d8c14ea21dafa09d3a Mon Sep 17 00:00:00 2001 From: anita-1372 Date: Mon, 20 May 2024 12:56:19 +0530 Subject: [PATCH 2/6] updating the message resources for cron threshold profiles --- docs/resources/threshold_profile.md | 20 ++++++++++++++++++++ site24x7/threshold_profile.go | 2 +- site24x7/threshold_profile_data_source.go | 4 ++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/resources/threshold_profile.md b/docs/resources/threshold_profile.md index dc54686..18c8289 100644 --- a/docs/resources/threshold_profile.md +++ b/docs/resources/threshold_profile.md @@ -128,6 +128,26 @@ resource "site24x7_threshold_profile" "ssl_certificate_threshold_profile_us" { } + +// CRON Threshold Profile API doc](https://www.site24x7.com/help/api/#threshold-cron)) +resource "site24x7_threshold_profile" "cron_threshold" { + // (Required) Name of the profile + profile_name = "Cron Threshold - Terraform" + // (Required) Type of the profile - Denotes monitor type (eg) RESTAPI, SSL_CERT + type = "CRON" + // (Optional) Triggers Alert, if job does not start on schedule + cron_no_run_alert = { + severity = 0 + value = true + } + // (Optional) Generate Trouble Alert if not pinged for more than x seconds + cron_duration_alert = { + trouble = 30 + } + +} + + // HEARTBEAT Threshold Profile API doc](https://www.site24x7.com/help/api/#threshold-heartbeat)) resource "site24x7_threshold_profile" "heartbeat_threshold" { // (Required) Name of the profile diff --git a/site24x7/threshold_profile.go b/site24x7/threshold_profile.go index 47194c1..f49c5f0 100644 --- a/site24x7/threshold_profile.go +++ b/site24x7/threshold_profile.go @@ -356,7 +356,7 @@ var ThresholdProfileSchema = map[string]*schema.Schema{ }, }, }, - Description: "Generate Down Alert if not pinged for more than x mins.", + Description: "Generate Trouble Alert if not pinged for more than x seconds.", }, // HEARTBEAT monitor type attributes diff --git a/site24x7/threshold_profile_data_source.go b/site24x7/threshold_profile_data_source.go index 946993e..ccbaad7 100644 --- a/site24x7/threshold_profile_data_source.go +++ b/site24x7/threshold_profile_data_source.go @@ -56,13 +56,13 @@ var thresholdProfileDataSourceSchema = map[string]*schema.Schema{ "cron_no_run_alert": { Type: schema.TypeMap, Computed: true, - Description: "Triggers alert when the website content is modified.", + Description: "Triggers Alert, if job does not start on schedule", }, "cron_duration_alert": { Type: schema.TypeMap, Computed: true, - Description: "Triggers alert when the website content is modified.", + Description: "Generate Trouble Alert if not pinged for more than x seconds.", }, } From 2ef5cf6e22470f945991079ceed487ffdb0ed362 Mon Sep 17 00:00:00 2001 From: Jim Billy Date: Fri, 31 May 2024 20:04:33 +0530 Subject: [PATCH 3/6] Plugin installation commands. --- examples/server_agent_installation.tf | 1 + examples/server_agent_installation_GCP.tf | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/server_agent_installation.tf b/examples/server_agent_installation.tf index c24b12d..2e41fe8 100644 --- a/examples/server_agent_installation.tf +++ b/examples/server_agent_installation.tf @@ -80,6 +80,7 @@ resource "aws_instance" "t2_micro_instance" { inline = [ "sudo wget https://staticdownloads.site24x7.com/server/Site24x7InstallScript.sh", "sudo bash Site24x7InstallScript.sh -i -key=", + "sudo wget https://raw.githubusercontent.com/site24x7/plugins/master/check_updates/installer/Site24x7CheckUpdatesPluginInstaller.sh && sudo bash Site24x7CheckUpdatesPluginInstaller.sh", ] } } diff --git a/examples/server_agent_installation_GCP.tf b/examples/server_agent_installation_GCP.tf index ee0b01d..edc815c 100644 --- a/examples/server_agent_installation_GCP.tf +++ b/examples/server_agent_installation_GCP.tf @@ -87,7 +87,7 @@ resource "google_compute_instance" "default" { } # Install - metadata_startup_script = "sudo apt-get update; sudo apt-get install -yq build-essential python3-pip rsync; wget https://staticdownloads.site24x7.com/server/Site24x7InstallScript.sh; bash Site24x7InstallScript.sh -i -key=${data.site24x7_device_key.s247devicekey.id} -automation=true" + metadata_startup_script = "sudo apt-get update; sudo apt-get install -yq build-essential python3-pip rsync; wget https://staticdownloads.site24x7.com/server/Site24x7InstallScript.sh; bash Site24x7InstallScript.sh -i -key=${data.site24x7_device_key.s247devicekey.id} -automation=true; wget https://raw.githubusercontent.com/site24x7/plugins/master/check_updates/installer/Site24x7CheckUpdatesPluginInstaller.sh && sudo bash Site24x7CheckUpdatesPluginInstaller.sh" network_interface { subnetwork = google_compute_subnetwork.default.id From 460a9ce8fc77a1b029bcae2b16bff4fd77def624 Mon Sep 17 00:00:00 2001 From: Jim Billy Date: Wed, 5 Jun 2024 16:54:57 +0530 Subject: [PATCH 4/6] Monitor group changes --- api/types.go | 29 +++-- docs/resources/monitor_group.md | 44 +++++++- examples/monitor_group_us.tf | 33 +++++- examples/user_us.tf | 10 +- site24x7/monitor_group.go | 144 +++++++++++++++++++++++- site24x7/user.go | 10 +- utilities/importer/site24x7_importer.py | 4 +- 7 files changed, 244 insertions(+), 30 deletions(-) diff --git a/api/types.go b/api/types.go index c72f08c..ce08d75 100644 --- a/api/types.go +++ b/api/types.go @@ -141,16 +141,25 @@ type ActionRef struct { // MonitorGroup organizes monitor resources into groups. type MonitorGroup struct { - _ struct{} `type:"structure"` // Enforces key based initialization. - GroupID string `json:"group_id,omitempty"` - DisplayName string `json:"display_name"` - Description string `json:"description,omitempty"` - Monitors []string `json:"monitors,omitempty"` - HealthThresholdCount int `json:"health_threshold_count"` - DependencyResourceIDs []string `json:"dependency_resource_ids,omitempty"` - SuppressAlert bool `json:"suppress_alert"` - DependencyResourceType int `json:"selection_type,omitempty"` - TagIDs []string `json:"tags,omitempty"` + _ struct{} `type:"structure"` // Enforces key based initialization. + GroupID string `json:"group_id,omitempty"` + DisplayName string `json:"display_name"` + Description string `json:"description,omitempty"` + // GroupType int `json:"group_type,omitempty"` + Monitors []string `json:"monitors,omitempty"` + HealthThresholdCount int `json:"health_threshold_count"` + DependencyResourceIDs []string `json:"dependency_resource_ids,omitempty"` + SuppressAlert bool `json:"suppress_alert"` + DependencyResourceType int `json:"selection_type,omitempty"` + NotificationProfileID string `json:"notification_profile_id"` + HealthCheckProfileID string `json:"healthcheck_profile_id"` + TagIDs []string `json:"tags,omitempty"` + UserGroupIDs []string `json:"user_group_ids,omitempty"` + ThirdPartyServiceIDs []string `json:"third_party_services,omitempty"` + EnableIncidentManagement bool `json:"enable_incident_management"` + HealingPeriod int `json:"healing_period"` + AlertFrequency int `json:"alert_frequency"` + AlertPeriodically bool `json:"alert_periodically"` } func (monitorGroup *MonitorGroup) String() string { diff --git a/docs/resources/monitor_group.md b/docs/resources/monitor_group.md index 273941c..f211117 100644 --- a/docs/resources/monitor_group.md +++ b/docs/resources/monitor_group.md @@ -30,10 +30,40 @@ resource "site24x7_monitor_group" "monitor_group_us" { // (Optional) Boolean value indicating whether to suppress alert when the dependent monitor is down // Setting suppress_alert = true with an empty dependency_resource_id is meaningless. suppress_alert = true - // (Optional) List if tag IDs to be associated to the monitor. + + // (Optional) Health check profile to be associated with the monitor group. + healthcheck_profile_id = "100000000000029001" + + // (Optional) Notification profile to be associated with the monitor group. + notification_profile_id = "100000000000029001" + + // (Optional) List of user groups to be notified when the monitor group is down. + user_group_ids = [ + "100000000000025005", + "100000000000025007" + ] + + // (Optional) List if tag IDs to be associated to the monitor group. tag_ids = [ - "100000000024829007", + "100000000048172001" ] + + // (Optional) List of Third Party Service IDs to be associated to the monitor group. + third_party_service_ids = [ + "100000000048172001" + ] + + // (Optional) Enable incident management. Default value is false. + enable_incident_management = true + + // (Optional) Healing period for the incident. + healing_period = 10 + + // (Optional) Alert frequency for the incident. + alert_frequency = 10 + + // (Optional) Enable periodic alerting. + alert_periodically = true } ``` @@ -52,7 +82,15 @@ resource "site24x7_monitor_group" "monitor_group_us" { * `health_threshold_count` (Number) Number of monitors' health that decide the group status. ‘0’ implies that all the monitors are considered for determining the group status. Default value is 1. * `id` (String) The ID of this resource. * `suppress_alert` (Boolean) Boolean value indicating whether to suppress alert when the dependent monitor is down. Setting suppress_alert = true with an empty dependency_resource_id is meaningless. -* `tag_ids` (List of String) List of tags IDs to be associated to the monitor group. +* `healthcheck_profile_id` (String) Health check profile to be associated with the monitor group. +* `notification_profile_id` (String) Notification profile to be associated with the monitor group. +* `user_group_ids` (List of String) List of user groups to be notified when the monitor group is down. +* `tag_ids` (List of String) List of tag IDs to be associated to the monitor group. +* `third_party_service_ids` (List of String) List of Third Party Service IDs to be associated to the monitor group. +* `enable_incident_management` (Boolean) Enable incident management. Default value is false. +* `healing_period` (Number) Healing period for the incident. +* `alert_frequency` (Number) Alert frequency for the incident. +* `alert_periodically` (Boolean) Enable periodic alerting. Refer [API documentation](https://www.site24x7.com/help/api/#monitor-groups) for more information about attributes. \ No newline at end of file diff --git a/examples/monitor_group_us.tf b/examples/monitor_group_us.tf index 31ccc31..729336b 100644 --- a/examples/monitor_group_us.tf +++ b/examples/monitor_group_us.tf @@ -65,8 +65,37 @@ resource "site24x7_monitor_group" "monitor_group_us" { // Setting suppress_alert = true with an empty dependency_resource_id is meaningless. suppress_alert = true - // (Optional) List if tag IDs to be associated to the monitor. + // (Optional) Health check profile to be associated with the monitor group. + healthcheck_profile_id = "100000000000029001" + + // (Optional) Notification profile to be associated with the monitor group. + notification_profile_id = "100000000000029001" + + // (Optional) List of user groups to be notified when the monitor group is down. + user_group_ids = [ + "100000000000025005", + "100000000000025007" + ] + + // (Optional) List if tag IDs to be associated to the monitor group. tag_ids = [ - "100000000024829007", + "100000000048172001" + ] + + // (Optional) List of Third Party Service IDs to be associated to the monitor group. + third_party_service_ids = [ + "100000000048172001" ] + + // (Optional) Enable incident management. Default value is false. + enable_incident_management = true + + // (Optional) Healing period for the incident. + healing_period = 10 + + // (Optional) Alert frequency for the incident. + alert_frequency = 10 + + // (Optional) Enable periodic alerting. + alert_periodically = true } \ No newline at end of file diff --git a/examples/user_us.tf b/examples/user_us.tf index 6b73feb..8fd82ab 100644 --- a/examples/user_us.tf +++ b/examples/user_us.tf @@ -149,15 +149,15 @@ resource "site24x7_user" "user_example" { // (Optional) List of monitor groups to which the user has access to. 'monitor_groups' attribute is mandatory when the 'selection_type' is '1'. monitor_groups = [ - "306947000021059031", - "306947000033224882" + "100000000021059031", + "100000000033224882" ] // (Optional) Groups to be associated for the user for receiving alerts. user_group_ids = [ - "306947000000025005", - "306947000000025009", - "306947000000025007" + "100000000000025005", + "100000000000025009", + "100000000000025007" ] } diff --git a/site24x7/monitor_group.go b/site24x7/monitor_group.go index fa824f2..2bc2992 100644 --- a/site24x7/monitor_group.go +++ b/site24x7/monitor_group.go @@ -6,6 +6,32 @@ import ( apierrors "github.com/site24x7/terraform-provider-site24x7/api/errors" ) +// { +// "display_name": "group11", +// "description": "System Generated", +// "health_threshold_count": 1, +// "group_type": 1, +// "check_frequency": 1, +// "notification_profile_id": "100000000000029001", +// "healthcheck_profile_id": "100000000037110001", +// "monitors": [ +// "100000000000880011", +// "100000000021370006", +// "100000000030676016" +// ], +// "tags": [] +// "user_group_ids": [ +// "100000000000025005", +// "100000000000025007" +// "enable_incident_management": false, +// "healing_period": 10, +// "alert_frequency": 10, +// "alert_periodically": true, + +// ], + +// } + var MonitorGroupSchema = map[string]*schema.Schema{ "display_name": { Type: schema.TypeString, @@ -45,6 +71,27 @@ var MonitorGroupSchema = map[string]*schema.Schema{ Default: false, Description: "Boolean value indicating whether to suppress alert when the dependent monitor is down. Setting suppress_alert = true with an empty dependency_resource_id is meaningless.", }, + "healthcheck_profile_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Health check profile to be associated with the monitor group.", + }, + "notification_profile_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Notification profile to be associated with the monitor group.", + }, + "user_group_ids": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Computed: true, + Description: "List of user groups to be notified when the monitor group is down.", + }, "tag_ids": { Type: schema.TypeSet, Elem: &schema.Schema{ @@ -54,6 +101,36 @@ var MonitorGroupSchema = map[string]*schema.Schema{ Computed: true, Description: "List of tag IDs to be associated to the monitor group.", }, + "third_party_service_ids": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + Description: "List of Third Party Service IDs to be associated to the monitor group.", + }, + "enable_incident_management": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable incident management. Default value is false.", + }, + "healing_period": { + Type: schema.TypeInt, + Optional: true, + Description: "Healing period for the incident.", + }, + "alert_frequency": { + Type: schema.TypeInt, + Optional: true, + Description: "Alert frequency for the incident.", + }, + "alert_periodically": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Enable periodic alerting.", + }, } func ResourceSite24x7MonitorGroup() *schema.Resource { @@ -168,6 +245,13 @@ func resourceDataToMonitorGroupCreate(d *schema.ResourceData) *api.MonitorGroup } } + var userGroupIDs []string + for _, id := range d.Get("user_group_ids").([]interface{}) { + if id != nil { + userGroupIDs = append(userGroupIDs, id.(string)) + } + } + var tagIDs []string for _, id := range d.Get("tag_ids").(*schema.Set).List() { if id != nil { @@ -175,7 +259,14 @@ func resourceDataToMonitorGroupCreate(d *schema.ResourceData) *api.MonitorGroup } } - return &api.MonitorGroup{ + var thirdPartyServiceIDs []string + for _, id := range d.Get("third_party_service_ids").([]interface{}) { + if id != nil { + thirdPartyServiceIDs = append(thirdPartyServiceIDs, id.(string)) + } + } + + monitorGroup := &api.MonitorGroup{ GroupID: d.Id(), DisplayName: d.Get("display_name").(string), Description: d.Get("description").(string), @@ -184,8 +275,20 @@ func resourceDataToMonitorGroupCreate(d *schema.ResourceData) *api.MonitorGroup DependencyResourceIDs: dependencyResourceIDs, SuppressAlert: d.Get("suppress_alert").(bool), DependencyResourceType: 2, - TagIDs: tagIDs, } + + monitorGroup.NotificationProfileID = d.Get("notification_profile_id").(string) + monitorGroup.HealthCheckProfileID = d.Get("healthcheck_profile_id").(string) + monitorGroup.UserGroupIDs = userGroupIDs + monitorGroup.TagIDs = tagIDs + monitorGroup.ThirdPartyServiceIDs = thirdPartyServiceIDs + + monitorGroup.EnableIncidentManagement = d.Get("enable_incident_management").(bool) + monitorGroup.HealingPeriod = d.Get("healing_period").(int) + monitorGroup.AlertFrequency = d.Get("alert_frequency").(int) + monitorGroup.AlertPeriodically = d.Get("alert_periodically").(bool) + + return monitorGroup } func resourceDataToMonitorGroupUpdate(d *schema.ResourceData, monitorGroup *api.MonitorGroup) *api.MonitorGroup { @@ -227,6 +330,13 @@ func resourceDataToMonitorGroupUpdate(d *schema.ResourceData, monitorGroup *api. } } + var userGroupIDs []string + for _, id := range d.Get("user_group_ids").([]interface{}) { + if id != nil { + userGroupIDs = append(userGroupIDs, id.(string)) + } + } + var tagIDs []string for _, id := range d.Get("tag_ids").(*schema.Set).List() { if id != nil { @@ -234,7 +344,14 @@ func resourceDataToMonitorGroupUpdate(d *schema.ResourceData, monitorGroup *api. } } - return &api.MonitorGroup{ + var thirdPartyServiceIDs []string + for _, id := range d.Get("third_party_service_ids").([]interface{}) { + if id != nil { + thirdPartyServiceIDs = append(thirdPartyServiceIDs, id.(string)) + } + } + + monitorGroupToReturn := &api.MonitorGroup{ GroupID: d.Id(), DisplayName: d.Get("display_name").(string), Description: d.Get("description").(string), @@ -246,6 +363,19 @@ func resourceDataToMonitorGroupUpdate(d *schema.ResourceData, monitorGroup *api. DependencyResourceType: 2, TagIDs: tagIDs, } + + monitorGroupToReturn.NotificationProfileID = d.Get("notification_profile_id").(string) + monitorGroupToReturn.HealthCheckProfileID = d.Get("healthcheck_profile_id").(string) + monitorGroupToReturn.UserGroupIDs = userGroupIDs + monitorGroupToReturn.TagIDs = tagIDs + monitorGroupToReturn.ThirdPartyServiceIDs = thirdPartyServiceIDs + + monitorGroupToReturn.EnableIncidentManagement = d.Get("enable_incident_management").(bool) + monitorGroupToReturn.HealingPeriod = d.Get("healing_period").(int) + monitorGroupToReturn.AlertFrequency = d.Get("alert_frequency").(int) + monitorGroupToReturn.AlertPeriodically = d.Get("alert_periodically").(bool) + + return monitorGroupToReturn } func updateMonitorGroupResourceData(d *schema.ResourceData, monitorGroup *api.MonitorGroup) { @@ -256,4 +386,12 @@ func updateMonitorGroupResourceData(d *schema.ResourceData, monitorGroup *api.Mo d.Set("dependency_resource_ids", monitorGroup.DependencyResourceIDs) d.Set("suppress_alert", monitorGroup.SuppressAlert) d.Set("tag_ids", monitorGroup.TagIDs) + d.Set("notification_profile_id", monitorGroup.NotificationProfileID) + d.Set("healthcheck_profile_id", monitorGroup.HealthCheckProfileID) + d.Set("user_group_ids", monitorGroup.UserGroupIDs) + d.Set("third_party_service_ids", monitorGroup.ThirdPartyServiceIDs) + d.Set("enable_incident_management", monitorGroup.EnableIncidentManagement) + d.Set("healing_period", monitorGroup.HealingPeriod) + d.Set("alert_frequency", monitorGroup.AlertFrequency) + d.Set("alert_periodically", monitorGroup.AlertPeriodically) } diff --git a/site24x7/user.go b/site24x7/user.go index 7fe5985..99d3450 100644 --- a/site24x7/user.go +++ b/site24x7/user.go @@ -56,13 +56,13 @@ import ( // 1 // ], // "user_groups": [ -// "306947000000025005", -// "306947000000025009", -// "306947000000025007" +// "100000000000025005", +// "100000000000025009", +// "100000000000025007" // ], // "monitor_groups": [ -// "306947000021059031", -// "306947000033224882" +// "100000000021059031", +// "100000000033224882" // ] // } diff --git a/utilities/importer/site24x7_importer.py b/utilities/importer/site24x7_importer.py index ff13dcb..a53e56b 100644 --- a/utilities/importer/site24x7_importer.py +++ b/utilities/importer/site24x7_importer.py @@ -29,14 +29,14 @@ # Import a website monitor -# Monitor ID in Site24x7 = 306947000007878003 +# Monitor ID in Site24x7 = 100000000007878003 # main.tf entry # resource "site24x7_website_monitor" "peru_monitor" { # } # Import command -# terraform import site24x7_website_monitor.peru_monitor 306947000007878003 +# terraform import site24x7_website_monitor.peru_monitor 100000000007878003 ResourceNameVsAttributesJSONInState = {} ResourceNameVsFullConfiguration = {} From 9919affa40505ac3279eba187b35397d75306bef Mon Sep 17 00:00:00 2001 From: Jim Billy Date: Wed, 5 Jun 2024 18:58:43 +0530 Subject: [PATCH 5/6] build changes --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43c0911..39d9d10 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ jobs: uses: goreleaser/goreleaser-action@v2.7.0 with: version: latest - args: release --rm-dist + args: release --clean env: GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} # GitHub sets this automatically From 8dcc8b57204faa29b4b3e12b6c9c1da3b7d388ee Mon Sep 17 00:00:00 2001 From: Jim Billy Date: Wed, 5 Jun 2024 20:49:21 +0530 Subject: [PATCH 6/6] Changes for importing user group --- site24x7/user_group.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/site24x7/user_group.go b/site24x7/user_group.go index 480b216..702cc2d 100644 --- a/site24x7/user_group.go +++ b/site24x7/user_group.go @@ -52,7 +52,9 @@ func ResourceSite24x7UserGroup() *schema.Resource { Update: userGroupUpdate, Delete: userGroupDelete, Exists: userGroupExists, - + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: UserGroupSchema, } }