Skip to content

Instantly share code, notes, and snippets.

@mrjamiebowman
Created September 24, 2020 12:54
Show Gist options
  • Save mrjamiebowman/ced0d015b3bcdd52a59056678e74d60f to your computer and use it in GitHub Desktop.
Save mrjamiebowman/ced0d015b3bcdd52a59056678e74d60f to your computer and use it in GitHub Desktop.
.NET Health Check SQL Permissions
public class SqlPermsHealthCheck : IHealthCheck
{
private string sql = @"SELECT
p.name,
p.schema_id,
schema_name = sch.name,
has_perms_by_name(p.name, 'OBJECT', 'EXECUTE') as has_execute,
has_perms_by_name(p.name, 'OBJECT', 'VIEW DEFINITION') as has_view_definition
FROM sys.procedures p
LEFT JOIN sys.schemas sch ON sch.schema_id = p.schema_id
WHERE p.type = 'P'";
public string ConnectionString { get; set; }
public List<HealthCheckSqlPermission> SqlPerms { get; set; } = new List<HealthCheckSqlPermission>();
public SqlPermsHealthCheck(string connectionString)
{
ConnectionString = connectionString;
}
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
bool? healthCheckResultHealthy = null;
var data = new ConcurrentDictionary<string, object>();
// verify connection string
if (String.IsNullOrWhiteSpace(ConnectionString))
throw new ArgumentException("Connection string is not set.");
// get stored procs and perms from db
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
// Create a SqlCommand object.
using (SqlCommand sqlCommand = new SqlCommand(sql, connection))
{
try
{
connection.Open();
// Run the query by calling ExecuteReader().
using (SqlDataReader dataReader = sqlCommand.ExecuteReader())
{
// Create a data table to hold the retrieved data.
DataTable dataTable = new DataTable();
// Load the data from SqlDataReader into the data table.
dataTable.Load(dataReader);
foreach (DataRow row in dataTable.Rows)
{
HealthCheckSqlPermission model = new HealthCheckSqlPermission();
model.name = row["name"].ToString();
model.schema_id = row["schema_id"].ToString();
model.schema_name = row["schema_name"].ToString();
model.has_execute = Convert.ToBoolean(row["has_execute"]);
model.has_view_definition = Convert.ToBoolean(row["has_view_definition"]);
SqlPerms.Add(model);
}
// Close the SqlDataReader.
dataReader.Close();
}
}
catch (Exception ex)
{
healthCheckResultHealthy = false;
data.TryAdd("error", "connection failure.");
goto handleresult;
}
finally
{
// Close the connection.
connection.Close();
}
}
}
// get degraded
var degradedPerms = SqlPerms.Where(x => x.has_view_definition == false || x.has_execute == false);
// handle result
if (degradedPerms.Count() == 0 && healthCheckResultHealthy == null)
{
healthCheckResultHealthy = true;
}
else
{
// return degraded
foreach (var perm in degradedPerms)
{
data.TryAdd("degraded", $"{perm.schema_name}.{perm.name}");
}
}
handleresult:
// return health check
if (healthCheckResultHealthy == true)
{
data.TryAdd("status", "UP");
var health = HealthCheckResult.Healthy("A healthy result.", data);
return Task.FromResult(health);
}
else
{
data.TryAdd("status", "DEGRADED");
var health = HealthCheckResult.Degraded("An unhealthy result.", null, data);
return Task.FromResult(health);
}
}
}
@mrjamiebowman
Copy link
Author

FYI.. WIP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment