public async Task DoesDeployMultipleStacksIfSelected()
        {
            // first create a stack which has a resource

            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix",
                                                               new AlertingGroupServices()
            {
                AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >()
                    {
                        new ResourceThresholds <AutoScalingResourceConfig>()
                        {
                            Name = "group-1"
                        }
                    }
                }
            },
                                                               2);

            var cloudformation = new FakeCloudFormation();

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

            firstTestContext.GetMock <IAmazonAutoScaling>().HasAutoScalingGroups(new[]
            {
                new AutoScalingGroup()
                {
                    AutoScalingGroupName = "group-1",
                    DesiredCapacity      = 40
                }
            });

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

            // check it got deployed

            var stack = cloudformation
                        .Stack("Watchman-test");

            Assert.That(stack, Is.Not.Null);
            Assert.That(stack.Resources
                        .Values
                        .Where(r => r.Type == "AWS::CloudWatch::Alarm")
                        .Count, Is.GreaterThan(0));

            var stack2 = cloudformation
                         .Stack("Watchman-test-1");

            Assert.That(stack2, Is.Not.Null);
            Assert.That(stack2.Resources
                        .Values
                        .Where(r => r.Type == "AWS::CloudWatch::Alarm")
                        .Count, Is.GreaterThan(0));
        }
Ejemplo n.º 2
0
        public async Task CanUseExtendedStatisticsForResource()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration(
                "test",
                "group-suffix",
                new AlertingGroupServices()
            {
                Elb = new AwsServiceAlarms <ResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >()
                    {
                        new ResourceThresholds <ResourceConfig>()
                        {
                            Name   = "elb-1",
                            Values = new Dictionary <string, AlarmValues>()
                            {
                                {
                                    "LatencyHigh", new AlarmValues(extendedStatistic: "p97")
                                }
                            }
                        }
                    }
                }
            }
                );

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

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

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByElb = fakeCloudFormation
                              .Stack("Watchman-test")
                              .AlarmsByDimension("LoadBalancerName");

            var alarm = alarmsByElb["elb-1"].FirstOrDefault(a => a.Properties["AlarmName"].ToString().Contains("LatencyHigh"));

            Assert.That(alarm, Is.Not.Null);
            Assert.That(alarm.Properties.ContainsKey("Statistic"), Is.False);
            Assert.That(alarm.Properties["ExtendedStatistic"].ToString(), Is.EqualTo("p97"));
        }
Ejemplo n.º 3
0
        public async Task AlarmWithIncludeErrorQueuesFalseWillNotCreateErrorQueueAlarms()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                Sqs = new AwsServiceAlarms <SqsResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <SqsResourceConfig> >()
                    {
                        new ResourceThresholds <SqsResourceConfig>()
                        {
                            Pattern = "first-sqs-queue",
                            Options = new SqsResourceConfig()
                            {
                                IncludeErrorQueues = false
                            },
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonCloudWatch>().HasSqsQueues(new[]
            {
                "first-sqs-queue",
                "first-sqs-queue_error"
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByQueue = cloudformation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("QueueName");

            Assert.That(alarmsByQueue.ContainsKey("first-sqs-queue"), Is.True);
            var alarmsForQueue = alarmsByQueue["first-sqs-queue"];

            Assert.That(
                alarmsForQueue.Exists(
                    alarm => alarm.Properties["MetricName"].Value <string>() == "ApproximateNumberOfMessagesVisible")
                );

            Assert.That(!alarmsByQueue.ContainsKey("first-sqs-queue_error"));
        }
Ejemplo n.º 4
0
        public async Task <AlbTestSetupData> Build()
        {
            if (!_loadBalancers.Any())
            {
                WithDefaultLoadBalancer();
            }

            var config = ConfigHelper.CreateBasicConfiguration(_configurationName, _configurationSuffix,
                                                               new AlertingGroupServices()
            {
                Alb = new AwsServiceAlarms <ResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >()
                    {
                        new ResourceThresholds <ResourceConfig>()
                        {
                            Pattern = _pattern
                        }
                    },
                    Values = _overrides
                }
            });

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

            ioc.GetMock <IAmazonElasticLoadBalancingV2>()
            .Setup(x => x.DescribeLoadBalancersAsync(It.IsAny <DescribeLoadBalancersRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new DescribeLoadBalancersResponse
            {
                LoadBalancers = _loadBalancers
            });

            var sut = ioc.Get <AlarmLoaderAndGenerator>();
            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            var alarms = cloudFormation
                         .Stack($"Watchman-{_configurationName}")
                         ?.Resources
                         ?.Where(x => x.Value.Type.Equals("AWS::CloudWatch::Alarm", StringComparison.InvariantCultureIgnoreCase))
                         .Select(x => x.Value)
                         .ToList();

            return(new AlbTestSetupData
            {
                ConfigurationSuffix = _configurationSuffix,
                FakeCloudFormation = cloudFormation,
                LoadBalancers = _loadBalancers,
                Alarms = alarms
            });
        }
        public async Task AlarmCreatedWithCorrectProperties()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                CloudFront = new AwsServiceAlarms <ResourceConfig>
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >
                    {
                        new ResourceThresholds <ResourceConfig>
                        {
                            Name   = "distribution-1",
                            Values = new Dictionary <string, AlarmValues>
                            {
                                { "4xxErrorRate", new AlarmValues(10, TimeSpan.FromMinutes(5).Minutes) }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonCloudFront>().HasCloudFrontDistributions(new[]
            {
                new DistributionSummary
                {
                    Id = "distribution-1"
                }
            });

            var sut = ioc.Get <AlarmLoaderAndGenerator>();
            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            var alarmsByDistributionId = cloudformation
                                         .Stack("Watchman-test")
                                         .AlarmsByDimension("DistributionId");

            Assert.That(alarmsByDistributionId.ContainsKey("distribution-1"), Is.True);

            var alarms = alarmsByDistributionId["distribution-1"];

            Assert.That(alarms.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "4xxErrorRate" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("4xxErrorRate") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix")
                            ));
        }
Ejemplo n.º 6
0
        public async Task CanOverrideThreshold()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix",
                                                               new AlertingGroupServices()
            {
                AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >()
                    {
                        new ResourceThresholds <AutoScalingResourceConfig>()
                        {
                            Name   = "group-1",
                            Values = new Dictionary <string, AlarmValues>()
                            {
                                { "GroupInServiceInstancesLow", 10 }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonAutoScaling>().HasAutoScalingGroups(new[]
            {
                new AutoScalingGroup()
                {
                    AutoScalingGroupName = "group-1",
                    DesiredCapacity      = 40
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarms = cloudFormation
                         .Stack("Watchman-test")
                         .AlarmsByDimension("AutoScalingGroupName");

            var alarm = alarms["group-1"].Single(a => a.Properties["AlarmName"].ToString().Contains("InService"));

            Assert.That((decimal)alarm.Properties["Threshold"], Is.EqualTo(40 * 0.1));
        }
Ejemplo n.º 7
0
        public async Task GuessesErrorQueueNameWhenNotReportedByCloudWatch()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                Sqs = new AwsServiceAlarms <SqsResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <SqsResourceConfig> >()
                    {
                        new ResourceThresholds <SqsResourceConfig>()
                        {
                            Pattern = "first-sqs-queue"
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonCloudWatch>().HasSqsQueues(new[]
            {
                "first-sqs-queue"
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByQueue = cloudFormation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("QueueName");

            var alarmsForQueue = alarmsByQueue["first-sqs-queue"];

            Assert.That(alarmsForQueue, Is.Not.Empty);

            var alarmsForErrorQueue = alarmsByQueue["first-sqs-queue_error"];

            Assert.That(alarmsForErrorQueue, Is.Not.Empty);
        }
Ejemplo n.º 8
0
        public async Task DoesNotDeployNewEmptyStack()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix",
                                                               new AlertingGroupServices()
            {
                AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >()
                    {
                        new ResourceThresholds <AutoScalingResourceConfig>()
                        {
                            Name = "non-existent-resource"
                        }
                    }
                }
            });

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

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


            var now = DateTime.Parse("2018-01-26");

            ioc.GetMock <ICurrentTimeProvider>()
            .Setup(f => f.UtcNow)
            .Returns(now);


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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var stack = cloudformation
                        .Stack("Watchman-test");

            Assert.That(stack, Is.Null);
        }
Ejemplo n.º 9
0
        public async Task CanOverrideThresholdPercentage()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources =
                        new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Pattern = "first-table",
                            Values  = new Dictionary <string, AlarmValues>()
                            {
                                { "GsiConsumedReadCapacityUnitsHigh", 20 },
                                { "ConsumedReadCapacityUnitsHigh", 10 }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonDynamoDB>().HasDynamoTables(new[]
            {
                new TableDescription()
                {
                    TableName             = "production-first-table",
                    ProvisionedThroughput = new ProvisionedThroughputDescription()
                    {
                        ReadCapacityUnits  = 100,
                        WriteCapacityUnits = 200
                    },
                    GlobalSecondaryIndexes = new List <GlobalSecondaryIndexDescription>()
                    {
                        new GlobalSecondaryIndexDescription()
                        {
                            IndexName             = "first-gsi",
                            ProvisionedThroughput = new ProvisionedThroughputDescription()
                            {
                                ReadCapacityUnits  = 400,
                                WriteCapacityUnits = 500
                            }
                        }
                    }
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByGsi = cloudFormation
                              .Stack("Watchman-test")
                              .AlarmsByDimension("GlobalSecondaryIndexName");
            var gsiAlarms = alarmsByGsi["first-gsi"];

            var consumedReadGsi = gsiAlarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-first-gsi-GsiConsumedReadCapacityUnitsHigh"));

            Assert.That(consumedReadGsi.Properties["Threshold"].Value <int>(),
                        Is.EqualTo(400 * OneMinuteInSeconds * 0.2m));

            var alarmsByTable = cloudFormation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("TableName");
            var tableAlarms = alarmsByTable["production-first-table"];

            var consumedReadForTable = tableAlarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-ConsumedReadCapacityUnitsHigh"));

            Assert.That(consumedReadForTable.Properties["Threshold"].Value <int>(),
                        Is.EqualTo(100 * OneMinuteInSeconds * 0.1m));
        }
Ejemplo n.º 10
0
        public async Task AlarmsCanBeAddedToGlobalSecondaryIndexes()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources =
                        new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Name = "first-table"
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonDynamoDB>().HasDynamoTables(new[]
            {
                new TableDescription()
                {
                    TableName             = "first-table",
                    ProvisionedThroughput = new ProvisionedThroughputDescription()
                    {
                        ReadCapacityUnits  = 100,
                        WriteCapacityUnits = 200
                    },
                    GlobalSecondaryIndexes = new List <GlobalSecondaryIndexDescription>()
                    {
                        new GlobalSecondaryIndexDescription()
                        {
                            IndexName             = "first-gsi",
                            ProvisionedThroughput = new ProvisionedThroughputDescription()
                            {
                                ReadCapacityUnits  = 400,
                                WriteCapacityUnits = 500
                            }
                        }
                    }
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert
            const decimal defaultCapacityThreshold = 0.8m;
            const decimal capacityMultiplier       = defaultCapacityThreshold * OneMinuteInSeconds;
            const int     defaultThrottleThreshold = 2;

            // basic check we still have table alarms
            Assert.That(cloudformation.Stack("Watchman-test").AlarmsByDimension("TableName").Any(), Is.True);

            var alarmsByGsi = cloudformation
                              .Stack("Watchman-test")
                              .AlarmsByDimension("GlobalSecondaryIndexName");

            Assert.That(alarmsByGsi.ContainsKey("first-gsi"), Is.True);
            var alarms = alarmsByGsi["first-gsi"];

            var consumedRead = alarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-first-gsi-GsiConsumedReadCapacityUnitsHigh"));

            Assert.That(consumedRead, Is.Not.Null, "GSI read alarm missing");
            Assert.That(consumedRead.Properties["MetricName"].Value <string>(), Is.EqualTo("ConsumedReadCapacityUnits"));
            Assert.That(consumedRead.Properties["Threshold"].Value <int>(),
                        Is.EqualTo(400 * capacityMultiplier));
            Assert.That(consumedRead.Properties["Period"].Value <int>(), Is.EqualTo(60));
            Assert.That(consumedRead.Properties["ComparisonOperator"].Value <string>(),
                        Is.EqualTo("GreaterThanOrEqualToThreshold"));
            Assert.That(consumedRead.Properties["Statistic"].Value <string>(), Is.EqualTo("Sum"));
            Assert.That(consumedRead.Properties["Namespace"].Value <string>(), Is.EqualTo(AwsNamespace.DynamoDb));
            Assert.That(consumedRead.Dimension("TableName"), Is.EqualTo("first-table"));

            var consumedWrite = alarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-first-gsi-GsiConsumedWriteCapacityUnitsHigh"));

            Assert.That(consumedWrite, Is.Not.Null, "GSI write alarm missing");
            Assert.That(consumedWrite.Properties["MetricName"].Value <string>(),
                        Is.EqualTo("ConsumedWriteCapacityUnits"));
            Assert.That(consumedWrite.Properties["Threshold"].Value <int>(),
                        Is.EqualTo(500 * capacityMultiplier));
            Assert.That(consumedWrite.Properties["Period"].Value <int>(), Is.EqualTo(60));
            Assert.That(consumedWrite.Properties["ComparisonOperator"].Value <string>(),
                        Is.EqualTo("GreaterThanOrEqualToThreshold"));
            Assert.That(consumedWrite.Properties["Statistic"].Value <string>(), Is.EqualTo("Sum"));
            Assert.That(consumedWrite.Properties["Namespace"].Value <string>(), Is.EqualTo(AwsNamespace.DynamoDb));
            Assert.That(consumedWrite.Dimension("TableName"), Is.EqualTo("first-table"));

            var readThrottle = alarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-first-gsi-GsiReadThrottleEventsHigh"));

            Assert.That(readThrottle, Is.Not.Null, "GSI read throttle alarm missing");
            Assert.That(readThrottle.Properties["MetricName"].Value <string>(), Is.EqualTo("ReadThrottleEvents"));
            Assert.That(readThrottle.Properties["Threshold"].Value <int>(), Is.EqualTo(defaultThrottleThreshold));
            Assert.That(readThrottle.Properties["Period"].Value <int>(), Is.EqualTo(60));
            Assert.That(readThrottle.Properties["ComparisonOperator"].Value <string>(),
                        Is.EqualTo("GreaterThanOrEqualToThreshold"));
            Assert.That(readThrottle.Properties["Statistic"].Value <string>(), Is.EqualTo("Sum"));
            Assert.That(readThrottle.Properties["Namespace"].Value <string>(), Is.EqualTo(AwsNamespace.DynamoDb));
            Assert.That(readThrottle.Dimension("TableName"), Is.EqualTo("first-table"));

            var writeThrottle = alarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-first-gsi-GsiWriteThrottleEventsHigh"));

            Assert.That(writeThrottle, Is.Not.Null, "GSI write throttle alarm missing");
            Assert.That(writeThrottle.Properties["MetricName"].Value <string>(), Is.EqualTo("WriteThrottleEvents"));
            Assert.That(writeThrottle.Properties["Threshold"].Value <int>(), Is.EqualTo(defaultThrottleThreshold));
            Assert.That(writeThrottle.Properties["Period"].Value <int>(), Is.EqualTo(60));
            Assert.That(writeThrottle.Properties["ComparisonOperator"].Value <string>(),
                        Is.EqualTo("GreaterThanOrEqualToThreshold"));
            Assert.That(writeThrottle.Properties["Statistic"].Value <string>(), Is.EqualTo("Sum"));
            Assert.That(writeThrottle.Properties["Namespace"].Value <string>(), Is.EqualTo(AwsNamespace.DynamoDb));
            Assert.That(writeThrottle.Dimension("TableName"), Is.EqualTo("first-table"));
        }
Ejemplo n.º 11
0
        public async Task AlarmCreatedWithCorrectProperties()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Name = "first-dynamo-table"
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonDynamoDB>().HasDynamoTables(new[]
            {
                new TableDescription()
                {
                    TableName             = "first-dynamo-table",
                    ProvisionedThroughput = new ProvisionedThroughputDescription()
                    {
                        ReadCapacityUnits  = 100,
                        WriteCapacityUnits = 200
                    }
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            const decimal defaultCapacityThreshold = 0.8m;
            const decimal capacityMultiplier       = defaultCapacityThreshold * OneMinuteInSeconds;
            const int     defaultThrottleThreshold = 2;

            var alarmsByTable = cloudformation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("TableName");

            Assert.That(alarmsByTable.ContainsKey("first-dynamo-table"), Is.True);
            var alarms = alarmsByTable["first-dynamo-table"];

            Assert.That(alarms.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ConsumedReadCapacityUnits" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("ConsumedReadCapacityUnitsHigh") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 100 * capacityMultiplier &&
                            alarm.Properties["Period"].Value <int>() == 60 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Sum" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.DynamoDb
                            )
                        );

            Assert.That(alarms.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ConsumedWriteCapacityUnits" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("ConsumedWriteCapacityUnitsHigh") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 200 * capacityMultiplier &&
                            alarm.Properties["Period"].Value <int>() == 60 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Sum" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.DynamoDb
                            )
                        );

            var readThrottleAlarm =
                alarms.Single(a => a.Properties["MetricName"].Value <string>() == "ReadThrottleEvents");

            Assert.That(readThrottleAlarm.Properties["AlarmName"].Value <string>(),
                        Contains.Substring("ReadThrottleEventsHigh"));
            Assert.That(readThrottleAlarm.Properties["AlarmName"].Value <string>(), Contains.Substring("-group-suffix"));
            Assert.That(readThrottleAlarm.Properties["Threshold"].Value <int>(), Is.EqualTo(defaultThrottleThreshold));
            Assert.That(readThrottleAlarm.Properties["Period"].Value <int>(), Is.EqualTo(60));
            Assert.That(readThrottleAlarm.Properties["ComparisonOperator"].Value <string>(),
                        Is.EqualTo("GreaterThanOrEqualToThreshold"));
            Assert.That(readThrottleAlarm.Properties["Statistic"].Value <string>(), Is.EqualTo("Sum"));
            Assert.That(readThrottleAlarm.Properties["Namespace"].Value <string>(), Is.EqualTo(AwsNamespace.DynamoDb));

            var writeThrottleAlarm =
                alarms.Single(a => a.Properties["MetricName"].Value <string>() == "WriteThrottleEvents");

            Assert.That(writeThrottleAlarm.Properties["AlarmName"].Value <string>(),
                        Contains.Substring("WriteThrottleEventsHigh"));
            Assert.That(writeThrottleAlarm.Properties["AlarmName"].Value <string>(),
                        Contains.Substring("-group-suffix"));
            Assert.That(writeThrottleAlarm.Properties["Threshold"].Value <int>(), Is.EqualTo(defaultThrottleThreshold));
            Assert.That(writeThrottleAlarm.Properties["Period"].Value <int>(), Is.EqualTo(60));
            Assert.That(writeThrottleAlarm.Properties["ComparisonOperator"].Value <string>(),
                        Is.EqualTo("GreaterThanOrEqualToThreshold"));
            Assert.That(writeThrottleAlarm.Properties["Statistic"].Value <string>(), Is.EqualTo("Sum"));
            Assert.That(writeThrottleAlarm.Properties["Namespace"].Value <string>(), Is.EqualTo(AwsNamespace.DynamoDb));
        }
Ejemplo n.º 12
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"));
        }
Ejemplo n.º 13
0
        public async Task AlarmCreatedWithCorrectProperties()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                Dax = new AwsServiceAlarms <ResourceConfig>
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >
                    {
                        new ResourceThresholds <ResourceConfig>
                        {
                            Name   = "first-dax-cluster",
                            Values = new Dictionary <string, AlarmValues>
                            {
                                { "CPUUtilizationHigh", new AlarmValues(10) }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonDAX>().HasClusters(new[]
            {
                new Cluster
                {
                    ClusterName = "first-dax-cluster",
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByCluster = cloudformation
                                  .Stack("Watchman-test")
                                  .AlarmsByDimension("ClusterId");

            Assert.That(alarmsByCluster.ContainsKey("first-dax-cluster"), Is.True);
            var alarms = alarmsByCluster["first-dax-cluster"];

            Assert.That(alarms.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "CPUUtilization" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("CPUUtilizationHigh") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 10 &&
                            alarm.Properties["Period"].Value <int>() == 60 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Maximum" &&
                            alarm.Properties["Namespace"].Value <string>() == "AWS/DAX" &&
                            alarm.Properties["TreatMissingData"].Value <string>() == "missing"
                            )
                        );
        }
Ejemplo n.º 14
0
        public async Task AlarmCreatedWithCorrectDefaults()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices
            {
                Lambda = new AwsServiceAlarms <ResourceConfig>
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >()
                    {
                        new ResourceThresholds <ResourceConfig>()
                        {
                            Pattern = "lambda-test"
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonLambda>().HasLambdaFunctions(new[]
            {
                new FunctionConfiguration  {
                    FunctionName = "lambda-test", Timeout = 10
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var stack = cloudformation
                        .Stack("Watchman-test");

            var alarmsByFunction = stack
                                   .AlarmsByDimension("FunctionName");

            Assert.That(alarmsByFunction.ContainsKey("lambda-test"), Is.True);
            var alarmsForLambda = alarmsByFunction["lambda-test"];

            Assert.That(alarmsForLambda.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "Errors" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("ErrorsHigh") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 3 &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["EvaluationPeriods"].Value <int>() == 1 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Sum" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.Lambda &&
                            alarm.Properties["TreatMissingData"].Value <string>() == TreatMissingDataConstants.NotBreaching
                            )
                        );

            Assert.That(alarmsForLambda.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "Duration" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("DurationHigh") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 10 * 1000 * 50 / 100 &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["EvaluationPeriods"].Value <int>() == 1 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Average" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.Lambda &&
                            alarm.Properties["TreatMissingData"].Value <string>() == TreatMissingDataConstants.Missing
                            )
                        );
        }
Ejemplo n.º 15
0
        public async Task IgnoresTablesThatOnlyExistInListings()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix",
                                                               new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Pattern = "^.*$"
                        }
                    }
                }
            });

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

            var dynamo = ioc.GetMock <IAmazonDynamoDB>();

            dynamo
            .Setup(x => x.ListTablesAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new ListTablesResponse()
            {
                TableNames = new List <string>()
                {
                    "non-existent", "existent"
                }
            });

            dynamo
            .Setup(x => x.DescribeTableAsync("non-existent", It.IsAny <CancellationToken>()))
            .ThrowsAsync(new ResourceNotFoundException("bad"))

            // so we know this actually got hit and the error was thrown
            .Verifiable();

            dynamo
            .Setup(x => x.DescribeTableAsync("existent", It.IsAny <CancellationToken>()))
            .ReturnsAsync(new DescribeTableResponse()
            {
                Table = new TableDescription()
                {
                    TableName = "existent",
                    GlobalSecondaryIndexes = new List <GlobalSecondaryIndexDescription>(),
                    ProvisionedThroughput  = new ProvisionedThroughputDescription()
                }
            });


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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            dynamo.Verify();
            Assert.That(cloudformation.StacksDeployed, Is.EqualTo(1));

            var alarms = cloudformation
                         .Stack("Watchman-test")
                         .AlarmsByDimension("TableName");

            Assert.That(alarms.Keys.ToArray(), Is.EquivalentTo(new[] { "existent" }));
        }
Ejemplo n.º 16
0
        public async Task OptionsConfigInParentPatternAppliedWhenNoChild()
        {
            var consumedReadCapacityUnitsHigh = 900;

            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources =
                        new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Pattern = "first-table",
                            Values  = new Dictionary <string, AlarmValues>()
                            {
                                { "ConsumedReadCapacityUnitsHigh", consumedReadCapacityUnitsHigh }
                            }
                        }
                    },
                    Options = new DynamoResourceConfig()
                    {
                        ThresholdIsAbsolute = true,
                        MonitorWrites       = false
                    }
                }
            });

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

            ioc.GetMock <IAmazonDynamoDB>().HasDynamoTables(new[]
            {
                new TableDescription()
                {
                    TableName             = "production-first-table",
                    ProvisionedThroughput = new ProvisionedThroughputDescription()
                    {
                        ReadCapacityUnits  = 1000,
                        WriteCapacityUnits = 2000
                    }
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByTable = cloudFormation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("TableName");
            var tableAlarms = alarmsByTable["production-first-table"];

            var consumedReadForTable = tableAlarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-ConsumedReadCapacityUnitsHigh"));

            Assert.That(consumedReadForTable.Properties["Threshold"].Value <int>(),
                        Is.EqualTo(consumedReadCapacityUnitsHigh));

            var consumedWriteForTable = tableAlarms.SingleOrDefault(
                a => a.Properties["AlarmName"].ToString()
                .Contains("first-table-ConsumedWriteCapacityUnitsHigh"));

            Assert.That(consumedWriteForTable, Is.Null);
        }
Ejemplo n.º 17
0
        public async Task DoesDeployEmptyStackIfAlreadyPresentButResourcesNoLongerExist()
        {
            // first create a stack which has a resource

            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix",
                                                               new AlertingGroupServices()
            {
                AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >()
                    {
                        new ResourceThresholds <AutoScalingResourceConfig>()
                        {
                            Name = "group-1"
                        }
                    }
                }
            });

            var cloudformation = new FakeCloudFormation();

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

            firstTestContext.GetMock <IAmazonAutoScaling>().HasAutoScalingGroups(new[]
            {
                new AutoScalingGroup()
                {
                    AutoScalingGroupName = "group-1",
                    DesiredCapacity      = 40
                }
            });

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

            // check it got deployed

            var stack = cloudformation
                        .Stack("Watchman-test");

            Assert.That(stack, Is.Not.Null);
            Assert.That(stack.Resources
                        .Values
                        .Where(r => r.Type == "AWS::CloudWatch::Alarm")
                        .Count, Is.GreaterThan(0));

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

            // no matching resource so the next run results in an empty stack

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

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

            stack = cloudformation
                    .Stack("Watchman-test");

            //check we deployed an empty stack and deleted the redundant resources
            Assert.That(stack, Is.Not.Null);
            Assert.That(stack.Resources.Any(x => x.Value.Type == "AWS::CloudWatch::Alarm"), Is.False);
        }
Ejemplo n.º 18
0
        public async Task AlarmWithManuallySetThresholdRetainsThatValueForTheRelevantAlarm()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                Sqs = new AwsServiceAlarms <SqsResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <SqsResourceConfig> >()
                    {
                        new ResourceThresholds <SqsResourceConfig>()
                        {
                            Pattern = "first-sqs-queue",
                            Values  = new Dictionary <string, AlarmValues>()
                            {
                                { "NumberOfVisibleMessages_Error", new AlarmValues(value: 1) }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonCloudWatch>().HasSqsQueues(new[]
            {
                "first-sqs-queue",
                "first-sqs-queue_error"
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByQueue = cloudformation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("QueueName");

            Assert.That(alarmsByQueue.ContainsKey("first-sqs-queue"), Is.True);
            var alarmsForQueue = alarmsByQueue["first-sqs-queue"];

            Assert.That(alarmsForQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateNumberOfMessagesVisible" &&
                            alarm.Properties["Threshold"].Value <int>() == 100
                            )
                        );

            Assert.That(alarmsForQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateAgeOfOldestMessage" &&
                            alarm.Properties["Threshold"].Value <int>() == 600
                            )
                        );

            var alarmsForErrorQueue = alarmsByQueue["first-sqs-queue_error"];

            Assert.That(alarmsForErrorQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateNumberOfMessagesVisible" &&
                            alarm.Properties["Threshold"].Value <int>() == 1
                            )
                        );

            Assert.That(alarmsForErrorQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateAgeOfOldestMessage" &&
                            alarm.Properties["Threshold"].Value <int>() == 600
                            )
                        );
        }
Ejemplo n.º 19
0
        public async Task UsesDesiredInstancesForThresholdIfCloudWatchMetricsDoNotExist()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix",
                                                               new AlertingGroupServices()
            {
                AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >()
                    {
                        new ResourceThresholds <AutoScalingResourceConfig>()
                        {
                            Name    = "group-1",
                            Options = new AutoScalingResourceConfig()
                            {
                                InstanceCountIncreaseDelayMinutes = 10
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonAutoScaling>().HasAutoScalingGroups(new[]
            {
                new AutoScalingGroup()
                {
                    AutoScalingGroupName = "group-1",
                    DesiredCapacity      = 40
                }
            });

            var now = DateTime.UtcNow;

            ioc.GetMock <ICurrentTimeProvider>().Setup(a => a.UtcNow).Returns(now);

            ioc.GetMock <IAmazonCloudWatch>().Setup(x =>
                                                    x.GetMetricStatisticsAsync(It.IsAny <GetMetricStatisticsRequest>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new GetMetricStatisticsResponse()
            {
                Datapoints = new List <Datapoint>()
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarms = cloudformation
                         .Stack("Watchman-test")
                         .AlarmsByDimension("AutoScalingGroupName");

            var alarm = alarms["group-1"].Single(a => a.Properties["AlarmName"].ToString().Contains("InService"));

            var defaultAlarmThreshold = 0.5m;

            Assert.That((decimal)alarm.Properties["Threshold"], Is.EqualTo(40 * defaultAlarmThreshold));
        }
Ejemplo n.º 20
0
        public async Task AlarmCreatedWithCorrectProperties()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration(
                "test",
                "group-suffix",
                new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Name = "first-dynamo-table"
                        }
                    }
                },
                Lambda = new AwsServiceAlarms <ResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >()
                    {
                        new ResourceThresholds <ResourceConfig>()
                        {
                            Name = "first-lambda-function"
                        }
                    }
                }
            }
                );

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

            ioc.GetMock <IAmazonDynamoDB>().HasDynamoTables(new[]
            {
                new TableDescription()
                {
                    TableName             = "first-dynamo-table",
                    ProvisionedThroughput = new ProvisionedThroughputDescription()
                    {
                        ReadCapacityUnits  = 100,
                        WriteCapacityUnits = 200
                    }
                }
            });

            ioc.GetMock <IAmazonLambda>().HasLambdaFunctions(new[]
            {
                new FunctionConfiguration()
                {
                    FunctionName = "first-lambda-function"
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByTable = cloudformation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("TableName");

            Assert.That(alarmsByTable.ContainsKey("first-dynamo-table"), Is.True);

            var alarmsByFunction = cloudformation
                                   .Stack("Watchman-test")
                                   .AlarmsByDimension("FunctionName");

            Assert.That(alarmsByFunction.ContainsKey("first-lambda-function"), Is.True);
        }
Ejemplo n.º 21
0
        public async Task AlarmCreatedWithCorrectOverrides()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices
            {
                Lambda = new AwsServiceAlarms <ResourceConfig>
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >()
                    {
                        new ResourceThresholds <ResourceConfig>()
                        {
                            Pattern = "lambda-test",
                            Values  = new Dictionary <string, AlarmValues>
                            {
                                {
                                    "ErrorsHigh", new AlarmValues
                                    (
                                        evaluationPeriods: 3,
                                        periodMinutes: 10,
                                        value: 100
                                    )
                                }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonLambda>().HasLambdaFunctions(new[]
            {
                new FunctionConfiguration  {
                    FunctionName = "lambda-test", Timeout = 10
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var stack = cloudformation
                        .Stack("Watchman-test");

            var alarmsByFunction = stack
                                   .AlarmsByDimension("FunctionName");

            Assert.That(alarmsByFunction.ContainsKey("lambda-test"), Is.True);
            var alarmsForLambda = alarmsByFunction["lambda-test"];

            Assert.That(alarmsForLambda.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "Errors" &&
                            alarm.Properties["Period"].Value <int>() == 60 * 10 &&
                            alarm.Properties["EvaluationPeriods"].Value <int>() == 3 &&
                            alarm.Properties["Threshold"].Value <int>() == 100)
                        );
        }
Ejemplo n.º 22
0
        public async Task GsiLogicalResourceNameContainsTable()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources =
                        new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Pattern = "first-table",
                            Values  = new Dictionary <string, AlarmValues>()
                            {
                                { "GsiConsumedReadCapacityUnitsHigh", 20 },
                                { "ConsumedReadCapacityUnitsHigh", 10 }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonDynamoDB>().HasDynamoTables(new[]
            {
                new TableDescription()
                {
                    TableName             = "production-first-table",
                    ProvisionedThroughput = new ProvisionedThroughputDescription()
                    {
                        ReadCapacityUnits  = 100,
                        WriteCapacityUnits = 200
                    },
                    GlobalSecondaryIndexes = new List <GlobalSecondaryIndexDescription>()
                    {
                        new GlobalSecondaryIndexDescription()
                        {
                            IndexName             = "first-gsi",
                            ProvisionedThroughput = new ProvisionedThroughputDescription()
                            {
                                ReadCapacityUnits  = 400,
                                WriteCapacityUnits = 500
                            }
                        }
                    }
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var resources = cloudFormation
                            .Stack("Watchman-test")
                            .Resources;

            // TODO: logical name should include table and GSI name
            Assert.That(resources, Contains.Key("productionfirsttableGsiConsumedReadCapacityUnitsHigh"));
        }
Ejemplo n.º 23
0
        public async Task CanDisableWritesAcrossTableAndGsi()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                DynamoDb = new AwsServiceAlarms <DynamoResourceConfig>()
                {
                    Resources =
                        new List <ResourceThresholds <DynamoResourceConfig> >()
                    {
                        new ResourceThresholds <DynamoResourceConfig>()
                        {
                            Name = "first-table"
                        }
                    },
                    Options = new DynamoResourceConfig()
                    {
                        MonitorWrites = false
                    }
                }
            });

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

            ioc.GetMock <IAmazonDynamoDB>().HasDynamoTables(new[]
            {
                new TableDescription()
                {
                    TableName             = "first-table",
                    ProvisionedThroughput = new ProvisionedThroughputDescription()
                    {
                        ReadCapacityUnits  = 100,
                        WriteCapacityUnits = 200
                    },
                    GlobalSecondaryIndexes = new List <GlobalSecondaryIndexDescription>()
                    {
                        new GlobalSecondaryIndexDescription()
                        {
                            IndexName             = "first-gsi",
                            ProvisionedThroughput = new ProvisionedThroughputDescription()
                            {
                                ReadCapacityUnits  = 400,
                                WriteCapacityUnits = 500
                            }
                        }
                    }
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarms = cloudformation
                         .Stack("Watchman-test")
                         .Alarms();

            // check we didn't disable read alarms

            Assert.That(alarms.Count(
                            a => a.Properties["MetricName"].ToString()
                            .Contains("ReadThrottleEvents")), Is.AtLeast(2));

            Assert.That(alarms.Count(
                            a => a.Properties["MetricName"].ToString()
                            .Contains("ConsumedReadCapacityUnits")), Is.AtLeast(2));

            // no write alarms

            Assert.That(alarms.Where(
                            a => a.Properties["MetricName"].ToString()
                            == "ConsumedWriteCapacityUnits"), Is.Empty);

            Assert.That(alarms.Where(
                            a => a.Properties["MetricName"].ToString()
                            == "WriteThrottleEvents"), Is.Empty);
        }
Ejemplo n.º 24
0
        public async Task AlarmCreatedWithCorrectOverrides()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices
            {
                Lambda = new AwsServiceAlarms <ResourceConfig>
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >()
                    {
                        new ResourceThresholds <ResourceConfig>()
                        {
                            Pattern = "rdscluster-test",
                            Values  = new Dictionary <string, AlarmValues>
                            {
                                {
                                    "CPUUtilizationHigh", new AlarmValues
                                    (
                                        evaluationPeriods: 1,
                                        periodMinutes: 5,
                                        value: 70
                                    )
                                }
                            }
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonRDS>().HasRdsClusters(new[]
            {
                new DBCluster {
                    DBClusterIdentifier = "rdscluster-test"
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var stack = cloudformation
                        .Stack("Watchman-test");

            var alarmsByRdscluster = stack
                                     .AlarmsByDimension("DBClusterIdentifier");

            Assert.That(alarmsByRdscluster.ContainsKey("rdscluster-test"), Is.True);
            var alarmsForCluster = alarmsByRdscluster["rdscluster-test"];

            Assert.That(alarmsForCluster.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "CPUUtilization" &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["EvaluationPeriods"].Value <int>() == 1 &&
                            alarm.Properties["Threshold"].Value <int>() == 70)
                        );
        }
Ejemplo n.º 25
0
        public async Task AlarmCreatedWithCorrectDefaults()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices
            {
                RdsCluster = new AwsServiceAlarms <ResourceConfig>
                {
                    Resources = new List <ResourceThresholds <ResourceConfig> >()
                    {
                        new ResourceThresholds <ResourceConfig>()
                        {
                            Pattern = "rdscluster-test"
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonRDS>().HasRdsClusters(new[]
            {
                new DBCluster {
                    DBClusterIdentifier = "rdscluster-test"
                }
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var stack = cloudformation
                        .Stack("Watchman-test");

            var alarmsByRdscluster = stack
                                     .AlarmsByDimension("DBClusterIdentifier");

            Assert.That(alarmsByRdscluster.ContainsKey("rdscluster-test"), Is.True);
            var alarmsForCluster = alarmsByRdscluster["rdscluster-test"];

            Assert.That(alarmsForCluster.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "CPUUtilization" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("CPUUtilizationHigh") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 60 &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["EvaluationPeriods"].Value <int>() == 5 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Maximum" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.Rds &&
                            alarm.Properties["TreatMissingData"].Value <string>() == TreatMissingDataConstants.Missing
                            )
                        );
        }
Ejemplo n.º 26
0
        public async Task UsesDelayedScalingThresholdFromCloudWatch()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix",
                                                               new AlertingGroupServices()
            {
                AutoScaling = new AwsServiceAlarms <AutoScalingResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <AutoScalingResourceConfig> >()
                    {
                        new ResourceThresholds <AutoScalingResourceConfig>()
                        {
                            Name    = "group-delay-20",
                            Options = new AutoScalingResourceConfig()
                            {
                                InstanceCountIncreaseDelayMinutes = 20
                            }
                        },
                        new ResourceThresholds <AutoScalingResourceConfig>()
                        {
                            Name = "group-delay-100"
                        }
                    },

                    Options = new AutoScalingResourceConfig()
                    {
                        InstanceCountIncreaseDelayMinutes = 100
                    }
                }
            });

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

            ioc.GetMock <IAmazonAutoScaling>().HasAutoScalingGroups(new[]
            {
                new AutoScalingGroup()
                {
                    AutoScalingGroupName = "group-delay-20"
                },
                new AutoScalingGroup()
                {
                    AutoScalingGroupName = "group-delay-100"
                }
            });


            var now = DateTime.Parse("2018-01-26");

            ioc.GetMock <ICurrentTimeProvider>()
            .Setup(f => f.UtcNow)
            .Returns(now);

            var cloudWatch = ioc.GetMock <IAmazonCloudWatch>();

            SetupCloudWatchDesiredMetric(cloudWatch, 100 * 60, now, "group-delay-100", 90);
            SetupCloudWatchDesiredMetric(cloudWatch, 20 * 60, now, "group-delay-20", 80);

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarms = cloudformation
                         .Stack("Watchman-test")
                         .AlarmsByDimension("AutoScalingGroupName");

            var alarm100 = alarms["group-delay-100"].Single(a => a.Properties["AlarmName"].ToString().Contains("InService"));
            var alarm20  = alarms["group-delay-20"].Single(a => a.Properties["AlarmName"].ToString().Contains("InService"));

            var defaultAlarmThreshold = 0.5m;

            Assert.That((decimal)alarm100.Properties["Threshold"], Is.EqualTo(90 * defaultAlarmThreshold));
            Assert.That((decimal)alarm20.Properties["Threshold"], Is.EqualTo(80 * defaultAlarmThreshold));
        }
Ejemplo n.º 27
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);
        }
Ejemplo n.º 28
0
        public async Task AlarmCreatedWithCorrectProperties()
        {
            // arrange
            var config = ConfigHelper.CreateBasicConfiguration("test", "group-suffix", new AlertingGroupServices()
            {
                Sqs = new AwsServiceAlarms <SqsResourceConfig>()
                {
                    Resources = new List <ResourceThresholds <SqsResourceConfig> >()
                    {
                        new ResourceThresholds <SqsResourceConfig>()
                        {
                            Pattern = "first-sqs-queue"
                        }
                    }
                }
            });

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

            ioc.GetMock <IAmazonCloudWatch>().HasSqsQueues(new[]
            {
                "first-sqs-queue",
                "first-sqs-queue_error"
            });

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

            // act

            await sut.LoadAndGenerateAlarms(RunMode.GenerateAlarms);

            // assert

            var alarmsByQueue = cloudformation
                                .Stack("Watchman-test")
                                .AlarmsByDimension("QueueName");

            Assert.That(alarmsByQueue.ContainsKey("first-sqs-queue"), Is.True);
            var alarmsForQueue = alarmsByQueue["first-sqs-queue"];

            Assert.That(alarmsForQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateNumberOfMessagesVisible" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("NumberOfVisibleMessages") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 100 &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Average" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.Sqs &&
                            alarm.Properties["TreatMissingData"].Value <string>() == TreatMissingDataConstants.Missing
                            )
                        );

            Assert.That(alarmsForQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateAgeOfOldestMessage" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("AgeOfOldestMessage") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 600 &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Maximum" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.Sqs &&
                            alarm.Properties["TreatMissingData"].Value <string>() == TreatMissingDataConstants.Missing
                            )
                        );

            var alarmsForErrorQueue = alarmsByQueue["first-sqs-queue_error"];

            Assert.That(alarmsForErrorQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateNumberOfMessagesVisible" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("NumberOfVisibleMessages_Error") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 10 &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Average" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.Sqs &&
                            alarm.Properties["TreatMissingData"].Value <string>() == TreatMissingDataConstants.Missing
                            )
                        );

            Assert.That(alarmsForErrorQueue.Exists(
                            alarm =>
                            alarm.Properties["MetricName"].Value <string>() == "ApproximateAgeOfOldestMessage" &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("AgeOfOldestMessage_Error") &&
                            alarm.Properties["AlarmName"].Value <string>().Contains("-group-suffix") &&
                            alarm.Properties["Threshold"].Value <int>() == 600 &&
                            alarm.Properties["Period"].Value <int>() == 60 * 5 &&
                            alarm.Properties["ComparisonOperator"].Value <string>() == "GreaterThanOrEqualToThreshold" &&
                            alarm.Properties["Statistic"].Value <string>() == "Maximum" &&
                            alarm.Properties["Namespace"].Value <string>() == AwsNamespace.Sqs &&
                            alarm.Properties["TreatMissingData"].Value <string>() == TreatMissingDataConstants.Missing
                            )
                        );
        }