如何从Terraform中的文件加载输入数据?

时间:2019-08-12 00:42:54

标签: terraform

我在Terraform中定义了一个f[a_, b_] := a*b; g[c_, d_, e_] := c*e[c, d]; g[3, 5, f] (* 45 *) ,以将事件从import UIKit class NoBreakSectionCollectionViewLayout: UICollectionViewLayout { var cachedItemAttributes = [IndexPath: UICollectionViewLayoutAttributes]() var cachedContentSize = CGSize.zero override func prepare() { super.prepare() calculateAttributes() } override func invalidateLayout() { super.invalidateLayout() cachedItemAttributes = [:] calculateAttributes() } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { return cachedItemAttributes[indexPath] } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { return cachedItemAttributes.filter { rect.intersects($0.value.frame) }.map { $0.value } } override var collectionViewContentSize: CGSize { return cachedContentSize } func calculateAttributes() { var y = CGFloat(0) var x = CGFloat(0) var lastHeight = CGFloat(0) let xSpacing = CGFloat(5) let ySpacing = CGFloat(2) if let collectionView = collectionView, let datasource = collectionView.dataSource, let sizeDelegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout { let sections = datasource.numberOfSections?(in: collectionView) ?? 1 for section in 0..<sections { for item in 0..<datasource.collectionView(collectionView, numberOfItemsInSection: section){ let indexPath = IndexPath(item: item, section: section) let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) if let size = sizeDelegate.collectionView?(collectionView, layout: self, sizeForItemAt: indexPath) { if x > 0 && (x + size.width + xSpacing) > collectionView.bounds.width { y += size.height + ySpacing x = CGFloat(0) } attributes.frame = CGRect(x: x, y: y, width: size.width, height: size.height) lastHeight = size.height x += size.width + xSpacing } cachedItemAttributes[indexPath] = attributes } } cachedContentSize = CGSize(width: collectionView.bounds.width, height: y + lastHeight) } } } 发射到lambda。 aws_cloudwatch_event_target字段是事件参数,例如:

cloudwatch

我想知道如何从外部文件加载input json数据。

3 个答案:

答案 0 :(得分:4)

这里的答案取决于几个不同的问题:

  • 此文件是配置的静态部分,还是与.tf文件一起签入版本控制,还是在应用过程中动态生成?
  • 您要直接使用文件内容,还是需要从Terraform配置中的其他位置替换值?

这两个问题构成了四个不同答案的矩阵:

             |  Literal Content            Include Values from Elsewhere
-------------|----------------------------------------------------------
Static File  |  file(...) function         templatefile(...) function
Dynamic File |  local_file data source     template_file data source

我将在下面更详细地描述这四个选项。

在所有这些示例中,一个共同的主题是对path.module的引用,该变量的计算结果是从中加载当前模块的路径。另一种考虑方式是它是包含当前.tf文件的目录。允许访问其他目录中的文件 ,但是在大多数情况下,通过将数据文件和配置文件保持在一起,使模块中的内容保持独立是适当的。

Terraform字符串是Unicode字符序列,因此Terraform只能读取包含有效UTF-8编码文本的文件。对于JSON来说,这没问题,但要记住其他通常不是UTF-8编码的文件格式。

file函数

The file function从磁盘读取文件的文字内容,作为对配置进行初始评估的一部分。为了验证目的,将文件的内容视为是文字字符串值,因此文件必须作为配置的静态部分存在于磁盘上(通常在版本控制中)。 ,而不是在terraform apply期间动态生成。

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = file("${path.module}/input.json")
}

这是最常见和最简单的选项。如果file功能足以满足您的需求,那么最好将其用作默认选项。

templatefile函数

The templatefile functionfile函数类似,但是它不只是按字面意义返回文件内容,而是将文件内容解析为a string template,然后使用一组局部变量对其进行求值在第二个参数中给出。如果您需要从Terraform配置中的其他地方传递一些数据,这将很有用,如以下示例所示:

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = templatefile("${path.module}/input.json.tmpl", {
    instance_id = aws_instance.example.id
  })
}

input.json.tmpl中,您可以使用Terraform模板语法替换该变量值:

{"instance_id":${jsonencode(instance_id)}}

在这样的情况下,整个 result 是JSON,我建议只使用jsonencode生成整个结果,因为这样您就可以让Terraform担心JSON的转义,等等。只需使用Terraform的对象语法编写数据结构:

${jsonencode({
  instance_id = instance_id
})}

file一样,由于templatefile是一个函数,因此在配置的初始解码期间会对其进行评估,并将其结果验证为文字值。因此,模板文件还必须是作为配置的一部分分发的静态文件,而不是动态生成的文件。

local_file数据源

Data sources是特殊的资源类型,用于读取现有对象或计算结果,而不是创建和管理新对象。因为它们是资源,所以它们可以参与依赖关系图,从而可以利用在terraform apply期间由同一Terraform配置中的其他资源创建的对象(包括本地文件)。

The local_file data source属于the local provider,本质上是与file函数等效的数据源。

在以下示例中,我使用var.input_file作为占位符,以引用由相同配置中的其他资源创建的文件路径。在一个真实的示例中,最有可能直接引用资源的属性。

data "local_file" "input" {
  filename = var.input_file
}

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = data.local_file.input.content
}

template_file数据源

The template_file data source是等效于templatefile函数的数据源。它的用法类似于local_file,尽管在这种情况下,我们根据模板是否使用来使用file函数或local_file来将模板读取为静态文件,从而填充模板本身位于静态文件或动态生成的文件中,尽管如果它是静态文件,我们希望使用templatefile函数,因此我们将在此处使用local_file数据源:

data "local_file" "input_template" {
  filename = var.input_template_file
}

data "template_file" "input" {
  template = data.local_file.input_template.content
  vars = {
    instance_id = aws_instance.example.id
  }
}

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = data.template_file.input.rendered
}

templatefile函数是在Terraform 0.12.0中添加的,因此您可能会在其他地方看到使用template_file数据源呈现静态模板文件的示例。这是一个旧模式,现在在Terraform 0.12中已弃用,因为在大多数情况下,templatefile函数使配置更加直接和可读。

template_file函数相对,templatefile数据源的一个怪癖是该数据源属于the template provider而不是Terraform Core,因此,哪些模板功能可用于它取决于安装的提供程序版本,而不是安装的Terraform CLI版本。 template提供程序在可用模板语言功能方面可能会落后于Terraform Core,这是在可能的情况下更喜欢templatefile函数的另一个原因。

其他可能性

这个问题专门用于从文件中读取数据,但出于完整性考虑,我还想指出,对于小型JSON有效负载,有时最好将其直接内联为Terraform数据结构,并以{ {3}},就像这样:

resource "aws_cloudwatch_event_target" "data" {
  rule      = aws_cloudwatch_event_rule.scheduler.name
  target_id = "finance_producer_cloudwatch"
  arn       = aws_lambda_function.finance_data_producer.arn
  input     = jsonencode({
    instance_id = aws_instance.example.id
  })
}

将数据结构作为Terraform表达式内联编写意味着将来的读者可以直接看到将要发送的内容,而无需引用单独的文件。但是,如果数据结构非常庞大和复杂,则内联包含它会损害整体可读性,因为它可能使同一文件中的其他配置不堪重负。

因此,选择哪个选项在很大程度上取决于特定的情况,但始终值得考虑的是,单独文件的间接访问是否是可读性最好的选择。

Terraform还具有jsonencode(在撰写本文时进行实验),可以直接在.tf文件内部或外部模板的插值序列中对YAML格式的数据结构进行类似的处理。

答案 1 :(得分:0)

您可以使用file() operator从外部文件中提取数据:

input = "${file("myjson.json")}"

只需确保myjson.json与其余Terraform文件位于同一目录的磁盘上。

答案 2 :(得分:0)

我将使用数据template_file资源。像这样...

data "template_file" "my_file" {
  template = "${file("${path.module}/my_file.json")}"
  vars = {
    var_to_use_in_file = "${var.my_value}"
  }
}

然后在您的资源块中。...

resource "aws_cloudwatch_event_target" "data" {
  rule      = "${aws_cloudwatch_event_rule.scheduler.name}"
  target_id = "finance_producer_cloudwatch"
  arn       = "${aws_lambda_function.finance_data_producer.arn}"
  input     = "${data.template_file.my_file.rendered}"
}