protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await Task.Yield();

            IReadOnlyCollection <DeploymentTargetId> targetIds;

            try
            {
                if (!int.TryParse(
                        _configuration[DeployerAppConstants.StartupTargetsTimeoutInSeconds],
                        out int startupTimeoutInSeconds) ||
                    startupTimeoutInSeconds <= 0)
                {
                    startupTimeoutInSeconds = 30;
                }

                using CancellationTokenSource startupToken =
                          _timeoutHelper.CreateCancellationTokenSource(TimeSpan.FromSeconds(startupTimeoutInSeconds));
                using var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(
                          stoppingToken,
                          startupToken.Token);
                targetIds =
                    (await _deploymentTargetReadService.GetDeploymentTargetsAsync(stoppingToken: linkedToken.Token))
                    .Select(deploymentTarget => deploymentTarget.Id)
                    .ToArray();

                _logger.Debug("Found deployment target IDs {IDs}", targetIds);
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                _logger.Warning(ex, "Could not get target ids");
                IsCompleted = true;
                return;
            }

            foreach (var targetId in targetIds)
            {
                var deploymentTargetWorker = new DeploymentTargetWorker(targetId, _logger, _mediator,
                                                                        _workerConfiguration, _timeoutHelper, _clock, _serviceProvider);

                _holder.Add(new NamedInstance <DeploymentTargetWorker>(
                                deploymentTargetWorker,
                                targetId.TargetId));

                await _mediator.Send(new StartWorker(deploymentTargetWorker), stoppingToken);
            }

            IsCompleted = true;
        }
Beispiel #2
0
        public async Task SeedAsync(CancellationToken cancellationToken)
        {
            AgentPoolListResult types = await _mediator.Send(new GetAgentPoolsQuery(), cancellationToken);

            if (!types.AgentPools.IsDefaultOrEmpty)
            {
                return;
            }

            var agentPoolId = new AgentPoolId("Default");
            var result      = await _mediator.Send(new CreateAgentPool(agentPoolId, new AgentPoolName("Default")), cancellationToken);

            _logger.Debug("CreateAgentPool result for Id {Id}: {Status}", agentPoolId, result);

            var deploymentTargets = await _deploymentTargetReadService.GetDeploymentTargetsAsync(stoppingToken : cancellationToken);

            foreach (var deploymentTarget in deploymentTargets)
            {
                await _mediator.Send(new AssignTargetToPool(agentPoolId, deploymentTarget.Id), cancellationToken);
            }

            var agents = await _mediator.Send(new GetAgentsQuery(), cancellationToken);

            var assignedAgents = await _mediator.Send(new GetAssignedAgentsInPoolsQuery(), cancellationToken);

            foreach (var agent in agents.Agents)
            {
                bool assigned = false;
                foreach (var assignedAgentsAssignedAgent in assignedAgents.AssignedAgents)
                {
                    if (assignedAgentsAssignedAgent.Value.Contains(agent.Id))
                    {
                        assigned = true;
                        break;
                    }
                }

                if (!assigned)
                {
                    await _mediator.Send(new AssignAgentToPool(agentPoolId, agent.Id), cancellationToken);
                }
            }
        }
        public async Task SeedAsync(CancellationToken cancellationToken)
        {
            try
            {
                var environmentTypes = await _environmentTypeService.GetEnvironmentTypes(cancellationToken);

                var targets =
                    await _deploymentTargetReadService.GetDeploymentTargetsAsync(stoppingToken : cancellationToken);

                foreach (DeploymentTarget deploymentTarget in targets)
                {
                    await UpdateTarget(cancellationToken, deploymentTarget, environmentTypes);
                }
            }
            catch (TaskCanceledException ex)
            {
                _logger.Error(ex, "Could not run seeder task");
            }
        }
        public async Task Handle(PackageUpdatedEvent notification, CancellationToken cancellationToken)
        {
            var deploymentTargets = await _readService.GetDeploymentTargetsAsync(stoppingToken : cancellationToken);

            DeploymentTarget[] targetsMatchingPackage = deploymentTargets
                                                        .Where(
                target => target.PackageId.Equals(
                    notification.PackageVersion.PackageId,
                    StringComparison.OrdinalIgnoreCase))
                                                        .ToArray();

            if (targetsMatchingPackage.Length == 0)
            {
                return;
            }

            IClientProxy clientProxy = _targetHubContext.Clients.All;

            await clientProxy.SendAsync(TargetHub.TargetsWithUpdates, notification.PackageVersion.PackageId,
                                        notification.PackageVersion.Version.ToNormalizedString(),
                                        targetsMatchingPackage.Select(target => target.Id).ToArray(), cancellationToken);
        }
        public async Task Handle(PackageUpdatedEvent notification, CancellationToken cancellationToken)
        {
            if (!(await _applicationSettingsStore.GetApplicationSettings(cancellationToken)).AutoDeploy.Enabled)
            {
                _logger.Information("Auto deploy is disabled, skipping package web hook notification");
                return;
            }

            PackageVersion packageIdentifier = notification.PackageVersion;

            if (packageIdentifier is null)
            {
                throw new ArgumentException(nameof(packageIdentifier));
            }

            _logger.Information("Received hook for package {Package}", packageIdentifier);

            IReadOnlyCollection <DeploymentTarget> deploymentTargets =
                (await _targetSource.GetDeploymentTargetsAsync(stoppingToken: cancellationToken))
                .SafeToReadOnlyCollection();

            DeploymentTarget[] withAutoDeploy = deploymentTargets.Where(target => target.AutoDeployEnabled).ToArray();

            if (!withAutoDeploy.Any())
            {
                _logger.Information("No target has auto deploy enabled");
            }
            else
            {
                foreach (DeploymentTarget deploymentTarget in withAutoDeploy)
                {
                    if (deploymentTarget.PackageId.Equals(
                            packageIdentifier.PackageId,
                            StringComparison.OrdinalIgnoreCase))
                    {
                        if (deploymentTarget.NuGet.NuGetConfigFile is {} &&
        public async Task AutoDeployAsync([NotNull] IReadOnlyCollection <PackageVersion> packageIdentifiers)
        {
            if (packageIdentifiers == null)
            {
                throw new ArgumentNullException(nameof(packageIdentifiers));
            }

            _logger.Information("Received hook for packages {Packages}", string.Join(", ", packageIdentifiers.Select(p => p.ToString())));

            IReadOnlyCollection <DeploymentTarget> deploymentTargets =
                (await _targetSource.GetDeploymentTargetsAsync(CancellationToken.None))
                .SafeToReadOnlyCollection();

            DeploymentTarget[] withAutoDeploy = deploymentTargets.Where(t => t.AutoDeployEnabled).ToArray();

            if (!withAutoDeploy.Any())
            {
                _logger.Information("No target has auto deploy enabled");
            }
            else
            {
                foreach (DeploymentTarget deploymentTarget in withAutoDeploy)
                {
                    foreach (PackageVersion packageIdentifier in packageIdentifiers)
                    {
                        if (deploymentTarget.PackageId.Equals(
                                packageIdentifier.PackageId,
                                StringComparison.OrdinalIgnoreCase))
                        {
                            bool allowDeployment =
                                !packageIdentifier.Version.IsPrerelease || deploymentTarget.AllowPreRelease;

                            if (allowDeployment)
                            {
                                AppVersion metadata = await _monitoringService.GetAppMetadataAsync(
                                    deploymentTarget,
                                    CancellationToken.None);

                                if (metadata.SemanticVersion != null)
                                {
                                    if (packageIdentifier.Version > metadata.SemanticVersion)
                                    {
                                        _logger.Information("Auto deploying package {PackageIdentifier} to target {Name} from web hook", packageIdentifier, deploymentTarget.Name);

                                        DeploymentTaskResult result =
                                            await
                                            _deploymentService.ExecuteDeploymentAsync(
                                                new DeploymentTask(
                                                    $"{packageIdentifier.PackageId}, {packageIdentifier.Version.ToNormalizedString()}",
                                                    deploymentTarget.Id, Guid.NewGuid()
                                                    ),
                                                _logger,
                                                CancellationToken.None);

                                        _logger.Information("Deployed package {PackageIdentifier} to target {Name} from web hook with result {Result}", packageIdentifier, deploymentTarget.Name, result);
                                    }
                                    else
                                    {
                                        _logger.Information("Auto deployment skipped for {PackageIdentifier} since deployed version is higher {V}", packageIdentifier, metadata.SemanticVersion.ToNormalizedString());
                                    }
                                }
                                else
                                {
                                    _logger.Information("Auto deployment skipped for {PackageIdentifier} since the target version could not be determined", packageIdentifier);
                                }
                            }
                            else
                            {
                                _logger.Information("Auto deployment skipped for {PackageIdentifier} since the target does not allow pre-release", packageIdentifier);
                            }
                        }
                        else
                        {
                            _logger.Information("No package id matched {PackageIdentifier} for target {Name}", packageIdentifier, deploymentTarget.Name);
                        }
                    }
                }
            }
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            if (!_autoDeployConfiguration.Enabled)
            {
                return;
            }

            await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.StartupDelayInSeconds), stoppingToken);

            while (!stoppingToken.IsCancellationRequested)
            {
                ImmutableArray <DeploymentTarget> deploymentTargets;
                using (var targetsTokenSource =
                           new CancellationTokenSource(TimeSpan.FromSeconds(_autoDeployConfiguration.DefaultTimeoutInSeconds)))
                {
                    using (CancellationTokenSource linked =
                               CancellationTokenSource.CreateLinkedTokenSource(stoppingToken,
                                                                               targetsTokenSource.Token))
                    {
                        deploymentTargets = (await _deploymentTargetReadService.GetDeploymentTargetsAsync(linked.Token))
                                            .Where(target => target.Enabled && target.AutoDeployEnabled)
                                            .ToImmutableArray();
                    }
                }

                if (deploymentTargets.IsDefaultOrEmpty)
                {
                    _logger.Verbose("Found no deployment targets with auto deployment enabled, waiting {DelayInSeconds} seconds", _autoDeployConfiguration.EmptyTargetsDelayInSeconds);
                    await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.EmptyTargetsDelayInSeconds), stoppingToken);

                    continue;
                }

                ImmutableArray <DeploymentTarget> targetsWithUrl = deploymentTargets.Where(target => target.Url.HasValue()).ToImmutableArray();

                if (targetsWithUrl.IsDefaultOrEmpty)
                {
                    _logger.Verbose("Found no deployment targets with auto deployment enabled and URL defined, waiting {DelayInSeconds} seconds", _autoDeployConfiguration.EmptyTargetsDelayInSeconds);
                    await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.EmptyTargetsDelayInSeconds), stoppingToken);

                    continue;
                }

                AppVersion[] appVersions;
                using (var cancellationTokenSource =
                           new CancellationTokenSource(
                               TimeSpan.FromSeconds(_autoDeployConfiguration.MetadataTimeoutInSeconds)))
                {
                    using (CancellationTokenSource linkedCancellationTokenSource =
                               CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, stoppingToken))
                    {
                        CancellationToken cancellationToken = linkedCancellationTokenSource.Token;

                        IEnumerable <Task <AppVersion> > tasks = targetsWithUrl.Select(target =>
                                                                                       _monitoringService.GetAppMetadataAsync(target, cancellationToken));

                        appVersions = await Task.WhenAll(tasks);
                    }
                }

                foreach (DeploymentTarget deploymentTarget in targetsWithUrl)
                {
                    AppVersion appVersion = appVersions.SingleOrDefault(v =>
                                                                        v.Target.Id.Equals(deploymentTarget.Id, StringComparison.OrdinalIgnoreCase));

                    if (appVersion?.SemanticVersion is null || appVersion.PackageId.IsNullOrWhiteSpace())
                    {
                        continue;
                    }

                    ImmutableHashSet <PackageVersion> packageVersions;
                    using (var packageVersionCancellationTokenSource =
                               new CancellationTokenSource(TimeSpan.FromSeconds(_autoDeployConfiguration.DefaultTimeoutInSeconds)))
                    {
                        using (CancellationTokenSource linked =
                                   CancellationTokenSource.CreateLinkedTokenSource(stoppingToken,
                                                                                   packageVersionCancellationTokenSource.Token))
                        {
                            packageVersions =
                                (await _packageService.GetPackageVersionsAsync(deploymentTarget.PackageId, cancellationToken: linked.Token, logger: _logger)).ToImmutableHashSet();
                        }
                    }

                    if (packageVersions.IsEmpty)
                    {
                        continue;
                    }

                    ImmutableHashSet <PackageVersion> filteredPackages = !deploymentTarget.AllowPreRelease ? packageVersions.Where(p => !p.Version.IsPrerelease).ToImmutableHashSet() : packageVersions;

                    if (filteredPackages.IsEmpty)
                    {
                        continue;
                    }

                    ImmutableHashSet <PackageVersion> newerPackages = filteredPackages
                                                                      .Where(package =>
                                                                             package.PackageId.Equals(appVersion.PackageId, StringComparison.OrdinalIgnoreCase) &&
                                                                             package.Version > appVersion.SemanticVersion)
                                                                      .ToImmutableHashSet();

                    PackageVersion packageToDeploy = newerPackages
                                                     .OrderByDescending(package => package.Version)
                                                     .FirstOrDefault();

                    if (packageToDeploy != null)
                    {
                        var task = new DeploymentTask(packageToDeploy, deploymentTarget.Id, Guid.NewGuid());

                        _logger.Information("Auto-deploying package {Package} to target {TargetId}",
                                            packageToDeploy,
                                            deploymentTarget.Id);

                        _deploymentWorker.Enqueue(task);
                    }
                }

                await Task.Delay(TimeSpan.FromSeconds(_autoDeployConfiguration.AfterDeployDelayInSeconds), stoppingToken);
            }
        }