示例#1
0
        public static void Validate(WatchmanConfiguration config)
        {
            if (config == null)
            {
                throw new ConfigException("Config cannot be null");
            }

            if (!HasAny(config.AlertingGroups))
            {
                throw new ConfigException("Config must have alerting groups");
            }

            foreach (var alertingGroup in config.AlertingGroups)
            {
                Validate(alertingGroup);
            }

            var duplicateNames = config.AlertingGroups
                                 .Select(g => g.Name)
                                 .GroupBy(_ => _)
                                 .Where(g => g.Count() > 1)
                                 .Select(g => g.Key)
                                 .ToList();

            if (duplicateNames.Any())
            {
                throw new ConfigException($"The following alerting group names exist in multiple config files: {string.Join(", ", duplicateNames)}");
            }
        }
示例#2
0
        public async Task <GenerateAlarmsResult> GenerateAlarmsForService(
            WatchmanConfiguration config, RunMode mode)
        {
            var serviceConfig = _serviceConfigMapper(config);

            // hack to make sure the alarm creator knows about all groups
            foreach (var group in serviceConfig.AlertingGroups)
            {
                _creator.AddAlarms(group.GroupParameters, new List <Alarm>());
            }

            if (!ServiceConfigIsPopulated(serviceConfig))
            {
                _logger.Info($"No resources for {serviceConfig.ServiceName}. No action taken for this resource type");
                return(new GenerateAlarmsResult());
            }

            var populatedServiceConfig = await PopulateResourceNames(serviceConfig);

            var failures = await GenerateAlarms(populatedServiceConfig, mode);

            await ReportOrphans(populatedServiceConfig);

            return(new GenerateAlarmsResult(failures));
        }
示例#3
0
        public void Setup()
        {
            _config = ConfigTestData.ValidConfig();

            _config.AlertingGroups.First().DynamoDb.Tables = new List <Table>
            {
                new Table {
                    Name = "TableName"
                }
            };
            _config.AlertingGroups.First().Sqs = new Sqs
            {
                Queues = new List <Queue>
                {
                    new Queue {
                        Name = "QueueName"
                    }
                }
            };
            _config.AlertingGroups.First().Services = new Dictionary <string, AwsServiceAlarms>
            {
                {
                    "ServiceName", new AwsServiceAlarms
                    {
                        Resources = new List <ResourceThresholds>
                        {
                            new ResourceThresholds {
                                Pattern = "ResourceName"
                            }
                        }
                    }
                }
            };
        }
        public async Task DoesNotThrowIfTableIsReturnedInListingButCannotBeDescribed()
        {
            var mockery   = new DynamoAlarmGeneratorMockery();
            var generator = mockery.AlarmGenerator;

            mockery.GivenAListOfTables(new[] { "banana", "apple" });
            mockery.GivenATable("apple", 1300, 600);
            mockery.ValidSnsTopic();

            var config = new WatchmanConfiguration()
            {
                AlertingGroups = new List <AlertingGroup>()
                {
                    new AlertingGroup()
                    {
                        Name            = "TestGroup",
                        AlarmNameSuffix = "TestGroup",
                        DynamoDb        = new DynamoDb()
                        {
                            Tables = new List <Table>
                            {
                                new Table {
                                    Pattern = "^.*$"
                                }
                            }
                        }
                    }
                }
            };

            await generator.GenerateAlarmsFor(config, RunMode.GenerateAlarms);
        }
示例#5
0
        public void Setup()
        {
            _config = ConfigTestData.ValidConfig();

            _config.AlertingGroups.First().DynamoDb.Tables = new List <Table>
            {
                new Table {
                    Name = "TableName"
                }
            };
            _config.AlertingGroups.First().Sqs = new Sqs
            {
                Queues = new List <Queue>
                {
                    new Queue {
                        Name = "QueueName"
                    }
                }
            };
            _config.AlertingGroups.First().Services = new AlertingGroupServices()
            {
                AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>
                {
                    Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >
                    {
                        new ResourceThresholds <AutoScalingResourceConfig> {
                            Pattern = "ResourceName"
                        }
                    }
                }
            };
        }
        private async Task GenerateAlarms(WatchmanConfiguration config, RunMode mode)
        {
            await _dynamoGenerator.GenerateAlarmsFor(config, mode);

            await _orphanTablesReporter.FindAndReport(config);

            await _sqsGenerator.GenerateAlarmsFor(config, mode);

            await _orphanQueuesReporter.FindAndReport(config);

            var failed = new List <IList <string> >();

            foreach (var service in _otherServices)
            {
                var result = await service.GenerateAlarmsForService(config, mode);

                failed.Add(result.FailingGroups);
            }

            var allFailed = failed.SelectMany(_ => _).Distinct().ToArray();

            if (mode == RunMode.DryRun || mode == RunMode.GenerateAlarms)
            {
                await _creator.SaveChanges(mode == RunMode.DryRun);
            }

            if (allFailed.Any())
            {
                throw new Exception("The following groups reported errors and were not deployed: " +
                                    $"{string.Join(", ", allFailed)}. please see logs.");
            }
        }
        public void Setup()
        {
            _awsServiceAlarms = new AwsServiceAlarms <ResourceConfig>
            {
                ExcludeResourcesPrefixedWith = new List <string>
                {
                    "ExcludePrefix"
                },
                Resources = new List <ResourceThresholds <ResourceConfig> >
                {
                    new ResourceThresholds <ResourceConfig>
                    {
                        Name   = "ResourceName",
                        Values = new Dictionary <string, AlarmValues>
                        {
                            { "testThresholdLow", 42 }
                        }
                    }
                },
                Values = new Dictionary <string, AlarmValues>
                {
                    { "testThresholdHigh", 242 }
                }
            };

            _config = ConfigTestData.ValidConfig();
            _config.AlertingGroups.First().Services = new AlertingGroupServices()
            {
                Lambda = _awsServiceAlarms
            };
        }
        public void Setup()
        {
            _sqs = new Sqs
            {
                LengthThreshold        = 42,
                OldestMessageThreshold = 42,
                Queues = new List <Queue>
                {
                    new Queue
                    {
                        Name                   = "QueueName",
                        LengthThreshold        = 42,
                        OldestMessageThreshold = 42,
                        Errors                 = new ErrorQueue
                        {
                            LengthThreshold        = 42,
                            OldestMessageThreshold = 42
                        }
                    }
                },
                Errors = new ErrorQueue
                {
                    LengthThreshold        = 42,
                    OldestMessageThreshold = 42
                }
            };

            _config = ConfigTestData.ValidConfig();
            _config.AlertingGroups.First().Sqs = _sqs;
        }
示例#9
0
        public async Task TestNullRefIssueWhenMixingOldAndNewConfig()
        {
            var config = new WatchmanConfiguration()
            {
                AlertingGroups = new List <AlertingGroup>()
                {
                    new AlertingGroup()
                    {
                        Name            = "ag1",
                        AlarmNameSuffix = "ag1suffix",
                        Services        = null,
                        DynamoDb        = new DynamoDb()
                        {
                            Tables = new List <Table>()
                            {
                                new Table()
                                {
                                    Name = "banana"
                                }
                            }
                        }
                    },
                    new AlertingGroup()
                    {
                        Name            = "ag2",
                        AlarmNameSuffix = "ag2suffix",

                        Services = new AlertingGroupServices()
                        {
                            AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>()
                            {
                                Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >()
                                {
                                    new ResourceThresholds <AutoScalingResourceConfig>()
                                    {
                                        Name = "asg"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            var cloudformation = new FakeCloudFormation();

            var context = new TestingIocBootstrapper()
                          .WithCloudFormation(cloudformation.Instance)
                          .WithConfig(config);

            context.GetMock <IAmazonAutoScaling>()
            .HasAutoScalingGroups(new AutoScalingGroup[0]);

            await context.Get <AlarmLoaderAndGenerator>()
            .LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // pass as did not throw
        }
示例#10
0
        public void Config_Fails_When_Null()
        {
            // arrange
            _config = null;

            // act

            // assert
            ConfigAssert.NotValid(_config, "Config cannot be null");
        }
示例#11
0
        public static IConfigLoader ConfigLoaderFor(WatchmanConfiguration config)
        {
            var fake = new Mock <IConfigLoader>();

            fake
            .Setup(x => x.LoadConfig())
            .Returns(config);

            return(fake.Object);
        }
示例#12
0
        public void Setup()
        {
            var testFilePath      = TestFiles.GetRelativePathTo(($"data\\withThresholds".ToCrossPlatformPath()));
            var testFilesSettings = new FileSettings(testFilePath);

            var logger = new Mock <IConfigLoadLogger>();
            var loader = new ConfigLoader(testFilesSettings, logger.Object);

            _config = loader.LoadConfig();
        }
示例#13
0
        private static WatchmanServiceConfiguration <TConfig> Map <TConfig>(WatchmanConfiguration input,
                                                                            string serviceName,
                                                                            Func <AlertingGroup, AwsServiceAlarms <TConfig> > readServiceFromGroup) where TConfig : class
        {
            var groups = input.AlertingGroups
                         .Select(x => ServiceAlertingGroup(x, readServiceFromGroup))
                         .ToList();

            return(new WatchmanServiceConfiguration <TConfig>(serviceName, groups));
        }
        public void Setup()
        {
            var testFilePath      = TestFiles.GetRelativePathTo("data");
            var testFilesSettings = new FileSettings(testFilePath);

            var logger = new Mock <IConfigLoadLogger>();
            var loader = new ConfigLoader(testFilesSettings, logger.Object);

            _config = loader.LoadConfig();
        }
        private static WatchmanServiceConfiguration Map(WatchmanConfiguration input,
                                                        string serviceName,
                                                        Func <AlertingGroup, AwsServiceAlarms> readServiceFromGroup,
                                                        IList <AlarmDefinition> defaults)
        {
            var groups = input.AlertingGroups
                         .Select(x => ServiceAlertingGroup(x, readServiceFromGroup))
                         .Where(x => x != null)
                         .ToList();

            return(new WatchmanServiceConfiguration(serviceName, groups, defaults));
        }
示例#16
0
        public async Task GenerateAlarmsFor(WatchmanConfiguration config, RunMode mode)
        {
            var dryRun = mode == RunMode.DryRun;

            await LogTableNames();

            foreach (var alertingGroup in config.AlertingGroups)
            {
                await GenerateAlarmsFor(alertingGroup, dryRun);
            }

            ReportPutCounts(dryRun);
        }
示例#17
0
        public async Task CatchAllgroupCanBeExcluded()
        {
            var loader = MockTableSource(new List <string> {
                "tableA", "tableB", "tableC", "tableD"
            });

            var reporter = new OrphanTablesFinder(loader.Object);

            var config = new WatchmanConfiguration
            {
                AlertingGroups = new List <AlertingGroup>
                {
                    new AlertingGroup
                    {
                        DynamoDb = new DynamoDb
                        {
                            Tables = new List <Table> {
                                "tableA"
                            }
                        }
                    },
                    new AlertingGroup
                    {
                        DynamoDb = new DynamoDb
                        {
                            Tables = new List <Table> {
                                "tableD"
                            }
                        }
                    },
                    new AlertingGroup
                    {
                        Name       = "catchAll",
                        IsCatchAll = true,
                        DynamoDb   = new DynamoDb
                        {
                            Tables = new List <Table> {
                                "tableA", "tableB", "tableC", "tableD"
                            }
                        }
                    }
                }
            };

            var orphans = await reporter.FindOrphanTables(config);

            AssertHasOrphans(orphans, new List <string> {
                "tableB", "tableC"
            });
        }
示例#18
0
        public async Task GenerateAlarmsForService(
            WatchmanConfiguration config, RunMode mode)
        {
            var serviceConfig = _serviceConfigMapper(config);

            if (!ServiceConfigIsPopulated(serviceConfig))
            {
                _logger.Info($"No resources for {serviceConfig.ServiceName}. No action taken for this resource type");
                return;
            }

            await PopulateResourceNames(serviceConfig);
            await GenerateAlarms(serviceConfig, mode);
            await ReportOrphans(serviceConfig);
        }
示例#19
0
        public static void Validate(WatchmanConfiguration config)
        {
            if (config == null)
            {
                throw new ConfigException("Config cannot be null");
            }

            if (!HasAny(config.AlertingGroups))
            {
                throw new ConfigException("Config must have alerting groups");
            }

            foreach (var alertingGroup in config.AlertingGroups)
            {
                Validate(alertingGroup);
            }
        }
        public void Setup()
        {
            _dynamoDb = new DynamoDb
            {
                Threshold           = 0.7,
                ThrottlingThreshold = 42,
                Tables = new List <Table>
                {
                    new Table
                    {
                        Name      = "TableName",
                        Threshold = 0.8
                    }
                }
            };

            _config = ConfigTestData.ValidConfig();
            _config.AlertingGroups.First().DynamoDb = _dynamoDb;
        }
示例#21
0
        private async Task GenerateAlarms(WatchmanConfiguration config, RunMode mode)
        {
            await _dynamoGenerator.GenerateAlarmsFor(config, mode);

            await _orphanTablesReporter.FindAndReport(config);

            await _sqsGenerator.GenerateAlarmsFor(config, mode);

            await _orphanQueuesReporter.FindAndReport(config);

            foreach (var service in _otherServices)
            {
                await service.GenerateAlarmsForService(config, mode);
            }

            if (mode == RunMode.DryRun || mode == RunMode.GenerateAlarms)
            {
                await _creator.SaveChanges(mode == RunMode.DryRun);
            }
        }
示例#22
0
        public async Task <OrphansModel> FindOrphanTables(WatchmanConfiguration config)
        {
            var monitoredTables = config.AlertingGroups
                                  .Where(ag => !ag.IsCatchAll && ag.DynamoDb?.Tables != null)
                                  .SelectMany(ag => ag.DynamoDb.Tables)
                                  .Select(t => t.Name)
                                  .Distinct();

            var allTables = await _tableSource.GetResourceNamesAsync();

            var unMonitoredTables = allTables
                                    .Except(monitoredTables)
                                    .OrderBy(t => t)
                                    .ToList();

            return(new OrphansModel
            {
                Items = unMonitoredTables.ToList(),
                ServiceName = "table"
            });
        }
示例#23
0
        public async Task NamedTableThatDoesNotExistIsIgnored()
        {
            var mockery   = new DynamoAlarmGeneratorMockery();
            var generator = mockery.AlarmGenerator;

            ConfigureTables(mockery);

            var config = new WatchmanConfiguration()
            {
                AlertingGroups = new List <AlertingGroup>()
                {
                    new AlertingGroup()
                    {
                        Name            = "TestGroup",
                        AlarmNameSuffix = "TestGroup",
                        DynamoDb        = new DynamoDb()
                        {
                            Tables = new List <Table>
                            {
                                new Table {
                                    Name = "table-that-exists"
                                },
                                new Table {
                                    Name = "missing-table"
                                }
                            }
                        }
                    }
                }
            };

            await generator.GenerateAlarmsFor(config, RunMode.GenerateAlarms);

            CloudwatchVerify.AlarmWasPutOnTable(mockery.Cloudwatch,
                                                alarmName: "table-that-exists-ConsumedWriteCapacityUnits-TestGroup",
                                                tableName: "table-that-exists",
                                                metricName: "ConsumedWriteCapacityUnits",
                                                threshold: 144000,
                                                period: 300);
        }
示例#24
0
        public async Task MultipleAlertingGroupsAreCovered()
        {
            var loader = MockTableSource(new List <string> {
                "tableA", "tableB", "tableC", "tableD"
            });

            var reporter = new OrphanTablesFinder(loader.Object);

            var config = new WatchmanConfiguration
            {
                AlertingGroups = new List <AlertingGroup>
                {
                    new AlertingGroup
                    {
                        DynamoDb = new DynamoDb
                        {
                            Tables = new List <Table> {
                                "tableA"
                            }
                        }
                    },
                    new AlertingGroup
                    {
                        DynamoDb = new DynamoDb
                        {
                            Tables = new List <Table> {
                                "tableD"
                            }
                        }
                    }
                }
            };

            var orphans = await reporter.FindOrphanTables(config);

            AssertHasOrphans(orphans, new List <string> {
                "tableB", "tableC"
            });
        }
示例#25
0
        public async Task CanOptOut()
        {
            // arrange
            var config = new WatchmanConfiguration()
            {
                AlertingGroups = new List <AlertingGroup>()
                {
                    new AlertingGroup()
                    {
                        Name            = "group-with-description",
                        AlarmNameSuffix = "group-suffix-1",
                        Services        = new AlertingGroupServices()
                        {
                            Elb = new AwsServiceAlarms <ResourceConfig>()
                            {
                                Resources = new List <ResourceThresholds <ResourceConfig> >()
                                {
                                    new ResourceThresholds <ResourceConfig>()
                                    {
                                        Name   = "elb-1",
                                        Values = new Dictionary <string, AlarmValues>()
                                        {
                                            // to test we can opt out at resource level
                                            { "LatencyHigh", new AlarmValues(enabled: false) },

                                            // to test we can revert an opt-out at service level
                                            { "UnHealthyHostCountHigh", new AlarmValues(enabled: true) }
                                        }
                                    }
                                },
                                Values = new Dictionary <string, AlarmValues>()
                                {
                                    // test we can opt out at service level
                                    { "Http5xxErrorsHigh", new AlarmValues(enabled: false) },

                                    // setup for above (we can revert an opt-out at service level)
                                    { "UnHealthyHostCountHigh", new AlarmValues(enabled: false) }
                                }
                            }
                        }
                    }
                }
            };

            var fakeCloudFormation = new FakeCloudFormation();
            var ioc = new TestingIocBootstrapper()
                      .WithCloudFormation(fakeCloudFormation.Instance)
                      .WithConfig(config);

            ioc.GetMock <IAmazonElasticLoadBalancing>().DescribeReturnsLoadBalancers(new[]
            {
                new LoadBalancerDescription()
                {
                    LoadBalancerName = "elb-1"
                },
                new LoadBalancerDescription()
                {
                    LoadBalancerName = "elb-2"
                }
            });

            var sut = ioc.Get <AlarmLoaderAndGenerator>();

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarms = fakeCloudFormation
                         .Stack("Watchman-group-with-description")
                         .AlarmsByDimension("LoadBalancerName");

            var alarmsForElb1 = alarms["elb-1"];

            Assert.That(alarmsForElb1.Any(
                            alarm => alarm.Properties["AlarmName"].ToString().Contains("LatencyHigh")
                            ), Is.False);

            Assert.That(alarmsForElb1.Any(
                            alarm => alarm.Properties["AlarmName"].ToString().Contains("Http5xxErrorsHigh")
                            ), Is.False);

            Assert.That(alarmsForElb1.Any(
                            alarm => alarm.Properties["AlarmName"].ToString().Contains("UnHealthyHostCountHigh")
                            ), Is.True);
        }
        public static WatchmanServiceConfiguration <ResourceConfig> MapStepFunction(WatchmanConfiguration input)
        {
            const string id = "StepFunction";

            return(Map(input, id, a => a?.Services?.StepFunction, Defaults.StepFunction));
        }
        public static WatchmanServiceConfiguration <ResourceConfig> MapDynamoDb(WatchmanConfiguration input)
        {
            const string id = "DynamoDb";

            return(Map(input, id, a => a?.Services?.DynamoDb, Defaults.DynamoDb));
        }
        public async Task FindAndReport(WatchmanConfiguration config)
        {
            var orphans = await _orphanTablesFinder.FindOrphanTables(config);

            _logger.Log(orphans);
        }
示例#29
0
 public static void HasConfig(this Mock <IConfigLoader> loader, WatchmanConfiguration config)
 {
     loader.Setup(x => x.LoadConfig()).Returns(config);
 }
示例#30
0
        public async Task AlarmsHaveMeaningfulDescription()
        {
            // arrange
            var config = new WatchmanConfiguration()
            {
                AlertingGroups = new List <AlertingGroup>()
                {
                    new AlertingGroup()
                    {
                        Name            = "group-with-description",
                        AlarmNameSuffix = "group-suffix-1",
                        Description     = "Group description for group 1",
                        Services        = new AlertingGroupServices()
                        {
                            Elb = new AwsServiceAlarms <ResourceConfig>()
                            {
                                Resources = new List <ResourceThresholds <ResourceConfig> >()
                                {
                                    new ResourceThresholds <ResourceConfig>()
                                    {
                                        Name = "elb-1"
                                    }
                                }
                            }
                        }
                    },


                    new AlertingGroup()
                    {
                        Name            = "group-without-description",
                        AlarmNameSuffix = "group-suffix-2",
                        Services        = new AlertingGroupServices()
                        {
                            Elb = new AwsServiceAlarms <ResourceConfig>()
                            {
                                Resources = new List <ResourceThresholds <ResourceConfig> >()
                                {
                                    new ResourceThresholds <ResourceConfig>()
                                    {
                                        Name = "elb-2"
                                    }
                                }
                            }
                        }
                    }
                }
            };

            var fakeCloudFormation = new FakeCloudFormation();
            var ioc = new TestingIocBootstrapper()
                      .WithCloudFormation(fakeCloudFormation.Instance)
                      .WithConfig(config);

            ioc.GetMock <IAmazonElasticLoadBalancing>().DescribeReturnsLoadBalancers(new[]
            {
                new LoadBalancerDescription()
                {
                    LoadBalancerName = "elb-1"
                },
                new LoadBalancerDescription()
                {
                    LoadBalancerName = "elb-2"
                }
            });

            var sut = ioc.Get <AlarmLoaderAndGenerator>();

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var firstGroupAlarm = fakeCloudFormation
                                  .Stack("Watchman-group-with-description")
                                  .Alarms()
                                  .First();

            var description = firstGroupAlarm.Properties["AlarmDescription"].ToString();

            Assert.That(description, Contains.Substring("Alarm generated by AwsWatchman"));
            Assert.That(description, Contains.Substring("group-with-description"));
            Assert.That(description, Contains.Substring("Group description for group 1"));

            var secondGroupAlarm = fakeCloudFormation
                                   .Stack("Watchman-group-without-description")
                                   .Alarms()
                                   .First();

            var description2 = secondGroupAlarm.Properties["AlarmDescription"].ToString();

            Assert.That(description2, Contains.Substring("Alarm generated by AwsWatchman"));
            Assert.That(description2, Contains.Substring("group-without-description"));
        }