Exemplo n.º 1
0
        private AzFunctionType GetAzFunctionType(ReadOnlyBindingInfo bindingInfo)
        {
            switch (bindingInfo.Type)
            {
            case OrchestrationTrigger:
                return(AzFunctionType.OrchestrationFunction);

            case ActivityTrigger:
                return(AzFunctionType.ActivityFunction);

            default:
                // All other triggers are considered regular functions
                return(AzFunctionType.RegularFunction);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Set the 'ReturnValue' and 'OutputData' based on the invocation results appropriately.
        /// </summary>
        private void BindOutputFromResult(InvocationResponse response, AzFunctionInfo functionInfo, Hashtable results)
        {
            switch (functionInfo.Type)
            {
            case AzFunctionType.RegularFunction:
                // Set out binding data and return response to be sent back to host
                foreach (KeyValuePair <string, ReadOnlyBindingInfo> binding in functionInfo.OutputBindings)
                {
                    string outBindingName           = binding.Key;
                    ReadOnlyBindingInfo bindingInfo = binding.Value;

                    object    outValue         = results[outBindingName];
                    object    transformedValue = Utils.TransformOutBindingValueAsNeeded(outBindingName, bindingInfo, outValue);
                    TypedData dataToUse        = transformedValue.ToTypedData();

                    // if one of the bindings is '$return' we need to set the ReturnValue
                    if (string.Equals(outBindingName, AzFunctionInfo.DollarReturn, StringComparison.OrdinalIgnoreCase))
                    {
                        response.ReturnValue = dataToUse;
                        continue;
                    }

                    ParameterBinding paramBinding = new ParameterBinding()
                    {
                        Name = outBindingName,
                        Data = dataToUse
                    };

                    response.OutputData.Add(paramBinding);
                }
                break;

            case AzFunctionType.OrchestrationFunction:
            case AzFunctionType.ActivityFunction:
                response.ReturnValue = results[AzFunctionInfo.DollarReturn].ToTypedData();
                break;

            default:
                throw new InvalidOperationException("Unreachable code.");
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Construct an object of AzFunctionInfo from the 'RpcFunctionMetadata'.
        /// Necessary validations are done on the metadata and script.
        /// </summary>
        internal AzFunctionInfo(RpcFunctionMetadata metadata)
        {
            FuncName      = metadata.Name;
            FuncDirectory = metadata.Directory;
            EntryPoint    = metadata.EntryPoint;
            ScriptPath    = metadata.ScriptFile;

            // Support 'entryPoint' only if 'scriptFile' is a .psm1 file;
            // Support .psm1 'scriptFile' only if 'entryPoint' is specified.
            bool isScriptFilePsm1     = ScriptPath.EndsWith(".psm1", StringComparison.OrdinalIgnoreCase);
            bool entryPointNotDefined = string.IsNullOrEmpty(EntryPoint);

            if (entryPointNotDefined)
            {
                if (isScriptFilePsm1)
                {
                    throw new ArgumentException(PowerShellWorkerStrings.RequireEntryPointForScriptModule);
                }
            }
            else if (!isScriptFilePsm1)
            {
                throw new ArgumentException(PowerShellWorkerStrings.InvalidEntryPointForScriptFile);
            }

            // Get the parameter names of the script or function.
            var psScriptParams = GetParameters(ScriptPath, EntryPoint, out ScriptBlockAst scriptAst);

            FuncParameters = new ReadOnlyDictionary <string, PSScriptParamInfo>(psScriptParams);

            var parametersCopy = new Dictionary <string, PSScriptParamInfo>(psScriptParams, StringComparer.OrdinalIgnoreCase);

            HasTriggerMetadataParam = parametersCopy.Remove(TriggerMetadata);
            HasTraceContextParam    = parametersCopy.Remove(TraceContext);

            var allBindings    = new Dictionary <string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);
            var inputBindings  = new Dictionary <string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);
            var outputBindings = new Dictionary <string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);

            var inputsMissingFromParams = new List <string>();

            foreach (var binding in metadata.Bindings)
            {
                string bindingName = binding.Key;
                var    bindingInfo = new ReadOnlyBindingInfo(binding.Value);

                allBindings.Add(bindingName, bindingInfo);

                if (bindingInfo.Direction == BindingInfo.Types.Direction.In)
                {
                    Type = GetAzFunctionType(bindingInfo);
                    inputBindings.Add(bindingName, bindingInfo);

                    // If the input binding name is in the set, we remove it;
                    // otherwise, the binding name is missing from the params.
                    if (!parametersCopy.Remove(bindingName))
                    {
                        inputsMissingFromParams.Add(bindingName);
                    }
                }
                else if (bindingInfo.Direction == BindingInfo.Types.Direction.Out)
                {
                    if (bindingInfo.Type == OrchestrationClient)
                    {
                        OrchestrationClientBindingName = bindingName;
                    }

                    outputBindings.Add(bindingName, bindingInfo);
                }
                else
                {
                    // PowerShell doesn't support the 'InOut' type binding
                    throw new InvalidOperationException(string.Format(PowerShellWorkerStrings.InOutBindingNotSupported, bindingName));
                }
            }

            if (inputsMissingFromParams.Count != 0 || parametersCopy.Count != 0)
            {
                StringBuilder stringBuilder = new StringBuilder();
                foreach (string inputBindingName in inputsMissingFromParams)
                {
                    stringBuilder.AppendFormat(PowerShellWorkerStrings.MissingParameter, inputBindingName).AppendLine();
                }

                foreach (string param in parametersCopy.Keys)
                {
                    stringBuilder.AppendFormat(PowerShellWorkerStrings.UnknownParameter, param).AppendLine();
                }

                string errorMsg = stringBuilder.ToString();
                throw new InvalidOperationException(errorMsg);
            }

            if (entryPointNotDefined && scriptAst.ScriptRequirements == null)
            {
                // If the function script is a '.ps1' file that doesn't have '#requires' defined,
                // then we get the script block and will deploy it as a PowerShell function in the
                // global scope of each Runspace, so as to avoid hitting the disk every invocation.
                FuncScriptBlock    = scriptAst.GetScriptBlock();
                DeployedPSFuncName = $"_{FuncName}_";
            }

            AllBindings    = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(allBindings);
            InputBindings  = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(inputBindings);
            OutputBindings = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(outputBindings);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Construct an object of AzFunctionInfo from the 'RpcFunctionMetadata'.
        /// Necessary validations are done on the metadata and script.
        /// </summary>
        internal AzFunctionInfo(RpcFunctionMetadata metadata)
        {
            FuncName      = metadata.Name;
            FuncDirectory = metadata.Directory;
            EntryPoint    = metadata.EntryPoint;
            ScriptPath    = metadata.ScriptFile;

            // Support 'entryPoint' only if 'scriptFile' is a .psm1 file;
            // Support .psm1 'scriptFile' only if 'entryPoint' is specified.
            bool isScriptFilePsm1 = ScriptPath.EndsWith(".psm1", StringComparison.OrdinalIgnoreCase);

            if (string.IsNullOrEmpty(EntryPoint))
            {
                if (isScriptFilePsm1)
                {
                    throw new ArgumentException(PowerShellWorkerStrings.RequireEntryPointForScriptModule);
                }
            }
            else if (!isScriptFilePsm1)
            {
                throw new ArgumentException(PowerShellWorkerStrings.InvalidEntryPointForScriptFile);
            }

            // Get the parameter names of the script or function.
            var psScriptParams = GetParameters(ScriptPath, EntryPoint);

            FuncParameters = new ReadOnlyDictionary <string, PSScriptParamInfo>(psScriptParams);

            var parametersCopy = new Dictionary <string, PSScriptParamInfo>(psScriptParams, StringComparer.OrdinalIgnoreCase);

            HasTriggerMetadataParam = parametersCopy.Remove(TriggerMetadata);

            var allBindings    = new Dictionary <string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);
            var inputBindings  = new Dictionary <string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);
            var outputBindings = new Dictionary <string, ReadOnlyBindingInfo>(StringComparer.OrdinalIgnoreCase);

            var inputsMissingFromParams = new List <string>();

            foreach (var binding in metadata.Bindings)
            {
                string bindingName = binding.Key;
                var    bindingInfo = new ReadOnlyBindingInfo(binding.Value);

                allBindings.Add(bindingName, bindingInfo);

                if (bindingInfo.Direction == BindingInfo.Types.Direction.In)
                {
                    Type = GetAzFunctionType(bindingInfo);
                    inputBindings.Add(bindingName, bindingInfo);

                    // If the input binding name is in the set, we remove it;
                    // otherwise, the binding name is missing from the params.
                    if (!parametersCopy.Remove(bindingName))
                    {
                        inputsMissingFromParams.Add(bindingName);
                    }
                }
                else if (bindingInfo.Direction == BindingInfo.Types.Direction.Out)
                {
                    outputBindings.Add(bindingName, bindingInfo);
                }
                else
                {
                    // PowerShell doesn't support the 'InOut' type binding
                    throw new InvalidOperationException(string.Format(PowerShellWorkerStrings.InOutBindingNotSupported, bindingName));
                }
            }

            if (inputsMissingFromParams.Count != 0 || parametersCopy.Count != 0)
            {
                StringBuilder stringBuilder = new StringBuilder();
                foreach (string inputBindingName in inputsMissingFromParams)
                {
                    stringBuilder.AppendFormat(PowerShellWorkerStrings.MissingParameter, inputBindingName).AppendLine();
                }

                foreach (string param in parametersCopy.Keys)
                {
                    stringBuilder.AppendFormat(PowerShellWorkerStrings.UnknownParameter, param).AppendLine();
                }

                string errorMsg = stringBuilder.ToString();
                throw new InvalidOperationException(errorMsg);
            }

            AllBindings    = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(allBindings);
            InputBindings  = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(inputBindings);
            OutputBindings = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(outputBindings);
        }
        /// <summary>
        /// Construct an object of AzFunctionInfo from the 'RpcFunctionMetadata'.
        /// Necessary validations are done on the metadata and script.
        /// </summary>
        internal AzFunctionInfo(RpcFunctionMetadata metadata)
        {
            FuncName      = metadata.Name;
            FuncDirectory = metadata.Directory;
            EntryPoint    = metadata.EntryPoint;
            ScriptPath    = metadata.ScriptFile;

            // Support 'entryPoint' only if 'scriptFile' is a .psm1 file;
            // Support .psm1 'scriptFile' only if 'entryPoint' is specified.
            bool isScriptFilePsm1 = ScriptPath.EndsWith(".psm1", StringComparison.OrdinalIgnoreCase);

            if (string.IsNullOrEmpty(EntryPoint))
            {
                if (isScriptFilePsm1)
                {
                    throw new ArgumentException($"The 'entryPoint' property needs to be specified when 'scriptFile' points to a PowerShell module script file (.psm1).");
                }
            }
            else if (!isScriptFilePsm1)
            {
                throw new ArgumentException($"The 'entryPoint' property is supported only if 'scriptFile' points to a PowerShell module script file (.psm1).");
            }

            // Get the parameter names of the script or function.
            FuncParameters = GetParameters(ScriptPath, EntryPoint);
            var parametersCopy = new HashSet <string>(FuncParameters, StringComparer.OrdinalIgnoreCase);

            parametersCopy.Remove(TriggerMetadata);

            var allBindings    = new Dictionary <string, ReadOnlyBindingInfo>();
            var inputBindings  = new Dictionary <string, ReadOnlyBindingInfo>();
            var outputBindings = new Dictionary <string, ReadOnlyBindingInfo>();

            var inputsMissingFromParams = new List <string>();

            foreach (var binding in metadata.Bindings)
            {
                string bindingName = binding.Key;
                var    bindingInfo = new ReadOnlyBindingInfo(binding.Value);

                allBindings.Add(bindingName, bindingInfo);

                if (bindingInfo.Direction == BindingInfo.Types.Direction.In)
                {
                    Type = GetAzFunctionType(bindingInfo);
                    inputBindings.Add(bindingName, bindingInfo);

                    // If the input binding name is in the set, we remove it;
                    // otherwise, the binding name is missing from the params.
                    if (!parametersCopy.Remove(bindingName))
                    {
                        inputsMissingFromParams.Add(bindingName);
                    }
                }
                else if (bindingInfo.Direction == BindingInfo.Types.Direction.Out)
                {
                    outputBindings.Add(bindingName, bindingInfo);
                }
                else
                {
                    // PowerShell doesn't support the 'InOut' type binding
                    throw new InvalidOperationException($"The binding '{bindingName}' is declared with 'InOut' direction, which is not supported by PowerShell functions.");
                }
            }

            if (inputsMissingFromParams.Count != 0 || parametersCopy.Count != 0)
            {
                StringBuilder stringBuilder = new StringBuilder();
                foreach (string inputBindingName in inputsMissingFromParams)
                {
                    stringBuilder.AppendLine($"No parameter defined in the script or function for the input binding '{inputBindingName}'.");
                }

                foreach (string param in parametersCopy)
                {
                    stringBuilder.AppendLine($"No input binding defined for the parameter '{param}' that is declared in the script or function.");
                }

                string errorMsg = stringBuilder.ToString();
                throw new InvalidOperationException(errorMsg);
            }

            AllBindings    = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(allBindings);
            InputBindings  = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(inputBindings);
            OutputBindings = new ReadOnlyDictionary <string, ReadOnlyBindingInfo>(outputBindings);
        }