Beispiel #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Scalar"/> class.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="isQuoted">if set to <c>true</c> [is quoted].</param>
        public Scalar(object value, bool isQuoted)
        {
            this.IsQuoted = isQuoted;

            switch (value)
            {
            case null:
                return;

            // ReSharper disable once AssignNullToNotNullAttribute - typeof an existing type cannot be null
            case string s when s.StartsWith(typeof(Reference).Namespace):
            {
                // Re-hydrate a smuggled in "Reference" type.
                var split     = s.Split(':');
                var type      = Assembly.GetCallingAssembly().GetType(split[0]);
                var reference = (Reference)Activator.CreateInstance(type, split[1]);
                this.Value    = reference.ReferenceExpression;
                this.IsQuoted = false;
                return;
            }

            case bool _:

                this.Value    = value.ToString().ToLowerInvariant();
                this.IsQuoted = false;
                break;

            default:
            {
                this.Value = value.ToString();

                if (string.IsNullOrWhiteSpace(this.Value))
                {
                    return;
                }

                this.IsJsonDocument = StateFileSerializer.TryGetJson(
                    this.Value,
                    false,
                    "Unknown",
                    "Unknown",
                    out var document);

                if (this.IsJsonDocument)
                {
                    this.JsonDocumentType = document.Type;
                }

                break;
            }
            }
        }
Beispiel #2
0
        public void ShouldSerializeResource(string stateFile)
        {
            this.output.WriteLine($"Serialize {stateFile}");
            var state = JsonConvert.DeserializeObject <StateFile>(
                (string)ResourceLoader.GetStringResource(ResourceLoader.GetResourceStream(stateFile, ThisAssembly)));

            using var sw = new StringWriter();

            var events = new List <HclEvent>();

            var emitter    = new he(sw);
            var serializer = new StateFileSerializer(emitter);

            var action = new Action(() => serializer.Serialize(state));

            action.Should().NotThrow <HclSerializerException>();

            this.fixture.Validate(sw.ToString(), new TestLogger(this.output)).Should().BeTrue();
        }
Beispiel #3
0
            /// <summary>
            /// Visits a string value in the JSON object graph.
            /// Look to see if this matches the evaluation of any CloudFormation intrinsic
            /// and generate a <see cref="StateModification"/> where a match is found.
            /// </summary>
            /// <param name="jsonValue">A JValue of type string.</param>
            /// <param name="context">The visitor context.</param>
            protected override void VisitString(JValue jsonValue, TerraformAttributeSetterContext context)
            {
                if (context.IsComputedValue(GetParentPropertyPath(jsonValue)))
                {
                    // Don't adjust computed attributes
                    return;
                }

                var stringValue = jsonValue.Value <string>();

                if (StateFileSerializer.TryGetJson(
                        stringValue,
                        false,
                        context.Resource.Name,
                        context.Resource.Type,
                        out var document))
                {
                    try
                    {
                        context.EnterNestedJson((JProperty)jsonValue.Parent);

                        // Build a new visitor to visit the nested JSON document
                        document.Accept(new TerraformAttributeSetterVisitor(), context);
                    }
                    finally
                    {
                        context.ExitNestedJson();
                    }

                    return;
                }

                var intrinsicInfo = context.IntrinsicInfos.FirstOrDefault(i => i.Evaluation.ToString() == stringValue);

                if (intrinsicInfo == null)
                {
                    // No intrinsic evaluation matches this JValue
                    return;
                }

                CreateModification(jsonValue, context, intrinsicInfo);
            }
        /// <summary>
        /// Resolves the dependencies for the given terraform resource.
        /// </summary>
        /// <param name="terraformStateFileResource">The current terraform resource from state file.</param>
        public void ResolveResourceDependencies(StateFileResourceDeclaration terraformStateFileResource)
        {
            try
            {
                var referenceLocations = new List <IntrinsicInfo>();

                // Get CF resource for the current state file resource entry
                this.currentCloudFormationResource =
                    this.settings.Resources.First(r => r.LogicalResourceId == terraformStateFileResource.Name);

                // Find related resources that may be merged into this one
                var relatedResources = this.template.DependencyGraph.Edges.Where(
                    e => e.Source.Name == this.currentCloudFormationResource.LogicalResourceId &&
                    e.Target.TemplateObject is IResource res &&
                    TerraformExporterConstants.MergedResources.Contains(res.Type))
                                       .Select(e => (IResource)e.Target.TemplateObject);

                foreach (var cloudFormationResource in new[] { this.currentCloudFormationResource.TemplateResource }
                         .Concat(relatedResources))
                {
                    // Visit the CF resource gathering all intrinsics that might imply reference to another resource or input
                    var intrinsicVisitorContext = new IntrinsicVisitorContext(
                        this.settings,
                        this.terraformResources,
                        this.module.Inputs,
                        cloudFormationResource,
                        this.warnings,
                        this.module);

                    var intrinsicVisitor = new IntrinsicVisitor(this.template);
                    cloudFormationResource.Accept(intrinsicVisitor, intrinsicVisitorContext);

                    referenceLocations.AddRange(intrinsicVisitorContext.ReferenceLocations);
                }

                // Visit the terraform resource finding value matches between resource attributes and intrinsic evaluations, recording what needs to be modified
                var dependencyContext = new TerraformAttributeSetterContext(
                    referenceLocations,
                    this.template,
                    terraformStateFileResource,
                    this.module.Inputs);

                terraformStateFileResource.ResourceInstance.Attributes.Accept(
                    new TerraformAttributeSetterVisitor(),
                    dependencyContext);

                // For each found modification, update attribute value with JSON encoded reference expression or string interpolation.
                foreach (var modification in dependencyContext.Modifications.Where(m => m.Reference != null))
                {
                    if (modification.ContainingProperty == null)
                    {
                        // Normal resource attribute
                        ApplyResourceAttributeReference(
                            terraformStateFileResource.ResourceInstance.Attributes.SelectToken(
                                modification.ValueToReplace.Path),
                            modification);
                    }
                    else
                    {
                        // Modification lies within nested JSON, e.g. a policy document.
                        // First, deserialize the nested JSON - which will work because we already did it once.
                        StateFileSerializer.TryGetJson(
                            modification.ContainingProperty.Value.Value <string>(),
                            false,
                            terraformStateFileResource.Name,
                            terraformStateFileResource.Type,
                            out var document);

                        ApplyResourceAttributeReference(
                            document.SelectToken(modification.ValueToReplace.Path),
                            modification);

                        // Now put back the nested JSON complete with added reference
                        var enc = document.ToString(Formatting.None);
                        modification.ContainingProperty.Value = enc;
                    }
                }
            }
            catch (HclSerializerException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new HclSerializerException(
                          $"Internal error: {e.Message}",
                          terraformStateFileResource.Name,
                          terraformStateFileResource.Type,
                          e);
            }
        }