diff --git a/README.md b/README.md index 20ca0a3..436f33c 100644 --- a/README.md +++ b/README.md @@ -53,14 +53,14 @@ Bringing SCOM in to the 21. century with a Restful Web API. | [GET] API/MonitoringObject/{id} | Get a monitoring object and all child object | | [GET] API/MonitoringObject/class/{classId} | Get all objects of a class. Limited properties returned. | +### Performance -### Installation +| Route | Description | Parameters | +| ------ | ------ | ------ | +| [GET] API/Perf/{managedEntityId} | Get RAW performance data from a specific managedEntity and metric | managedEntityId, counterName, startDate, endDate | +| [GET] API/Perf/hourly/{managedEntityId} | Get hourly aggregated performance data from a specific managedEntity and metric | managedEntityId, counterName, startDate, endDate | +| [GET] API/Perf/daily/{managedEntityId} | Get daily aggregated performance data from a specific managedEntity and metric | managedEntityId, counterName, startDate, endDate | -- Download the zip and extract to your SCOM management server running IIS or download the whole source to make your own customizations -- Create a new web site and application pool -- Set your application pool to use Network Service -- Enable windows authentication (basic if needed) -- Copy SCOM specific .dll's to the BIN folder where you extracted the .Zip +### Installation -### Remarks -- Please note that versioning isn't implemented and current version have breaking changes to Alert endpoints. Please review the changes to get an understanding on how this affects your application. For first time users this is not a problem. +Follow the (very limited) guide here https://github.com/ehrnst/System-Center-Operations-Manager-API/wiki/Installation-and-configuration diff --git a/SCOM API/Controllers/SCOMAlertController.cs b/SCOM API/Controllers/SCOMAlertController.cs index a1643d5..a117a9b 100644 --- a/SCOM API/Controllers/SCOMAlertController.cs +++ b/SCOM API/Controllers/SCOMAlertController.cs @@ -160,9 +160,10 @@ public IList GetAlertByMonitoringObjectId(Guid MonitoringObject /// For more information please see technet documentation "http://bit.ly/2zblZLh" /// Specify alert guid you want to update [HttpPut] - [ResponseType(typeof(IEnumerable))] + [ResponseType(typeof(HttpResponseMessage))] [Route("Alerts/{Id:Guid}")] - public IList UpdateAlertById([FromUri()]Guid Id, [FromBody()] SCOMAlertUpdateModel Properties) + //public IList UpdateAlertById([FromUri()]Guid Id, [FromBody()] SCOMAlertUpdateModel Properties) + public IHttpActionResult UpdateAlertById([FromUri()]Guid Id, [FromBody()] SCOMAlertUpdateModel Properties) { if (Id == Guid.Empty) { @@ -246,7 +247,8 @@ public IList UpdateAlertById([FromUri()]Guid Id, [FromBody()] S } } - return alerts; + // creating OK response + return Ok(new { message = "Alert updated", alertId = Id.ToString() }); } diff --git a/SCOM API/Controllers/SCOMMaintenanceController.cs b/SCOM API/Controllers/SCOMMaintenanceController.cs index 4e3d5cb..b2b93c9 100644 --- a/SCOM API/Controllers/SCOMMaintenanceController.cs +++ b/SCOM API/Controllers/SCOMMaintenanceController.cs @@ -16,6 +16,7 @@ using System.Configuration; using System.Web.Http.Description; using Microsoft.EnterpriseManagement.Monitoring.MaintenanceSchedule; +using Swashbuckle.Swagger.Annotations; namespace SCOM_API.Controllers { @@ -59,7 +60,7 @@ public IHttpActionResult EnableComputerMaintenance(SCOMComputerMaintenanceModel List MaintenanceComputers = new List(); - ///travers trough all classes to get monitoring objects + //travers trough all classes to get monitoring objects foreach (ManagementPackClass monClass in monClasses) { monObjects.AddRange(mg.EntityObjects.GetObjectReader(criteria, ObjectQueryOptions.Default)); @@ -111,8 +112,6 @@ public IHttpActionResult EnableComputerMaintenance(SCOMComputerMaintenanceModel - - /// /// Puts the specified monitoring object in maintenance mode. /// @@ -190,14 +189,92 @@ public IHttpActionResult EnableObjectMaintenance(SCOMObjectMaintenanceModel Data } + /// + /// Updates or ends existing maintenance mode for object. + /// + /// Json string with object id and new endTime + /// If true, maintenance will end + /// + /// { + /// "id": "Guid", + /// "EndTime": "2017-07-07T19:00:00.000Z" + /// } + /// + /// Successfully updated maintenance mode + /// Bad request. Check json input + /// Object not in maintenance. Nothing to update + + [HttpPut] + [SwaggerResponse(HttpStatusCode.OK, "Object maintenance mode updated")] + [ResponseType(typeof(HttpResponseMessage))] + [Route("API/ObjectMaintenance")] + public IHttpActionResult UpdateObjectMaintenance(SCOMUpdateObjectMaintenanceModel Data, bool EndNow = false) + { + //Validate input + if (ModelState.IsValid) + { + //create a Guid from the json input + var ObjectId = new Guid(Data.id); + //get the monitoring object by Guid + var monObject = mg.EntityObjects.GetObject(ObjectId, ObjectQueryOptions.Default); + + //If object not in maintenance not modified + if (!monObject.InMaintenanceMode) + { + { + HttpResponseMessage res = new HttpResponseMessage(HttpStatusCode.NotModified); + res.Content = new StringContent("Specified object not in maintenance mode. Nothing to update..."); + throw new HttpResponseException(res); + } + } + + //If object in maintenanance update + else + { + //If endNow parameter validate true. End maintenance mode + if (EndNow.Equals(true)) + { + monObject.StopMaintenanceMode(DateTime.UtcNow, TraversalDepth.Recursive); + + } + + // Get the maintenance window + MaintenanceWindow MaintenanceWindow = monObject.GetMaintenanceWindow(); + + //If user specifies an end date + if (Data.EndTime > DateTime.MinValue) + { + + //Compare specified end time with current maintenance end time + int TimeCompare = DateTime.Compare(Data.EndTime, MaintenanceWindow.ScheduledEndTime); + //Update end time but use same reason and comment + monObject.UpdateMaintenanceMode(Data.EndTime, MaintenanceWindow.Reason, MaintenanceWindow.Comments); + } + + } + // creating OK response + return Ok(new { message = "Updated maintenance mode", monitoringObjectId = Data.id }); + + } + + // throw error message + else + { + HttpResponseMessage res = new HttpResponseMessage(HttpStatusCode.BadRequest); + res.Content = new StringContent("Please check request body"); + throw new HttpResponseException(res); + } + } + + /// /// Creates a new maintenance schedule with the specified monitoring objects. /// - /// Json string scheduleName, object ids, StartTime, EndTime, comment + /// scheduleName, object ids, StartTime, EndTime, comment are mandatory /// /// { /// "scheduleName": "string", - /// "id": "[monitoringObjectId]", + /// "id": "[monitoringObjectId's]", /// "StartTime": "2017-05-22T07:01:00.374Z", /// "EndTime": "2017-05-22T08:01:00.374Z", /// "comment": "doing maintenance" @@ -233,7 +310,6 @@ public IHttpActionResult ScheduleObjectMaintenance(SCOMObjectSchedMaintenanceMod ObjectList.Add(item); } - // //create a recurrencePattern this is 'sourced' from OmCommands.10.dll ( new-scommaintenanceSchedule CMDLET ) //read more: https://docs.microsoft.com/en-us/powershell/systemcenter/systemcenter2016/operationsmanager/vlatest/new-scommaintenanceschedule @@ -263,10 +339,11 @@ public IHttpActionResult ScheduleObjectMaintenance(SCOMObjectSchedMaintenanceMod var shed = MaintenanceSchedule.GetMaintenanceScheduleById(guid, mg); List MaintenanceScheduleList = new List(); SCOMObjectSchedMaintenanceModel mSched = new SCOMObjectSchedMaintenanceModel(); + mSched.scheduleId = guid; + mSched.scheduleName = shed.ScheduleName; mSched.id = array; mSched.StartTime = shed.ActiveStartTime; mSched.EndTime = shed.ScheduledEndTime; - mSched.scheduleName = shed.ScheduleName; mSched.comment = shed.Comments; MaintenanceScheduleList.Add(mSched); @@ -276,5 +353,6 @@ public IHttpActionResult ScheduleObjectMaintenance(SCOMObjectSchedMaintenanceMod } + } }//END diff --git a/SCOM API/Controllers/SCOMPerfController.cs b/SCOM API/Controllers/SCOMPerfController.cs new file mode 100644 index 0000000..7c9fd74 --- /dev/null +++ b/SCOM API/Controllers/SCOMPerfController.cs @@ -0,0 +1,333 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Web.Http; +using System.Data.SqlClient; +using System.Configuration; +using System.Data; +using System.Text; +using Newtonsoft.Json; +using System.Data.SqlTypes; +using Microsoft.SqlServer.Server; +using System.Security.Principal; + +namespace SCOM_API.Controllers +{ + + public class SCOMPerfController : ApiController + { + SqlConnection DWConnection = new SqlConnection(); + public SCOMPerfController() + { + System.Security.Principal.WindowsImpersonationContext impersonationContext; + impersonationContext = + ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate(); + + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + var SCOMDW = ConfigurationManager.AppSettings["ScomDWServer"]; + builder["Data Source"] = SCOMDW; + builder["Integrated Security"] = "SSPI"; + builder["Initial Catalog"] = "OperationsManagerDW"; + + + + DWConnection.ConnectionString = builder.ConnectionString; + } + + private DataTable dataTable = new DataTable(); + + #region rawData + + /// + /// Get RAW performance data from a specific managedEntity and metric + /// + /// + /// API/Perf/5f2f477c-3b19-4ce8-b27a-eef59b9dc377?counterName=PercentMemoryUsed + /// + /// The guid of your managed entity, ie: windows computer + /// The performance counter you want to retrieve data from + /// Optionally add your start date. Data will be pulled between start and end dates + /// Optionally add your start date. Data will be pulled between start and end dates + + [HttpGet] + [Route("API/Perf/{managedEntityId:Guid}")] + public IHttpActionResult GetPerformanceData(Guid managedEntityId, string counterName, DateTime? startDate = null, DateTime? endDate = null) + { + using (WindowsImpersonationContext context = (WindowsIdentity.GetCurrent()).Impersonate()) + { + if (managedEntityId == Guid.Empty && string.IsNullOrEmpty(counterName)) + { + throw new HttpResponseException(Request + .CreateResponse(HttpStatusCode.BadRequest)); + } + + + else + { + + if (!endDate.HasValue) + { + endDate = DateTime.UtcNow; + } + + if (!startDate.HasValue) + { + startDate = (DateTime)SqlDateTime.MinValue; + } + + // Construct the actual DW sql query + string sqlQuery = @" + USE OperationsManagerDW + SELECT DateTime, SampleValue, ObjectName, InstanceName, CounterName + FROM + Perf.vPerfRaw INNER JOIN + vPerformanceRuleInstance ON Perf.vPerfRaw.PerformanceRuleInstanceRowId = vPerformanceRuleInstance.PerformanceRuleInstanceRowId INNER JOIN + vPerformanceRule ON vPerformanceRuleInstance.RuleRowId = vPerformanceRule.RuleRowId INNER JOIN + vRelationship ON Perf.vPerfRaw.ManagedEntityRowId = vRelationship.TargetManagedEntityRowId INNER JOIN + vManagedEntity ON vRelationship.SourceManagedEntityRowId = vManagedEntity.ManagedEntityRowId + WHERE ManagedEntityGuid = @entity + AND vPerformanceRule.CounterName = @counter + AND DateTime between @startDate and @endDate + ORDER BY Perf.vPerfRaw.DateTime DESC"; + + try + { + + // Initiate command and add parameters + + SqlCommand sqlCmd = new SqlCommand(); + sqlCmd.CommandType = CommandType.Text; + SqlParameter counter = sqlCmd.Parameters.Add("@counter", SqlDbType.VarChar, 256); + counter.Value = counterName; + sqlCmd.Parameters.AddWithValue("@entity", managedEntityId); + sqlCmd.Parameters.AddWithValue("@startDate", startDate); + sqlCmd.Parameters.AddWithValue("@endDate", endDate); + + sqlCmd.CommandText = sqlQuery; + sqlCmd.Connection = DWConnection; + + + // Connect SQL + DWConnection.Open(); + // Fill datatable with result from SQL query + SqlDataAdapter da = new SqlDataAdapter(sqlCmd); + da.Fill(dataTable); + + // Close connections and reurn dataTable + da.Dispose(); + DWConnection.Close(); + return Ok(dataTable); + } + + catch (Exception Ex) + { + + HttpResponseMessage exeption = new HttpResponseMessage(HttpStatusCode.InternalServerError); + exeption.Content = new StringContent(Ex.ToString()); + throw new HttpResponseException(exeption); + } + } + + } + + } + + #endregion + + #region hourlyData + + /// + /// Get hourly performance data from a specific managedEntity and metric + /// + /// + /// API/Perf/5f2f477c-3b19-4ce8-b27a-eef59b9dc377?counterName=PercentMemoryUsed + /// + /// The guid of your managed entity, ie: windows computer + /// The performance counter you want to retrieve data from + /// Optionally add your start date. Data will be pulled between start and end dates + /// Optionally add your start date. Data will be pulled between start and end dates + + [HttpGet] + [Route("API/Perf/Hourly/{managedEntityId:Guid}")] + public IHttpActionResult GetHourlyPerformanceData(Guid managedEntityId, string counterName, DateTime? startDate = null, DateTime? endDate = null) + { + using (WindowsImpersonationContext context = (WindowsIdentity.GetCurrent()).Impersonate()) + { + if (managedEntityId == Guid.Empty && string.IsNullOrEmpty(counterName)) + { + throw new HttpResponseException(Request + .CreateResponse(HttpStatusCode.BadRequest)); + } + + + else + { + + if (!endDate.HasValue) + { + endDate = DateTime.UtcNow; + } + + if (!startDate.HasValue) + { + startDate = (DateTime)SqlDateTime.MinValue; + } + + // Construct the actual DW sql query + string sqlQuery = @" + USE OperationsManagerDW + SELECT DateTime, MaxValue, AverageValue, MinValue, StandardDeviation, ObjectName, InstanceName, CounterName + FROM + Perf.vPerfHourly INNER JOIN + vPerformanceRuleInstance ON Perf.vPerfHourly.PerformanceRuleInstanceRowId = vPerformanceRuleInstance.PerformanceRuleInstanceRowId INNER JOIN + vPerformanceRule ON vPerformanceRuleInstance.RuleRowId = vPerformanceRule.RuleRowId INNER JOIN + vRelationship ON Perf.vPerfHourly.ManagedEntityRowId = vRelationship.TargetManagedEntityRowId INNER JOIN + vManagedEntity ON vRelationship.SourceManagedEntityRowId = vManagedEntity.ManagedEntityRowId + WHERE ManagedEntityGuid = @entity + AND vPerformanceRule.CounterName = @counter + AND DateTime between @startDate and @endDate + ORDER BY Perf.vPerfHourly.DateTime DESC"; + + try + { + // Initiate command and add parameters + SqlCommand sqlCmd = new SqlCommand(); + sqlCmd.CommandType = CommandType.Text; + SqlParameter counter = sqlCmd.Parameters.Add("@counter", SqlDbType.VarChar, 256); + counter.Value = counterName; + sqlCmd.Parameters.AddWithValue("@entity", managedEntityId); + sqlCmd.Parameters.AddWithValue("@startDate", startDate); + sqlCmd.Parameters.AddWithValue("@endDate", endDate); + + sqlCmd.CommandText = sqlQuery; + sqlCmd.Connection = DWConnection; + + + // Connect SQL + DWConnection.Open(); + // Fill datatable with result from SQL query + SqlDataAdapter da = new SqlDataAdapter(sqlCmd); + da.Fill(dataTable); + + // Close connections and reurn dataTable + da.Dispose(); + DWConnection.Close(); + return Ok(dataTable); + } + + catch (Exception Ex) + { + + HttpResponseMessage exeption = new HttpResponseMessage(HttpStatusCode.InternalServerError); + exeption.Content = new StringContent(Ex.ToString()); + throw new HttpResponseException(exeption); + } + } + + } + } + #endregion + + #region dailyData + + /// + /// Get daily aggragated performance data from a specific managedEntity and metric + /// + /// + /// API/Perf/5f2f477c-3b19-4ce8-b27a-eef59b9dc377?counterName=PercentMemoryUsed + /// + /// The guid of your managed entity, ie: windows computer + /// The performance counter you want to retrieve data from + /// Optionally add your start date. Data will be pulled between start and end dates + /// Optionally add your start date. Data will be pulled between start and end dates + + [HttpGet] + [Route("API/Perf/Daily/{managedEntityId:Guid}")] + public IHttpActionResult GetDailyPerformanceData(Guid managedEntityId, string counterName, DateTime? startDate = null, DateTime? endDate = null) + { + using (WindowsImpersonationContext context = (WindowsIdentity.GetCurrent()).Impersonate()) + { + if (managedEntityId == Guid.Empty && string.IsNullOrEmpty(counterName)) + { + throw new HttpResponseException(Request + .CreateResponse(HttpStatusCode.BadRequest)); + } + + + else + { + + if (!endDate.HasValue) + { + endDate = DateTime.UtcNow; + } + + if (!startDate.HasValue) + { + startDate = (DateTime)SqlDateTime.MinValue; + } + + // Construct the actual DW sql query + string sqlQuery = @" + USE OperationsManagerDW + SELECT DateTime, MaxValue, AverageValue, MinValue, StandardDeviation, ObjectName, InstanceName, CounterName + FROM + Perf.vPerfDaily INNER JOIN + vPerformanceRuleInstance ON Perf.vPerfDaily.PerformanceRuleInstanceRowId = vPerformanceRuleInstance.PerformanceRuleInstanceRowId INNER JOIN + vPerformanceRule ON vPerformanceRuleInstance.RuleRowId = vPerformanceRule.RuleRowId INNER JOIN + vRelationship ON Perf.vPerfDaily.ManagedEntityRowId = vRelationship.TargetManagedEntityRowId INNER JOIN + vManagedEntity ON vRelationship.SourceManagedEntityRowId = vManagedEntity.ManagedEntityRowId + WHERE ManagedEntityGuid = @entity + AND vPerformanceRule.CounterName = @counter + AND DateTime between @startDate and @endDate + ORDER BY Perf.vPerfDaily.DateTime DESC"; + + try + { + // Initiate command and add parameters + SqlCommand sqlCmd = new SqlCommand(); + sqlCmd.CommandType = CommandType.Text; + SqlParameter counter = sqlCmd.Parameters.Add("@counter", SqlDbType.VarChar, 256); + counter.Value = counterName; + sqlCmd.Parameters.AddWithValue("@entity", managedEntityId); + sqlCmd.Parameters.AddWithValue("@startDate", startDate); + sqlCmd.Parameters.AddWithValue("@endDate", endDate); + + sqlCmd.CommandText = sqlQuery; + sqlCmd.Connection = DWConnection; + + // Connect SQL + DWConnection.Open(); + + if (DWConnection.State == ConnectionState.Closed) + { + throw new HttpResponseException(HttpStatusCode.ServiceUnavailable); + } + + + // Fill datatable with result from SQL query + SqlDataAdapter da = new SqlDataAdapter(sqlCmd); + da.Fill(dataTable); + + // Close connections and reurn dataTable + da.Dispose(); + DWConnection.Close(); + return Ok(dataTable); + } + + catch (Exception Ex) + { + + HttpResponseMessage exeption = new HttpResponseMessage(HttpStatusCode.InternalServerError); + exeption.Content = new StringContent(Ex.ToString()); + throw new HttpResponseException(exeption); + } + } + + } + } + #endregion + + } +} +//END diff --git a/SCOM API/Models/SCOMObjectMaintenanceModel.cs b/SCOM API/Models/SCOMObjectMaintenanceModel.cs index 1ac4011..e9193e4 100644 --- a/SCOM API/Models/SCOMObjectMaintenanceModel.cs +++ b/SCOM API/Models/SCOMObjectMaintenanceModel.cs @@ -15,6 +15,7 @@ public class SCOMObjectMaintenanceModel public string id { get; set; } public string displayName { get; set; } + /// /// Minutes to maintenance /// @@ -27,4 +28,24 @@ public class SCOMObjectMaintenanceModel /// public string comment { get; set; } } + + public class SCOMUpdateObjectMaintenanceModel + { + /// + /// Monitoring object id + /// + [Required(ErrorMessage = "Please provide object guid")] + public string id { get; set; } + + /// + /// New endtime for the maintenance + /// + [Required(ErrorMessage = "End time is required")] + public DateTime EndTime { get; set; } + + /// + /// comment for the maintenance + /// + public string comment { get; set; } + } } \ No newline at end of file diff --git a/SCOM API/Models/SCOMObjectScheduleMaintenanceModel.cs b/SCOM API/Models/SCOMObjectScheduleMaintenanceModel.cs index b0e39c6..f429fc6 100644 --- a/SCOM API/Models/SCOMObjectScheduleMaintenanceModel.cs +++ b/SCOM API/Models/SCOMObjectScheduleMaintenanceModel.cs @@ -8,30 +8,40 @@ namespace SCOM_API.Models { public class SCOMObjectSchedMaintenanceModel { + /// + /// Guid for the maintenance schedule + /// + /// remarks GUID will be created + public Guid scheduleId { get; set; } + /// /// Name of the maintenance schedule /// [Required] public string scheduleName { get; set; } - [Required] + /// /// Monitoring object ID(s) /// - public string[] id { get; set; } [Required] + public string[] id { get; set; } + /// /// Start time and date /// - public DateTime StartTime { get; set; } [Required] + public DateTime StartTime { get; set; } + /// /// End time and date /// - public DateTime EndTime { get; set; } [Required] + public DateTime EndTime { get; set; } + /// /// Comment /// + [Required] public string comment { get; set; } } } \ No newline at end of file diff --git a/SCOM API/SCOM API.csproj b/SCOM API/SCOM API.csproj index e138bae..a45eef0 100644 --- a/SCOM API/SCOM API.csproj +++ b/SCOM API/SCOM API.csproj @@ -119,16 +119,16 @@ True - False - \\distr\users\aa98\PUBLIC\Microsoft.EnterpriseManagement.Core.dll + ..\packages\Unofficial.Microsoft.EnterpriseManagement.OperationsManager.7.0.5000\lib\net40\Microsoft.EnterpriseManagement.Core.dll + True - False - \\distr\users\aa98\PUBLIC\Microsoft.EnterpriseManagement.OperationsManager.dll + ..\packages\Unofficial.Microsoft.EnterpriseManagement.OperationsManager.7.0.5000\lib\net40\Microsoft.EnterpriseManagement.OperationsManager.dll + True - False - \\distr\users\aa98\PUBLIC\Microsoft.EnterpriseManagement.Runtime.dll + ..\packages\Unofficial.Microsoft.EnterpriseManagement.OperationsManager.7.0.5000\lib\net40\Microsoft.EnterpriseManagement.Runtime.dll + True ..\packages\Microsoft.Extensions.Configuration.Abstractions.1.0.0\lib\netstandard1.0\Microsoft.Extensions.Configuration.Abstractions.dll @@ -270,6 +270,7 @@ + Global.asax diff --git a/SCOM API/Web.config b/SCOM API/Web.config index 5c29591..3e383f9 100644 --- a/SCOM API/Web.config +++ b/SCOM API/Web.config @@ -6,6 +6,7 @@ + @@ -22,11 +23,7 @@ - + diff --git a/SCOM API/packages.config b/SCOM API/packages.config index dea8c35..269e26b 100644 --- a/SCOM API/packages.config +++ b/SCOM API/packages.config @@ -66,5 +66,6 @@ + \ No newline at end of file