private static async Task AwaitInstanceCreatedAndReady(
            InstancesResource resource,
            InstanceLocator locator)
        {
            for (int i = 0; i < 60; i++)
            {
                try
                {
                    var instance = await resource.Get(
                        locator.ProjectId,
                        locator.Zone,
                        locator.Name)
                                   .ExecuteAsync();

                    // Determine the name of the guest attribute we need to await.
                    var guestAttributeToAwait = instance.Metadata.Items
                                                .EnsureNotNull()
                                                .FirstOrDefault(item => item.Key == GuestAttributeToAwaitKey)
                                                .Value;

                    var request = resource.GetGuestAttributes(
                        locator.ProjectId,
                        locator.Zone,
                        locator.Name);
                    request.QueryPath = GuestAttributeNamespace + "/";
                    var guestAttributes = await request.ExecuteAsync();

                    if (guestAttributes
                        .QueryValue
                        .Items
                        .Where(item => item.Namespace__ == GuestAttributeNamespace &&
                               item.Key == guestAttributeToAwait)
                        .Any())
                    {
                        return;
                    }
                }
                catch (Exception)
                { }

                TraceSources.Common.TraceVerbose(
                    "Waiting for instance {0} to become ready...", locator.Name);

                await Task.Delay(5 * 1000);
            }

            throw new TimeoutException($"Timeout waiting for {locator} to become ready");
        }
Esempio n. 2
0
        /// <summary>
        /// Query a metadata entry for an instance.
        /// </summary>
        /// <returns>null if not set/found</returns>
        public static async Task <Metadata.ItemsData> QueryMetadataKeyAsync(
            this InstancesResource resource,
            InstanceLocator instanceRef,
            string key)
        {
            var instance = await resource.Get(
                instanceRef.ProjectId,
                instanceRef.Zone,
                instanceRef.Name).ExecuteAsync().ConfigureAwait(false);

            if (instance.Metadata == null || instance.Metadata.Items == null)
            {
                return(null);
            }

            return(instance.Metadata.Items
                   .Where(i => i.Key == key)
                   .FirstOrDefault());
        }
        //---------------------------------------------------------------------
        // Instance metadata.
        //---------------------------------------------------------------------

        /// <summary>
        /// Modify instance metadata.
        /// </summary>
        public static async Task UpdateMetadataAsync(
            this InstancesResource resource,
            InstanceLocator instanceRef,
            Action <Metadata> updateMetadata,
            CancellationToken token,
            uint maxAttempts = DefaultAttempts)
        {
            using (CommonTraceSources.Default.TraceMethod().WithParameters(instanceRef))
            {
                await UpdateMetadataAsync(
                    async() =>
                {
                    var instance = await resource.Get(
                        instanceRef.ProjectId,
                        instanceRef.Zone,
                        instanceRef.Name)
                                   .ExecuteAsync(token)
                                   .ConfigureAwait(false);

                    return(instance.Metadata);
                },
                    async metadata =>
                {
                    await resource.SetMetadata(
                        metadata,
                        instanceRef.ProjectId,
                        instanceRef.Zone,
                        instanceRef.Name)
                    .ExecuteAndAwaitOperationAsync(
                        instanceRef.ProjectId,
                        token)
                    .ConfigureAwait(false);
                },
                    updateMetadata,
                    maxAttempts)
                .ConfigureAwait(false);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Adds or overwrites a metadata key/value pair to a GCE
        /// instance. Any existing metadata is kept as is.
        /// </summary>
        public static async Task AddMetadataAsync(
            this InstancesResource resource,
            InstanceLocator instanceRef,
            string key,
            string value,
            CancellationToken token)
        {
            using (TraceSources.Common.TraceMethod().WithParameters(instanceRef, key))
            {
                for (int attempt = 0; attempt < 6; attempt++)
                {
                    var instance = await resource.Get(
                        instanceRef.ProjectId,
                        instanceRef.Zone,
                        instanceRef.Name).ExecuteAsync(token).ConfigureAwait(false);

                    var metadata = instance.Metadata;

                    if (metadata.Items == null)
                    {
                        metadata.Items = new List <Metadata.ItemsData>();
                    }

                    var existingEntry = metadata.Items
                                        .Where(i => i.Key == key)
                                        .FirstOrDefault();
                    if (existingEntry != null)
                    {
                        existingEntry.Value = value;
                    }
                    else
                    {
                        metadata.Items.Add(new Metadata.ItemsData()
                        {
                            Key   = key,
                            Value = value
                        });
                    }

                    TraceSources.Common.TraceVerbose("Setting metdata {0} on {1}...", key, instanceRef.Name);

                    try
                    {
                        await resource.SetMetadata(
                            metadata,
                            instanceRef.ProjectId,
                            instanceRef.Zone,
                            instanceRef.Name).ExecuteAndAwaitOperationAsync(instanceRef.ProjectId, token).ConfigureAwait(false);

                        break;
                    }
                    catch (GoogleApiException e)
                    {
                        if (e.Error != null && e.Error.Code == 412)
                        {
                            // Fingerprint mismatch - that happens when somebody else updated metadata
                            // in patallel.

                            int backoff = 100;
                            TraceSources.Common.TraceWarning(
                                "SetMetadata failed with {0} - retrying after {1}ms", e.Message,
                                e.Error?.Code,
                                backoff);

                            await Task.Delay(backoff).ConfigureAwait(false);
                        }
                        else
                        {
                            TraceSources.Common.TraceWarning(
                                "Setting metdata failed {0} (code error {1})", e.Message,
                                e.Error?.Code);

                            throw;
                        }
                    }
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Adds or overwrites a metadata key/value pair to a GCE
        /// instance. Any existing metadata is kept as is.
        /// </summary>
        public static async Task AddMetadataAsync(
            this InstancesResource resource,
            InstanceLocator instanceRef,
            Metadata metadata,
            CancellationToken token)
        {
            using (TraceSources.Common.TraceMethod().WithParameters(instanceRef))
            {
                for (int attempt = 0; attempt < 6; attempt++)
                {
                    TraceSources.Common.TraceVerbose("Adding metadata {0} on {1}...", metadata, instanceRef.Name);

                    //
                    // NB. Metadata must be updated all-at-once. Therefore,
                    // fetch the existing entries first before merging them
                    // with the new entries.
                    //

                    var instance = await resource.Get(
                        instanceRef.ProjectId,
                        instanceRef.Zone,
                        instanceRef.Name).ExecuteAsync(token).ConfigureAwait(false);

                    var mergedMetadata = instance.Metadata;
                    mergedMetadata.Add(metadata);

                    try
                    {
                        await resource.SetMetadata(
                            mergedMetadata,
                            instanceRef.ProjectId,
                            instanceRef.Zone,
                            instanceRef.Name).ExecuteAndAwaitOperationAsync(instanceRef.ProjectId, token).ConfigureAwait(false);

                        break;
                    }
                    catch (GoogleApiException e)
                    {
                        if (e.Error != null && e.Error.Code == 412)
                        {
                            // Fingerprint mismatch - that happens when somebody else updated metadata
                            // in patallel.

                            int backoff = 100;
                            TraceSources.Common.TraceWarning(
                                "SetMetadata failed with {0} - retrying after {1}ms", e.Message,
                                e.Error?.Code,
                                backoff);

                            await Task.Delay(backoff).ConfigureAwait(false);
                        }
                        else
                        {
                            TraceSources.Common.TraceWarning(
                                "Setting metdata failed {0} (code error {1})", e.Message,
                                e.Error?.Code);

                            throw;
                        }
                    }
                }
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Adds or overwrites a metadata key/value pair to a GCE
        /// instance. Any existing metadata is kept as is.
        /// </summary>
        public static async Task AddMetadataAsync(
            this InstancesResource resource,
            VmInstanceReference instanceRef,
            string key,
            string value)
        {
            var instance = await resource.Get(
                instanceRef.ProjectId,
                instanceRef.Zone,
                instanceRef.InstanceName).ExecuteAsync().ConfigureAwait(false);

            var metadata = instance.Metadata;

            if (metadata.Items == null)
            {
                metadata.Items = new List <Metadata.ItemsData>();
            }

            var existingEntry = metadata.Items
                                .Where(i => i.Key == key)
                                .FirstOrDefault();

            if (existingEntry != null)
            {
                existingEntry.Value = value;
            }
            else
            {
                metadata.Items.Add(new Metadata.ItemsData()
                {
                    Key   = key,
                    Value = value
                });
            }

            TraceSources.Compute.TraceVerbose("Setting metdata {0} on {1}...", key, instanceRef.InstanceName);

            await resource.SetMetadata(
                metadata,
                instanceRef.ProjectId,
                instanceRef.Zone,
                instanceRef.InstanceName).ExecuteAsync().ConfigureAwait(false);

            // Setting the metadata might fail silently, cf b/140226028 - so check if
            // it worked. Sometimes, the change also takes a few seconds to apply (sic).
            for (int attempt = 0; attempt < 10; attempt++)
            {
                var appliedValue = await resource.QueryMetadataKeyAsync(
                    instanceRef,
                    key).ConfigureAwait(false);

                if (appliedValue != null && appliedValue.Value == value)
                {
                    // Success.
                    return;
                }
                else
                {
                    // Wait and retry.
                    TraceSources.Compute.TraceVerbose("Metdata change not applied yet, trying again...");

                    await Task.Delay(500).ConfigureAwait(false);
                }
            }

            throw new GoogleApiException("Compute", "Setting metdata failed");
        }