terraformpy是一个库和命令行工具,可以使用成熟的python环境来增强terraform配置!
terraformp的Python项目详细描述
地形
terraformpy是一个库和命令行工具,可以使用成熟的python环境来增强terraform配置!
但是,随着定义的增长,hcl语法很快就留下了很多需要改进的地方,而且是不是太冗长了……那么多变量和输出的定义需要重复,一遍又一遍地重复,因为您组成了更多的模块,使用每个模块其他,
由于hcl是"完全兼容json的",python擅长生成json数据,因此我们构建terraformpy是为了提供一个更高效的环境来构建和维护复杂的terraform配置。自2016年以来,它每天都在Nerdwallet的 Nerdwallet 生产中使用,在加快我们整个工程组织对Terraform的采用方面证明非常有价值。
安装TerraFormPy
安装和使用terraformpy的推荐方法是通过pipenv
例如:
$ mkdir my-terraform-project
$ cd my-terraform-project
$ pipenv install --two terraformpy
然后可以使用pipenv run运行terraformpy
$ pipenv run terraformpy ...
或者可以使用pipenv shell激活virtualenv,这样就不需要使用pipenv run。本文档的其余部分假设您已经运行了pipenv shell,并且可以直接运行terraformpy。
使用cli工具
terraformpy 命令行工具用作底层 terraform 工具的填充程序。调用时,它将首先在当前目录中找到所有 *.tf.py 文件,使用 imp 模块加载它们,生成名为 main.tf.json 的文件,然后调用底层工具。
# just replace terraform in your regular workflow terraformpy plan -out=tf.plan # review changes... # apply them! # since we're going to operate on the generated plan here, we don't event need to use terraformpy anymore terraform apply tf.plan
每个 *.tf.py 文件都使用声明性语法,使用从该库导入的对象。您不需要定义主函数,只需在模块的根目录中创建类的实例(匿名的或其他的)(您正在这里构建常规的python代码)。由于您处于一个成熟的python环境中,因此您可以做的事情没有限制—导入内容、连接到数据库等。
正在写入文件
terraformpy的名称空间提供了许多类,它们直接映射到您在normal .tf. 文件中声明的内容。要编写定义,只需导入这些类并开始创建它们的实例。下面是 terraform入门指南中的第一个示例
fromterraformpyimportProvider,ResourceProvider('aws',profile='default',region='us-east-1')Resource('aws_instance','example',ami='ami-2757f631'instance_type='t2.micro')
可以从terraformpy导入的内容
- 提供商
- 变量
- 数据
- 资源
- 输出
有关完整的功能示例,请参见 示例/ 目录。
插值
到目前为止,我们只匿名使用了terraformpy,但是返回的 data 和 resource 类实例提供了方便的插值属性。例如,一个常见的任务是使用 data 类来获取远程数据:
αααα5在这里,我们只需在创建 aws\u实例时引用ami对象的id属性。在编译阶段,它将被转换为正确的语法: "${data.aws\u ami.ecs\u ami.id}"
这是通过在我们的
模块
模块被明确地排除在这个实现之外,因为它们的目标是解决相同的问题——在TerraForm配置中构建可重用的块。
利用python的所有特性,不使用terraform中的本机模块就可以直接构建可重用单元,但是请参阅资源集合(下一页)中的一些帮助程序脚手架!
资源集合
在使用python构建configs时,一个常见的模式是希望在单个对象的伪装下抽象出许多不同的资源,这与本地terraform模块要解决的模式是相同的。在terraformpy中,我们为构建表示多个资源的对象提供了一个资源集合基类。
您可以使用 示意图来定义字段并执行验证。
例如,在配置rds集群时,您可能需要一组标准的选项,这些选项随集群一起提供。您可以通过资源集合来表达这一点:
fromschematicsimporttypesfromschematics.typesimportcompoundfromterraformpyimportResource,ResourceCollectionclassRDSCluster(ResourceCollection):# Defining attributes of your resource collection is like defining a Schematics Model, in fact the# ResourceCollection class is just a specialized subclass of the Schematics Model class.## Each attribute becomes a field on the collection, and can be provided as a keyword when constructing# an instance of your collection.## Validation works the same as in Schematics. You can attach validators to the fields themselves and# also define "validate_field" functions.name=types.StringType(required=True)azs=compound.ListType(types.StringType,required=True)instance_class=types.StringType(required=True,choices=('db.r3.large',...))# The create_resources function is invoked once the instance has been created and the kwargs provided have been# processed against the inputs. All of the instance attributes have been converted to the values provided, so# if you access self.name in create_resources you're accessing whatever value was provided to the instancedefcreate_resources(self):self.param_group=Resource('aws_rds_cluster_parameter_group','{0}_pg'.format(self.name),family='aurora5.6',parameter=[{'name':'character_set_server','value':'utf8'},{'name':'character_set_client','value':'utf8'}])self.cluster=Resource('aws_rds_cluster',self.name,cluster_identifier=self.name,availability_zones=self.azs,database_name=self.name,master_username='root',master_password='password',db_cluster_parameter_group_name=self.param_group.id)self.instances=Resource('aws_rds_cluster_instance','{0}_instances'.format(self.name),count=2,identifier='{0}-${{count.index}}'.format(self.name),cluster_identifier=self.cluster.id,instance_class=self.instance_class)
然后可以导入该定义并在terraformpy配置中使用。
frommodules.rdsimportRDSClustercluster1=RDSCluster(name='cluster1',azs=['us-west-2a','us-west-2b','us-west-2c'],instance_class='db.r3.large')# you can then refer to the resources themselves, for interpolation, through the attrs# i.e. cluster1.cluster.id
变型
存在于许多不同环境中的资源定义通常在每个环境之间仅略有不同。为了便于对这些差异进行定义,您可以使用变体分组。
首先创建文件夹: configs/stage/ , configs/prod/ , configs/shared/ 。在每一个包里放一个初始化包。
接下来创建文件configs/shared/instances.py
fromterraformpyimportResourceResource('aws_instance','example',ami=ami.id,prod_variant=dict(instance_type='m4.xlarge'),stage_variant=dict(instance_type='t2.medium'))
然后创建configs/stage/main.tf.py
fromterraformpyimportVariantwithVariant('stage'):importconfigs.shared.instances
由于实例文件的导入是在variant上下文中进行的,因此资源将被创建,就好像它被定义为:
$ mkdir my-terraform-project
$ cd my-terraform-project
$ pipenv install --two terraformpy
0
多个提供商
根据您对terraform的使用情况,您可能最终需要在某个时间点使用多个提供者。要使用terraform中的多个提供者,请使用别名定义它们,然后在资源定义中引用这些别名。
为了简化此模式,您可以将terraformpy provider 对象用作上下文管理器,然后在上下文中创建的任何资源都将自动引用该提供程序别名:
$ mkdir my-terraform-project
$ cd my-terraform-project
$ pipenv install --two terraformpy
1
使用文件内容
通常情况下,您会希望包含位于python代码旁边的文件的内容,但是当运行terraform和插值函数路径时,将与编译后的主文件所在的位置而不是python代码所在的位置相关。
为了帮助解决这种情况,在terraformpy.helpers中提供了一个名为 relative_file 的函数。
$ mkdir my-terraform-project
$ cd my-terraform-project
$ pipenv install --two terraformpy
2
这将产生一个定义,该定义利用 ${file(…)} 插值函数和一个从定义角色的python代码所在的同一目录读取 role\u policy.json 文件的路径。