在这里,我们将给大家分享关于Terraform:从variables.tf到Vault如何使用Vault解决Terraform中的for_each的知识,让您更了解tf.trainable_varia
在这里,我们将给大家分享关于Terraform:从variables.tf到Vault如何使用Vault解决Terraform中的for_each的知识,让您更了解tf.trainable_variables的本质,同时也会涉及到如何更有效地angular – FormArray TypeError:value.forEach不是函数、angular – 如何在动态formArray下的formGroup中的控件上观察valueChanges、Module 让 Terraform 使用更简单、py-libterraform 的使用和实现:一个 Terraform 的 Python 绑定的内容。
本文目录一览:- Terraform:从variables.tf到Vault如何使用Vault解决Terraform中的for_each(tf.trainable_variables)
- angular – FormArray TypeError:value.forEach不是函数
- angular – 如何在动态formArray下的formGroup中的控件上观察valueChanges
- Module 让 Terraform 使用更简单
- py-libterraform 的使用和实现:一个 Terraform 的 Python 绑定
Terraform:从variables.tf到Vault如何使用Vault解决Terraform中的for_each(tf.trainable_variables)
如何解决Terraform:从variables.tf到Vault如何使用Vault解决Terraform中的for_each?
我有一个terraform代码(带有terraform v0.12.21),该代码在基础架构方面构建一个GKE和Cloudsql,在部署方面,在GKE内部署N个Web服务器容器。
在variables.tf文件中,我定义了一个“ wordpress_site”数组。
如今,当需要进行新的部署时,我只需在“默认”中添加一个新项目,并使用terraform apply
完成部署。
variables.tf包含以下内容:
variable "wordpress_site" {
type = map(object({
name = string
url = string
disk = string
MysqL_passwd = string
api_token = string
api_key = string
api_country = string
api_language = string
api_wp_lang = string
api_colour = string
template = string
}))
default = {
example1 = {
name = "example1"
url = "example1.com"
disk = "1Gi"
MysqL_passwd = "PaSSwOrd1"
api_token = "TokenHERE"
api_key = "APIHere"
api_country = "it"
api_language = "it"
api_wp_lang = "it_IT"
api_colour = "1"
template = "p1"
}
example2 = {
name = "example2"
url = "example2.com"
disk = "1Gi"
MysqL_passwd = "PaSSwOrd2"
api_token = "TokenHERE"
api_key = "APIHere"
api_country = "uk"
api_language = "en"
api_wp_lang = "en_US"
api_colour = "1"
template = "p1"
}
...
...
...
exampleN = {
name = "exampleN"
url = "exampleN.com"
disk = "1Gi"
MysqL_passwd = "PaSSwOrdN"
api_token = "TokenHERE"
api_key = "APIHere"
api_country = "uk"
api_language = "en"
api_wp_lang = "en_US"
api_colour = "1"
template = "p1"
}
}
然后,当我调用它们进行部署时,我正在使用for_each函数和each.value.XXX来获取其变量:
resource "kubernetes_deployment" "wordpress" {
for_each = var.wordpress_site
Metadata {
name = each.value.name
labels = {
app = each.value.name
app-function = "wordpress"
}
}
...
...
}
好吧,让Vault作为terraform的提供者,所以在main.tf中,我将添加新的提供者,例如:
provider "vault" {
address = "http://XXX.YYY.ZZZ.TTT:8200"
}
并在调用terraform应用之前制作一个vault login
,但是,由于我要部署3000多个WordPress网站,因此我希望将它们全部定义在Vault存储中并通过Vault引擎进行组织,但是进行这些更改的最佳方式是什么?
还有,如何将它们全部放入保险柜?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)
angular – FormArray TypeError:value.forEach不是函数
“EXCEPTION:Uncaught(承诺):TypeError:value.forEach不是函数
TypeError:value.forEach不是FormArray.setValue中的函数“
组件类:
jobDetails: FormGroup; techFormArray: FormArray; constructor(private formBuilder: FormBuilder){ this.techFormArray = new FormArray([ new FormControl(''),new FormControl(''),new FormControl('') ]); this.jobDetails = this.formBuilder.group({ techs: this.formBuilder.array([]) }); this.jobDetails.setValue({ techs: this.techFormArray }); }
HTML:
<form [formGroup]="jobDetails"> <div formArrayName="techs" > <divhttps://www.jb51.cc/tag/dis/" target="_blank">display: flex; flex-direction: column"> <div *ngFor="let tech of techFormArray.controls; let i=index"> <md-checkBox [formControlName]="i"> {{i}} </md-checkBox> </div> </div> </div> </form>
解:
FunStuff没错,我无法使用setValue ….所以我删除了它.问题解决了哈哈.我改变了一些事情,我不确定我做了什么,它基本上是蛮力的试验和错误几个小时,但后来它工作了!
总结
以上是小编为你收集整理的angular – FormArray TypeError:value.forEach不是函数全部内容。
如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。
angular – 如何在动态formArray下的formGroup中的控件上观察valueChanges
我已经构建了一个formArray of formGroups of variants,如下面的 HTML所示.
<form [formGroup]="this.purchaseInvoiceItemVariantsForm" novalidate> <div formArrayName="variants"> <div *ngFor="let variant of this.purchaseInvoiceItemVariantsForm.controls.variants.controls; let i = index"> <div [formGroupName]="i"> <md-input-container> <input mdInput placeholder="Product Code" formControlName="productBarcode"[readonly]="this.mode == 'view'"> </md-input-container> <md-input-container> <input mdInput placeholder="Color" formControlName="variant1"[readonly]="this.mode == 'view'" required> </md-input-container> <md-input-container> <input mdInput placeholder="Size" formControlName="variant2"[readonly]="this.mode == 'view'" required> </md-input-container> <md-input-container> <input mdInput placeholder="MRP" formControlName="mrp"[readonly]="this.mode == 'view'"> </md-input-container> <md-input-container> <input mdInput placeholder="Purchase Price" formControlName="purchasePrice"[readonly]="this.mode == 'view'" required> </md-input-container> <md-input-container> <input mdInput placeholder="Sell Price" formControlName="sellPrice"[readonly]="this.mode == 'view'" required> </md-input-container> <md-input-container> <input mdInput placeholder="Quantity" formControlName="variantQuantity"[readonly]="this.mode == 'view'" required> </md-input-container> <md-input-container> <input mdInput placeholder="discount" formControlName="variantdiscount"[readonly]="this.mode == 'view'"> </md-input-container> <button md-icon-button (click)="removeVariant(i)" color="warn" *ngIf="purchaseInvoiceItemVariantsForm.controls.variants.length > 1 && this.mode != 'view'"><md-icon>delete</md-icon></button> </div> </div>
现在,一旦用户添加了3个变体,我希望能够监听formControl“productBarcode”的valueChanges,以便我可以从数据库中获取颜色和大小细节.
有什么建议可以实现吗?
提前致谢!
问候,
纳文
解决方法
一个例子:
ngDoCheck() { if (this.arraOfItems.length > 3) { // Do stuff } }
在你的课堂上你应该实现DoCheck,如下所示:
export class myClass implements OnInit,DoCheck {}
这样,如果您设法将项目添加到数组中,请说:arraOfItems.然后它会工作.
文档:https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#docheck
另一种方法:
在向arraOfItems添加项目的逻辑中,进行检查并添加逻辑,例如:
addingItemToArray(item) { this.arraOfItems.push(item); if (this.arraOfItems.length > 3) { // do stuff } }
此示例认为您创建了一个将项添加到数组的additionItemToArray方法.在它的逻辑中你可以放一个控制来检查数组的长度,如果你添加了超过3个项目,那么你可以做任何你想做的事情.
Module 让 Terraform 使用更简单
众所周知,Terraform 是一个开源的自动化的资源编排工具,支持多家云服务提供商。阿里云作为第三大云服务提供商,terraform-alicloud-provider 已经支持了超过 90 多个 Resource 和 Data Source,覆盖20多个服务和产品,吸引了越来越多的开发者加入到阿里云Terraform生态的建设中。
随着 Resource 和 DataSource 的不断增加和完善,业务架构的不断发展,Terraform 模板编写的成本和复杂度也在不断的增加。如何让Terraform 模板更加简单和重用,就是本文所要解决的问题。
本文将通过一个典型的负载均衡架构,向大家介绍如何使用 Module 简化 Terraform 的模板。
如图所示,这个架构中,包含 ECS 实例,SLB 实例,RDS 实例,OSS 等资源和服务,同时所有的 ECS,RDS 和部分 SLB 在一个 VPC 网络环境中。
将所有Resource放在一个模板中进行统一管理
面对这样的一个架构,模板可以有多种写法。通常的写法是将架构中涉及到的所有资源写到一个模板中,并通过参数和关系型 resource 将这些资源关联起来,如下所示:
这样写的好处是,所有资源都在一个模板中管理,编写时可以很清楚了解资源之间的引用关系;但是,当资源不断增加时,扩展非常不灵活,资源间关系越复杂,模板越难以维护。
分类管理,目录作为单元化资源
从架构图和上文模板中不难看出,并不是所有的Resource都有直接关联关系,比如VPC只和VSwitch和SecurityGroup有关,与其他资源的创建无直接关联关系。因此,为了使整个架构的逻辑可以更加清楚的展示在模板中,我们可以考虑,对资源进行分类,将每一类资源用一个单独的目录进行管理,最后用一个模板来管理所有的目录,进而完成对所有资源及资源关系的串联,如下所示:
将该架构中的资源分为网络(VPC),负载均衡(SLB),计算(ECS),数据库(RDS)和存储(OSS)这几类,然后将上文模板中的资源分别在对应的目录中予以实现。
接下来,用统一的模版main.tf将这些目录关联起来,如下所示:
可以看出,main.tf中资源的结构更加清楚,更加接近于架构图。
同时,大家已经注意到了,main.tf引入了一个 module,通过module将资源目录串联起来。
什么是Module
Module 是 Terraform 为了管理单元化资源而设计的,是子节点,子资源,子架构模板的整合和抽象。正如本文架构中提到的,在实际复杂的技术架构中,涉及到的资源多种多样,资源与资源之间的关系错综复杂,资源模版的编写,扩展,维护等多个问题的成本都会不断增加。将多种可以复用的资源定义为一个module,通过对 module 的管理简化模板的架构,降低模板管理的复杂度,这就是module的作用。
除此之外,对开发者和用户而言,只需关心 module 的 input 参数即可,无需关心module中资源的定义,参数,语法等细节问题,抽出更多的时间和精力投入到架构设计和资源关系整合上。
开源Module,使其更完善,更分享,更便捷
上文中,虽然已经实现了module,但是这个module只能在自己本地机器上实现,无法实现与他人的实时分享,无法实现团队内部的及时共享。
Terraform 提供了 Module 的注册地址,将自己的module上传到Github,并注册为一个Terraform Module后,即可将远端的Module应用到我们自己的模板中。
利用开源 module,我们可对上文中的模板进行完善:
Module 让资源模板架构更清楚,模板管理更简单;开源 Module 让资源模板更便捷,更分享。除此之外,开源 Module 可实现对模板的版本控制,基于不同的版本,实现不同架构不断升级的控制和完善。
欢迎加入 Terraform AliCloud Modules
目前我们已经在在 Terraform Module 上发布了一些常用的 Module,但这些 Module 远远无法满足大家多种多样的技术架构和复杂的应用场景,非常欢迎大家可以将自己的模板Module注册到官方 Module 上,借助社区的力量,不断完善自己模板,丰富我们的社区。
本文作者:箫竹aron
阅读原文
本文为云栖社区原创内容,未经允许不得转载。
py-libterraform 的使用和实现:一个 Terraform 的 Python 绑定
在某个使用 Python 开发的业务中,涉及到 Terraform 的交互,具体有两个需求:
- 需要调用 Terraform 的各种命令,以完成对资源的部署、销毁等操作
- 需要解析 Terraform 配置文件(HCL 语法)的内容,分析里面的组成
对于前者,有一个名为 python-terraform 的开源库,它封装了 Terraform 的命令,当我们在代码中调用时,背后会新启一个进程执行 Terraform 的对应命令,并能返回命令退出码和捕获的stdout和 stderr。python-terraform用起来虽然方便,但最大的缺点在于要求执行环境事先安装了 Terraform,而且新启进程也带来了额外的开销。
对于后者,尚未找到 Python 开源库能满足要求。
我希望能有一个库无需用户事先安装 Terraform,能在当前进程执行 Terraform 命令,而且还能解析 Terraform 配置文件,py-libterraform 就这样诞生了。
使用
在说明 py-libterraform 的实现原理之前,不妨先看看是如何安装和使用的。
它的安装十分简单,执行 pip 命令即可,支持 Mac、Linux和Windows,并支持 Python3.6 及以上版本:
$ pip install libterraform
py-libterraform 目前提供两个功能:TerraformCommand 用于执行 Terraform CLI,TerraformConfig 用于解析 Terraform 配置文件。后文将通过示例介绍这两个功能。假定当前有一个 sleep 文件夹,里面的 main.tf 文件内容如下:
variable "time1" {
type = string
default = "1s"
}
variable "time2" {
type = string
default = "1s"
}
resource "time_sleep" "wait1" {
create_duration = var.time1
}
resource "time_sleep" "wait2" {
create_duration = var.time2
}
output "wait1_id" {
value = time_sleep.wait1.id
}
output "wait2_id" {
value = time_sleep.wait2.id
}
▌Terraform CLI
现在进入 sleep 目录,需要对它执行 Terraform init, apply 和 show,以部署资源并查看资源属性,那么可以这么做:
>>> from libterraform import TerraformCommand
>>> cli = TerraformCommand()
>>> cli.init()
<CommandResult retcode=0 json=False>
>>> _.value
''\nInitializing the backend...\n\nInitializing provider plugins...\n- Reusing previous version of hashicorp/time from the dependency lock file\n- Using previously-installed hashicorp/time v0.7.2\n\nTerraform has been successfully initialized!\n\nYou may now begin working with Terraform. Try running "terraform plan" to see\nany changes that are required for your infrastructure. All Terraform commands\nshould now work.\n\nIf you ever set or change modules or backend configuration for Terraform,\nrerun this command to reinitialize your working directory. If you forget, other\ncommands will detect it and remind you to do so if necessary.\n''
>>> cli.apply()
<CommandResult retcode=0 json=True>
>>> _.value
[{''@level'': ''info'', ''@message'': ''Terraform 1.1.7'', ''@module'': ''terraform.ui'', ''@timestamp'': ''2022-04-08T19:16:59.984727+08:00'', ''terraform'': ''1.1.7'', ''type'': ''version'', ''ui'': ''1.0''}, ... ]
>>> cli.show()
<CommandResult retcode=0 json=True>
>>> _.value
{''format_version'': ''1.0'', ''terraform_version'': ''1.1.7'', ''values'': {''outputs'': {''wait1_id'': {''sensitive'': False, ''value'': ''2022-04-08T11:17:01Z''}, ''wait2_id'': {''sensitive'': False, ''value'': ''2022-04-08T11:17:01Z''}}, ''root_module'': {''resources'': [{''address'': ''time_sleep.wait1'', ''mode'': ''managed'', ''type'': ''time_sleep'', ''name'': ''wait1'', ''provider_name'': ''registry.terraform.io/hashicorp/time'', ''schema_version'': 0, ''values'': {''create_duration'': ''1s'', ''destroy_duration'': None, ''id'': ''2022-04-08T11:17:01Z'', ''triggers'': None}, ''sensitive_values'': {}}, {''address'': ''time_sleep.wait2'', ''mode'': ''managed'', ''type'': ''time_sleep'', ''name'': ''wait2'', ''provider_name'': ''registry.terraform.io/hashicorp/time'', ''schema_version'': 0, ''values'': {''create_duration'': ''1s'', ''destroy_duration'': None, ''id'': ''2022-04-08T11:17:01Z'', ''triggers'': None}, ''sensitive_values'': {}}]}}}
从上述执行过程可以看出,不论执行什么命令,都会返回一个 CommandResult 对象,用来表示命令执行结果(包含返回码、输出、错误输出、是否为 json 结构)。其中:
- init() 返回的 value 是 Terraform init 命令的标准输出,一个字符串
- apply() 返回的 value 默认是 Terraform apply -json 命令的标准输出被视作 json 加载后的数据,一个展示日志记录的列表。如果不希望解析标准输出,则可以使用 apply(json=False)
- show() 返回的 value 默认是 Terraform show -jon 命令的标准输出被视作 json 加载后的数据,一个展示 Terraform state 文件数据结构的字典
所有命令的封装函数的思路是尽可能让结果方便给程序处理,因此对于支持 -json 的 Terraform 命令都会默认使用此选项并对结果进行解析。
以上是一个简单的示例,实际上 TerraformCommand 封装了所有的 Terraform 命令,具体可以调用 help(TerraformCommand) 进行查看。
▌Terraform 配置文件解析
如果希望拿到 Terraform 对配置文件的解析结果做进一步处理,那么 TerraformConfig 就可以满足需求,通过它可以解析指定的 Terraform 配置目录,获取其中的变量、资源、输出、行号等信息,这对分析配置组成很有帮助。可以这么做(部分输出较多使用...做了省略):
>>> from libterraform import TerraformConfig
>>> mod, _ = TerraformConfig.load_config_dir(''.'')
>>> mod
{''SourceDir'': ''.'', ''CoreVersionConstraints'': None, ''ActiveExperiments'': {}, ''Backend'': None, ''CloudConfig'': None, ''ProviderConfigs'': None, ''ProviderRequirements'': {''RequiredProviders'': {}, ''DeclRange'': ...}, ''Variables'': {''time1'': ..., ''time2'': ...}, ''Locals'': {}, ''Outputs'': {''wait1_id'': ..., ''wait2_id'': ...}, ''ModuleCalls'': {}, ''ManagedResources'': {''time_sleep.wait1'': ..., ''time_sleep.wait2'': ...}, ''DataResources'': {}, ''Moved'': None}
TerraformConfig.load_config_dir 背后会调用 Terraform 源码中 internal/configs/parser_config_dir.go 中的 LoadConfigDir 方法,以加载 Terraform 配置文件目录,返回内容是原生返回结果 *Module, hcl.Diagnostics 的经序列化后分别加载为 Python 中的字典。
实现原理
由于 Terraform 是用 GoLang 编写的,Python 无法直接调用,但好在它可以编译为动态链接库,然后再被 Python 加载调用。因此,总体思路上可以这么做:
- 使用 cgo 编写 Terraform 的 C 接口文件
- 将它编译为动态链接库,Linux/Unix 上以 .so 结尾,在 Windows 上以 .dll 结尾
- 在 Python 中通过 ctypes 加载此动态链接库,在此之上实现命令封装
本质上,GoLang 和 Python 之间以 C 作为媒介,完成交互。关于如何使用 cgo 和 ctypes 网上有很多文章,本文着重介绍实现过程中遇到的各种“坑”以及如何解决的。
▌坑 1:GoLang 的 internal packages 机制阻隔了外部调用
GoLang 从 1.4 版本开始,增加了 Internal packages 机制,只允许 internal 的父级目录及父级目录的子包导入,其它包无法导入。而 Terraform 最新版本中,几乎所有的代码都放在了 internal 中,这意味着使用 cgo 写的接口文件(本项目中叫 libterraform.go)如果作为外部包(比如包名叫 libterraform)是无法调用 Terraform 代码的,也就无法实现 Terraform 命令的封装。
一个解决方法是把 Terraform 中的 internal 改为 public,但这意味着需要修改大量的 Terraform 源码,这可不是个好主意。
那么另一个思路就是让 libterraform.go 作为整个 Terraform 项目的“一份子”,来“欺骗” Go 编译器。具体过程如下:
- libterraform.go 的包名和 Terraform 主包保持一致,即 main
- 构建前把 libterraform.go 移动到 Terraform 源码根目录下,作为 Terraform 项目的成员
- 构建时,使用 go build -buildmode=c-shared -o=libterraform.so github.com/hashicorp/terraform 命令进行编译,这样编译出的动态链接库就能包含 libterraform.go 的逻辑
▌坑 2:注意管理 C 运行时申请的内存空间
不论是 GoLang 还是 Python,我们都不需要担心内存管理的问题,因为它们自会被语言的垃圾回收机制在合适的时机去回收。但是涉及到 C 的逻辑就需要各位注意内存管理了。使用 cgo 中定义的接口中可能会返回 *C.char,它实际是 C 层面上开辟的一段内存空间,需要被显式释放。例如,libterraform.go 中定义了加载 Terraform 配置目录的方法 ConfigLoadConfigDir,其实现如下:
//export ConfigLoadConfigDir
func ConfigLoadConfigDir(cPath *C.char) (cMod *C.char, cDiags *C.char, cError *C.char) {
defer func() {
recover()
}()
parser := configs.NewParser(nil)
path := C.GoString(cPath)
mod, diags := parser.LoadConfigDir(path)
modBytes, err := json.Marshal(convertModule(mod))
if err != nil {
cMod = C.CString("")
cDiags = C.CString("")
cError = C.CString(err.Error())
return cMod, cDiags, cError
}
diagsBytes, err := json.Marshal(diags)
if err != nil {
cMod = C.CString(string(modBytes))
cDiags = C.CString("")
cError = C.CString(err.Error())
return cMod, cDiags, cError
}
cMod = C.CString(string(modBytes))
cDiags = C.CString(string(diagsBytes))
cError = C.CString("")
return cMod, cDiags, cError
}
上述方法实现中,使用 C.CString 会在 C 层面上申请了一段内存空间,并返回结果返回给调用者,那么调用者(Python 进程)需要在使用完返回值之后显式释放内存。
在此之前,需要先通过 cgo 暴露释放内存的方法:
//export Free
func Free(cString *int) {
C.free(unsafe.Pointer(cString))
}
然后,在 Python 中就可以实现如下封装:
import os
from ctypes import cdll, c_void_p
from libterraform.common import WINDOWS
class LoadConfigDirResult(Structure):
_fields_ = [("r0", c_void_p),
("r1", c_void_p),
("r2", c_void_p)]
_load_config_dir = _lib_tf.ConfigLoadConfigDir
_load_config_dir.argtypes = [c_char_p]
_load_config_dir.restype = LoadConfigDirResult
root = os.path.dirname(os.path.abspath(__file__))
_lib_filename = ''libterraform.dll'' if WINDOWS else ''libterraform.so''
_lib_tf = cdll.LoadLibrary(os.path.join(root, _lib_filename))
_free = _lib_tf.Free
_free.argtypes = [c_void_p]
def load_config_dir(path: str) -> (dict, dict):
ret = _load_config_dir(path.encode(''utf-8''))
r_mod = cast(ret.r0, c_char_p).value
_free(ret.r0)
r_diags = cast(ret.r1, c_char_p).value
_free(ret.r1)
err = cast(ret.r2, c_char_p).value
_free(ret.r2)
...
这里,在获取到返回结果后,调用 _free (也就是 libterraform.go 中的 Free)来显式释放内存,从而避免内存泄露。
▌坑 3:捕获输出
在 Terraform 的源码中,执行命令的输出会打印到标准输出 stdout 和标准错误输出 stderr 上,那么使用 cgo 封装出 RunCli 的接口,并被 Python 调用时,默认情况下就直接输出到 stdout 和 stderr 上了。
这会有什么问题呢?如果同时执行两个命令,输出结果会交错,没法区分这些结果是哪个命令的结果。
解决思路就是使用管道:
- 在 Python 进程中使用 os.pipe 分别创建用于标准输出和标准错误输出的管道(会生成文件描述符)
- 将两个文件描述符传入到 libterraform.go 的 RunCli 方法中,在内部使用 os.NewFile 打开两个文件描述符,并分别替换 os.Stdout 和 os.Stderr
- 在 RunCli 方法结束时关闭这两个文件,并恢复原始的 os.Stdout 和 os.Stderr
此外,使用 os.pipe 获取到的文件描述符给 libterraform.go 使用时要注意操作系统的不同:
- 对于 Linux/Unix 来说,直接传进去使用即可
- 对于 Windows 来说,需要额外将文件描述符转换成文件句柄,这是因为在 Windows 上 GoLang 的 os.NewFile 接收的是文件句柄
Python 中相关代码如下:
if WINDOWS:
import msvcrt
w_stdout_handle = msvcrt.get_osfhandle(w_stdout_fd)
w_stderr_handle = msvcrt.get_osfhandle(w_stderr_fd)
retcode = _run_cli(argc, c_argv, w_stdout_handle, w_stderr_handle)
else:
retcode = _run_cli(argc, c_argv, w_stdout_fd, w_stderr_fd)
▌坑 4:管道 Hang
由于管道的大小有限制,如果写入超过了限制就会导致写 Hang。因此不能在调用 RunCli (即会把命令输出写入管道)之后去管道中读取输出,否则会发现在执行简单命令(如version)时正常,在执行复杂命令(如apply,因为有大量输出)时会 Hang 住。
解决思路就是在调用 RunCli 前就启动两个线程分别读取标准输出和标准错误输出的文件描述符内容,在调用 RunCli 命令之后去 join 这两个线程。Python 中相关代码如下:
r_stdout_fd, w_stdout_fd = os.pipe()
r_stderr_fd, w_stderr_fd = os.pipe()
stdout_buffer = []
stderr_buffer = []
stdout_thread = Thread(target=cls._fdread, args=(r_stdout_fd, stdout_buffer))
stdout_thread.daemon = True
stdout_thread.start()
stderr_thread = Thread(target=cls._fdread, args=(r_stderr_fd, stderr_buffer))
stderr_thread.daemon = True
stderr_thread.start()
if WINDOWS:
import msvcrt
w_stdout_handle = msvcrt.get_osfhandle(w_stdout_fd)
w_stderr_handle = msvcrt.get_osfhandle(w_stderr_fd)
retcode = _run_cli(argc, c_argv, w_stdout_handle, w_stderr_handle)
else:
retcode = _run_cli(argc, c_argv, w_stdout_fd, w_stderr_fd)
stdout_thread.join()
stderr_thread.join()
if not stdout_buffer:
raise TerraformFdReadError(fd=r_stdout_fd)
if not stderr_buffer:
raise TerraformFdReadError(fd=r_stderr_fd)
stdout = stdout_buffer[0]
stderr = stderr_buffer[0]
总结
当发现现有的开源库满足不了需求时,手撸了 py-libterraform,基本实现了在单进程中调用 Terraform 命令的要求。尽管在开发过程中遇到了各种问题,并需要不断在 Python、GoLang、C 之间跳转,但好在一个个解决了,记录此过程若能让大家少“踩坑”也算值啦!
参考资料
python-terraform:
https://github.com/beelit94/p...
py-libterraform:
https://github.com/Prodesire/...
微软最有价值专家(MVP)
微软最有价值专家是微软公司授予第三方技术专业人士的一个全球奖项。29年来,世界各地的技术社区领导者,因其在线上和线下的技术社区中分享专业知识和经验而获得此奖项。
MVP是经过严格挑选的专家团队,他们代表着技术最精湛且最具智慧的人,是对社区投入极大的热情并乐于助人的专家。MVP致力于通过演讲、论坛问答、创建网站、撰写博客、分享视频、开源项目、组织会议等方式来帮助他人,并最大程度地帮助微软技术社区用户使用 Microsoft 技术。
更多详情请登录官方网站
扫码关注微软中国MSDN,获取更多前沿技术资讯和学习内容!
今天关于Terraform:从variables.tf到Vault如何使用Vault解决Terraform中的for_each和tf.trainable_variables的介绍到此结束,谢谢您的阅读,有关angular – FormArray TypeError:value.forEach不是函数、angular – 如何在动态formArray下的formGroup中的控件上观察valueChanges、Module 让 Terraform 使用更简单、py-libterraform 的使用和实现:一个 Terraform 的 Python 绑定等更多相关知识的信息可以在本站进行查询。
本文标签: