-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathAlwaysOn - Master Control Job and Alert.sql
212 lines (186 loc) · 7.55 KB
/
AlwaysOn - Master Control Job and Alert.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
USE [msdb];
DECLARE @MasterControlJobName SYSNAME, @AlertName SYSNAME, @SpecialConfigurations XML;
SET @MasterControlJobName = N'AlwaysOn: Master Control Job';
SET @AlertName = N'AlwaysOn: Role Changes';
SET @SpecialConfigurations = N'<config>
<item type="category" enablewhen="never">JobsToDisable</item>
<item type="category" enablewhen="ignore">SQL Sentry Jobs</item>
<item type="category" enablewhen="both">Database Maintenance</item>
<item type="category" enablewhen="both">AlwaysOn</item>
<item type="category" enablewhen="both">Mirroring</item>
<item type="category" enablewhen="primary" dbname="ReportServer">Report Server</item>
</config>'
;
DECLARE @ReturnCode INT, @CMD NVARCHAR(MAX), @saName SYSNAME;
SELECT @saName = [name] FROM sys.server_principals WHERE sid = 0x01;
BEGIN TRANSACTION
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'AlwaysOn' AND category_class=1)
BEGIN
PRINT N'Adding job category...';
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'AlwaysOn';
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
END;
IF EXISTS (SELECT * FROM msdb..sysjobs WHERE name = @MasterControlJobName)
BEGIN
PRINT N'Deleting existing job...';
EXEC msdb.dbo.sp_delete_job @job_name=@MasterControlJobName, @delete_unused_schedule=1;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
END
SET @CMD = N'SET NOCOUNT, ARITHABORT, XACT_ABORT, QUOTED_IDENTIFIER ON;
DECLARE @WhatIf BIT = 0;
DECLARE @SpecialConfigurations XML;
SET @SpecialConfigurations = N''' + REPLACE(CONVERT(nvarchar(max), @SpecialConfigurations), '''', '''''') + N''';
DECLARE @JobDesiredState INT, @CurrentRole VARCHAR(10), @CurrJob NVARCHAR(500);
DECLARE JobsToUpdate CURSOR
READ_ONLY FORWARD_ONLY
FOR
SELECT job_name, role_desc, desired_state
FROM
(
SELECT j.job_id, j.name AS job_name, jc.name AS category_name, j.enabled
--, Config.EnableWhen, db.dbname
, MIN(ag.role_desc) AS role_desc
, desired_state =
MAX(CASE WHEN Config.EnableWhen = ''never'' THEN 0
WHEN Config.EnableWhen = ''both'' THEN 1
WHEN DATABASEPROPERTYEX(db.dbname, ''Status'') = ''ONLINE'' AND Config.EnableWhen = ''secondary'' AND ag.role_desc = ''SECONDARY'' AND ag.secondary_role_allow_connections > 0 THEN 1
WHEN DATABASEPROPERTYEX(db.dbname, ''Status'') = ''ONLINE'' AND ISNULL(Config.EnableWhen, ''primary'') <> ''secondary'' AND ag.role_desc = ''PRIMARY'' THEN 1
ELSE 0
END)
FROM msdb..sysjobs AS j
INNER JOIN msdb..syscategories AS jc ON j.category_id=jc.category_id
INNER JOIN msdb..sysjobsteps AS js ON j.job_id=js.job_id
LEFT JOIN
(
SELECT
ConfigType = x.value(''(@type)[1]'',''varchar(10)'')
, EnableWhen = x.value(''(@enablewhen)[1]'',''varchar(10)'')
, DBName = x.value(''(@dbname)[1]'',''sysname'')
, ItemName = x.value(''(text())[1]'',''nvarchar(4000)'')
FROM @SpecialConfigurations.nodes(''config/item'') AS T(x)
) AS Config
ON
(Config.ConfigType = ''job'' AND j.name LIKE Config.ItemName)
OR (Config.ConfigType = ''category'' AND jc.name LIKE Config.ItemName)
OR (Config.ConfigType = ''step'' AND js.step_name LIKE Config.ItemName)
LEFT JOIN (
select databaselist.[name] as databasename, secondary_role_allow_connections, ars.role_desc
from sys.databases databaselist
inner join sys.availability_replicas ar ON databaselist.replica_id = ar.replica_id
inner join sys.dm_hadr_availability_replica_states ars ON ars.group_id = ar.group_id and ars.is_local = 1
) AS ag
ON (Config.DBName IS NULL AND js.database_name = ag.databasename)
OR (command like ''exec ''+QUOTENAME(ag.databasename)+''.%'')
OR (Config.DBName = ag.databasename)
CROSS APPLY
(VALUES(COALESCE(Config.DBName, ag.databasename, js.database_name))) AS db(dbname)
WHERE (Config.DBName IS NOT NULL OR ag.databasename IS NOT NULL) -- at least one combination found
AND (Config.EnableWhen IS NULL OR Config.EnableWhen <> ''ignore'')
group by j.job_id, j.name, jc.name, j.enabled
--, Config.EnableWhen, db.dbname
) AS q
WHERE enabled <> desired_state
ORDER BY job_name;
OPEN JobsToUpdate;
FETCH NEXT FROM JobsToUpdate INTO @CurrJob, @CurrentRole, @JobDesiredState;
WHILE @@FETCH_STATUS = 0
BEGIN
RAISERROR(N''Job: "%s", New Status: "%d" (role: "%s")'', 0, 1, @CurrJob, @JobDesiredState, @CurrentRole) WITH LOG;
IF @WhatIf = 0 EXEC msdb.dbo.sp_update_job @job_name=@CurrJob, @enabled=@JobDesiredState;
FETCH NEXT FROM JobsToUpdate INTO @CurrJob, @CurrentRole, @JobDesiredState;
END
CLOSE JobsToUpdate;
DEALLOCATE JobsToUpdate;'
IF @CMD IS NULL OR @CMD = N''
BEGIN
RAISERROR(N'@CMD is empty!',16,1);
GOTO QuitWithRollback;
END
PRINT N'Creating job...'
DECLARE @jobId UNIQUEIDENTIFIER
EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=@MasterControlJobName,
@enabled=1,
@notify_level_eventlog=0,
@notify_level_email=0,
@notify_level_netsend=0,
@notify_level_page=0,
@delete_level=0,
@description=N'Source: https://madeiradata.github.io/mssql-jobs-hadr',
@category_name=N'AlwaysOn',
@owner_login_name=@saName, @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
PRINT N'Adding job step...'
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'enable or disable jobs',
@step_id=1,
@cmdexec_success_code=0,
@on_success_action=1,
@on_success_step_id=0,
@on_fail_action=2,
@on_fail_step_id=0,
@retry_attempts=0,
@retry_interval=0,
@os_run_priority=0, @subsystem=N'TSQL',
@command=@CMD,
@database_name=N'master',
@flags=8
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
PRINT N'Setting job schedules...'
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'Every_60min',
@enabled=1,
@freq_type=4,
@freq_interval=1,
@freq_subday_type=4,
@freq_subday_interval=60,
@freq_relative_interval=0,
@freq_recurrence_factor=0,
@active_start_date=20100101,
@active_end_date=99991231,
@active_start_time=0,
@active_end_time=235959
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'RunAsSQLAgentServiceStartSchedule',
@enabled=1,
@freq_type=64,
@freq_interval=0,
@freq_subday_type=0,
@freq_subday_interval=0,
@freq_relative_interval=0,
@freq_recurrence_factor=0,
@active_start_date=20100101,
@active_end_date=99991231,
@active_start_time=0,
@active_end_time=235959
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
BEGIN TRANSACTION
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'AlwaysOn' AND category_class=2)
BEGIN
PRINT N'Adding alert category...'
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'ALERT', @type=N'NONE', @name=N'AlwaysOn';
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
END
IF EXISTS (SELECT * FROM msdb..sysalerts WHERE name = @AlertName)
BEGIN
PRINT N'Deleting existing alert...'
EXEC msdb.dbo.sp_delete_alert @name=@AlertName
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
END
PRINT CONCAT(N'Job Id: ', @jobId)
RAISERROR(N'Adding alert...',0,1) WITH NOWAIT;
EXEC msdb.dbo.sp_add_alert @name=@AlertName,
@enabled=1,
@message_id=1480,
@severity=0,
@delay_between_responses=0,
@include_event_description_in=0,
@job_id=@jobId;
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback;
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave: