diff --git a/KustoSchemaTools/Model/Cluster.cs b/KustoSchemaTools/Model/Cluster.cs index 832b648..e8bb2fb 100644 --- a/KustoSchemaTools/Model/Cluster.cs +++ b/KustoSchemaTools/Model/Cluster.cs @@ -6,6 +6,7 @@ public class Cluster public string Url { get; set; } public List Scripts { get; set; } = new List(); public ClusterCapacityPolicy? CapacityPolicy { get; set; } + public List WorkloadGroups { get; set; } = new List(); } } diff --git a/KustoSchemaTools/Model/WorkloadGroup.cs b/KustoSchemaTools/Model/WorkloadGroup.cs new file mode 100644 index 0000000..980976e --- /dev/null +++ b/KustoSchemaTools/Model/WorkloadGroup.cs @@ -0,0 +1,400 @@ +using Newtonsoft.Json; + +namespace KustoSchemaTools.Model +{ + public enum RateLimitKind + { + ConcurrentRequests, + ResourceUtilization + } + + public enum RateLimitScope + { + WorkloadGroup, + Principal + } + + public enum QueriesEnforcementLevel + { + QueryHead, + Cluster + } + + public enum CommandsEnforcementLevel + { + Cluster, + Database + } + + public enum QueryConsistency + { + Strong, + Weak, + WeakAffinitizedByQuery, + WeakAffinitizedByDatabase + } + + public enum RateLimitResourceKind + { + RequestCount, + TotalCpuSeconds + } + + public class WorkloadGroup : IEquatable + { + public required string WorkloadGroupName { get; set; } + + public WorkloadGroupPolicy? WorkloadGroupPolicy { get; set; } + public bool Equals(WorkloadGroup? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return + WorkloadGroupName == other.WorkloadGroupName && + EqualityComparer.Default.Equals(WorkloadGroupPolicy, other.WorkloadGroupPolicy); + } + + public override bool Equals(object? obj) => Equals(obj as WorkloadGroup); + public override int GetHashCode() + { + var hc = new HashCode(); + hc.Add(WorkloadGroupName); + hc.Add(WorkloadGroupPolicy); + return hc.ToHashCode(); + } + + public string ToCreateScript() + { + if (WorkloadGroupPolicy == null) + { + throw new InvalidOperationException("WorkloadGroupPolicy cannot be null when generating create script"); + } + + var workloadGroupPolicyJson = WorkloadGroupPolicy.ToJson(); + var script = $".create-or-alter workload_group {WorkloadGroupName} ```{workloadGroupPolicyJson}```"; + return script; + } + + public string ToUpdateScript() + { + if (WorkloadGroupPolicy == null) + { + throw new InvalidOperationException("WorkloadGroupPolicy cannot be null when generating update script"); + } + + var workloadGroupPolicyJson = WorkloadGroupPolicy.ToJson(); + var script = $".alter-merge workload_group {WorkloadGroupName} ```{workloadGroupPolicyJson}```"; + return script; + } + } + + public class WorkloadGroupPolicy : IEquatable + { + [JsonProperty("RequestLimitsPolicy")] + public RequestLimitsPolicy? RequestLimitsPolicy { get; set; } + + [JsonProperty("RequestRateLimitPolicies")] + public List? RequestRateLimitPolicies { get; set; } + + [JsonProperty("RequestRateLimitsEnforcementPolicy")] + public RequestRateLimitsEnforcementPolicy? RequestRateLimitsEnforcementPolicy { get; set; } + + [JsonProperty("QueryConsistencyPolicy")] + public QueryConsistencyPolicy? QueryConsistencyPolicy { get; set; } + + public bool Equals(WorkloadGroupPolicy? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return EqualityComparer.Default.Equals(RequestLimitsPolicy, other.RequestLimitsPolicy) && + (RequestRateLimitPolicies == null && other.RequestRateLimitPolicies == null || + RequestRateLimitPolicies != null && other.RequestRateLimitPolicies != null && + RequestRateLimitPolicies.SequenceEqual(other.RequestRateLimitPolicies)) && + EqualityComparer.Default.Equals(RequestRateLimitsEnforcementPolicy, other.RequestRateLimitsEnforcementPolicy) && + EqualityComparer.Default.Equals(QueryConsistencyPolicy, other.QueryConsistencyPolicy); + } + + public override bool Equals(object? obj) => Equals(obj as WorkloadGroupPolicy); + + public override int GetHashCode() + { + var hc = new HashCode(); + hc.Add(RequestLimitsPolicy); + hc.Add(RequestRateLimitsEnforcementPolicy); + hc.Add(QueryConsistencyPolicy); + if (RequestRateLimitPolicies != null) + { + foreach (var policy in RequestRateLimitPolicies) + { + hc.Add(policy); + } + } + return hc.ToHashCode(); + } + + public string ToJson() + { + return JsonConvert.SerializeObject(this, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.Indented + }); + } + } + + public class PolicyValue : IEquatable> + { + [JsonProperty("IsRelaxable")] + public bool IsRelaxable { get; set; } + + [JsonProperty("Value")] + public T? Value { get; set; } + + public bool Equals(PolicyValue? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return IsRelaxable == other.IsRelaxable && + EqualityComparer.Default.Equals(Value, other.Value); + } + + public override bool Equals(object? obj) => Equals(obj as PolicyValue); + + public override int GetHashCode() + { + return HashCode.Combine(IsRelaxable, Value); + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + } + + public class RequestLimitsPolicy : IEquatable + { + [JsonProperty("DataScope")] + public PolicyValue? DataScope { get; set; } + + [JsonProperty("MaxMemoryPerQueryPerNode")] + public PolicyValue? MaxMemoryPerQueryPerNode { get; set; } + + [JsonProperty("MaxMemoryPerIterator")] + public PolicyValue? MaxMemoryPerIterator { get; set; } + + [JsonProperty("MaxFanoutThreadsPercentage")] + public PolicyValue? MaxFanoutThreadsPercentage { get; set; } + + [JsonProperty("MaxFanoutNodesPercentage")] + public PolicyValue? MaxFanoutNodesPercentage { get; set; } + + [JsonProperty("MaxResultRecords")] + public PolicyValue? MaxResultRecords { get; set; } + + [JsonProperty("MaxResultBytes")] + public PolicyValue? MaxResultBytes { get; set; } + + [JsonProperty("MaxExecutionTime")] + public PolicyValue? MaxExecutionTime { get; set; } + + [JsonProperty("QueryResultsProgressiveUpdatePeriod")] + public PolicyValue? QueryResultsProgressiveUpdatePeriod { get; set; } + + public bool Equals(RequestLimitsPolicy? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return EqualityComparer?>.Default.Equals(DataScope, other.DataScope) && + EqualityComparer?>.Default.Equals(MaxMemoryPerQueryPerNode, other.MaxMemoryPerQueryPerNode) && + EqualityComparer?>.Default.Equals(MaxMemoryPerIterator, other.MaxMemoryPerIterator) && + EqualityComparer?>.Default.Equals(MaxFanoutThreadsPercentage, other.MaxFanoutThreadsPercentage) && + EqualityComparer?>.Default.Equals(MaxFanoutNodesPercentage, other.MaxFanoutNodesPercentage) && + EqualityComparer?>.Default.Equals(MaxResultRecords, other.MaxResultRecords) && + EqualityComparer?>.Default.Equals(MaxResultBytes, other.MaxResultBytes) && + EqualityComparer?>.Default.Equals(MaxExecutionTime, other.MaxExecutionTime) && + EqualityComparer?>.Default.Equals(QueryResultsProgressiveUpdatePeriod, other.QueryResultsProgressiveUpdatePeriod); + } + + public override bool Equals(object? obj) => Equals(obj as RequestLimitsPolicy); + + public override int GetHashCode() + { + var hc = new HashCode(); + hc.Add(DataScope); + hc.Add(MaxMemoryPerQueryPerNode); + hc.Add(MaxMemoryPerIterator); + hc.Add(MaxFanoutThreadsPercentage); + hc.Add(MaxFanoutNodesPercentage); + hc.Add(MaxResultRecords); + hc.Add(MaxResultBytes); + hc.Add(MaxExecutionTime); + hc.Add(QueryResultsProgressiveUpdatePeriod); + return hc.ToHashCode(); + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + } + + public class RateLimitProperties : IEquatable + { + [JsonProperty("MaxConcurrentRequests")] + public int? MaxConcurrentRequests { get; set; } + + [JsonProperty("ResourceKind")] + public RateLimitResourceKind? ResourceKind { get; set; } + + [JsonProperty("MaxUtilization")] + public double? MaxUtilization { get; set; } + + [JsonProperty("TimeWindow")] + public TimeSpan? TimeWindow { get; set; } + + public bool Equals(RateLimitProperties? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return MaxConcurrentRequests == other.MaxConcurrentRequests && + ResourceKind == other.ResourceKind && + MaxUtilization == other.MaxUtilization && + TimeWindow == other.TimeWindow; + } + + public override bool Equals(object? obj) => Equals(obj as RateLimitProperties); + + public override int GetHashCode() + { + return HashCode.Combine(MaxConcurrentRequests, ResourceKind, MaxUtilization, TimeWindow); + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + } + + public class RequestRateLimitPolicy : IEquatable + { + [JsonProperty("IsEnabled")] + public bool IsEnabled { get; set; } + + [JsonProperty("Scope")] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public RateLimitScope Scope { get; set; } + + [JsonProperty("LimitKind")] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public RateLimitKind LimitKind { get; set; } + + [JsonProperty("Properties")] + public RateLimitProperties? Properties { get; set; } + + public bool Equals(RequestRateLimitPolicy? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return IsEnabled == other.IsEnabled && + Scope == other.Scope && + LimitKind == other.LimitKind && + EqualityComparer.Default.Equals(Properties, other.Properties); + } + + public override bool Equals(object? obj) => Equals(obj as RequestRateLimitPolicy); + + public override int GetHashCode() + { + return HashCode.Combine(IsEnabled, Scope, LimitKind, Properties); + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + } + + public class RequestRateLimitsEnforcementPolicy : IEquatable + { + [JsonProperty("QueriesEnforcementLevel")] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public QueriesEnforcementLevel QueriesEnforcementLevel { get; set; } + + [JsonProperty("CommandsEnforcementLevel")] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public CommandsEnforcementLevel CommandsEnforcementLevel { get; set; } + + public bool Equals(RequestRateLimitsEnforcementPolicy? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return QueriesEnforcementLevel == other.QueriesEnforcementLevel && + CommandsEnforcementLevel == other.CommandsEnforcementLevel; + } + + public override bool Equals(object? obj) => Equals(obj as RequestRateLimitsEnforcementPolicy); + + public override int GetHashCode() + { + return HashCode.Combine(QueriesEnforcementLevel, CommandsEnforcementLevel); + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + } + + public class QueryConsistencyPolicy : IEquatable + { + [JsonProperty("QueryConsistency")] + public PolicyValue? QueryConsistency { get; set; } + + [JsonProperty("CachedResultsMaxAge")] + public PolicyValue? CachedResultsMaxAge { get; set; } + + public bool Equals(QueryConsistencyPolicy? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return EqualityComparer?>.Default.Equals(QueryConsistency, other.QueryConsistency) && + EqualityComparer?>.Default.Equals(CachedResultsMaxAge, other.CachedResultsMaxAge); + } + + public override bool Equals(object? obj) => Equals(obj as QueryConsistencyPolicy); + + public override int GetHashCode() + { + return HashCode.Combine(QueryConsistency, CachedResultsMaxAge); + } + + public override string ToString() + { + return JsonConvert.SerializeObject(this, new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None + }); + } + } +} \ No newline at end of file