Esempio n. 1
0
        private async Task <PrepareResult> PrepareResourceAsync(
            string label, Resource res, bool custom, bool remote,
            ResourceArgs args, ResourceOptions options)
        {
            // Before we can proceed, all our dependencies must be finished.
            var type = res.GetResourceType();
            var name = res.GetResourceName();

            LogExcessive($"Gathering explicit dependencies: t={type}, name={name}, custom={custom}, remote={remote}");
            var explicitDirectDependencies = new HashSet <Resource>(
                await GatherExplicitDependenciesAsync(options.DependsOn).ConfigureAwait(false));

            LogExcessive($"Gathered explicit dependencies: t={type}, name={name}, custom={custom}, remote={remote}");

            // Serialize out all our props to their final values.  In doing so, we'll also collect all
            // the Resources pointed to by any Dependency objects we encounter, adding them to 'propertyDependencies'.
            LogExcessive($"Serializing properties: t={type}, name={name}, custom={custom}, remote={remote}");
            var dictionary = await args.ToDictionaryAsync().ConfigureAwait(false);

            var(serializedProps, propertyToDirectDependencies) =
                await SerializeResourcePropertiesAsync(
                    label,
                    dictionary,
                    await this.MonitorSupportsResourceReferences().ConfigureAwait(false),
                    keepOutputValues : remote && await MonitorSupportsOutputValues().ConfigureAwait(false)).ConfigureAwait(false);

            LogExcessive($"Serialized properties: t={type}, name={name}, custom={custom}, remote={remote}");

            // Wait for the parent to complete.
            // If no parent was provided, parent to the root resource.
            LogExcessive($"Getting parent urn: t={type}, name={name}, custom={custom}, remote={remote}");
            var parentUrn = options.Parent != null
                ? await options.Parent.Urn.GetValueAsync(whenUnknown : default !).ConfigureAwait(false)
Esempio n. 2
0
        private async Task <(string urn, string id, Struct data, ImmutableDictionary <string, ImmutableHashSet <Resource> > dependencies)> RegisterResourceAsync(
            Resource resource, bool remote, Func <string, Resource> newDependency, ResourceArgs args,
            ResourceOptions options)
        {
            var name   = resource.GetResourceName();
            var type   = resource.GetResourceType();
            var custom = resource is CustomResource;

            var label = $"resource:{name}[{type}]";

            Log.Debug($"Registering resource start: t={type}, name={name}, custom={custom}, remote={remote}");

            var request = CreateRegisterResourceRequest(type, name, custom, remote, options);

            Log.Debug($"Preparing resource: t={type}, name={name}, custom={custom}, remote={remote}");
            var prepareResult = await PrepareResourceAsync(label, resource, custom, remote, args, options).ConfigureAwait(false);

            Log.Debug($"Prepared resource: t={type}, name={name}, custom={custom}, remote={remote}");

            PopulateRequest(request, prepareResult);

            Log.Debug($"Registering resource monitor start: t={type}, name={name}, custom={custom}, remote={remote}");
            var result = await this.Monitor.RegisterResourceAsync(resource, request);

            Log.Debug($"Registering resource monitor end: t={type}, name={name}, custom={custom}, remote={remote}");

            var dependencies = ImmutableDictionary.CreateBuilder <string, ImmutableHashSet <Resource> >();

            foreach (var(key, propertyDependencies) in result.PropertyDependencies)
            {
                var urns = ImmutableHashSet.CreateBuilder <Resource>();
                foreach (var urn in propertyDependencies.Urns)
                {
                    urns.Add(newDependency(urn));
                }
                dependencies[key] = urns.ToImmutable();
            }

            return(result.Urn, result.Id, result.Object, dependencies.ToImmutable());
        }
Esempio n. 3
0
        private async Task <PrepareResult> PrepareResourceAsync(
            string label, Resource res, bool custom, bool remote,
            ResourceArgs args, ResourceOptions options)
        {
            /* IMPORTANT!  We should never await prior to this line, otherwise the Resource will be partly uninitialized. */

            // Before we can proceed, all our dependencies must be finished.
            var type = res.GetResourceType();
            var name = res.GetResourceName();

            LogExcessive($"Gathering explicit dependencies: t={type}, name={name}, custom={custom}, remote={remote}");
            var explicitDirectDependencies = new HashSet <Resource>(
                await GatherExplicitDependenciesAsync(options.DependsOn).ConfigureAwait(false));

            LogExcessive($"Gathered explicit dependencies: t={type}, name={name}, custom={custom}, remote={remote}");

            // Serialize out all our props to their final values.  In doing so, we'll also collect all
            // the Resources pointed to by any Dependency objects we encounter, adding them to 'propertyDependencies'.
            LogExcessive($"Serializing properties: t={type}, name={name}, custom={custom}, remote={remote}");
            var dictionary = await args.ToDictionaryAsync().ConfigureAwait(false);

            var(serializedProps, propertyToDirectDependencies) =
                await SerializeResourcePropertiesAsync(
                    label,
                    dictionary,
                    await this.MonitorSupportsResourceReferences().ConfigureAwait(false)).ConfigureAwait(false);

            LogExcessive($"Serialized properties: t={type}, name={name}, custom={custom}, remote={remote}");

            // Wait for the parent to complete.
            // If no parent was provided, parent to the root resource.
            LogExcessive($"Getting parent urn: t={type}, name={name}, custom={custom}, remote={remote}");
            var parentUrn = options.Parent != null
                ? await options.Parent.Urn.GetValueAsync().ConfigureAwait(false)
                : await GetRootResourceAsync(type).ConfigureAwait(false);

            LogExcessive($"Got parent urn: t={type}, name={name}, custom={custom}, remote={remote}");

            string?providerRef = null;

            if (custom)
            {
                var customOpts = options as CustomResourceOptions;
                providerRef = await ProviderResource.RegisterAsync(customOpts?.Provider).ConfigureAwait(false);
            }

            var providerRefs = new Dictionary <string, string>();

            if (remote && options is ComponentResourceOptions componentOpts)
            {
                // If only the Provider opt is set, move it to the Providers list for further processing.
                if (componentOpts.Provider != null && componentOpts.Providers.Count == 0)
                {
                    componentOpts.Providers.Add(componentOpts.Provider);
                    componentOpts.Provider = null;
                }

                foreach (var provider in componentOpts.Providers)
                {
                    var pref = await ProviderResource.RegisterAsync(provider).ConfigureAwait(false);

                    if (pref != null)
                    {
                        providerRefs.Add(provider.Package, pref);
                    }
                }
            }

            // Collect the URNs for explicit/implicit dependencies for the engine so that it can understand
            // the dependency graph and optimize operations accordingly.

            // The list of all dependencies (implicit or explicit).
            var allDirectDependencies = new HashSet <Resource>(explicitDirectDependencies);

            var allDirectDependencyUrns = await GetAllTransitivelyReferencedResourceUrnsAsync(explicitDirectDependencies).ConfigureAwait(false);

            var propertyToDirectDependencyUrns = new Dictionary <string, HashSet <string> >();

            foreach (var(propertyName, directDependencies) in propertyToDirectDependencies)
            {
                allDirectDependencies.AddRange(directDependencies);

                var urns = await GetAllTransitivelyReferencedResourceUrnsAsync(directDependencies).ConfigureAwait(false);

                allDirectDependencyUrns.AddRange(urns);
                propertyToDirectDependencyUrns[propertyName] = urns;
            }

            // Wait for all aliases. Note that we use 'res._aliases' instead of 'options.aliases' as
            // the former has been processed in the Resource constructor prior to calling
            // 'registerResource' - both adding new inherited aliases and simplifying aliases down
            // to URNs.
            var aliases       = new List <string>();
            var uniqueAliases = new HashSet <string>();

            foreach (var alias in res._aliases)
            {
                var aliasVal = await alias.ToOutput().GetValueAsync().ConfigureAwait(false);

                if (uniqueAliases.Add(aliasVal))
                {
                    aliases.Add(aliasVal);
                }
            }

            return(new PrepareResult(
                       serializedProps,
                       parentUrn ?? "",
                       providerRef ?? "",
                       providerRefs,
                       allDirectDependencyUrns,
                       propertyToDirectDependencyUrns,
                       aliases));

            void LogExcessive(string message)
            {
                if (_excessiveDebugOutput)
                {
                    Log.Debug(message);
                }
            }
        }
        void IDeploymentInternal.ReadOrRegisterResource(
            Resource resource, bool remote, Func <string, Resource> newDependency, ResourceArgs args,
            ResourceOptions options)
        {
            // ReadOrRegisterResource is called in a fire-and-forget manner.  Make sure we keep
            // track of this task so that the application will not quit until this async work
            // completes.
            //
            // Also, we can only do our work once the constructor for the resource has actually
            // finished.  Otherwise, we might actually read and get the result back *prior* to the
            // object finishing initializing.  Note: this is not a speculative concern. This is
            // something that does happen and has to be accounted for.
            //
            // IMPORTANT! We have to make sure we run 'OutputCompletionSource.InitializeOutputs'
            // synchronously directly when `resource`'s constructor runs since this will set all of
            // the `[Output(...)] Output<T>` properties.  We need those properties assigned by the
            // time the base 'Resource' constructor finishes so that both derived classes and
            // external consumers can use the Output properties of `resource`.
            var completionSources = OutputCompletionSource.InitializeOutputs(resource);

            _runner.RegisterTask(
                $"{nameof(IDeploymentInternal.ReadOrRegisterResource)}: {resource.GetResourceType()}-{resource.GetResourceName()}",
                CompleteResourceAsync(resource, remote, newDependency, args, options, completionSources));
        }
 void IDeploymentInternal.RegisterResourceOutputs(Resource resource, Output <IDictionary <string, object?> > outputs)
 {
     // RegisterResourceOutputs is called in a fire-and-forget manner.  Make sure we keep track of
     // this task so that the application will not quit until this async work completes.
     _runner.RegisterTask(
         $"{nameof(IDeploymentInternal.RegisterResourceOutputs)}: {resource.GetResourceType()}-{resource.GetResourceName()}",
         RegisterResourceOutputsAsync(resource, outputs));
 }
 void IDeploymentInternal.ReadOrRegisterResource(
     Resource resource, bool remote, Func<string, Resource> newDependency, ResourceArgs args,
     ResourceOptions options)
 {
     // ReadOrRegisterResource is called in a fire-and-forget manner.  Make sure we keep
     // track of this task so that the application will not quit until this async work
     // completes.
     //
     // Also, we can only do our work once the constructor for the resource has actually
     // finished.  Otherwise, we might actually read and get the result back *prior* to the
     // object finishing initializing.  Note: this is not a speculative concern. This is
     // something that does happen and has to be accounted for.
     _runner.RegisterTask(
         $"{nameof(IDeploymentInternal.ReadOrRegisterResource)}: {resource.GetResourceType()}-{resource.GetResourceName()}",
         CompleteResourceAsync(resource, remote, newDependency, args, options, resource.CompletionSources));
 }