private Task AwaitReady(ComputeEngine engine, InstanceLocator instanceRef)
        {
            return(Task.Run(async() =>
            {
                for (int i = 0; i < 60; i++)
                {
                    try
                    {
                        var instance = await engine.Service.Instances.Get(
                            instanceRef.ProjectId, instanceRef.Zone, instanceRef.Name)
                                       .ExecuteAsync();

                        if (await IsReadyAsync(engine, instanceRef, instance))
                        {
                            return;
                        }
                    }
                    catch (Exception)
                    { }

                    await Task.Delay(5 * 1000);
                }

                throw new TimeoutException($"Timeout waiting for {instanceRef} to become ready");
            }));
        }
        protected virtual async Task <bool> IsReadyAsync(
            ComputeEngine engine,
            InstanceLocator instanceRef,
            Instance instance)
        {
            var request = engine.Service.Instances.GetGuestAttributes(
                instanceRef.ProjectId,
                instanceRef.Zone,
                instanceRef.Name);

            request.QueryPath = GuestAttributeNamespace + "/";
            var guestAttributes = await request.ExecuteAsync();

            return(guestAttributes
                   .QueryValue
                   .Items
                   .Where(i => i.Namespace__ == GuestAttributeNamespace && i.Key == GuestAttributeKey)
                   .Any());
        }
        private async Task <InstanceLocator> GetInstanceAsync(InstanceLocator vmRef)
        {
            var computeEngine = ComputeEngine.Connect();

            try
            {
                var instance = await computeEngine.Service.Instances
                               .Get(vmRef.ProjectId, vmRef.Zone, vmRef.Name)
                               .ExecuteAsync();

                if (instance.Status == "STOPPED")
                {
                    await computeEngine.Service.Instances.Start(
                        vmRef.ProjectId, vmRef.Zone, vmRef.Name)
                    .ExecuteAsync();
                }

                await AwaitReady(computeEngine, vmRef);
            }
            catch (Exception)
            {
                var metadata = new List <Metadata.ItemsData>(this.Metadata.ToList());

                // Add metdata that marks this instance as temporary.
                metadata.Add(new Metadata.ItemsData()
                {
                    Key   = "type",
                    Value = "auto-cleanup"
                });
                metadata.Add(new Metadata.ItemsData()
                {
                    Key   = "ttl",
                    Value = "120" // minutes
                });

                await computeEngine.Service.Instances.Insert(
                    new Apis.Compute.v1.Data.Instance()
                {
                    Name        = vmRef.Name,
                    MachineType = $"zones/{this.Zone}/machineTypes/{this.MachineType}",
                    Disks       = new[]
                    {
                        new AttachedDisk()
                        {
                            AutoDelete       = true,
                            Boot             = true,
                            InitializeParams = new AttachedDiskInitializeParams()
                            {
                                SourceImage = this.ImageFamily
                            }
                        }
                    },
                    Metadata = new Metadata()
                    {
                        Items = metadata
                    },
                    NetworkInterfaces = new[]
                    {
                        new NetworkInterface()
                        {
                            AccessConfigs = new []
                            {
                                new AccessConfig()
                            }
                        }
                    }
                },
                    vmRef.ProjectId,
                    vmRef.Zone).ExecuteAsync();

                await AwaitReady(computeEngine, vmRef);
            }

            return(vmRef);
        }