/// <summary>Get the virtual machine batch operation.</summary> /// <param name="virtualMachines">List of the virtual machines</param> /// <param name="partitionKey"></param> /// <param name="log"></param> /// <returns></returns> private static TableBatchOperation GetVirtualMachineBatchOperation(IList <IVirtualMachine> virtualMachines, string partitionKey, TraceWriter log) { if (virtualMachines == null) { return(null); } var virtualMachineTableBatchOperation = new TableBatchOperation(); partitionKey = partitionKey.Replace(Delimeters.ForwardSlash, Delimeters.Exclamatory); foreach (var eachVirtualMachine in virtualMachines) { try { var virtualMachineEntity = VirtualMachineHelper.ConvertToVirtualMachineEntity( eachVirtualMachine, partitionKey, eachVirtualMachine.ResourceGroupName); virtualMachineEntity.VirtualMachineGroup = VirtualMachineGroup.AvailabilitySets.ToString(); virtualMachineTableBatchOperation.InsertOrReplace(virtualMachineEntity); } catch (Exception ex) { log.Error($"timercrawlerforavailableset threw the exception ", ex, "GetVirtualMachineBatchOperation"); } } return(virtualMachineTableBatchOperation); }
/// <summary>1. Convert the list of virtual machines into Virtual machine crawler entities /// 2. Add the entity into the table using the batch operation task</summary> /// <param name="virtualMachines">List of virtual machines, which needs to push into table</param> /// <param name="resourceGroupName"></param> /// <param name="log">Trace writer instance</param> /// <returns>Returns the list of the insert batch operation as task.</returns> private static TableBatchOperation InsertOrReplaceEntitiesIntoTable(List <IVirtualMachine> virtualMachines, string resourceGroupName, TraceWriter log) { if (virtualMachines.Count == 0) { return(null); } var batchOperation = new TableBatchOperation(); foreach (var eachVirtualMachine in virtualMachines) { try { var partitionKey = resourceGroupName; batchOperation.InsertOrReplace(VirtualMachineHelper.ConvertToVirtualMachineEntity(eachVirtualMachine, partitionKey)); } catch (Exception e) { log.Error($"timercrawlerforvirtualmachines threw the exception ", e, "InsertEntitiesIntoTable"); } } return(batchOperation); }
/// <summary>Get the virtual machines by resource group and availability set ids.</summary> /// <param name="resourceGroupName"></param> /// <param name="availabilitySetIds"></param> /// <param name="azureClient"></param> /// <returns></returns> private static IList <IGrouping <string, IVirtualMachine> > GetVirtualMachineListByResourceGroup( string resourceGroupName, List <string> availabilitySetIds, AzureClient azureClient) { // Get the virtual machines by resource group var virtualMachinesList = azureClient.AzureInstance.VirtualMachines.ListByResourceGroup(resourceGroupName).ToList(); if (!virtualMachinesList.Any()) { return(null); } var loadBalancerVmTask = VirtualMachineHelper.GetVirtualMachinesFromLoadBalancers(resourceGroupName, azureClient); var loadbalancerVms = loadBalancerVmTask.Result; if (loadbalancerVms != null && loadbalancerVms.Any()) { virtualMachinesList = virtualMachinesList.Where(x => !loadbalancerVms.Contains(x.Id))?.ToList(); } // Group the the virtual machine based on the availability set id var virtualMachinesByAvailabilitySetId = virtualMachinesList?.Where(x => availabilitySetIds .Contains(x.AvailabilitySetId, StringComparer.OrdinalIgnoreCase)) .GroupBy(x => x.AvailabilitySetId, x => x).ToList(); return(virtualMachinesByAvailabilitySetId); }
public void CreateRule(TraceWriter log) { try { var loadBalancer = GetRandomLoadBalancer(); if (loadBalancer == null) { log.Info("Loadbalancer RuleEngine: No load balancer found with virtual machines."); return; } var filteredVmSet = GetVirtualMachineSet(loadBalancer.Id); if (filteredVmSet == null) { log.Info("Loadbalancer RuleEngine: No virtual machines found for the load balancer name: " + loadBalancer.ResourceName); return; } var table = StorageAccountProvider.CreateOrGetTable(StorageTableNames.ScheduledRulesTableName); if (table == null) { return; } var count = VmCount(filteredVmSet.Count); var tasks = new List <Task>(); // do // { var randomSets = filteredVmSet.Take(count).ToList(); filteredVmSet = filteredVmSet.Except(randomSets).ToList(); for (var i = 0; i < randomSets.Count; i += TableConstants.TableServiceBatchMaximumOperations) { var batchItems = randomSets.Skip(i) .Take(TableConstants.TableServiceBatchMaximumOperations).ToList(); var batchOperation = VirtualMachineHelper.CreateScheduleEntity(batchItems, _azureClient.AzureSettings.Chaos.SchedulerFrequency, _azureClient.AzureSettings.Chaos.AzureFaultInjectionActions, VirtualMachineGroup.LoadBalancer); var operation = batchOperation; tasks.Add(table.ExecuteBatchAsync(operation)); } // } while (filteredVmSet.Any()); Task.WhenAll(tasks); log.Info("Loadbalancer RuleEngine: Completed creating rule engine."); } catch (Exception ex) { log.Error("LoadBalancer RuleEngine: Exception thrown. ", ex); } }
private void InsertVirtualMachineAvailabilitySetDomainResults(string availabilitySetId, int domainNumber) { var virtualMachineQuery = TableQuery.CombineFilters(TableQuery.GenerateFilterCondition("AvailabilitySetId", QueryComparisons.Equal, availabilitySetId), TableOperators.And, _azureClient.AzureSettings.Chaos.AvailabilitySetChaos.FaultDomainEnabled ? TableQuery.GenerateFilterConditionForInt("FaultDomain", QueryComparisons.Equal, domainNumber) : TableQuery.GenerateFilterConditionForInt("UpdateDomain", QueryComparisons.Equal, domainNumber)); //TableQuery.GenerateFilterConditionForInt("AvailabilityZone", QueryComparisons.GreaterThanOrEqual, 0); var virtualMachinesTableQuery = new TableQuery <VirtualMachineCrawlerResponse>().Where(virtualMachineQuery); var crawledVirtualMachinesResults = StorageAccountProvider.GetEntities(virtualMachinesTableQuery, StorageTableNames.VirtualMachineCrawlerTableName); var virtualMachinesResults = crawledVirtualMachinesResults.ToList(); if (!virtualMachinesResults.Any()) { return; } var domainFlag = !_azureClient.AzureSettings.Chaos.AvailabilitySetChaos.UpdateDomainEnabled; var batchTasks = new List <Task>(); var table = StorageAccountProvider.CreateOrGetTable(StorageTableNames.ScheduledRulesTableName); if (table == null) { return; } for (var i = 0; i < virtualMachinesResults.Count; i += TableConstants.TableServiceBatchMaximumOperations) { var batchItems = virtualMachinesResults.Skip(i) .Take(TableConstants.TableServiceBatchMaximumOperations).ToList(); var scheduledRulesbatchOperation = VirtualMachineHelper.CreateScheduleEntityForAvailabilitySet(batchItems, _azureClient.AzureSettings.Chaos.SchedulerFrequency, _azureClient.AzureSettings.Chaos.AzureFaultInjectionActions, domainFlag); if (scheduledRulesbatchOperation.Count <= 0) { return; } batchTasks.Add(table.ExecuteBatchAsync(scheduledRulesbatchOperation)); } if (batchTasks.Count > 0) { Task.WhenAll(batchTasks); } }
/// <summary>Get the list of the executer instances from the scheduled Rules data.</summary> /// <param name="scheduledRules">List of the scheduled Rules from the scheduled table.</param> /// /// <param name="rollbackRules">List of the rollback Rules from the scheduled table.</param> /// <param name="starter">Durable Orchestration client instance, to start the executer function</param> /// <param name="log">Trace writer to log the information/warning/errors.</param> /// <returns>The list of task, which has the instances of the executers.</returns> private static List <Task> GetListOfExecuters(IEnumerable <ScheduledRules> scheduledRules, IEnumerable <ScheduledRules> rollbackRules, DurableOrchestrationClient starter, TraceWriter log) { var tasks = new List <Task>(); foreach (var result in scheduledRules) { var partitionKey = result.ResourceType.Replace(Delimeters.Exclamatory, Delimeters.ForwardSlash); //Bug - need to map the vmss vm in the availability zone to vmscaleset executer if (!Mappings.FunctionNameMap.ContainsKey(partitionKey)) { continue; } var functionMapName = (partitionKey.Equals(VirtualMachineGroup.AvailabilityZones.ToString(), StringComparison.OrdinalIgnoreCase) && result.RowKey.ToLowerInvariant().Contains(VirtualMachineGroup.VirtualMachineScaleSets.ToString().ToLowerInvariant()) ? VirtualMachineGroup.AvailabilityZones.ToString() + VirtualMachineGroup.VirtualMachineScaleSets.ToString() : partitionKey); var functionName = Mappings.FunctionNameMap[functionMapName]; log.Info($"Timely trigger: invoking function: {functionName}"); var triggeredData = JsonConvert.DeserializeObject <InputObject>(result.TriggerData); tasks.Add(starter.StartNewAsync(functionName, result.TriggerData)); } foreach (var result in rollbackRules) { var partitionKey = result.ResourceType.Replace(Delimeters.Exclamatory, Delimeters.ForwardSlash); if (!Mappings.FunctionNameMap.ContainsKey(partitionKey)) { continue; } var triggeredData = JsonConvert.DeserializeObject <InputObject>(result.TriggerData); triggeredData.Action = VirtualMachineHelper.GetAction(result.FinalState).ToString(); if (!triggeredData.EnableRollback) { triggeredData.EnableRollback = true; } var functionMapName = (partitionKey.Equals(VirtualMachineGroup.AvailabilityZones.ToString(), StringComparison.OrdinalIgnoreCase) && result.RowKey.ToLowerInvariant().Contains(VirtualMachineGroup.VirtualMachineScaleSets.ToString().ToLowerInvariant()) ? VirtualMachineGroup.AvailabilityZones.ToString() + VirtualMachineGroup.VirtualMachineScaleSets.ToString() : partitionKey); var functionName = Mappings.FunctionNameMap[functionMapName]; log.Info($"Timely trigger: invoking function: {functionName}"); tasks.Add(starter.StartNewAsync(functionName, JsonConvert.SerializeObject(triggeredData))); } return(tasks); }
/// <summary>Create the virtual machine rules</summary> /// <param name="log"></param> public void CreateRule(TraceWriter log) { try { log.Info("VirtualMachine RuleEngine: Started the creating rules for the virtual machines."); var vmSets = GetRandomVmSet(); if (vmSets == null) { log.Info("VirtualMachine RuleEngine: No virtual machines found.."); return; } var table = StorageAccountProvider.CreateOrGetTable(StorageTableNames.ScheduledRulesTableName); var count = VmCount(vmSets.Count); var tasks = new List <Task>(); //do //{ var randomSets = vmSets.Take(count).ToList(); vmSets = vmSets.Except(randomSets).ToList(); for (var i = 0; i < randomSets.Count; i += TableConstants.TableServiceBatchMaximumOperations) { var batchItems = randomSets.Skip(i) .Take(TableConstants.TableServiceBatchMaximumOperations).ToList(); var batchOperation = VirtualMachineHelper.CreateScheduleEntity(batchItems, azureClient.AzureSettings.Chaos.SchedulerFrequency, azureClient.AzureSettings.Chaos.AzureFaultInjectionActions, VirtualMachineGroup.VirtualMachines); if (batchOperation == null) { continue; } tasks.Add(table.ExecuteBatchAsync(batchOperation)); } // } while (vmSets.Any()); Task.WhenAll(tasks); log.Info("VirtualMachine RuleEngine: Completed creating rule engine.."); } catch (Exception ex) { log.Error("VirtualMachine RuleEngine: Exception thrown. ", ex); } }
private static TableBatchOperation InsertLoadBalancerVirtualMachines(List <string> virtualMachineIds, ILoadBalancer eachLoadBalancer, AzureClient azureClient, TraceWriter log) { if (virtualMachineIds == null) { return(null); } var virtualMachineBatchOperation = new TableBatchOperation(); foreach (var eachvirtualMachineId in virtualMachineIds) { var virtualMachine = azureClient.AzureInstance.VirtualMachines.GetById(eachvirtualMachineId); var partitionKey = eachLoadBalancer.Id.Replace(Delimeters.ForwardSlash, Delimeters.Exclamatory); virtualMachineBatchOperation.InsertOrReplace(VirtualMachineHelper.ConvertToVirtualMachineEntityFromLB(virtualMachine, partitionKey, VirtualMachineGroup.LoadBalancer.ToString())); } return(virtualMachineBatchOperation); }
/// <summary>Insert the list of the scale set virtual machine instances into the table.</summary> /// <param name="virtualMachines">List of the virtual machines.</param> /// <param name="resourceGroupName">Resource group name of the scale set</param> /// <param name="scaleSetId">Id of the scale set</param> /// <param name="availabilityZone">Availability zone id of the scale set</param> /// <returns></returns> private static TableBatchOperation GetVirtualMachineBatchOperation(IEnumerable <IVirtualMachineScaleSetVM> virtualMachines, string resourceGroupName, string scaleSetId, int?availabilityZone) { if (virtualMachines == null) { return(null); } var virtualMachineBatchOperation = new TableBatchOperation(); foreach (var eachVirtualMachine in virtualMachines) { // Azure table doesnot allow partition key with forward slash var partitionKey = scaleSetId.Replace(Delimeters.ForwardSlash, Delimeters.Exclamatory); virtualMachineBatchOperation.InsertOrReplace(VirtualMachineHelper.ConvertToVirtualMachineEntity(eachVirtualMachine, resourceGroupName, scaleSetId, partitionKey, availabilityZone, VirtualMachineGroup.VirtualMachineScaleSets.ToString())); } return(virtualMachineBatchOperation); }
/// <summary>1. Get the List of virtual machines for the resource group. /// 2. Get all the virtual machines from the load balancers.</summary> /// <param name="resourceGroup">From which resource group needs to get the virtual machines.</param> /// <param name="log">Trace writer instance</param> /// <returns>List of virtual machines which excludes the load balancer virtual machines and availability set virtual machines.</returns> private static async Task <IEnumerable <IVirtualMachine> > GetVirtualMachinesByResourceGroup( IResourceGroup resourceGroup, TraceWriter log) { try { var azureClient = new AzureClient(); var loadBalancersVirtualMachines = VirtualMachineHelper.GetVirtualMachinesFromLoadBalancers(resourceGroup.Name, azureClient); var pagedCollection = azureClient.AzureInstance.VirtualMachines.ListByResourceGroupAsync(resourceGroup.Name); var tasks = new List <Task> { loadBalancersVirtualMachines, pagedCollection }; await Task.WhenAll(tasks); if (pagedCollection.Result == null || !pagedCollection.Result.Any()) { log.Info( $"timercrawlerforvirtualmachines: no virtual machines for the resource group: {resourceGroup.Name}"); return(null); } var loadBalancerIds = loadBalancersVirtualMachines.Result; var virtuallMachines = pagedCollection.Result; return(virtuallMachines?.Select(x => x).Where(x => string.IsNullOrWhiteSpace(x.AvailabilitySetId) && !loadBalancerIds.Contains(x.Id, StringComparer.OrdinalIgnoreCase))); } catch (Exception e) { log.Error("Error occured on GetVirtualMachinesByResourceGroup", e); return(null); } }
private void InsertVirtualMachineAvailabilityZoneRegionResults(string region, int availbilityZone, TraceWriter log) { try { var virtualMachineQuery = TableQuery.CombineFilters(TableQuery.GenerateFilterConditionForInt( "AvailabilityZone", QueryComparisons.Equal, availbilityZone), TableOperators.And, TableQuery.GenerateFilterCondition("RegionName", QueryComparisons.Equal, region)); //TableQuery.GenerateFilterConditionForInt("AvailabilityZone", QueryComparisons.GreaterThanOrEqual, 0); var virtualMachinesTableQuery = new TableQuery <VirtualMachineCrawlerResponse>().Where(virtualMachineQuery); var crawledVirtualMachinesResults = StorageAccountProvider.GetEntities( virtualMachinesTableQuery, StorageTableNames.VirtualMachineCrawlerTableName); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// crawledVirtualMachinesResults = crawledVirtualMachinesResults.Where(x => PowerState.Parse(x.State) == PowerState.Running); var virtualMachinesResults = crawledVirtualMachinesResults.ToList(); var meanTimeQuery = TableQuery.GenerateFilterConditionForDate("ScheduledExecutionTime", QueryComparisons.GreaterThanOrEqual, DateTimeOffset.UtcNow.AddMinutes(-azureClient.AzureSettings.Chaos.MeanTime)); var recentlyExecutedAvailabilityZoneRegionCombinationQuery = TableQuery.GenerateFilterCondition( "ResourceType", QueryComparisons.Equal, VirtualMachineGroup.VirtualMachineScaleSets.ToString()); var recentlyExecutedVMScaleSetsQuery = TableQuery.CombineFilters(meanTimeQuery, TableOperators.And, recentlyExecutedAvailabilityZoneRegionCombinationQuery); var scheduledQuery = new TableQuery <ScheduledRules>().Where(recentlyExecutedVMScaleSetsQuery); //Will get the executed query results. var executedVMScaleSetsResults = StorageAccountProvider.GetEntities(scheduledQuery, StorageTableNames.ScheduledRulesTableName); List <VirtualMachineCrawlerResponse> executedVMAvailabilityZones = null; if (virtualMachinesResults.Count() != 0 && executedVMScaleSetsResults.Count() != 0) { foreach (var virtualMachineResult in virtualMachinesResults) { foreach (var executedVMScaleSetsResult in executedVMScaleSetsResults) { if ((executedVMScaleSetsResult.RowKey.ToLowerInvariant().Contains(virtualMachineResult.ResourceName.ToLowerInvariant())) && (executedVMScaleSetsResult.RowKey.ToLowerInvariant().Contains(virtualMachineResult.ResourceGroupName.ToLowerInvariant())) && (executedVMScaleSetsResult.RowKey.ToLowerInvariant().Contains(virtualMachineResult.AvailabilityZone.ToString())) //&& (executedVMScaleSetsResult.RowKey.ToLowerInvariant().Contains(executedVMScaleSetsResult..ToLowerInvariant())) ) { executedVMAvailabilityZones.Add(virtualMachineResult); } } } if (executedVMAvailabilityZones != null && executedVMAvailabilityZones.Count() != 0) { virtualMachinesResults = virtualMachinesResults.Except(executedVMAvailabilityZones).ToList(); } } if (!virtualMachinesResults.Any()) { return; } var batchTasks = new List <Task>(); var table = StorageAccountProvider.CreateOrGetTable(StorageTableNames.ScheduledRulesTableName); if (table == null) { return; } for (var i = 0; i < virtualMachinesResults.Count; i += TableConstants.TableServiceBatchMaximumOperations) { var batchItems = virtualMachinesResults.Skip(i) .Take(TableConstants.TableServiceBatchMaximumOperations).ToList(); var scheduledRulesbatchOperation = VirtualMachineHelper .CreateScheduleEntityForAvailabilityZone( batchItems, azureClient.AzureSettings.Chaos.SchedulerFrequency, azureClient.AzureSettings.Chaos.AzureFaultInjectionActions); if (scheduledRulesbatchOperation.Count <= 0) { return; } batchTasks.Add(table.ExecuteBatchAsync(scheduledRulesbatchOperation)); } if (batchTasks.Count > 0) { Task.WhenAll(batchTasks); } } catch (Exception ex) { log.Error("AvailabilityZone RuleEngine: thrown exception", ex); log.Error(ex.Source); log.Error(ex.Message); } }
private async Task ProcessAllVirtualMachinesActionAsync(IDialogContext context, LuisResult result, Operations operation, ResumeAfter <AllVirtualMachinesFormState> resume) { EntityRecommendation resourceGroupEntity; var accessToken = await context.GetAccessToken(resourceId.Value); if (string.IsNullOrEmpty(accessToken)) { return; } var subscriptionId = context.GetSubscriptionId(); var availableVMs = (await new VMDomain().ListVirtualMachinesAsync(accessToken, subscriptionId)).ToList(); // retrieve the list of VMs that are in the correct power state var validPowerStates = VirtualMachineHelper.RetrieveValidPowerStateByOperation(operation); IEnumerable <VirtualMachine> candidateVMs = null; if (result.TryFindEntity("ResourceGroup", out resourceGroupEntity)) { // obtain the name specified by the user - text in LUIS result is different var resourceGroup = resourceGroupEntity.GetEntityOriginalText(result.Query); candidateVMs = availableVMs.Where(vm => vm.ResourceGroup.Equals(resourceGroup, StringComparison.InvariantCultureIgnoreCase)).ToList(); if (candidateVMs == null || !candidateVMs.Any()) { var operationText = VirtualMachineHelper.RetrieveOperationTextByOperation(operation); await context.PostAsync($"The {resourceGroup} resource group doesn't contain VMs or doesn't exist in the current subscription."); context.Done <string>(null); return; } candidateVMs = candidateVMs.Where(vm => validPowerStates.Contains(vm.PowerState)).ToList(); if (candidateVMs == null || !candidateVMs.Any()) { var operationText = VirtualMachineHelper.RetrieveOperationTextByOperation(operation); await context.PostAsync($"No virtual machines that can be {operationText} were found in the {resourceGroup} resource group of the current subscription."); context.Done <string>(null); return; } } else { candidateVMs = availableVMs.Where(vm => validPowerStates.Contains(vm.PowerState)).ToList(); if (!candidateVMs.Any()) { var operationText = VirtualMachineHelper.RetrieveOperationTextByOperation(operation); await context.PostAsync($"No virtual machines that can be {operationText} were found in the current subscription."); context.Done <string>(null); return; } } // prompt the user to select a VM from the list var form = new FormDialog <AllVirtualMachinesFormState>( new AllVirtualMachinesFormState(candidateVMs, operation), VMForms.BuildAllVirtualMachinesForm, FormOptions.PromptInStart, null); context.Call(form, resume); }
private async Task ProcessVirtualMachineActionAsync(IDialogContext context, LuisResult result, Operations operation, ResumeAfter <VirtualMachineFormState> resume) { EntityRecommendation virtualMachineEntity; // retrieve the list virtual machines from the subscription var accessToken = await context.GetAccessToken(resourceId.Value); if (string.IsNullOrEmpty(accessToken)) { return; } var subscriptionId = context.GetSubscriptionId(); var availableVMs = (await new VMDomain().ListVirtualMachinesAsync(accessToken, subscriptionId)).ToList(); // check if the user specified a virtual machine name in the command if (result.TryFindEntity("VirtualMachine", out virtualMachineEntity)) { // obtain the name specified by the user - text in LUIS result is different var virtualMachineName = virtualMachineEntity.GetEntityOriginalText(result.Query); // ensure that the virtual machine exists in the subscription var selectedVM = availableVMs.FirstOrDefault(p => p.Name.Equals(virtualMachineName, StringComparison.InvariantCultureIgnoreCase)); if (selectedVM == null) { await context.PostAsync($"The '{virtualMachineName}' virtual machine was not found in the current subscription."); context.Done <string>(null); return; } // ensure that the virtual machine is in the correct power state for the requested operation if ((operation == Operations.Start && (selectedVM.PowerState == VirtualMachinePowerState.Starting || selectedVM.PowerState == VirtualMachinePowerState.Running)) || (operation == Operations.Shutdown && (selectedVM.PowerState == VirtualMachinePowerState.Stopping || selectedVM.PowerState == VirtualMachinePowerState.Stopped)) || (operation == Operations.Stop && (selectedVM.PowerState == VirtualMachinePowerState.Deallocating || selectedVM.PowerState == VirtualMachinePowerState.Deallocated))) { var powerState = selectedVM.PowerState.ToString().ToLower(); await context.PostAsync($"The '{virtualMachineName}' virtual machine is already {powerState}."); context.Done <string>(null); return; } virtualMachineEntity.Entity = selectedVM.Name; } // retrieve the list of VMs that are in the correct power state var validPowerStates = VirtualMachineHelper.RetrieveValidPowerStateByOperation(operation); var candidateVMs = availableVMs.Where(vm => validPowerStates.Contains(vm.PowerState)).ToList(); if (candidateVMs.Any()) { // prompt the user to select a VM from the list var form = new FormDialog <VirtualMachineFormState>( new VirtualMachineFormState(candidateVMs, operation), VMForms.BuildVirtualMachinesForm, FormOptions.PromptInStart, result.Entities); context.Call(form, resume); } else { var operationText = VirtualMachineHelper.RetrieveOperationTextByOperation(operation); await context.PostAsync($"No virtual machines that can be {operationText} were found in the current subscription."); context.Done <string>(null); //context.Wait(this.MessageReceived); } }