public async Task WhenInstanceCreated_ThenListInstanceEventsAsyncCanFeedHistorySetBuilder(
            [LinuxInstance] InstanceRequest testInstance)
        {
            await testInstance.AwaitReady();

            var instanceRef = await testInstance.GetInstanceAsync();

            var instanceBuilder = new InstanceSetHistoryBuilder(
                DateTime.UtcNow.AddDays(-7),
                DateTime.UtcNow);

            var computeAdapter = new ComputeEngineAdapter(Defaults.GetCredential());

            instanceBuilder.AddExistingInstances(
                await computeAdapter.ListInstancesAsync(Defaults.ProjectId, CancellationToken.None),
                await computeAdapter.ListDisksAsync(Defaults.ProjectId, CancellationToken.None),
                Defaults.ProjectId);

            var adapter = new AuditLogAdapter(Defaults.GetCredential());

            await adapter.ListInstanceEventsAsync(
                new[] { Defaults.ProjectId },
                null,  // all zones.
                null,  // all instances.
                instanceBuilder.StartDate,
                instanceBuilder,
                CancellationToken.None);

            var set = instanceBuilder.Build();
            var testInstanceHistory = set.Instances.FirstOrDefault(i => i.Reference == instanceRef);

            Assert.IsNotNull(testInstanceHistory, "Instance found in history");
        }
        public ReportBuilder(
            IAuditLogAdapter auditLogAdapter,
            IAuditLogStorageSinkAdapter auditExportAdapter,
            IComputeEngineAdapter computeEngineAdapter,
            AuditLogSources sources,
            IEnumerable <string> projectIds,
            DateTime startDate)
        {
            var now = DateTime.UtcNow;

            if (startDate >= now)
            {
                throw new ArgumentException("Invalid start date");
            }
            else if ((now - startDate).TotalDays > MaxPeriod)
            {
                throw new ArgumentException("Start date is too far in the past");
            }

            this.sources              = sources;
            this.projectIds           = projectIds;
            this.auditLogAdapter      = auditLogAdapter;
            this.auditExportAdapter   = auditExportAdapter;
            this.computeEngineAdapter = computeEngineAdapter;

            this.builder = new InstanceSetHistoryBuilder(startDate, now);
        }
        public void WhenInstanceNotAddedButStopEventRecorded_ThenInstanceIncludedInSetAsMissingTenancy()
        {
            var b = new InstanceSetHistoryBuilder(
                new DateTime(2019, 12, 1, 0, 0, 0, DateTimeKind.Utc),
                new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            b.Process(new StopInstanceEvent(new LogRecord()
            {
                LogName      = "projects/project-1/logs/cloudaudit.googleapis.com%2Factivity",
                ProtoPayload = new AuditLogRecord()
                {
                    MethodName   = StopInstanceEvent.Method,
                    ResourceName = "projects/project-1/zones/us-central1-a/instances/instance-1"
                },
                Resource = new ResourceRecord()
                {
                    Labels = new Dictionary <string, string>
                    {
                        { "instance_id", "123" }
                    }
                },
                Timestamp = new DateTime(2019, 12, 31)
            }));

            var set = b.Build();

            Assert.AreEqual(1, set.Instances.Count());
            Assert.AreEqual(123, set.Instances.First().InstanceId);
            Assert.AreEqual(InstanceHistoryState.MissingTenancy, set.Instances.First().State);
        }
        private void AddExistingInstance(
            InstanceSetHistoryBuilder builder,
            int count,
            Tenancies tenancy)
        {
            for (int i = 0; i < count; i++)
            {
                instanceIdSequence++;
                builder.AddExistingInstance(
                    instanceIdSequence,
                    new InstanceLocator("project", "zone", $"instance-{instanceIdSequence}"),
                    new ImageLocator("project", $"image-{instanceIdSequence}"),
                    InstanceState.Running,
                    BaselineTime.AddDays(i),
                    tenancy);

                var instanceBuilder = builder.GetInstanceHistoryBuilder(instanceIdSequence);
                if (tenancy == Tenancies.SoleTenant)
                {
                    // Add sole tenant placement.
                    instanceBuilder.OnSetPlacement("server-1", BaselineTime);
                }

                // Add fleet placement.
                instanceBuilder.OnStop(
                    BaselineTime.AddDays(-1),
                    new InstanceLocator("project", "zone", $"instance-{instanceIdSequence}"));
                instanceBuilder.OnStart(
                    BaselineTime.AddDays(-2),
                    new InstanceLocator("project", "zone", $"instance-{instanceIdSequence}"));
            }
        }
        public async Task WhenInstanceCreated_ThenListInstanceEventsAsyncCanFeedHistorySetBuilder(
            [LinuxInstance] InstanceRequest testInstance)
        {
            await testInstance.AwaitReady();

            var instanceRef = await testInstance.GetInstanceAsync();

            var loggingService = new LoggingService(new BaseClientService.Initializer
            {
                HttpClientInitializer = Defaults.GetCredential()
            });

            var computeService = new ComputeService(new BaseClientService.Initializer
            {
                HttpClientInitializer = Defaults.GetCredential()
            });

            var instanceBuilder = new InstanceSetHistoryBuilder(
                DateTime.UtcNow.AddDays(-7),
                DateTime.UtcNow);
            await instanceBuilder.AddExistingInstances(
                computeService.Instances,
                computeService.Disks,
                Defaults.ProjectId);

            await loggingService.Entries.ListInstanceEventsAsync(
                new[] { Defaults.ProjectId },
                instanceBuilder.StartDate,
                instanceBuilder);

            var set = instanceBuilder.Build();
            var testInstanceHistory = set.Instances.FirstOrDefault(i => i.Reference == instanceRef);

            Assert.IsNotNull(testInstanceHistory, "Instance found in history");
        }
        private static InstanceSetHistory BuildHistoryFromResource(string resourceName)
        {
            var testDataResource = Assembly.GetExecutingAssembly()
                                   .GetManifestResourceNames()
                                   .First(n => n.EndsWith(resourceName));

            var b = new InstanceSetHistoryBuilder(
                new DateTime(2019, 12, 1, 0, 0, 0, DateTimeKind.Utc),
                new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(testDataResource))
                using (var reader = new JsonTextReader(new StreamReader(stream)))
                {
                    var events = new JsonSerializer().Deserialize <LogRecord[]>(reader)
                                 .Select(rec => rec.ToEvent())
                                 .OrderByDescending(e => e.Timestamp);

                    foreach (var e in events)
                    {
                        b.Process(e);
                    }
                }

            return(b.Build());
        }
        private void AddExistingInstance(
            InstanceSetHistoryBuilder builder,
            int count,
            DateTime lastSeen,
            Tenancies tenancy)
        {
            for (int i = 0; i < count; i++)
            {
                instanceIdSequence++;

                var locator = new InstanceLocator("project", "zone", $"instance-{instanceIdSequence}");
                builder.AddExistingInstance(
                    instanceIdSequence,
                    locator,
                    new ImageLocator("project", $"image-{instanceIdSequence}"),
                    InstanceState.Running,
                    lastSeen,
                    tenancy,
                    tenancy == Tenancies.SoleTenant
                        ? "server-1"
                        : null,
                    null);
                builder.GetInstanceHistoryBuilder(instanceIdSequence)
                .OnStart(BaselineTime.AddDays(i), locator);
            }
        }
        private void AddExistingInstance(
            InstanceSetHistoryBuilder builder,
            int count,
            DateTime lastSeen,
            Tenancies tenancy)
        {
            for (int i = 0; i < count; i++)
            {
                instanceIdSequence++;

                var locator = new InstanceLocator("project", "zone", $"instance-{instanceIdSequence}");
                builder.AddExistingInstance(
                    instanceIdSequence,
                    locator,
                    new ImageLocator("project", $"image-{instanceIdSequence}"),
                    InstanceState.Running,
                    lastSeen,
                    tenancy,
                    tenancy == Tenancies.SoleTenant
                        ? "server-1"
                        : null,
                    null);

                var instanceBuilder = builder.GetInstanceHistoryBuilder(instanceIdSequence);
                if (tenancy == Tenancies.SoleTenant)
                {
                    // Add sole tenant placement.
                    instanceBuilder.OnSetPlacement("server-1", null, lastSeen.AddHours(-1));
                }

                // Add fleet placement.
                instanceBuilder.OnStart(BaselineTime.AddDays(i), locator);
            }
        }
        private static ReportArchive CreateReportArchive()
        {
            var builder = new InstanceSetHistoryBuilder(
                BaselineTime,
                BaselineTime.AddDays(7));

            return(new ReportArchive(builder.Build()));
        }
        public void SupportedMethodsIncludeSystemAndLifecycleEvents()
        {
            var b = new InstanceSetHistoryBuilder(DateTime.UtcNow.AddDays(-1), DateTime.UtcNow);

            CollectionAssert.Contains(b.SupportedMethods, NotifyInstanceLocationEvent.Method);
            CollectionAssert.Contains(b.SupportedMethods, HostErrorEvent.Method);

            CollectionAssert.Contains(b.SupportedMethods, InsertInstanceEvent.Method);
            CollectionAssert.Contains(b.SupportedMethods, DeleteInstanceEvent.Method);
        }
        public async Task WhenInstanceCreated_ThenListLogEntriesReturnsInsertEvent(
            [LinuxInstance] InstanceRequest testInstance)
        {
            await testInstance.AwaitReady();

            var instanceRef = await testInstance.GetInstanceAsync();

            var loggingService = new LoggingService(new BaseClientService.Initializer
            {
                HttpClientInitializer = Defaults.GetCredential()
            });

            var startDate = DateTime.UtcNow.AddDays(-30);
            var endDate   = DateTime.UtcNow;

            var request = new ListLogEntriesRequest()
            {
                ResourceNames = new[]
                {
                    "projects/" + Defaults.ProjectId
                },
                Filter = $"resource.type=\"gce_instance\" " +
                         $"AND protoPayload.methodName:{InsertInstanceEvent.Method} " +
                         $"AND timestamp > {startDate:yyyy-MM-dd}",
                PageSize = 1000,
                OrderBy  = "timestamp desc"
            };

            var events          = new List <EventBase>();
            var instanceBuilder = new InstanceSetHistoryBuilder(startDate, endDate);

            // Creating the VM might be quicker than the logs become available.
            for (int retry = 0; retry < 4 && !events.Any(); retry++)
            {
                await loggingService.Entries.ListEventsAsync(
                    request,
                    events.Add,
                    new Apis.Util.ExponentialBackOff());

                if (!events.Any())
                {
                    await Task.Delay(20 * 1000);
                }
            }

            var insertEvent = events.OfType <InsertInstanceEvent>()
                              .First(e => e.InstanceReference == instanceRef);

            Assert.IsNotNull(insertEvent);
        }
        private ReportViewModel CreateParentViewModel(
            int fleetInstanceCount,
            int soleTenantInstanceCount)
        {
            this.instanceIdSequence = 0;

            var builder = new InstanceSetHistoryBuilder(
                BaselineTime,
                BaselineTime.AddDays(7));

            AddExistingInstance(builder, fleetInstanceCount, builder.EndDate, Tenancies.Fleet);
            AddExistingInstance(builder, soleTenantInstanceCount, builder.EndDate, Tenancies.SoleTenant);

            return(new ReportViewModel(new ReportArchive(builder.Build())));
        }
        public async Task WhenInstanceCreated_ThenListLogEntriesReturnsInsertEvent(
            [LinuxInstance] InstanceRequest testInstance,
            [Credential(Role = PredefinedRole.LogsViewer)] CredentialRequest credential)
        {
            await testInstance.AwaitReady();

            var instanceRef = await testInstance.GetInstanceAsync();

            var startDate = DateTime.UtcNow.AddDays(-30);
            var endDate   = DateTime.UtcNow;

            var adapter = new AuditLogAdapter(await credential.GetCredentialAsync());
            var request = new ListLogEntriesRequest()
            {
                ResourceNames = new[]
                {
                    "projects/" + TestProject.ProjectId
                },
                Filter = $"resource.type=\"gce_instance\" " +
                         $"AND protoPayload.methodName:{InsertInstanceEvent.Method} " +
                         $"AND timestamp > {startDate:yyyy-MM-dd}",
                PageSize = 1000,
                OrderBy  = "timestamp desc"
            };

            var events          = new List <EventBase>();
            var instanceBuilder = new InstanceSetHistoryBuilder(startDate, endDate);

            // Creating the VM might be quicker than the logs become available.
            for (int retry = 0; retry < 4 && !events.Any(); retry++)
            {
                await adapter.ListEventsAsync(
                    request,
                    events.Add,
                    new Apis.Util.ExponentialBackOff(),
                    CancellationToken.None);

                if (!events.Any())
                {
                    await Task.Delay(20 * 1000);
                }
            }

            var insertEvent = events.OfType <InsertInstanceEvent>()
                              .First(e => e.InstanceReference == instanceRef);

            Assert.IsNotNull(insertEvent);
        }
        public void WhenInstanceNotAddedButInsertEventRecorded_ThenInstanceIncludedInSet()
        {
            var b = new InstanceSetHistoryBuilder(
                new DateTime(2019, 12, 1, 0, 0, 0, DateTimeKind.Utc),
                new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            b.Process(new TerminateOnHostMaintenanceEvent(new LogRecord()
            {
                LogName      = "projects/project-1/logs/cloudaudit.googleapis.com%2Fsystem_event",
                ProtoPayload = new AuditLogRecord()
                {
                    MethodName   = TerminateOnHostMaintenanceEvent.Method,
                    ResourceName = "projects/project-1/zones/us-central1-a/instances/instance-1",
                },
                Resource = new ResourceRecord()
                {
                    Labels = new Dictionary <string, string>
                    {
                        { "instance_id", "123" }
                    }
                },
                Timestamp = new DateTime(2019, 12, 31),
                Severity  = "INFO"
            }));
            b.Process(new InsertInstanceEvent(new LogRecord()
            {
                LogName      = "projects/project-1/logs/cloudaudit.googleapis.com%2Factivity",
                ProtoPayload = new AuditLogRecord()
                {
                    MethodName   = InsertInstanceEvent.Method,
                    ResourceName = "projects/project-1/zones/us-central1-a/instances/instance-1",
                },
                Resource = new ResourceRecord()
                {
                    Labels = new Dictionary <string, string>
                    {
                        { "instance_id", "123" }
                    }
                },
                Timestamp = new DateTime(2019, 12, 31)
            }));

            var set = b.Build();

            Assert.AreEqual(1, set.Instances.Count());
            Assert.AreEqual(123, set.Instances.First().InstanceId);
        }
        private void AddExistingInstance(
            InstanceSetHistoryBuilder builder,
            int count,
            Tenancies tenancy)
        {
            for (int i = 0; i < count; i++)
            {
                instanceIdSequence++;

                builder.AddExistingInstance(
                    instanceIdSequence,
                    new InstanceLocator("project", "zone", $"instance-{instanceIdSequence}"),
                    new ImageLocator("project", $"image-{instanceIdSequence}"),
                    InstanceState.Running,
                    BaselineTime.AddDays(i),
                    tenancy);
            }
        }
        public void WhenInstanceAdded_ThenInstanceIncludedInSet()
        {
            var b = new InstanceSetHistoryBuilder(
                new DateTime(2019, 12, 1, 0, 0, 0, DateTimeKind.Utc),
                new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            b.AddExistingInstance(
                1,
                SampleReference,
                SampleImage,
                InstanceState.Running,
                DateTime.Now,
                Tenancies.Fleet);

            var set = b.Build();

            Assert.AreEqual(1, set.Instances.Count());
            Assert.AreEqual(1, set.Instances.First().InstanceId);
        }
        public async Task WhenUserNotInRole_ThenProcessInstanceEventsAsyncThrowsResourceAccessDeniedException(
            [LinuxInstance] ResourceTask <InstanceLocator> testInstance,
            [Credential(Role = PredefinedRole.ComputeViewer)] ResourceTask <ICredential> credential)
        {
            await testInstance;
            var   instanceRef = await testInstance;

            var instanceBuilder = new InstanceSetHistoryBuilder(
                DateTime.UtcNow.AddDays(-7),
                DateTime.UtcNow);

            var adapter = new AuditLogAdapter(await credential);

            AssertEx.ThrowsAggregateException <ResourceAccessDeniedException>(
                () => adapter.ProcessInstanceEventsAsync(
                    new[] { TestProject.ProjectId },
                    null,  // all zones.
                    null,  // all instances.
                    instanceBuilder.StartDate,
                    instanceBuilder,
                    CancellationToken.None).Wait());
        }
        public void WhenSoleTenantInstanceAdded_ThenInstanceIncludedInSet()
        {
            var b = new InstanceSetHistoryBuilder(
                new DateTime(2019, 12, 1, 0, 0, 0, DateTimeKind.Utc),
                new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            b.AddExistingInstance(
                1,
                SampleReference,
                SampleImage,
                InstanceState.Running,
                DateTime.Now,
                Tenancies.SoleTenant,
                "server-1",
                new NodeTypeLocator("project-1", "zone-1", "type-1"));

            var set = b.Build();

            Assert.AreEqual(1, set.Instances.Count());
            Assert.AreEqual(1, set.Instances.First().InstanceId);
            Assert.AreEqual("server-1", set.Instances.First().Placements.First().ServerId);
            Assert.AreEqual("type-1", set.Instances.First().Placements.First().NodeType.Name);
        }
        public async Task WhenInstanceCreated_ThenProcessInstanceEventsAsyncCanFeedHistorySetBuilder(
            [LinuxInstance] ResourceTask <InstanceLocator> testInstance,
            [Credential(Roles = new[] {
            PredefinedRole.ComputeViewer,
            PredefinedRole.LogsViewer
        })] ResourceTask <ICredential> credential)
        {
            await testInstance;
            var   instanceRef = await testInstance;

            var instanceBuilder = new InstanceSetHistoryBuilder(
                DateTime.UtcNow.AddDays(-7),
                DateTime.UtcNow);

            var computeAdapter = new ComputeEngineAdapter(await credential);

            instanceBuilder.AddExistingInstances(
                await computeAdapter.ListInstancesAsync(TestProject.ProjectId, CancellationToken.None),
                await computeAdapter.ListNodesAsync(TestProject.ProjectId, CancellationToken.None),
                await computeAdapter.ListDisksAsync(TestProject.ProjectId, CancellationToken.None),
                TestProject.ProjectId);

            var adapter = new AuditLogAdapter(await credential);

            await adapter.ProcessInstanceEventsAsync(
                new[] { TestProject.ProjectId },
                null,  // all zones.
                null,  // all instances.
                instanceBuilder.StartDate,
                instanceBuilder,
                CancellationToken.None);

            var set = instanceBuilder.Build();
            var testInstanceHistory = set.Instances.FirstOrDefault(i => i.Reference == instanceRef);

            Assert.IsNotNull(testInstanceHistory, "Instance found in history");
        }