//parameter public override void OutAParameter(AParameter node) { Definition typeDef, varDef; String typeName = node.GetType().Text; String varName = node.GetName().Text; // check type name is defined if (!_currentSymbolTable.TryGetValue(typeName, out typeDef)) { Console.WriteLine("[" + node.GetType().Line + "] : " + typeName + " is not defined."); // check if type name is defined as a type } else if (!(typeDef is TypeDefinition)) { Console.WriteLine("[" + node.GetType().Line + "] : " + typeName + " is not a valid type."); // check var name is not defined } else if (_currentSymbolTable.TryGetValue(varName, out varDef) || _globalSymbolTable.TryGetValue(varName, out varDef)) { Console.WriteLine("[" + node.GetName().Line + "] : " + varName + " is already defined."); // add to symbol table } else { VariableDefinition newDef = new VariableDefinition(); newDef.name = varName; newDef.vartype = (TypeDefinition)typeDef; _currentSymbolTable.Add(varName, newDef); _currentParamList.Add(newDef); } }
public IList <AParameter> ConvertParameters( IList <ParameterNode> parameters, string resourcePrefix = "" ) { var resultList = new List <AParameter>(); if ((parameters == null) || !parameters.Any()) { return(resultList); } // convert all parameters var index = 0; foreach (var parameter in parameters) { ++index; var parameterName = parameter.Name ?? $"[{index}]"; AParameter result = null; var parameterFullName = resourcePrefix + parameter.Name; AtLocation(parameterName, () => { if (parameter.Secret != null) { // encrypted value AtLocation("Secret", () => { result = new SecretParameter { Name = parameter.Name, Description = parameter.Description, Secret = parameter.Secret, Export = parameter.Export, EncryptionContext = parameter.EncryptionContext }; }); } else if (parameter.Values != null) { // list of values AtLocation("Values", () => { result = new StringListParameter { Name = parameter.Name, Description = parameter.Description, Values = parameter.Values, Export = parameter.Export }; }); // TODO (2018-08-19, bjorg): this implementation creates unnecessary parameters if (parameter.Resource != null) { AtLocation("Resource", () => { // enumerate individual values with resource definition for each parameter.Parameters = new List <ParameterNode>(); for (var i = 1; i <= parameter.Values.Count; ++i) { parameter.Parameters.Add(new ParameterNode { Name = $"Index{i}", Value = parameter.Values[i - 1], Resource = parameter.Resource }); } }); } } else if (parameter.Package != null) { // package value result = new PackageParameter { Name = parameter.Name, Description = parameter.Description, DestinationBucketParameterName = parameter.Package.Bucket, DestinationKeyPrefix = parameter.Package.Prefix ?? "", PackagePath = parameter.Package.PackagePath }; } else if (parameter.Value != null) { if (parameter.Resource != null) { AtLocation("Resource", () => { // existing resource var resource = ConvertResource((string)parameter.Value, parameter.Resource); result = new ReferencedResourceParameter { Name = parameter.Name, Description = parameter.Description, Resource = resource }; }); } else if (parameter.Value is string text) { // plaintext value result = new StringParameter { Name = parameter.Name, Description = parameter.Description, Value = text }; } else { // plaintext value result = new ExpressionParameter { Name = parameter.Name, Description = parameter.Description, Expression = parameter.Value }; } } else if (parameter.Resource != null) { // managed resource AtLocation("Resource", () => { result = new CloudFormationResourceParameter { Name = parameter.Name, Description = parameter.Description, Resource = ConvertResource(null, parameter.Resource) }; }); } }); // check if there are nested parameters if (parameter.Parameters != null) { AtLocation("Parameters", () => { var nestedParameters = ConvertParameters( parameter.Parameters, parameterFullName ); // keep nested parameters only if they have values if (nestedParameters.Any()) { // create empty string parameter if collection has no value result = result ?? new StringParameter { Name = parameter.Name, Value = "", Description = parameter.Description, Export = parameter.Export }; result.Parameters = nestedParameters; } }); } // add parameter if (result != null) { result.FullName = parameterFullName; result.Export = parameter.Export; resultList.Add(result); } } return(resultList); }
private void AddParameter( AParameter parameter, string envPrefix, IDictionary <string, object> environmentRefVariables ) { object exportValue = null; var fullEnvName = envPrefix + parameter.Name.ToUpperInvariant(); switch (parameter) { case SecretParameter secretParameter: if (secretParameter.EncryptionContext?.Any() == true) { environmentRefVariables["SEC_" + fullEnvName] = $"{secretParameter.Secret}|{string.Join("|", secretParameter.EncryptionContext.Select(kv => $"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value)}"))}"; } else { environmentRefVariables["SEC_" + fullEnvName] = secretParameter.Secret; } break; case StringParameter stringParameter: environmentRefVariables["STR_" + fullEnvName] = stringParameter.Value; exportValue = stringParameter.Value; // add literal string parameter value as CloudFormation parameter so it can be referenced _stack.Add(stringParameter.FullName, new Parameter { Type = "String", Default = stringParameter.Value, Description = stringParameter.Description }); break; case StringListParameter stringListParameter: { var commaDelimitedValue = string.Join(",", stringListParameter.Values); environmentRefVariables["STR_" + fullEnvName] = commaDelimitedValue; exportValue = commaDelimitedValue; } // add literal string list parameter value as CloudFormation parameter so it can be referenced _stack.Add(stringListParameter.FullName, new Parameter { Type = "CommaDelimitedList", Default = string.Join(",", stringListParameter.Values), Description = stringListParameter.Description }); break; case PackageParameter packageParameter: environmentRefVariables["STR_" + fullEnvName] = Fn.GetAtt(parameter.FullName, "Result"); _stack.Add(packageParameter.FullName, new Model.CustomResource("Custom::LambdaSharpS3PackageLoader") { ["ServiceToken"] = Settings.S3PackageLoaderCustomResourceTopicArn, ["DestinationBucketName"] = Humidifier.Fn.Ref(packageParameter.DestinationBucketParameterName), ["DestinationKeyPrefix"] = packageParameter.DestinationKeyPrefix, ["SourceBucketName"] = Settings.DeploymentBucketName, ["SourcePackageKey"] = $"{_module.Name}/{Path.GetFileName(packageParameter.PackagePath)}" }); break; case ExpressionParameter expressionParameter: environmentRefVariables["STR_" + fullEnvName] = expressionParameter.Expression; exportValue = expressionParameter.Expression; break; case ReferencedResourceParameter referenceResourceParameter: { var resource = referenceResourceParameter.Resource; environmentRefVariables["STR_" + fullEnvName] = resource.ResourceArn; exportValue = resource.ResourceArn; // add permissions for resource if (resource.Allow?.Any() == true) { _resourceStatements.Add(new Statement { Sid = parameter.FullName, Effect = "Allow", Resource = resource.ResourceArn, Action = resource.Allow }); } // add reference resource parameter value as CloudFormation parameter so it can be referenced _stack.Add(referenceResourceParameter.FullName, new Parameter { Type = "String", Default = resource.ResourceArn, Description = referenceResourceParameter.Description }); } break; case CloudFormationResourceParameter cloudFormationResourceParameter: { var resource = cloudFormationResourceParameter.Resource; var resourceName = parameter.FullName; object resourceArn; object resourceParamFn; Humidifier.Resource resourceTemplate; if (resource.Type.StartsWith("Custom::")) { resourceArn = null; resourceParamFn = Fn.GetAtt(resourceName, "Result"); resourceTemplate = new Model.CustomResource(resource.Type, resource.Properties); } else if (!Settings.ResourceMapping.TryParseResourceProperties( resource.Type, resourceName, resource.Properties, out resourceArn, out resourceParamFn, out resourceTemplate )) { throw new NotImplementedException($"resource type is not supported: {resource.Type}"); } _stack.Add(resourceName, resourceTemplate, dependsOn: resource.DependsOn.ToArray()); exportValue = resourceParamFn; // only add parameters that the lambda functions are allowed to access if (resource.Type.StartsWith("Custom::") || (resource.Allow?.Any() == true)) { environmentRefVariables["STR_" + fullEnvName] = resourceParamFn; } // add permissions for resource if ((resourceArn != null) && (resource.Allow?.Any() == true)) { _resourceStatements.Add(new Statement { Sid = parameter.FullName, Effect = "Allow", Resource = resourceArn, Action = resource.Allow }); } } break; default: throw new ArgumentOutOfRangeException(nameof(parameter), parameter, "unknown parameter type"); } // check if nested parameters need to be added if (parameter.Parameters?.Any() == true) { foreach (var nestedResource in parameter.Parameters) { AddParameter( nestedResource, fullEnvName + "_", environmentRefVariables ); } } // check if resource name should be exported if (parameter.Export != null) { var export = parameter.Export.StartsWith("/") ? parameter.Export : $"/{Settings.Tier}/{_module.Name}/{parameter.Export}"; _stack.Add(parameter.FullName + "SsmParameter", new SSM.Parameter { Name = export, Description = parameter.Description, Type = "String", Value = exportValue }); } }
private void AddParameter( AParameter parameter, string envPrefix, IDictionary <string, object> environmentRefVariables ) { object exportValue = null; var fullEnvName = envPrefix + parameter.Name.ToUpperInvariant(); switch (parameter) { case SecretParameter secretParameter: if (secretParameter.Export != null) { // TODO (2018-08-16, bjorg): add support for exporting secrets (or error out sooner) throw new NotImplementedException("exporting secrets is not yet supported"); } break; case CollectionParameter collectionParameter: { foreach (var nestedResource in collectionParameter.Parameters) { AddParameter( nestedResource, fullEnvName + "_", environmentRefVariables ); } if (collectionParameter.Export != null) { // TODO (2018-08-16, bjorg): add support for exporting collections (or error out sooner) throw new NotImplementedException("exporting collections is not yet supported"); } } break; case StringParameter stringParameter: exportValue = stringParameter.Value; break; case PackageParameter packageParameter: environmentRefVariables[fullEnvName] = Fn.GetAtt(parameter.FullName, "Result"); _stack.Add(packageParameter.FullName, new Model.CustomResource("Custom::LambdaSharpS3PackageLoader", new Dictionary <string, object> { ["ServiceToken"] = _module.Settings.S3PackageLoaderCustomResourceTopicArn, ["DestinationBucketName"] = Humidifier.Fn.Ref(packageParameter.Bucket), ["DestinationKeyPrefix"] = packageParameter.Prefix, ["SourceBucketName"] = _module.Settings.DeploymentBucketName, ["SourcePackageKey"] = packageParameter.PackageS3Key, })); break; case ReferencedResourceParameter referenceResourceParameter: { var resource = referenceResourceParameter.Resource; exportValue = resource.ResourceArn; // add permissions for resource if (resource.Allow?.Any() == true) { _resourceStatements.Add(new Statement { Effect = "Allow", Resource = resource.ResourceArn, Action = resource.Allow }); } } break; case CloudFormationResourceParameter cloudFormationResourceParameter: { var resource = cloudFormationResourceParameter.Resource; var resourceName = parameter.FullName; object resourceArn; object resourceParamFn; Humidifier.Resource resourceTemplate; if (resource.Type.StartsWith("Custom::")) { resourceArn = null; resourceParamFn = Fn.GetAtt(resourceName, "Result"); resourceTemplate = new Model.CustomResource(resource.Type, resource.Properties); } else if (!_module.Settings.ResourceMapping.TryParseResourceProperties( resource.Type, resourceName, resource.Properties, out resourceArn, out resourceParamFn, out resourceTemplate )) { throw new NotImplementedException($"resource type is not supported: {resource.Type}"); } // for S3 buckets, we need to check if any functions use the bucket as an event source if (resource.Type == "AWS::S3::Bucket") { var s3Template = (Humidifier.S3.Bucket)resourceTemplate; var s3Sources = _module.Functions.SelectMany(function => function.Sources .OfType <S3Source>() .Where(source => source.Bucket == resourceName) .Select(source => new { Function = function, Source = source }) ) .ToList(); if (s3Sources.Any()) { // NOTE (2018-06-28, bjorg): for S3 buckets, we need to jump through a few hoops to make // everything work as expected; first, we need to know the final name of the bucket; // second, we cannot use `Ref()` to get its name, because it introduces a circular dependency. // check if we need to create a hashed bucket name and set `BucketName` in template if (s3Template.BucketName == null) { // NOTE (2018-08-16, bjorg): bucket names must be lowercase var bucketName = $"{_module.Settings.Tier}-{_module.Name}-{resourceName}-".ToLowerInvariant(); bucketName += $"{_module.Settings.AwsAccountId}-{_module.Settings.AwsRegion}-{bucketName}".ToMD5Hash().Substring(0, 7).ToLowerInvariant(); s3Template.BucketName = bucketName; var arn = $"arn:aws:s3:::{bucketName}"; resourceArn = new object[] { arn, arn + "/*" }; foreach (var src in s3Sources) { src.Source.BucketArn = arn; } } // use the hashed bucket name as environment variable resourceParamFn = s3Template.BucketName; // add notification configuration to template s3Template.NotificationConfiguration = new Humidifier.S3.BucketTypes.NotificationConfiguration { LambdaConfigurations = s3Sources.SelectMany(src => src.Source.Events.Select(evt => new Humidifier.S3.BucketTypes.LambdaConfiguration { Event = evt, Filter = ConvertFilter(src.Source.Prefix, src.Source.Suffix), Function = Fn.GetAtt(src.Function.Name, "Arn") })).ToList() }; } // local function Humidifier.S3.BucketTypes.NotificationFilter ConvertFilter(string prefix, string suffix) { if ((prefix == null) && (suffix == null)) { return(null); } var rules = new List <Humidifier.S3.BucketTypes.FilterRule>(); if (prefix != null) { rules.Add(new Humidifier.S3.BucketTypes.FilterRule { Name = "prefix", Value = prefix }); } if (suffix != null) { rules.Add(new Humidifier.S3.BucketTypes.FilterRule { Name = "suffix", Value = suffix }); } return(new Humidifier.S3.BucketTypes.NotificationFilter { S3Key = new Humidifier.S3.BucketTypes.S3KeyFilter { Rules = rules } }); } } _stack.Add(resourceName, resourceTemplate); exportValue = resourceParamFn; // only add parameters that the lambda functions are allowed to access if (resource.Type.StartsWith("Custom::") || (resource.Allow?.Any() == true)) { environmentRefVariables[fullEnvName] = resourceParamFn; } // add permissions for resource if ((resourceArn != null) && (resource.Allow?.Any() == true)) { _resourceStatements.Add(new Statement { Effect = "Allow", Resource = resourceArn, Action = resource.Allow }); } } break; default: throw new ArgumentOutOfRangeException(nameof(parameter), parameter, "unknown parameter type"); } // check if resource name should be exported if (parameter.Export != null) { var export = parameter.Export.StartsWith("/") ? parameter.Export : $"/{_module.Settings.Tier}/{_module.Name}/{parameter.Export}"; _stack.Add(parameter.FullName + "SsmParameter", new SSM.Parameter { Name = export, Description = parameter.Description, Type = "String", Value = exportValue }); } }