public override async Task <IOperationStatus> CreateOperationStatusAsync(IOperationDescription operationDescription, IOperationContext context)
        {
            context.ThrowIfNull(nameof(context));

            ClusterOperationDescription description = operationDescription == null ? null : operationDescription as ClusterOperationDescription;

            Trace.WriteInfo(TraceType, "CreateOperationStatusAsync: begin");
            IOperationStatus status = null;

            try
            {
                Trace.WriteInfo(TraceType, "CreateOperationStatusAsync: performing operation");
                var errorDetails = await DoOperation(description, context);

                Trace.WriteInfo(TraceType, "CreateOperationStatusAsync: building status");
                status = await BuildStatusAsync(description, context, errorDetails);
            }
            catch (Exception ex)
            {
                Trace.WriteError(this.TraceType, $"CreateOperationStatusAsync: Exception encountered: {ex}");
            }

            Trace.WriteInfo(TraceType, "CreateOperationStatusAsync: end");
            return(status);
        }
        private async Task <ClusterErrorDetails> DoOperation(ClusterOperationDescription description, IOperationContext context)
        {
            if (description == null)
            {
                Trace.WriteInfo(TraceType, "CreateOperationStatusAsync: operation description is null. No operation to perform.");
                return(null);
            }

            var upgradeTask = ClusterTask(
                () => this.ProcessClusterUpgradeAsync(description.UpgradeDescription, context.CancellationToken),
                ClusterOperation.ProcessClusterUpgrade);

            var enableNodesTask = ClusterTask(
                () => this.fabricClientWrapper.EnableNodesAsync(description.NodesToEnabled, Constants.MaxOperationTimeout, context.CancellationToken),
                ClusterOperation.EnableNodes);

            var disableNodesTask = ClusterTask(
                () => this.fabricClientWrapper.DisableNodesAsync(description.NodesToDisabled, Constants.MaxOperationTimeout, context.CancellationToken),
                ClusterOperation.DisableNodes);

            var updateSystemServiceSizeTask = ClusterTask(
                () => this.fabricClientWrapper.UpdateSystemServicesDescriptionAsync(
                    description.SystemServiceDescriptionsToSet,
                    Constants.MaxOperationTimeout,
                    context.CancellationToken),
                ClusterOperation.UpdateSystemServicesReplicaSetSize);

            var nodeListForAutoScaleTask = ClusterTask(
                () => this.nodeStatusManager.ProcessWRPResponse(
                    description.ProcessedNodesStatus,
                    Constants.KvsCommitTimeout,
                    context.CancellationToken),
                ClusterOperation.ProcessNodesStatus);

            var errors = await Task.WhenAll(
                upgradeTask,
                enableNodesTask,
                disableNodesTask,
                nodeListForAutoScaleTask,
                updateSystemServiceSizeTask);

            var taskErrors = errors.Where(item => item != null).ToList();

            if (!taskErrors.Any())
            {
                return(null);
            }

            return(new ClusterErrorDetails()
            {
                Errors = new List <ClusterOperationError>(taskErrors)
            });
        }
        private async Task <IOperationStatus> BuildStatusAsync(ClusterOperationDescription description, IOperationContext context, ClusterErrorDetails errorDetails)
        {
            var upgradeProgressTask = this.fabricClientWrapper.GetFabricUpgradeProgressAsync(Constants.MaxOperationTimeout, context.CancellationToken);

            var nodeListQueryTask = this.fabricClientWrapper.GetNodeListAsync(Constants.MaxOperationTimeout, context.CancellationToken);

            // Only query for system services when WRP needs to adjust the replica set size
            Task <Dictionary <string, ServiceRuntimeDescription> > systemServiceSizeQueryTask = null;

            if (description != null &&
                description.SystemServiceDescriptionsToSet != null &&
                description.SystemServiceDescriptionsToSet.Any())
            {
                systemServiceSizeQueryTask =
                    this.fabricClientWrapper.GetSystemServiceRuntimeDescriptionsAsync(Constants.MaxOperationTimeout, context.CancellationToken);
            }

            await Task.WhenAll(
                nodeListQueryTask,
                upgradeProgressTask,
                systemServiceSizeQueryTask ?? Task.FromResult <Dictionary <string, ServiceRuntimeDescription> >(null));

            FabricUpgradeProgress currentUpgradeProgress = GetResultFromTask(upgradeProgressTask);
            NodeList nodeList = FilterPrimaryNodeTypesStatus(GetResultFromTask(nodeListQueryTask), description?.PrimaryNodeTypes);
            Dictionary <string, ServiceRuntimeDescription> systemServicesRuntimeDescriptions = GetResultFromTask(systemServiceSizeQueryTask);

            List <PaasNodeStatusInfo> nodesDisabled = null;
            List <PaasNodeStatusInfo> nodesEnabled  = null;

            if (description != null &&
                nodeList != null)
            {
                Trace.WriteNoise(TraceType, "BuildStatusAsync: Begin this.nodeStatusManager.ProcessNodeQuery.");
                await this.nodeStatusManager.ProcessNodeQuery(nodeList, Constants.KvsCommitTimeout, context.CancellationToken);

                Trace.WriteNoise(TraceType, "BuildStatusAsync: End this.nodeStatusManager.ProcessNodeQuery.");

                // Send back the list of nodes that are disabled
                if (description.NodesToDisabled != null)
                {
                    nodesDisabled = new List <PaasNodeStatusInfo>();

                    // Send back the Instance# for the requested disabled nodes
                    foreach (var nodeToDisable in description.NodesToDisabled)
                    {
                        var matchingNodeStatus =
                            nodeList.FirstOrDefault(
                                node =>
                                string.Equals(node.NodeName, nodeToDisable.NodeName,
                                              StringComparison.OrdinalIgnoreCase));
                        if (matchingNodeStatus != null && matchingNodeStatus.NodeStatus == NodeStatus.Disabled)
                        {
                            var nodeDisabled = new PaasNodeStatusInfo(nodeToDisable)
                            {
                                NodeState = NodeState.Disabled
                            };

                            nodesDisabled.Add(nodeDisabled);

                            Trace.WriteInfo(TraceType, "BuildStatusAsync: Node has been successfully disabled. {0}", nodeDisabled);
                        }
                    }
                }

                // Send back the list of nodes that are Enabled
                if (description.NodesToEnabled != null)
                {
                    nodesEnabled = new List <PaasNodeStatusInfo>();

                    // Send back the Instance# for the requested up nodes
                    foreach (var nodeToEnable in description.NodesToEnabled)
                    {
                        var matchingNodeStatus =
                            nodeList.FirstOrDefault(
                                node =>
                                string.Equals(node.NodeName, nodeToEnable.NodeName,
                                              StringComparison.OrdinalIgnoreCase));

                        // Since a node can be enabled and can still be down, we infer enabled status instead.
                        if (matchingNodeStatus != null &&
                            (matchingNodeStatus.NodeStatus != NodeStatus.Disabling) &&
                            (matchingNodeStatus.NodeStatus != NodeStatus.Disabled) &&
                            (matchingNodeStatus.NodeStatus != NodeStatus.Enabling))
                        {
                            var nodeEnabled = new PaasNodeStatusInfo(nodeToEnable);
                            nodeEnabled.NodeState = NodeState.Enabled;

                            nodesEnabled.Add(nodeEnabled);

                            Trace.WriteInfo(TraceType, "BuildStatusAsync: Node has been successfully enabled. {0}", nodeEnabled);
                        }
                    }
                }
            }

            Trace.WriteNoise(TraceType, "BuildStatusAsync: Begin this.nodeStatusManager.GetNodeStates.");
            var nodesStatus = await this.nodeStatusManager.GetNodeStates(Constants.KvsCommitTimeout, context.CancellationToken);

            Trace.WriteNoise(TraceType, "BuildStatusAsync: End this.nodeStatusManager.GetNodeStates.");

            var status = new ClusterOperationStatus(description)
            {
                DisabledNodes             = nodesDisabled,
                EnabledNodes              = nodesEnabled,
                NodesStatus               = nodesStatus,
                SystemServiceDescriptions = systemServicesRuntimeDescriptions,
            };

            if (currentUpgradeProgress != null)
            {
                status.Progress = JObject.FromObject(currentUpgradeProgress, this.serializer);
            }

            if (errorDetails != null)
            {
                status.ErrorDetails = JObject.FromObject(errorDetails, this.serializer);
            }

            return(status);
        }