/// <summary> /// Initializes a new instance of the <see cref="EmitterContext"/> class. /// </summary> /// <param name="emitter">The emitter.</param> /// <param name="currentResourceType">Type of the current resource.</param> /// <param name="currentResourceName">Name of the current resource.</param> public EmitterContext(IHclEmitter emitter, string currentResourceType, string currentResourceName) { this.Emitter = emitter; this.CurrentResourceName = currentResourceName; this.CurrentResourceType = currentResourceType; this.ResourceSchema = AwsSchema.GetResourceSchema(this.CurrentResourceType); }
public void AssertAttributeAsBlocksWillBeRenderedAsBlocks(string resourceType, string attributeName) { var resource = AwsSchema.GetResourceSchema(resourceType); var attribute = resource.GetAttributeByPath(attributeName); attribute.IsBlock.Should().BeTrue(); }
public void ShouldResolveASGConflicts() { var q = new EventQueue(EventQueues.AutoScalingGroupEvents); var traits = AwsSchema.GetResourceTraits("aws_autoscaling_group"); var resolver = new EventQueuePreprocessor(q); resolver.ResolveConflicts(); }
public void GetResourceByNameShouldThrowForUnknownTerraformResource() { const string TerraformName = "aws_foo_bar"; var expectedMessage = $"Resource \"{TerraformName}\" not found."; Action action = () => AwsSchema.GetResourceSchema(TerraformName); action.Should().Throw <KeyNotFoundException>().WithMessage(expectedMessage); }
public void AssertGetResourceSchemaWithUnknownAwsTypeThrows() { const string UnknownAwsType = "AWS::EC2::FooBar"; var expectedMessage = $"Resource \"{UnknownAwsType}\": No corresponding Terraform resource found. If this is incorrect, please raise an issue."; Action action = () => AwsSchema.GetResourceSchema(UnknownAwsType); action.Should().Throw <KeyNotFoundException>().WithMessage(expectedMessage); }
public void InvalidPathToAttributeWithValueSchemaShouldThrow() { const string InvalidAttribute = "managed_policy_arns.max_session_duration"; var expectedMessage = $"Resource does not contain an attribute at\"{InvalidAttribute}\"."; var resource = AwsSchema.GetResourceSchema("aws_iam_role"); Action action = () => resource.GetAttributeByPath(InvalidAttribute); action.Should().Throw <KeyNotFoundException>().WithMessage(expectedMessage); }
public void GetResourceByNameShouldThrowForUnknownAwsResource() { const string AwsName = "AWS::Foo::Bar"; var expectedMessage = $"Resource \"{AwsName}\": No corresponding Terraform resource found. If this is incorrect, please raise an issue."; Action action = () => AwsSchema.GetResourceSchema(AwsName); action.Should().Throw <KeyNotFoundException>().WithMessage(expectedMessage); }
/// <summary> /// Renders the specified GetAtt intrinsic. /// </summary> /// <param name="getAttIntrinsic">The GetAtt intrinsic.</param> /// <param name="template">The template.</param> /// <param name="resource">The resource.</param> /// <returns>An <see cref="IndirectReference"/> to an attribute on another resource.</returns> private static Reference Render(GetAttIntrinsic getAttIntrinsic, ITemplate template, ResourceMapping resource) { string attributeName; if (getAttIntrinsic.AttributeName is IIntrinsic) { if (!(getAttIntrinsic.AttributeName is RefIntrinsic refIntrinsic)) { // Only !Ref allowed here return(null); } attributeName = refIntrinsic.Evaluate(template).ToString(); } else { attributeName = getAttIntrinsic.AttributeName.ToString(); } // This GetAtt refers to a nested stack which may or may not have been imported as a terraform module. if (attributeName.StartsWith(TerraformExporterConstants.StackOutputQualifier)) { var referencedOutput = attributeName.Substring(TerraformExporterConstants.StackOutputQualifier.Length); if (resource.Module?.LogicalId == getAttIntrinsic.LogicalId && resource.Module.Outputs.Any(o => o.OutputKey == referencedOutput)) { // This reference is to a module output return(new ModuleReference($"{resource.Module.Name}.{referencedOutput}")); } // The reference is to an aws_cloudformation_stack as the use did not elect to import nested stacks. // Just lowercase "Outputs." which will then resolve to the terraform resource. attributeName = attributeName.Replace( TerraformExporterConstants.StackOutputQualifier, TerraformExporterConstants.StackOutputQualifier.ToLowerInvariant()); } else { var traits = AwsSchema.GetResourceTraits(resource.TerraformType); attributeName = traits.AttributeMap.ContainsKey(attributeName) ? traits.AttributeMap[attributeName] : attributeName.CamelCaseToSnakeCase(); } if (getAttIntrinsic.ExtraData is IntrinsicInfo intrinsicInfo) { resource = intrinsicInfo.TargetResource; } return(template.Resources.Any(r => r.Name == resource.LogicalId) ? new IndirectReference($"{resource.Address}.{attributeName}") : null); }
/// <summary> /// Emits the resource start. /// </summary> /// <param name="event">A <see cref="ResourceStart"/> event.</param> private void EmitResourceStart(HclEvent @event) { var rs = GetTypedEvent <ResourceStart>(@event); this.Write("resource"); this.isWhitespace = false; this.resourceTraits = AwsSchema.GetResourceTraits(rs.ResourceType); this.currentResourceName = rs.ResourceName; this.currentResourceType = rs.ResourceType; this.EmitScalar(new Scalar(rs.ResourceType, true)); this.EmitScalar(new Scalar(rs.ResourceName, true)); }
/// <summary> /// Initializes a new instance of the <see cref="TerraformAttributeSetterContext"/> class. /// </summary> /// <param name="intrinsicInfo">The intrinsic information.</param> /// <param name="template">Reference to parsed CloudFormation template.</param> /// <param name="resource">Reference to resource being updated.</param> /// <param name="inputs">The list of input variables and data sources.</param> public TerraformAttributeSetterContext( IReadOnlyCollection <IntrinsicInfo> intrinsicInfo, ITemplate template, StateFileResourceDeclaration resource, IList <InputVariable> inputs) { this.Template = template; this.IntrinsicInfos = intrinsicInfo; this.Resource = resource; this.Inputs = inputs; this.Schema = AwsSchema.GetResourceSchema(resource.Type); }
public void Test() { var stack = new Stack("test"); var lc = new LaunchConfiguration(stack, "lc") .ImageId("123") .InstanceType("123"); string json = JsonConvert.SerializeObject(lc); AwsSchema schema = LoadSchema(); validateAgainstSchema(json, schema); }
private void validateAgainstSchema(string json, AwsSchema schema) { JObject parsed = JObject.Parse(json); string type = parsed.Property("Type").Value.ToString(); Resource resource = schema.ResourceType[type]; Assert.True(resource != null, $"Schema does not contain resource : {type}"); JToken properties = parsed.GetValue("Properties"); foreach (var prop in resource.Properties) { JToken jsonProp = properties[prop.Key]; switch (jsonProp.Type) { case JTokenType.Object: // TODO : possible ref or param break; case JTokenType.None: case JTokenType.Null: Assert.False(prop.Value.Required, $"Property {prop.Key} is required on {type}"); continue; default: break; } if (prop.Value.PrimitiveType != null) { Assert.Equal(prop.Value.PrimitiveType, jsonProp.Type.ToString()); } else if (prop.Value.ItemType != null) { // TODO : recursive check of the type on the property } else { } } }
/// <summary> /// Creates an <see cref="IntrinsicInfo"/> for a <c>!GetAtt</c> intrinsic. /// </summary> /// <param name="getAttIntrinsic">The <c>!GetAtt</c> intrinsic.</param> /// <param name="currentPath">The current path.</param> /// <returns>An <see cref="IntrinsicInfo"/></returns> private IntrinsicInfo ProcessGetAtt(GetAttIntrinsic getAttIntrinsic, PropertyPath currentPath) { object evaluation; // Logical name of the resource being referenced by this !GetAtt var(referencedResourceName, attribute) = (Tuple <string, string>)getAttIntrinsic.Evaluate(this.template); // Is the reference to a nested stack module? var referencedModule = this.module.NestedModules.FirstOrDefault(m => m.LogicalId == referencedResourceName); if (referencedModule != null) { var targetModuleSummary = new ResourceMapping { AwsType = TerraformExporterConstants.AwsCloudFormationStack, LogicalId = referencedModule.LogicalId, PhysicalId = referencedModule.Name, Module = referencedModule }; var parts = attribute.Split('.'); evaluation = referencedModule.Outputs.Where(o => o.OutputKey == parts[1]) .Select(o => o.OutputValue).SingleOrDefault(); return(new IntrinsicInfo(currentPath, getAttIntrinsic, targetModuleSummary, evaluation)); } // State file instance of the resource being referenced by this !GetAtt var referencedResource = this.TerraformResources.FirstOrDefault(r => r.Name == referencedResourceName) ?.Instances.First(); if (referencedResource == null) { // If not found, then reference is to a resource that couldn't be imported eg. a custom resource. throw new UnsupportedResourceWarning( getAttIntrinsic, this.currentCloudFormationResource, currentPath); } // CloudFormation instance of the resource being referenced by this !GetAtt var cloudFormationResource = this.CloudFormationResources.First(r => r.LogicalResourceId == getAttIntrinsic.LogicalId); // Summary of the resource to which this !GetAtt refers to var targetResourceSummary = new ResourceMapping { AwsType = cloudFormationResource.ResourceType, LogicalId = cloudFormationResource.LogicalResourceId, PhysicalId = cloudFormationResource.PhysicalResourceId, TerraformType = this.TerraformResources.First( tr => tr.Name == cloudFormationResource.LogicalResourceId).Type }; // Now attempt to match up the CloudFormation resource attribute name with the corresponding terraform one // and get the current value from state. // First, look up the attribute map var traits = AwsSchema.GetResourceTraits(referencedResource.Parent.Type); if (traits.AttributeMap.ContainsKey(attribute)) { var token = referencedResource.Attributes[traits.AttributeMap[attribute]]; evaluation = GetEvaluation(token); } else if (attribute.StartsWith(TerraformExporterConstants.StackOutputQualifier)) { // Nested stack output reference var token = referencedResource.Attributes.SelectToken( attribute.Replace( TerraformExporterConstants.StackOutputQualifier, TerraformExporterConstants.StackOutputQualifier.ToLowerInvariant())); evaluation = GetEvaluation(token); } else { var result = getAttIntrinsic.GetTargetValue(this.template, referencedResource); if (result.Success) { evaluation = result.Value; } else { throw new UnreferenceableIntrinsicWarning( getAttIntrinsic, cloudFormationResource.TemplateResource, currentPath); } } return(new IntrinsicInfo(currentPath, getAttIntrinsic, targetResourceSummary, evaluation)); object GetEvaluation(JToken token) { if (token is JValue jv) { // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault switch (jv.Type) { case JTokenType.String: evaluation = jv.Value <string>(); break; case JTokenType.Integer: case JTokenType.Float: evaluation = jv.Value <double>(); break; case JTokenType.Boolean: evaluation = jv.Value <bool>(); break; default: throw new InvalidOperationException( $"Unexpected JValue type: {jv.Type} while processing {getAttIntrinsic}"); } } else { throw new InvalidOperationException( $"Unexpected JToken type: {token.Type} while processing {getAttIntrinsic}"); } return(evaluation); } }
public void AssertGetResourceSchemaWithValidAwsTypeDoesNotThrow() { Action action = () => AwsSchema.GetResourceSchema("AWS::EC2::Instance"); action.Should().NotThrow(); }
/// <summary> /// Initializes a new instance of the <see cref="EventQueuePreprocessor"/> class. /// </summary> /// <param name="queue">The event queue.</param> public EventQueuePreprocessor(EventQueue queue) { this.queue = queue; this.traits = AwsSchema.GetResourceTraits(this.GetResourceType()); }