/// <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> /// Determines whether argument at current path should be omitted due to its value. /// </summary> /// <param name="self"><see cref="IResourceTraits"/> derivative</param> /// <param name="currentPath">The current path.</param> /// <param name="value">The value.</param> /// <returns> /// <c>true</c> if argument at current path should be omitted due to its value, else <c>false</c>. /// </returns> public static bool IsOmittedConditionalAttrbute(this IResourceTraits self, string currentPath, string value) { if (self == null) { throw new ArgumentNullException(nameof(self)); } var conditionalAttribute = self.ConditionalAttributes.FirstOrDefault(ca => ca.Name.IsLike(currentPath)); if (conditionalAttribute == null) { return(false); } return(value == conditionalAttribute.Value); }
/// <summary> /// Initializes a new instance of the <see cref="ConsolidatedResourceTraits"/> class. /// </summary> /// <param name="sharedTraits">The shared traits.</param> /// <param name="specificResourceTraits">The specific resource traits.</param> public ConsolidatedResourceTraits(IResourceTraits sharedTraits, IResourceTraits specificResourceTraits) { // No conflicting arguments defined for all resources this.ConflictingArguments = specificResourceTraits.ConflictingArguments; // No default values defined for all resources this.DefaultValues = specificResourceTraits.DefaultValues; // No conditional attributes defined for all resources this.ConditionalAttributes = specificResourceTraits.ConditionalAttributes; // No attribute map defined for all resources this.AttributeMap = specificResourceTraits.AttributeMap; this.ResourceType = specificResourceTraits.ResourceType; this.MissingFromSchema = specificResourceTraits.MissingFromSchema; this.ComputedAttributes = sharedTraits.ComputedAttributes.Concat(specificResourceTraits.ComputedAttributes).ToList(); }
/// <summary> /// Initializes a new instance of the <see cref="ResourceSchema"/> class. /// </summary> /// <param name="resourceType">The resource type.</param> /// <param name="schema">The schema.</param> /// <param name="traits">The traits.</param> public ResourceSchema(string resourceType, ProviderResourceSchema schema, IResourceTraits traits) { this.Schema = schema; this.ResourceType = resourceType; this.Traits = traits; }
/// <summary> /// Analyzes the value in this scalar based on it's key schema and any additional resource traits. /// </summary> /// <param name="key">The attribute key associated with this value.</param> /// <param name="resourceTraits">The resource traits.</param> /// <returns>Value analysis.</returns> /// <exception cref="System.InvalidOperationException">Invalid \"{key.Schema.Type}\" for scalar value at \"{key.Path}\"</exception> public AttributeContent Analyze(MappingKey key, IResourceTraits resourceTraits) { var value = this.Value; if (!key.Schema.Optional) { return(AttributeContent.Value); } if (resourceTraits.IsOmittedConditionalAttrbute(key.Path, value)) { return(AttributeContent.Empty); } // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault switch (key.Schema.Type) { case SchemaValueType.TypeBool: if (bool.TryParse(value, out var boolValue) && boolValue) { return(AttributeContent.Value); } break; case SchemaValueType.TypeInt: if (int.TryParse(value, out var intValue) && intValue != 0) { return(AttributeContent.Value); } break; case SchemaValueType.TypeFloat: if (double.TryParse(value, out var doubleValue) && doubleValue != 0) { return(AttributeContent.Value); } break; case SchemaValueType.TypeString: return(string.IsNullOrEmpty(value) ? AttributeContent.Empty : AttributeContent.Value); case SchemaValueType.TypeJsonData: // Always emit return(AttributeContent.Value); case SchemaValueType.TypeSet: case SchemaValueType.TypeList: case SchemaValueType.TypeObject: case SchemaValueType.TypeMap: // If these are empty, then they can be represented by a null scalar if (string.IsNullOrEmpty(value)) { return(AttributeContent.Empty); } throw new InvalidOperationException($"Unexpected scalar value for attribute of \"{key.Schema.Type}\" at \"{key.Path}\""); default: throw new InvalidOperationException($"Invalid SchemaValueType:\"{key.Schema.Type}\" for scalar value of attribute \"{key.Path}\"."); } if (!string.IsNullOrEmpty(value) && char.IsLetter(value.First()) && value.Contains(".")) { // A reference return(AttributeContent.Value); } return(AttributeContent.Empty); }
/// <summary> /// Emits the next node. /// </summary> /// <param name="event">The event to write.</param> private void EmitNode(HclEvent @event) { // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault switch (@event.Type) { case EventType.ResourceStart: this.EmitResourceStart(@event); break; case EventType.MappingKey: this.EmitMappingKey(@event); break; case EventType.ScalarValue: this.EmitScalarValue(@event); break; case EventType.SequenceStart: this.EmitSequenceStart(@event); break; case EventType.SequenceEnd: this.EmitSequenceEnd(@event); break; case EventType.MappingStart: this.EmitMappingStart(@event); break; case EventType.MappingEnd: this.EmitMappingEnd(@event); break; case EventType.JsonStart: this.EmitJsonStart(@event); break; case EventType.JsonEnd: this.EmitJsonEnd(@event); break; case EventType.ResourceEnd: this.indents.Clear(); this.lifecycleKeys.Clear(); this.blockKeys.Clear(); this.column = 0; this.indent = 0; this.resourceTraits = AwsSchema.TraitsAll; this.WriteBreak(); this.WriteBreak(); break; } }
/// <summary> /// Initializes a new instance of the <see cref="HclEmitter"/> class. /// </summary> /// <param name="output">The output stream.</param> public HclEmitter(TextWriter output) { this.output = output; this.state = EmitterState.Resource; this.resourceTraits = AwsSchema.TraitsAll; }
/// <summary> /// Gets an attribute schema given path to it. /// </summary> /// <param name="path">The path.</param> /// <param name="resourceTraits">Locally maintained traits that can influence the returned schema.</param> /// <returns>A <see cref="ValueSchema"/> for the attribute.</returns> /// <exception cref="System.ArgumentException"> /// Value must be provided - path /// or /// Invalid attribute path \"{path}\" - path /// </exception> /// <exception cref="System.InvalidOperationException"> /// Invalid path \"{path}\": Attribute at \"{GetCurrentPathFromPathStack(processedPath)}\" is not a set or a list. /// or /// Invalid path \"{path}\": Attribute at \"{GetCurrentPathFromPathStack(processedPath)}\" is not a set or a list. /// </exception> /// <exception cref="System.Collections.Generic.KeyNotFoundException"> /// Resource does not contain an attribute \"{currentAttributeName}\". /// or /// Resource does not contain an attribute at\"{path}\". /// </exception> public ValueSchema GetAttributeByPath(string path, IResourceTraits resourceTraits) { if (string.IsNullOrEmpty(path)) { throw new ArgumentException("Value must be provided", nameof(path)); } if (IsListIndexIndicator(path.First().ToString()) || IsListIndexIndicator(path.Last().ToString(), true)) { throw new ArgumentException($"Invalid attribute path \"{path}\"", nameof(path)); } if (path == "id") { // 'id' is not stored in the schema because _everything_ has it return(IdentitySchema); } if (resourceTraits.MissingFromSchema.Contains(path)) { return(MissingFromSchemaValueSchema); } ValueSchema currentAttribute = null; var currentResource = this; var pathComponents = new Queue <string>(AttributePath.Split(path)); var processedPath = new Stack <string>(); while (true) { var currentAttributeName = pathComponents.Dequeue(); if (IsListIndexIndicator(currentAttributeName)) { processedPath.Push(currentAttributeName); continue; } var previousAttribute = currentAttribute; if (previousAttribute != null && previousAttribute.Type != SchemaValueType.TypeObject) { // To get here, the previous attribute must be a set or list if (!IsListIndexIndicator(processedPath.FirstOrDefault())) { throw new InvalidOperationException( $"Invalid path \"{path}\": Attribute at \"{GetCurrentPathFromPathStack()}\" is a set or a list. List indicator ('*', '#' or integer) was expected next in path."); } } if (currentAttributeName == "timeouts") { currentAttribute = TimeoutsSchema; } else { if (!currentResource.Attributes.ContainsKey(currentAttributeName)) { throw CreateKeyNotFoundException(); } currentAttribute = currentResource.Attributes[currentAttributeName]; } processedPath.Push(currentAttributeName); if (pathComponents.Count == 0) { return(currentAttribute); } switch (currentAttribute.Elem) { case ProviderResourceSchema resourceSchema: currentResource = resourceSchema; break; case ValueSchema valueSchema when pathComponents.Count == 1 && currentAttribute.Type == SchemaValueType.TypeMap: return(valueSchema); default: // If Elem is null or contains a value schema, then there are no further path components // below this attribute. throw CreateKeyNotFoundException(); } } KeyNotFoundException CreateKeyNotFoundException() { return(new KeyNotFoundException($"Resource does not contain an attribute at\"{path}\".")); } string GetCurrentPathFromPathStack() { return(string.Join(".", processedPath.Reverse().ToList())); } }
/// <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()); }