Exemple #1
0
        public async Task <ShardData> GetDataAsync(string type, Guid objectId)
        {
            switch (type)
            {
            case nameof(User):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <User>(s => s.Id == objectId));

            case nameof(BotKey):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <BotKey>(w => w.Id == objectId));

            case nameof(GlobalValue):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <GlobalValue>(s => s.Id == objectId));

            case nameof(StepTemplate):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(s => s.Id == objectId));

            case nameof(WorkflowTemplate):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(s => s.Id == objectId));

            case nameof(Step):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <Step>(s => s.Id == objectId));

            case nameof(Workflow):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == objectId));

            case nameof(ExecutionTemplate):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionTemplate>(w => w.Id == objectId));

            case nameof(ExecutionSchedule):
                return(await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionSchedule>(w => w.Id == objectId));

            default:
                return(null);
            }
        }
Exemple #2
0
        public async Task <CommandResult> Handle(ExecuteExecutionTemplateCommand request, CancellationToken cancellationToken)
        {
            var executionTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionTemplate>(et => et.Name == request.Name);

            if (executionTemplate == null)
            {
                throw new InvalidExecutionRequestException("Execution template " + request.Name + " does not exits.");
            }

            if (executionTemplate.ExecutionTemplateType == ExecutionTemplateTypes.Step)
            {
                return(await _mediator.Send(new CreateStepCommand()
                {
                    Name = executionTemplate.Name + " execution",
                    StepTemplateId = executionTemplate.ReferenceId,
                    ExecutionTemplateId = executionTemplate.Id,
                    Inputs = executionTemplate.Inputs,
                    CreatedBy = request.CreatedBy,
                    ExecutionScheduleId = request.ExecutionScheduleId
                }));
            }
            else
            {
                return(await _mediator.Send(new CreateWorkflowCommand()
                {
                    Name = executionTemplate.Name + " execution",
                    WorkflowTemplateId = executionTemplate.ReferenceId,
                    ExecutionTemplateId = executionTemplate.Id,
                    Inputs = executionTemplate.Inputs,
                    CreatedBy = request.CreatedBy,
                    ExecutionScheduleId = request.ExecutionScheduleId
                }));
            }
        }
Exemple #3
0
        public async Task <CommandResult> Handle(AuthenticateUserCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var user = await _entitiesRepository.GetFirstOrDefaultAsync <User>(u => u.Username == request.Username.ToLower());

            if (user != null)
            {
                if (!user.IsDisabled)
                {
                    if (SecurityUtility.IsMatchingHash(request.Password, user.HashedPassword, user.Salt))
                    {
                        return(new CommandResult()
                        {
                            ObjectRefId = user.Username,
                            ElapsedMs = stopwatch.ElapsedMilliseconds,
                            Type = CommandResultTypes.None
                        });
                    }
                }
            }
            return(new CommandResult()
            {
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                ObjectRefId = null,
                Type = CommandResultTypes.None
            });
        }
Exemple #4
0
        public async Task <CommandResult> Handle(RecalculateExecutionScheduleCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            ExecutionSchedule schedule = await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionSchedule>(st => st.Name == request.Name);

            if (schedule == null)
            {
                throw new InvalidExecutionScheduleException("Execution Schedule with name " + request.Name + " is invalid.");
            }

            var executionScheduleLock = await _node.Handle(new RequestDataShard()
            {
                Type          = schedule.ShardType,
                ObjectId      = schedule.Id,
                CreateLock    = true,
                LockTimeoutMs = 10000
            });


            ExecutionSchedule existingValue;

            if (executionScheduleLock.IsSuccessful && executionScheduleLock.AppliedLocked)
            {
                existingValue = (ExecutionSchedule)executionScheduleLock.Data;
                existingValue.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                {
                    CreatedOn = DateTime.UtcNow,
                    Updates   = new List <Domain.ValueObjects.Update>()
                    {
                        new Update()
                        {
                            Type      = UpdateType.Override,
                            FieldName = "nextrun",
                            Value     = SchedulerUtility.NextOccurence(existingValue.Schedule, DateTime.UtcNow)
                        }
                    }
                });

                var result = await _node.Handle(new AddShardWriteOperation()
                {
                    Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                    WaitForSafeWrite = true,
                    Data             = existingValue,
                    RemoveLock       = true
                });
            }

            stopwatch.Stop();
            return(new CommandResult <ExecutionSchedule>()
            {
                ObjectRefId = schedule.Id.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Update,
                Result = schedule
            });
        }
Exemple #5
0
        public async Task <QueryResult <string> > Handle(UnencryptStepFieldQuery request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (request.Type != StepEncryptionTypes.Inputs && request.Type != StepEncryptionTypes.Outputs)
            {
                throw new InvalidUnencryptionRequestException("No such encryption type " + request.Type);
            }
            var step = await _entitiesRepository.GetFirstOrDefaultAsync <Step>(s => s.Id == request.StepId);


            if (step.CreatedBy != request.UserId)
            {
                throw new InvalidStepPermissionException("Only the creating user can decrypt the step secret.");
            }

            var stepTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == step.StepTemplateId);

            //Compare the to lower of inputs, TODO - this is inefficient
            if (!stepTemplate.InputDefinitions.ContainsKey(request.FieldName.ToLower()))
            {
                throw new InvalidUnencryptionRequestException("Field " + request.FieldName + " does not exist on step template " + stepTemplate.Id);
            }

            DynamicDataDescription kv = request.Type == StepEncryptionTypes.Inputs ? stepTemplate.InputDefinitions[request.FieldName.ToLower()] : stepTemplate.OutputDefinitions[request.FieldName.ToLower()];

            if (kv.Type != InputDataTypes.Secret)
            {
                throw new InvalidUnencryptionRequestException("Field " + request.FieldName + " is not a secret type.");
            }

            var decryptedInput = DynamicDataUtility.DecryptDynamicData(stepTemplate.InputDefinitions, request.Type == StepEncryptionTypes.Inputs ? step.Inputs : step.Outputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey(), false);

            stopwatch.Stop();

            return(new QueryResult <string>()
            {
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Count = 1,
                Result = (string)decryptedInput[request.FieldName.ToLower()]
            });
        }
Exemple #6
0
        public async Task <QueryResult <T> > Handle(GetEntityQuery <T> request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var result = await _entitiesRepository.GetFirstOrDefaultAsync <T>(request.Expression);

            stopwatch.Stop();
            return(new QueryResult <T>()
            {
                Result = result,
                Count = result == null ? 0 : 1,
                ElapsedMs = stopwatch.ElapsedMilliseconds
            });
        }
Exemple #7
0
        public async Task <QueryResult <object> > Handle(GetMetricsQuery request, CancellationToken cancellationToken)
        {
            var foundMetric = await _entitiesRepository.GetFirstOrDefaultAsync <Metric>(m => m.MetricName == request.MetricName);

            if (foundMetric == null)
            {
                throw new NotImplementedException("No metric " + request.MetricName);
            }

            var result = await _metricTicksRepository.GetMetricTicksAsync(request.From, request.To, foundMetric.MetricId, request.Aggs, request.Interval, null, null, request.IncludeSubcategories);

            return(new QueryResult <object>()
            {
                Result = result
            });
        }
Exemple #8
0
        public async Task <CommandResult> Handle(AppendStepLogCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var step = await _entitiesRepository.GetFirstOrDefaultAsync <Step>(e => e.Id == request.StepId);

            if (StepStatuses.IsCompleteStatus(step.Status))
            {
                throw new InvalidStepStatusException("Cannot append log to step, step status is complete with " + step.Status);
            }

            step.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
            {
                CreatedBy = request.CreatedBy,
                CreatedOn = DateTime.UtcNow,
                Updates   = new List <Domain.ValueObjects.Update>()
                {
                    new Update()
                    {
                        Type      = UpdateType.Append,
                        FieldName = "logs",
                        Value     = new StepLog()
                        {
                            CreatedOn = DateTime.UtcNow,
                            Message   = request.Log
                        },
                    }
                }
            });

            //await _entitiesRepository.UpdateStep(step);

            var createdWorkflowTemplateId = await _node.Handle(new AddShardWriteOperation()
            {
                Data             = step,
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
            });

            return(new CommandResult()
            {
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                ObjectRefId = step.Id.ToString(),
                Type = CommandResultTypes.Update
            });
        }
Exemple #9
0
        public async Task <CommandResult <Step> > Handle(CreateStepCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var resolvedTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == request.StepTemplateId);

            if (resolvedTemplate == null)
            {
                throw new StepTemplateNotFoundException("Step template " + request.StepTemplateId + " not found.");
            }

            var newStep = resolvedTemplate.GenerateStep(request.StepTemplateId,
                                                        request.CreatedBy,
                                                        request.Name, request.Description,
                                                        request.Inputs,
                                                        request.Tests, request.WorkflowId,
                                                        ClusterStateService.GetEncryptionKey(),
                                                        request.ExecutionTemplateId,
                                                        request.ExecutionScheduleId);

            /* var createdStepId = await _entitiesRepository.InsertStepAsync(
             *   newStep
             *   );*/

            await _node.Handle(new AddShardWriteOperation()
            {
                Data             = newStep,
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });


            stopwatch.Stop();
            return(new CommandResult <Step>()
            {
                ObjectRefId = newStep.Id.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create,
                Result = newStep
            });
        }
Exemple #10
0
        public async Task <CommandResult <Workflow> > Handle(CreateWorkflowCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            WorkflowTemplate template = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(wft => wft.ReferenceId == request.WorkflowTemplateId);

            if (template == null)
            {
                throw new WorkflowTemplateNotFoundException("Workflow Template " + request.WorkflowTemplateId + " not found.");
            }

            if (template.InputDefinitions.Count() < request.Inputs.Count())
            {
                throw new InvalidInputsException("Invalid number of inputs, number passed was " + request.Inputs.Count() + " which is less then defined " + template.InputDefinitions.Count());
            }

            var verifiedWorkflowInputs = new Dictionary <string, object>();

            if (template.InputDefinitions != null)
            {
                foreach (var input in template.InputDefinitions)
                {
                    if (!request.Inputs.ContainsKey(input.Key))
                    {
                        throw new MissingInputException("Workflow input data is missing " + input.Key);
                    }
                }

                foreach (var input in request.Inputs)
                {
                    if (template.InputDefinitions.ContainsKey(input.Key) && template.InputDefinitions[input.Key].Type == InputDataTypes.Secret && !InputDataUtility.IsInputReference(input, out _, out _))
                    {
                        verifiedWorkflowInputs.Add(input.Key.ToLower(), SecurityUtility.SymmetricallyEncrypt((string)input.Value, ClusterStateService.GetEncryptionKey()));
                    }
                    else
                    {
                        verifiedWorkflowInputs.Add(input.Key.ToLower(), input.Value);
                    }
                }
            }

            var createdWorkflowId  = Guid.NewGuid();
            var startingLogicBlock = template.LogicBlocks.Where(lb => lb.Value.Dependencies.Evaluate(new List <Step>())).ToList();

            var createdWorkflowTemplateId = await _node.Handle(new AddShardWriteOperation()
            {
                Data = new Domain.Entities.Workflows.Workflow(
                    createdWorkflowId,
                    request.WorkflowTemplateId,
                    verifiedWorkflowInputs, //Encrypted inputs
                    request.Name,
                    request.CreatedBy,
                    DateTime.UtcNow,
                    request.ExecutionTemplateId,
                    request.ExecutionScheduleId
                    ),
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });

            var workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == createdWorkflowId);

            //When there are no conditions to be met

            // Needs to happen before first step is added
            DateTimeOffset WorkflowStartTime = DateTime.Now;

            foreach (var block in startingLogicBlock)
            {
                try
                {
                    foreach (var subBlock in block.Value.SubsequentSteps)
                    {
                        var newStepTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == subBlock.Value.StepTemplateId);

                        if (newStepTemplate == null)
                        {
                            throw new StepTemplateNotFoundException("Template " + subBlock.Value.StepTemplateId + " not found.");
                        }

                        var verifiedInputs = new Dictionary <string, object>();

                        foreach (var mapping in subBlock.Value.Mappings)
                        {
                            string mappedValue = "";
                            if ((mapping.Value.DefaultValue != null && (mapping.Value.OutputReferences == null || mapping.Value.OutputReferences.Count() == 0)) || (mapping.Value.DefaultValue != null && mapping.Value.OutputReferences.First() != null && mapping.Value.DefaultValue.Priority > mapping.Value.OutputReferences.First().Priority))
                            {
                                // Change the ID to match the output
                                verifiedInputs.Add(mapping.Key, mapping.Value.DefaultValue.Value);
                            }
                            else if (mapping.Value.OutputReferences != null)
                            {
                                verifiedInputs.Add(mapping.Key, DynamicDataUtility.GetData(request.Inputs, mapping.Value.OutputReferences.First().OutputId).Value);
                            }
                        }

                        await _mediator.Send(new CreateStepCommand()
                        {
                            StepTemplateId = subBlock.Value.StepTemplateId,
                            CreatedBy      = SystemUsers.QUEUE_MANAGER,
                            Description    = null,
                            Inputs         = verifiedInputs,
                            WorkflowId     = createdWorkflowId,
                            Name           = subBlock.Key
                        });
                    }


                    workflow.UpdateJournal(
                        new JournalEntry()
                    {
                        CreatedBy = request.CreatedBy,
                        CreatedOn = DateTime.UtcNow,
                        Updates   = new List <Update>()
                        {
                            new Update()
                            {
                                FieldName = "completedlogicblocks",
                                Type      = UpdateType.Append,
                                Value     = block.Key //Add the logic block
                            }
                        }
                    });

                    await _node.Handle(new AddShardWriteOperation()
                    {
                        Data             = workflow,
                        WaitForSafeWrite = true,
                        Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                    });
                }
                catch (Exception e)
                {
                    _logger.LogCritical("Failed to action logic block " + block.Key + " with error " + e.Message + Environment.NewLine + e.StackTrace);
                }
            }

            stopwatch.Stop();

            return(new CommandResult <Workflow>()
            {
                Result = workflow,
                ObjectRefId = createdWorkflowId.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create
            });
        }
Exemple #11
0
        public async Task <CommandResult <ExecutionTemplate> > Handle(CreateExecutionTemplateCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            ExecutionTemplate template = await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionTemplate>(st => st.Name == request.Name);

            if (template != null)
            {
                throw new InvalidExecutionTemplateException("Template with name " + request.Name + " is invalid.");
            }

            if (request.ExecutionTemplateType == ExecutionTemplateTypes.Step)
            {
                var stepTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == request.ReferenceId);

                if (stepTemplate == null)
                {
                    throw new InvalidExecutionTemplateException("Failed to create execution template as " + request.ReferenceId + " does not exist.");
                }
                else
                {
                    foreach (var input in request.Inputs)
                    {
                        if (!stepTemplate.IsStepInputValid(input))
                        {
                            throw new InvalidExecutionTemplateException("Input " + input.Key + " is invalid.");
                        }
                    }
                }
            }
            else if (request.ExecutionTemplateType == ExecutionTemplateTypes.Workflow)
            {
                var workflowTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(st => st.ReferenceId == request.ReferenceId);

                if (workflowTemplate == null)
                {
                    throw new InvalidExecutionTemplateException("Failed to create execution template as " + request.ReferenceId + " does not exist.");
                }
                else
                {
                    foreach (var input in request.Inputs)
                    {
                        if (!workflowTemplate.IsWorkflowInputValid(input))
                        {
                            throw new InvalidExecutionTemplateException("Input " + input.Key + " is invalid.");
                        }
                    }
                }
            }
            else
            {
                throw new InvalidExecutionTemplateException("Execution Template Type is Invalid.");
            }



            var executionTemplate = new ExecutionTemplate(
                Guid.NewGuid(),
                request.Name,
                request.ReferenceId,
                request.ExecutionTemplateType,
                request.Description,
                request.CreatedBy,
                request.Inputs);

            var executionTemplateResponse = await _node.Handle(new AddShardWriteOperation()
            {
                Data             = executionTemplate,
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });


            stopwatch.Stop();
            return(new CommandResult <ExecutionTemplate>()
            {
                ObjectRefId = executionTemplate.Id.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create,
                Result = executionTemplate
            });
        }
Exemple #12
0
        public async Task <CommandResult> Handle(CreateWorkflowTemplateCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var existingWorkflowTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(wft => wft.ReferenceId == request.Name + ":" + request.Version);

            if (existingWorkflowTemplate != null)
            {
                return(new CommandResult()
                {
                    ObjectRefId = existingWorkflowTemplate.ReferenceId,
                    ElapsedMs = stopwatch.ElapsedMilliseconds,
                    Type = CommandResultTypes.None
                });
            }

            //Check that all step templates exists
            foreach (var lg in request.LogicBlocks)
            {
                foreach (var ss in lg.Value.SubsequentSteps)
                {
                    var st = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(stepTemplate => stepTemplate.ReferenceId == ss.Value.StepTemplateId);

                    if (st == null)
                    {
                        throw new StepTemplateNotFoundException("Template " + ss.Value.StepTemplateId + " cannot be found.");
                    }
                }
            }

            //Detect duplicates workflow step ref Id
            List <StepTemplate> allStepTemplates = new List <StepTemplate>();

            HashSet <string> stepRefs = new HashSet <string>();

            foreach (var block in request.LogicBlocks)
            {
                foreach (var subStep in block.Value.SubsequentSteps)
                {
                    if (stepRefs.Contains(subStep.Key))
                    {
                        throw new DuplicateWorkflowStepRefException("Found duplicate step refs for " + subStep.Key);
                    }
                    else
                    {
                        stepRefs.Add(subStep.Key);
                    }
                    allStepTemplates.Add(await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(stepTemplate => stepTemplate.ReferenceId == subStep.Value.StepTemplateId));
                }
            }

            //Dictionary<int, HashSet<int>> ValidatedSubsequentSteps = new Dictionary<int, HashSet<int>>();

            //ValidatedSubsequentSteps.Add(-1, new HashSet<int>());

            //There should be at least one pre-requisite that returns as true
            var startingLogicBlock = request.LogicBlocks.Where(lb => lb.Value.Dependencies.Evaluate(new List <Domain.Entities.Steps.Step>())).ToList();

            if (startingLogicBlock.Count() == 0)
            {
                throw new NoValidStartingLogicBlockException();
            }

            var           validatedLogicBlock    = true;
            List <string> validatedLogicBlockIds = new List <string>();

            validatedLogicBlockIds.AddRange(startingLogicBlock.Select(slb => slb.Key));

            Dictionary <string, ConditionGroupValidation> validations = new Dictionary <string, ConditionGroupValidation>();

            foreach (var lb in request.LogicBlocks)
            {
                validations.Add(lb.Key, null);
            }

            foreach (var startingLb in startingLogicBlock)
            {
                validations[startingLb.Key] = new ConditionGroupValidation()
                {
                    IsValid = true,
                    Reason  = "Starting logic block"
                };
            }

            while (validatedLogicBlock)
            {
                //reset to true
                validatedLogicBlock = false;
                //Only evaluate unvalidatedlogicblocks
                foreach (var block in request.LogicBlocks.Where(lb => !validatedLogicBlockIds.Contains(lb.Key)))
                {
                    var validation = block.Value.Dependencies.ValidateConditionGroup(request.LogicBlocks.Where(lb => validatedLogicBlockIds.Contains(lb.Key)).Select(vlb => vlb.Value));

                    if (validations[block.Key] == null || !validations[block.Key].IsValid)
                    {
                        validations[block.Key] = validation;
                    }

                    if (validation.IsValid)
                    {
                        // Mark to re-evaluate the rest of the logicblocks
                        validatedLogicBlock = true;
                        validatedLogicBlockIds.Add(block.Key);

                        foreach (var step in block.Value.SubsequentSteps)
                        {
                            //Check whether the step template exists
                            var result = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(stepTemplate => stepTemplate.ReferenceId == step.Value.StepTemplateId);

                            foreach (var mapping in step.Value.Mappings)
                            {
                                WorkflowTemplate.ValidateMapping(mapping.Value);
                            }

                            if (result == null)
                            {
                                throw new StepTemplateNotFoundException("Step Template does not exist " + step.Value.StepTemplateId);
                            }

                            var flatMappedSubsequentSteps = request.LogicBlocks.Where(lb => validatedLogicBlockIds.Contains(lb.Key)).SelectMany(lb => lb.Value.SubsequentSteps.Select(ss => ss.Key)).ToList();
                            //Add start as a valid step
                            flatMappedSubsequentSteps.Add("start");
                            foreach (var mapping in step.Value.Mappings)
                            {
                                if (mapping.Value.OutputReferences != null)
                                {
                                    foreach (var reference in mapping.Value.OutputReferences)
                                    {
                                        if (!flatMappedSubsequentSteps.Contains(reference.StepName))
                                        {
                                            throw new MissingStepException("Defined mapping for substep " + step.Key + " for mapping " + mapping.Key + " is missing  " + reference.StepName);
                                        }
                                        else
                                        {
                                            if (reference.StepName != ReservedValues.WorkflowStartStepName)
                                            {
                                                var foundBlock = request.LogicBlocks.Where(st => st.Value.SubsequentSteps.Where(ss => ss.Key == reference.StepName).Count() > 0).First();

                                                var resolvedSubstep = foundBlock.Value.SubsequentSteps.Where(ss => ss.Key == reference.StepName).First();

                                                var foundTemplates = (allStepTemplates.Where(template => template.ReferenceId == resolvedSubstep.Value.StepTemplateId));

                                                if (foundTemplates.Count() != 0)
                                                {
                                                    var foundTemplate = foundTemplates.First();
                                                    if (foundTemplate.OutputDefinitions.Where(id => id.Key.ToLower() == reference.OutputId.ToLower()).Count() == 0)
                                                    {
                                                        throw new MissingOutputException("Missing output " + reference.OutputId + " for step " + step.Key + " from step template " + foundTemplate.Id);
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                var foundDefinition = request.InputDefinitions.Where(id => id.Key.ToLower() == reference.OutputId.ToLower());
                                                if (foundDefinition.Count() == 0)
                                                {
                                                    throw new MissingInputException("Missing input " + reference.OutputId + " for step " + step.Key + " from workflow input.");
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    if (mapping.Value.DefaultValue == null)
                                    {
                                        throw new MissingOutputException("Neither Value or Output References exist. If neither is required, this is a redundant output reference");
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // This is done inefficiently

            /*foreach (var block in request.LogicBlocks)
             * {
             *  foreach (var substep in block.SubsequentSteps)
             *  {
             *      foreach (var mapping in substep.Mappings)
             *      {
             *          if (mapping.OutputReferences != null)
             *          {
             *              foreach (var reference in mapping.OutputReferences)
             *              {
             *                  if (!ValidatedSubsequentSteps.ContainsKey(reference.WorkflowStepId))
             *                  {
             *                      throw new MissingStepException("Defined mapping for substep " + substep.WorkflowStepId + " for mapping " + mapping.StepInputId + " is missing  " + reference.WorkflowStepId);
             *                  }
             *                  else
             *                  {
             *                      if (reference.WorkflowStepId != -1)
             *                      {
             *                          var foundBlock = request.LogicBlocks.Where(st => st.SubsequentSteps.Where(ss => ss.WorkflowStepId == reference.WorkflowStepId).Count() > 0).First();
             *
             *                          var resolvedSubstep = foundBlock.SubsequentSteps.Where(ss => ss.WorkflowStepId == reference.WorkflowStepId).First();
             *
             *                          var foundTemplates = (allStepTemplates.Where(template => template.ReferenceId == resolvedSubstep.StepTemplateId));
             *
             *                          if (foundTemplates.Count() != 0)
             *                          {
             *                              var foundTemplate = foundTemplates.First();
             *                              if (foundTemplate.InputDefinitions.Where(id => id.Key.ToLower() != reference.OutputId.ToLower()).Count() == 0)
             *                              {
             *                                  throw new MissingInputException("Missing input " + reference.OutputId + " for step " + substep.WorkflowStepId + " from step template " + foundTemplate.Id);
             *                              }
             *                          }
             *                      }
             *                      else
             *                      {
             *                          var foundDefinition = request.InputDefinitions.Where(id => id.Key.ToLower() == reference.OutputId.ToLower());
             *                          if (foundDefinition.Count() == 0)
             *                          {
             *                              throw new MissingInputException("Missing input " + reference.OutputId + " for step " + substep.WorkflowStepId + " from workflow input.");
             *                          }
             *                      }
             *                  }
             *              }
             *          }
             *          else
             *          {
             *              if (mapping.DefaultValue == null)
             *              {
             *                  throw new MissingOutputException("Neither Value or Output References exist. If neither is required, this is a redundant output reference");
             *              }
             *          }
             *      }
             *  }
             * }*/

            var newId = Guid.NewGuid();
            var newWorkflowTemplate = new WorkflowTemplate(newId,
                                                           request.Name + ":" + request.Version,
                                                           request.Description,
                                                           request.InputDefinitions,
                                                           request.LogicBlocks,
                                                           request.CreatedBy,
                                                           DateTime.UtcNow
                                                           );

            var createdWorkflowTemplateId = await _node.Handle(new AddShardWriteOperation()
            {
                Data             = newWorkflowTemplate,
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });

            stopwatch.Stop();
            return(new CommandResult()
            {
                ObjectRefId = newWorkflowTemplate.ReferenceId,
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create
            });
        }
Exemple #13
0
        public async Task <CommandResult> Handle(UnassignStepCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            Step step;

            if ((step = await _entitiesRepository.GetFirstOrDefaultAsync <Step>(e => (e.Status == StepStatuses.Suspended || e.Status == StepStatuses.Assigned) && e.Id == request.StepId)) == null)
            {
                Logger.LogWarning("Step " + request.StepId + " has a status that cannot be unassigned.");
                return(new CommandResult()
                {
                    ElapsedMs = stopwatch.ElapsedMilliseconds,
                    ObjectRefId = request.StepId.ToString(),
                    Type = CommandResultTypes.None
                });
            }

            var stepLockResult = await _node.Handle(new RequestDataShard()
            {
                Type          = "Step",
                ObjectId      = request.StepId,
                CreateLock    = true,
                LockTimeoutMs = 10000
            });

            if (stepLockResult.IsSuccessful && stepLockResult.AppliedLocked)
            {
                step = (Step)stepLockResult.Data;
                if (step.Status != StepStatuses.Suspended && step.Status != StepStatuses.Assigned)
                {
                    Logger.LogWarning("Step " + request.StepId + " has status " + step.Status + ". Only suspended steps can be unassigned.");
                    return(new CommandResult()
                    {
                        ElapsedMs = stopwatch.ElapsedMilliseconds,
                        ObjectRefId = step.Id.ToString(),
                        Type = CommandResultTypes.None
                    });
                }

                step.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                {
                    CreatedOn = DateTime.UtcNow,
                    CreatedBy = request.CreatedBy,
                    Updates   = new List <Domain.ValueObjects.Update>()
                    {
                        new Update()
                        {
                            Type      = UpdateType.Override,
                            FieldName = "status",
                            Value     = StepStatuses.Unassigned,
                        },
                        new Update()
                        {
                            FieldName = "assignedto",
                            Type      = UpdateType.Override,
                            Value     = null
                        }
                    }
                });

                var result = await _node.Handle(new AddShardWriteOperation()
                {
                    Data             = step,
                    WaitForSafeWrite = true,
                    Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                    RemoveLock       = true
                });


                if (result.IsSuccessful)
                {
                    return(new CommandResult()
                    {
                        ElapsedMs = stopwatch.ElapsedMilliseconds,
                        ObjectRefId = step.Id.ToString(),
                        Type = CommandResultTypes.Update
                    });
                }
                else
                {
                    throw new FailedClusterOperationException("Failed to apply cluster operation with for step " + step.Id);
                }
            }
            else
            {
                throw new FailedClusterOperationException("Step " + request.StepId + " failed to have a lock applied.");
            }
        }
Exemple #14
0
        public async Task <CommandResult> Handle(UpdateExecutionScheduleCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            ExecutionSchedule schedule = await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionSchedule>(st => st.Name == request.Name);

            if (schedule == null)
            {
                throw new InvalidExecutionScheduleException("Execution Schedule with name " + request.Name + " is invalid.");
            }


            if (request.Schedule != null)
            {
                foreach (var scheduleString in request.Schedule)
                {
                    var isValid = SchedulerUtility.IsValidScheduleString(scheduleString);
                    if (!isValid)
                    {
                        throw new InvalidExecutionScheduleException("Schedule " + scheduleString + " is invalid.");
                    }
                }
            }

            var executionScheduleLock = await _node.Handle(new RequestDataShard()
            {
                Type       = schedule.ShardType,
                ObjectId   = schedule.Id,
                CreateLock = true
            });


            ExecutionSchedule existingValue;

            List <Update> updates = new List <Update>();

            if (request.IsDisabled != null && schedule.IsDisabled != request.IsDisabled)
            {
                updates.Add(new Update()
                {
                    Type      = UpdateType.Override,
                    FieldName = "isdisabled",
                    Value     = request.IsDisabled
                });
            }

            if (request.Schedule != null && schedule.Schedule != request.Schedule)
            {
                updates.Add(new Update()
                {
                    Type      = UpdateType.Override,
                    FieldName = "nextrun",
                    Value     = SchedulerUtility.NextOccurence(request.Schedule, DateTime.UtcNow)
                });

                updates.Add(new Update()
                {
                    Type      = UpdateType.Override,
                    FieldName = "schedule",
                    Value     = request.Schedule
                });
            }

            if (request.Description != null && schedule.Description != request.Description)
            {
                updates.Add(new Update()
                {
                    Type      = UpdateType.Override,
                    FieldName = "description",
                    Value     = request.Description
                });
            }


            if (executionScheduleLock.IsSuccessful && executionScheduleLock.AppliedLocked && updates.Count > 0)
            {
                existingValue = (ExecutionSchedule)executionScheduleLock.Data;
                existingValue.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                {
                    CreatedOn = DateTime.UtcNow,
                    Updates   = updates
                });

                var result = await _node.Handle(new AddShardWriteOperation()
                {
                    Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                    WaitForSafeWrite = true,
                    Data             = existingValue,
                    RemoveLock       = true
                });
            }

            stopwatch.Stop();
            return(new CommandResult <ExecutionSchedule>()
            {
                ObjectRefId = schedule.Id.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Update,
                Result = schedule
            });
        }
Exemple #15
0
        public async Task <CommandResult <GlobalValue> > Handle(UpdateGlobalValueCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            GlobalValue existingValue;

            if ((existingValue = await _entitiesRepository.GetFirstOrDefaultAsync <GlobalValue>(gv => gv.Name == request.Name)) == null)
            {
                throw new InvalidGlobalValuesException("The global value name " + request.Name + " does not exist.");
            }
            var globalValueLock = await _node.Handle(new RequestDataShard()
            {
                Type       = existingValue.ShardType,
                ObjectId   = existingValue.Id,
                CreateLock = true
            });

            if (globalValueLock.IsSuccessful && globalValueLock.AppliedLocked)
            {
                existingValue = (GlobalValue)globalValueLock.Data;
                existingValue.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                {
                    CreatedBy = request.CreatedBy,
                    CreatedOn = DateTime.UtcNow,
                    Updates   = new List <Domain.ValueObjects.Update>()
                    {
                        new Update()
                        {
                            Type      = UpdateType.Override,
                            FieldName = "value",
                            Value     = request.Value,
                        },
                        new Update()
                        {
                            Type      = UpdateType.Override,
                            FieldName = "description",
                            Value     = request.Description,
                        }
                    }
                });

                var result = await _node.Handle(new AddShardWriteOperation()
                {
                    Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                    WaitForSafeWrite = true,
                    Data             = existingValue,
                    RemoveLock       = true
                });

                stopwatch.Stop();

                return(new CommandResult <GlobalValue>()
                {
                    ObjectRefId = existingValue.Id.ToString(),
                    ElapsedMs = stopwatch.ElapsedMilliseconds,
                    Type = CommandResultTypes.Update,
                    Result = existingValue
                });
            }
            else
            {
                throw new FailedClusterOperationException("Global Value " + request.Name + " failed to have a lock applied.");
            }
        }
Exemple #16
0
        public async Task <CommandResult> Handle(SuspendStepCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            Step step = await _entitiesRepository.GetFirstOrDefaultAsync <Step>(e => e.Id == request.StepId);

            if (step == null)
            {
                throw new Exception("Failed to find step " + step.Id);
            }

            if (step.Status == StepStatuses.Suspended)
            {
                return(new CommandResult()
                {
                    ElapsedMs = stopwatch.ElapsedMilliseconds,
                    ObjectRefId = request.StepId.ToString(),
                    Type = CommandResultTypes.None
                });
            }

            var stepLockResult = await _node.Handle(new RequestDataShard()
            {
                Type          = "Step",
                ObjectId      = request.StepId,
                CreateLock    = true,
                LockTimeoutMs = 10000
            });

            // Applied the lock successfully
            if (stepLockResult.IsSuccessful && stepLockResult.AppliedLocked)
            {
                Logger.LogInformation("Applied lock on step " + request.StepId + " with lock id " + stepLockResult.LockId);
                step = (Step)stepLockResult.Data;
                if (step.Status == StepStatuses.Unassigned ||
                    step.Status == StepStatuses.Suspended ||
                    step.Status == StepStatuses.Assigned // You should only be suspending a assigned step if it is being suspended by the bot assigned, check to be done in presentation
                    )
                {
                    step.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                    {
                        CreatedOn = DateTime.UtcNow,
                        CreatedBy = request.CreatedBy,
                        Updates   = new List <Domain.ValueObjects.Update>()
                        {
                            new Update()
                            {
                                Type      = UpdateType.Override,
                                FieldName = "status",
                                Value     = StepStatuses.Suspended
                            },
                            new Update()
                            {
                                Type      = UpdateType.Override,
                                FieldName = "suspendeduntil",
                                Value     = request.SuspendedUntil
                            },
                            new Update()
                            {
                                FieldName = "assignedto",
                                Type      = UpdateType.Override,
                                Value     = null
                            }
                        }
                    });

                    var result = await _node.Handle(new AddShardWriteOperation()
                    {
                        Data             = step,
                        WaitForSafeWrite = true,
                        Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                        RemoveLock       = true,
                        LockId           = stepLockResult.LockId.Value
                    });

                    if (result.IsSuccessful)
                    {
                        return(new CommandResult()
                        {
                            ElapsedMs = stopwatch.ElapsedMilliseconds,
                            ObjectRefId = step.Id.ToString(),
                            Type = CommandResultTypes.Update
                        });
                    }
                    else
                    {
                        throw new FailedClusterOperationException("Failed to apply cluster operation with for step " + step.Id);
                    }
                }
                else
                {
                    throw new InvalidStepStatusException("Step " + request.StepId + " could not be paused as it has status " + step.Status);
                }
            }
            else
            {
                throw new FailedClusterOperationException("Step " + request.StepId + " failed to have a lock applied.");
            }
        }
Exemple #17
0
        public async Task <CommandResult> Handle(ScanWorkflowCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            List <string> messages             = new List <string>();
            bool          workflowStillRunning = false;

            var workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == request.WorkflowId);

            if (workflow == null)
            {
                throw new MissingWorkflowException("Failed to find workflow " + request.WorkflowId + " as workflow does not exist.");
            }

            //Get the workflow template
            var workflowTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <WorkflowTemplate>(wt => wt.ReferenceId == workflow.WorkflowTemplateId);

            if (workflowTemplate == null)
            {
                throw new WorkflowTemplateNotFoundException("Failed to scan workflow " + request.WorkflowId + " workflow template " + workflow.WorkflowTemplateId + ".");
            }

            //Get all the steps related to this task
            var workflowSteps = (await _entitiesRepository.GetAsync <Step>(s => s.WorkflowId == request.WorkflowId)).ToList();

            foreach (var workflowStep in workflowSteps)
            {
                workflowStep.Outputs = DynamicDataUtility.DecryptDynamicData((await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == workflowStep.StepTemplateId)).OutputDefinitions, workflowStep.Outputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());
                if (!workflowStep.IsComplete())
                {
                    messages.Add("Workflow step " + workflowStep.Id + " (" + workflowStep.Name + ")" + " is running.");
                    workflowStillRunning = true;
                }
            }

            bool stepCreated = false;

            if (!workflowStillRunning)
            {
                if (workflow.CompletedLogicBlocks == null)
                {
                    workflow.CompletedLogicBlocks = new List <string>();
                }

                //Evaluate all logic blocks that have not been completed
                var logicBlocks = workflowTemplate.LogicBlocks.Where(lb => !workflow.CompletedLogicBlocks.Contains(lb.Key)).ToList();

                foreach (var logicBlock in logicBlocks)
                {
                    var  lockId       = Guid.NewGuid();
                    bool lockObtained = false;
                    while (!lockObtained)
                    {
                        while (_clusterStateService.IsLogicBlockLocked(request.WorkflowId, logicBlock.Key))
                        {
                            Console.WriteLine("Found " + ("workflow:" + request.WorkflowId + ">logicBlock:" + logicBlock) + " Lock");
                            await Task.Delay(1000);
                        }

                        int entryNumber = await _clusterStateService.LockLogicBlock(lockId, request.WorkflowId, logicBlock.Key);

                        //Check whether you got the lock
                        lockObtained = _clusterStateService.WasLockObtained(lockId, request.WorkflowId, logicBlock.Key);
                    }

                    //When the logic block is released, recheck whether this logic block has been evaluated
                    workflow = await _entitiesRepository.GetFirstOrDefaultAsync <Workflow>(w => w.Id == request.WorkflowId);

                    workflow.Inputs = DynamicDataUtility.DecryptDynamicData(workflowTemplate.InputDefinitions, workflow.Inputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());


                    if (workflow.CompletedLogicBlocks == null)
                    {
                        workflow.CompletedLogicBlocks = new List <string>();
                    }

                    //If the logic block is ready to be processed, submit the steps
                    if (logicBlock.Value.Dependencies.Evaluate(workflowSteps) && !workflow.CompletedLogicBlocks.Contains(logicBlock.Key))
                    {
                        foreach (var substep in logicBlock.Value.SubsequentSteps)
                        {
                            if (workflowSteps.Where(s => s.Name == substep.Key).Count() == 0)
                            {
                                var verifiedInputs = new Dictionary <string, object>();

                                foreach (var mapping in substep.Value.Mappings)
                                {
                                    //find the mapping with the highest priority
                                    var highestPriorityReference = WorkflowTemplateUtility.GetHighestPriorityReference(mapping.Value.OutputReferences, workflowSteps.ToArray());
                                    //if the highest priority reference is null, there are no mappings
                                    if (highestPriorityReference == null && mapping.Value.DefaultValue == null)
                                    {
                                    }
                                    // If default value is higher priority
                                    else if (mapping.Value.DefaultValue != null && (highestPriorityReference == null || highestPriorityReference.Priority < mapping.Value.DefaultValue.Priority))
                                    {
                                        verifiedInputs.Add(mapping.Key, mapping.Value.DefaultValue.Value);
                                    }
                                    // If the step ref is not -1 it is a step in the array but the workflow
                                    else if (highestPriorityReference.StepName != ReservedValues.WorkflowStartStepName)
                                    {
                                        var parentStep = workflowSteps.Where(ss => ss.Name == highestPriorityReference.StepName).FirstOrDefault();

                                        //If there is a AND and there is no parent step, throw a error
                                        if (parentStep == null)
                                        {
                                            throw new InvalidWorkflowProcessingException("Missing source for mapping " + mapping.Key + " from step " + highestPriorityReference.StepName);
                                        }
                                        else
                                        {
                                            if (parentStep != null)
                                            {
                                                try
                                                {
                                                    // Get the output value based on the pre-requisite id
                                                    var outPutValue = DynamicDataUtility.GetData(parentStep.Outputs, highestPriorityReference.OutputId);
                                                    // Validate it is in the definition
                                                    verifiedInputs.Add(mapping.Key, outPutValue.Value);
                                                }
                                                catch (Exception e)
                                                {
                                                    //TO DO Move this to logger
                                                    Console.WriteLine("Found error at mapping " + mapping.Key + " for step " + substep.Key);
                                                    throw e;
                                                }
                                            }
                                        }
                                    }
                                    //Get the value from the workflow ref
                                    else
                                    {
                                        // Validate it is in the definition
                                        verifiedInputs.Add(mapping.Key, DynamicDataUtility.GetData(workflow.Inputs, highestPriorityReference.OutputId).Value);
                                    }
                                }
                                stepCreated = true;
                                //Add the step TODO, add step priority
                                await _mediator.Send(new CreateStepCommand()
                                {
                                    StepTemplateId = substep.Value.StepTemplateId,
                                    CreatedBy      = SystemUsers.QUEUE_MANAGER,
                                    Inputs         = verifiedInputs,
                                    WorkflowId     = workflow.Id,
                                    Name           = substep.Key //create the step with the right subsequent step
                                });

                                messages.Add("Started workflow step " + substep.Key);
                            }
                        }

                        //Mark it as evaluated
                        workflow.UpdateJournal(
                            new JournalEntry()
                        {
                            CreatedBy = request.CreatedBy,
                            CreatedOn = DateTime.UtcNow,
                            Updates   = new List <Update>()
                            {
                                new Update()
                                {
                                    FieldName = "completedlogicblocks",
                                    Type      = UpdateType.Append,
                                    Value     = logicBlock.Key
                                }
                            }
                        });

                        //await _workflowsRepository.UpdateWorkflow(workflow);
                        await _node.Handle(new AddShardWriteOperation()
                        {
                            Data             = workflow,
                            WaitForSafeWrite = true,
                            Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                        });
                    }
                    await _clusterStateService.UnlockLogicBlock(lockId, request.WorkflowId, logicBlock.Key);
                }

                //Check if there are no longer any steps that are unassigned or assigned

                var workflowStatus = workflow.Status;
                workflowSteps = (await _entitiesRepository.GetAsync <Step>(s => s.WorkflowId == request.WorkflowId)).ToList();
                var highestStatus     = StepStatuses.GetHighestPriority(workflowSteps.Select(s => s.Status).ToArray());
                var newWorkflowStatus = stepCreated ? WorkflowStatuses.ConvertStepStatusToWorkflowStatus(StepStatuses.Unassigned) : WorkflowStatuses.ConvertStepStatusToWorkflowStatus(highestStatus);

                if (newWorkflowStatus != workflow.Status)
                {
                    workflow.UpdateJournal(
                        new JournalEntry()
                    {
                        CreatedBy = request.CreatedBy,
                        CreatedOn = DateTime.UtcNow,
                        Updates   = new List <Update>()
                        {
                            new Update()
                            {
                                FieldName = "status",
                                Type      = UpdateType.Override,
                                Value     = newWorkflowStatus
                            }
                        }
                    });

                    //await _workflowsRepository.UpdateWorkflow(workflow);
                    await _node.Handle(new AddShardWriteOperation()
                    {
                        Data             = workflow,
                        WaitForSafeWrite = true,
                        Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update
                    });


                    messages.Add("Updated workflow status " + newWorkflowStatus + ".");
                }
            }

            return(new CommandResult()
            {
                ObjectRefId = request.WorkflowId.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Update,
                IsSuccessful = true,
                Messages = messages.ToArray()
            });
        }
Exemple #18
0
        public async Task <CommandResult <Step> > Handle(AssignStepCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            List <Guid> ignoreUnassignedSteps = new List <Guid>();

            if (_clusterStateService.GetSettings.AssignmentEnabled)
            {
                var    assignedStepSuccessfully = false;
                Step   unassignedStep           = null;
                var    dateChecked = DateTime.UtcNow;
                BotKey botkey;

                if (!_cache.TryGetValue(request.BotId, out botkey))
                {
                    // Set cache options.
                    var cacheEntryOptions = new MemoryCacheEntryOptions()
                                            // Keep in cache for this time, reset time if accessed.
                                            .SetSlidingExpiration(TimeSpan.FromSeconds(10));
                    botkey = await _entitiesRepository.GetFirstOrDefaultAsync <BotKey>(bk => bk.Id == request.BotId);

                    // Save data in cache.
                    _cache.Set(request.BotId, botkey, cacheEntryOptions);
                }

                if (botkey.IsDisabled)
                {
                    return(new CommandResult <Step>(new BotKeyAssignmentException("Bot " + botkey.Id + " is disabled."))
                    {
                        Type = CommandResultTypes.Update,
                        ElapsedMs = stopwatch.ElapsedMilliseconds
                    });
                }

                ignoreUnassignedSteps.AddRange(_clusterStateService.GetState().Locks.Where(l => l.Key.Contains("_object")).Select(ol => new Guid(ol.Key.Split(':').Last())));

                do
                {
                    unassignedStep = (await _entitiesRepository.GetAsync <Step>(s => s.Status == StepStatuses.Unassigned && request.StepTemplateIds.Contains(s.StepTemplateId) && !ignoreUnassignedSteps.Contains(s.Id), null, "CreatedOn:1", 1, 0)).FirstOrDefault();
                    if (unassignedStep != null)
                    {
                        var assigned = await _node.Handle(new RequestDataShard()
                        {
                            Type          = unassignedStep.ShardType,
                            ObjectId      = unassignedStep.Id,
                            CreateLock    = true,
                            LockTimeoutMs = 10000
                        });

                        //Apply a lock on the item
                        if (assigned != null && assigned.IsSuccessful && assigned.AppliedLocked)
                        {
                            //Real values to pass to the Microservice
                            Dictionary <string, object> realAssignedValues = new Dictionary <string, object>();
                            //Inputs that have been converted to reference expression
                            Dictionary <string, object> convertedInputs = new Dictionary <string, object>();

                            var template = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == unassignedStep.StepTemplateId);

                            try
                            {
                                //This should not throw a error externally, the server should loop to the next one and log a error
                                if (unassignedStep.Status != StepStatuses.Unassigned)
                                {
                                    throw new InvalidStepQueueException("You cannot assign step " + unassignedStep.Id + " as it is not unassigned.");
                                }


                                bool inputsUpdated = false;

                                foreach (var input in unassignedStep.Inputs)
                                {
                                    string convertedValue     = "";
                                    bool   isReferenceByValue = false;
                                    var    isReference        = InputDataUtility.IsInputReference(input, out convertedValue, out isReferenceByValue);
                                    if (input.Value is string && ((string)input.Value).Length > 1)
                                    {
                                        if (isReference)
                                        {
                                            //Copy by reference
                                            if (isReferenceByValue)
                                            {
                                                var foundGlobalValue = await _entitiesRepository.GetFirstOrDefaultAsync <GlobalValue>(gv => gv.Name == convertedValue);

                                                if (foundGlobalValue == null)
                                                {
                                                    Logger.LogWarning("No global value was found for value " + input.Value);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, input.Value + ":?");
                                                }
                                                else if (foundGlobalValue.Type != template.InputDefinitions[input.Key].Type)
                                                {
                                                    Logger.LogWarning("Global value was found for value " + input.Value + " however they are different types. " + template.InputDefinitions[input.Key].Type + " vs " + foundGlobalValue.Type);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, input.Value + ":?");
                                                }
                                                else
                                                {
                                                    realAssignedValues.Add(input.Key, foundGlobalValue.Value);
                                                    convertedInputs.Add(input.Key, input.Value + ":" + foundGlobalValue.Journal.GetCurrentChainId());
                                                }
                                            }
                                            //copy by value
                                            else
                                            {
                                                var foundGlobalValue = await _entitiesRepository.GetFirstOrDefaultAsync <GlobalValue>(gv => gv.Name == convertedValue);

                                                if (foundGlobalValue == null)
                                                {
                                                    Logger.LogWarning("No global value was found for value " + input.Value);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, null);
                                                }
                                                else if (foundGlobalValue.Type != template.InputDefinitions[input.Key].Type)
                                                {
                                                    Logger.LogWarning("Global value was found for value " + input.Value + " however they are different types. " + template.InputDefinitions[input.Key].Type + " vs " + foundGlobalValue.Type);
                                                    realAssignedValues.Add(input.Key, null);
                                                    convertedInputs.Add(input.Key, null);
                                                }
                                                else
                                                {
                                                    realAssignedValues.Add(input.Key, foundGlobalValue.Value);
                                                    convertedInputs.Add(input.Key, foundGlobalValue.Value);
                                                }
                                            }

                                            inputsUpdated = true;
                                        }
                                        else if (input.Value is string && ((string)input.Value).Length > 1 && ((string)input.Value).First() == '\\')
                                        {
                                            var escapedCommand = ((string)input.Value);
                                            //The $ is escaped
                                            realAssignedValues.Add(input.Key, ((string)input.Value).Substring(1, escapedCommand.Length - 1));
                                            convertedInputs.Add(input.Key, input.Value);
                                            inputsUpdated = true;
                                        }
                                        else
                                        {
                                            realAssignedValues.Add(input.Key, input.Value);
                                            convertedInputs.Add(input.Key, input.Value);
                                        }
                                    }
                                    else
                                    {
                                        realAssignedValues.Add(input.Key, input.Value);
                                        convertedInputs.Add(input.Key, input.Value);
                                    }
                                }

                                //If a update was detected then add it to the journal updates
                                if (inputsUpdated)
                                {
                                    unassignedStep.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                                    {
                                        CreatedBy = SystemUsers.QUEUE_MANAGER,
                                        CreatedOn = DateTime.UtcNow,
                                        Updates   = new List <Update>()
                                        {
                                            new Update()
                                            {
                                                Type      = UpdateType.Override,
                                                FieldName = "status",
                                                Value     = StepStatuses.Assigned
                                            },
                                            new Update()
                                            {
                                                FieldName = "inputs",
                                                Type      = UpdateType.Override,
                                                Value     = convertedInputs
                                            },
                                            new Update()
                                            {
                                                FieldName = "assignedto",
                                                Type      = UpdateType.Override,
                                                Value     = request.BotId
                                            }
                                        }
                                    });
                                }
                                else
                                {
                                    unassignedStep.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                                    {
                                        CreatedBy = SystemUsers.QUEUE_MANAGER,
                                        CreatedOn = DateTime.UtcNow,
                                        Updates   = new List <Update>()
                                        {
                                            new Update()
                                            {
                                                Type      = UpdateType.Override,
                                                FieldName = "status",
                                                Value     = StepStatuses.Assigned
                                            }
                                        }
                                    });
                                }

                                await _node.Handle(new AddShardWriteOperation()
                                {
                                    Data             = unassignedStep,
                                    WaitForSafeWrite = true,
                                    Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                                    RemoveLock       = true,
                                    LockId           = assigned.LockId.Value
                                });

                                //await _entitiesRepository.UpdateStep(unassignedStep);
                                if (inputsUpdated)
                                {
                                    //Update the record with real values, this is not commited to DB
                                    unassignedStep.UpdateJournal(new Domain.Entities.JournalEntries.JournalEntry()
                                    {
                                        CreatedBy = SystemUsers.QUEUE_MANAGER,
                                        CreatedOn = DateTime.UtcNow,
                                        Updates   = new List <Update>()
                                        {
                                            new Update()
                                            {
                                                FieldName = "inputs",
                                                Type      = UpdateType.Override,
                                                Value     = realAssignedValues
                                            }
                                        }
                                    });
                                }
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                                //throw e;
                            }
                            assignedStepSuccessfully = true;
                        }
                        else
                        {
                            ignoreUnassignedSteps.Add(unassignedStep.Id);
                            assignedStepSuccessfully = false;
                        }
                    }
                    //There were no unassigned steps to assign
                    else
                    {
                        assignedStepSuccessfully = true;
                    }
                }while (!assignedStepSuccessfully);


                if (unassignedStep != null)
                {
                    var template = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == unassignedStep.StepTemplateId);

                    //Decrypt the step
                    unassignedStep.Inputs = DynamicDataUtility.DecryptDynamicData(template.InputDefinitions, unassignedStep.Inputs, EncryptionProtocol.AES256, ClusterStateService.GetEncryptionKey());

                    unassignedStep.RemoveDelimiters();

                    //Encrypt the step
                    unassignedStep.Inputs = DynamicDataUtility.EncryptDynamicData(template.InputDefinitions, unassignedStep.Inputs, EncryptionProtocol.RSA, botkey.PublicEncryptionKey, true);
                }

                stopwatch.Stop();
                return(new CommandResult <Step>()
                {
                    ObjectRefId = unassignedStep != null?unassignedStep.Id.ToString() : "",
                                      ElapsedMs = stopwatch.ElapsedMilliseconds,
                                      Type = CommandResultTypes.Update,
                                      Result = unassignedStep != null ? unassignedStep : null
                });
            }
            else
            {
                return(new CommandResult <Step>()
                {
                    ObjectRefId = "",
                    ElapsedMs = stopwatch.ElapsedMilliseconds,
                    Type = CommandResultTypes.None
                });
            }
        }
Exemple #19
0
        public async Task <CommandResult> Handle(CreateExecutionScheduleCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            ExecutionSchedule schedule = await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionSchedule>(st => st.Name == request.Name);

            if (schedule != null)
            {
                throw new InvalidExecutionScheduleException("Execution Schedule with name " + request.Name + " is invalid.");
            }

            ExecutionTemplate template = await _entitiesRepository.GetFirstOrDefaultAsync <ExecutionTemplate>(st => st.Name == request.ExecutionTemplateName);

            if (template == null)
            {
                throw new InvalidExecutionScheduleException("Execution Template with name " + request.ExecutionTemplateName + " is invalid.");
            }

            foreach (var scheduleString in request.Schedule)
            {
                var isValid = SchedulerUtility.IsValidScheduleString(scheduleString);
                if (!isValid)
                {
                    throw new InvalidExecutionScheduleException("Schedule " + scheduleString + " is invalid.");
                }
            }

            var executionSchedule = new ExecutionSchedule(
                Guid.NewGuid(),
                request.Name,
                request.ExecutionTemplateName,
                request.Description,
                request.CreatedBy,
                request.Schedule,
                SchedulerUtility.NextOccurence(request.Schedule)
                );

            var executionScheduleResponse = await _node.Handle(new AddShardWriteOperation()
            {
                Data             = executionSchedule,
                WaitForSafeWrite = true,
                Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
            });

            if (request.RunImmediately)
            {
                await _mediator.Send(new ExecuteExecutionTemplateCommand()
                {
                    CreatedBy           = request.CreatedBy,
                    ExecutionScheduleId = executionSchedule.Id,
                    Name = executionSchedule.ExecutionTemplateName
                });
            }


            stopwatch.Stop();
            return(new CommandResult <ExecutionSchedule>()
            {
                ObjectRefId = executionSchedule.Id.ToString(),
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create,
                Result = executionSchedule
            });
        }
Exemple #20
0
        public async Task <CommandResult> Handle(CreateStepTemplateCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            if (request.ReferenceId != null)
            {
                request.Name    = request.ReferenceId.Split(':')[0];
                request.Version = request.ReferenceId.Split(':')[1];
            }


            var newId           = Guid.NewGuid();
            var newStepTemplate = new StepTemplate(
                newId,
                request.ReferenceId == null ? request.Name + ":" + request.Version : request.ReferenceId,
                request.Description,
                request.AllowDynamicInputs,
                request.InputDefinitions.ToDictionary(entry => entry.Key.ToLower(),
                                                      entry => entry.Value),
                request.OutputDefinitions.ToDictionary(entry => entry.Key.ToLower(),
                                                       entry => entry.Value),
                request.CreatedBy,
                DateTime.UtcNow
                );

            var existingStepTemplate = await _entitiesRepository.GetFirstOrDefaultAsync <StepTemplate>(st => st.ReferenceId == newStepTemplate.ReferenceId);

            if (existingStepTemplate == null)
            {
                if (request.Name.First() == '_' && request.CreatedBy != SystemUsers.SYSTEM_TEMPLATES_MANAGER)
                {
                    throw new InvalidStepTemplateException("Only system workflows can start with _");
                }

                var createdWorkflowTemplateId = await _node.Handle(new AddShardWriteOperation()
                {
                    Data             = newStepTemplate,
                    WaitForSafeWrite = true,
                    Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Create
                });
            }
            else
            {
                Logger.LogDebug("Found existing step template");

                BaseException exception;
                if (!existingStepTemplate.IsEqual(newStepTemplate, out exception))
                {
                    throw exception;
                }
            }

            stopwatch.Stop();
            return(new CommandResult()
            {
                ObjectRefId = newStepTemplate.ReferenceId,
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                Type = CommandResultTypes.Create
            });
        }
Exemple #21
0
        public async Task <CommandResult <BotKey> > Handle(UpdateBotKeyCommand request, CancellationToken cancellationToken)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var botKey = await _entitiesRepository.GetFirstOrDefaultAsync <BotKey>(bk => bk.Id == request.Id);

            var update = false;

            if (request.IsDisabled != null && botKey.IsDisabled != request.IsDisabled)
            {
                botKey.IsDisabled = request.IsDisabled.Value;
                update            = true;
            }

            if (request.BotName != null && botKey.BotName != request.BotName)
            {
                botKey.BotName = request.BotName;
                update         = true;
            }

            if (update)
            {
                var botLockResult = await _node.Handle(new RequestDataShard()
                {
                    Type       = "BotKey",
                    ObjectId   = request.Id,
                    CreateLock = true
                });

                if (botLockResult.IsSuccessful && botLockResult.AppliedLocked)
                {
                    if (update)
                    {
                        var result = await _node.Handle(new AddShardWriteOperation()
                        {
                            Data             = botKey,
                            WaitForSafeWrite = true,
                            Operation        = ConsensusCore.Domain.Enums.ShardOperationOptions.Update,
                            RemoveLock       = true
                        });

                        if (result.IsSuccessful)
                        {
                            return(new CommandResult <BotKey>()
                            {
                                ElapsedMs = stopwatch.ElapsedMilliseconds,
                                ObjectRefId = request.Id.ToString(),
                                Type = CommandResultTypes.Update,
                                Result = botKey
                            });
                        }
                        else
                        {
                            throw new FailedClusterOperationException("Failed to apply cluster operation with for botKey " + request.Id);
                        }
                    }
                }
                else
                {
                    throw new FailedClusterOperationException("Failed to apply cluster operation with for botkey " + botKey.Id);
                }
            }

            return(new CommandResult <BotKey>()
            {
                ElapsedMs = stopwatch.ElapsedMilliseconds,
                ObjectRefId = request.Id.ToString(),
                Type = CommandResultTypes.Update,
                Result = botKey
            });
        }