当前位置: 首页 > 科技观察

4行代码来改进您的Ansible剧本

时间:2023-03-18 14:12:07 科技观察

稍加努力,您不仅可以帮助下一个人绘制安全路径,还可以留下危险警告。随着博客圈对基础设施即代码、持续集成/持续交付(CI/CD)管道、代码审查和测试制度的所有赞誉,人们很容易忘记这座精心设计的象牙塔只是一个理想,而不是现实。虽然不完善的系统困扰着我们,但我们必须提供一些东西。在系统自动化的过程中,很少有塔比那些通过粘合API创建的象牙塔更脆弱。这是一个脆弱的世界。让它“工作”、交付它并继续前进的压力很大。待解决的问题想象一个简单的功能请求:编写一些Ansible代码在外部系统中创建一些记录来记录VLAN的一些细节。我最近很想做一些实验室管理工作来完成这个任务。这个外部系统是一个常见的互联网协议地址管理(IPAM)工具,但对于一个更抽象的配置管理数据库(CMDB)或一个网络无关的记录来说,难度是一样的。在这个例子中,我创建记录的直接愿望是让系统保存记录。如果我们的目标是一个超紧凑、直接、笨重的宏,它可能可以用100行代码编写。如果我记得API,我可能可以在一个小时内将其敲出,代码并没有超出预期,只留下完全一样的成品。完美地实现了它的目的,但对未来的扩展毫无用处。这些天来,我希望几乎每个人都以一个角色和几个任务文件开始这项任务,准备扩展到十几个创建、读取、更新和删除(CRUD)操作。由于我不了解API,因此我可能会花费数小时甚至数天的时间摆弄它,弄清楚它的内部模式和工艺,弥合其功能与我编写代码的意图之间的差距。在研究API时,我发现创建VLAN记录需要一个父对象引用vlan_view_ref。这看起来像是一个带有随机字符的路径片段。也许它是一个散列,也许它真的是随机的,我不确定。我猜很多人在泥泞中挣扎,迫在眉睫的最后期限,可能将这个任意字符串复制粘贴到Ansible中并继续前进。忽略这个角色角色的实现细节,很明显这个脚本的剧本级任务应该是这样的:-name:"CreateVLAN"include_role:name:otherthingtasks_from:vlan_create.ymlvars:vlan_name:"lab-infra"vlan_tag:100vlan_view_ref:"vlan_view/747f602d-0381"不幸的是,vlan_view_ref标识符不可用,除非通过API,因此即使将它移动到清单文件或额外的变量也无济于事。剧本的用户需要对系统有更深入的了解才能找出正确的参考ID。在实验室构建的情况下,我会经常重新部署这个记录系统。因此,这个父对象引用ID每天都在变化,我不想每次都必须手动查找它。所以,我肯定是在按名称搜索该参考资料。没问题:-name:GetLabvlanviewreferenceinclude_role:name:otherthingtasks_from:search_for.ymlvars:_resource:vlan_view_query:"name={{vlan_parent_view_name}}"最后,它进行REST调用。这“返回”一个JSON,我按照惯例将其填充到_otherthing_search_result中,以便在角色之外轻松访问。search_for.yml的实现是抽象的,它总是返回一个包含零个或多个结果的字典。正如我读过的几乎所有真实世界的Ansible代码所证明的那样,大多数Ansible开发人员会继续进行,就好像一切都很好,并且可以直接访问预期的单一结果:-name:Rememberourdefaultvlanviewrefset_fact:_thatthig_vlan_view_ref:"{{_otherthing_search_result[0]._ref}}"-name:"CreateVLAN"include_role:name:otherthingtasks_from:vlan_create.ymlvars:vlan_name:"lab-infra"vlan_tag:100vlan_view_ref:"{{vlan_parent_view_name}}"但有时_otherthing_search_result[0]未定义,因此_thatthig_vlan_view_ref也未定义。很可能是因为代码在不同的真实环境中运行,并且有人忘记在清单或命令行中更新{{vlan_parent_view_name}}。或者,无论公平与否,也许有人进入该工具的GUI并删除了记录或更改了它的名称或其他内容。我知道你在想什么。“嗯,别这样,这是没有笨蛋的场地,别那么笨。”。也许我对这种情况很好,反驳道:“Ansible会非常正确地告诉你错误:列表对象没有元素0,甚至有行号。你还想要什么?”作为开发人员,我当然知道这句话的意思——我刚刚写的代码。我刚刚结束与API的三天较量,我的头脑很清醒。明天又是另外一回事了,但是到明天,我可能会忘记父对象引用是什么,我肯定会忘记第30行的内容。如果一个月后出现问题,即使你能找到我,我也会有花一个下午重新阅读API指南以找出问题所在。如果我出去怎么办?如果我将代码交给一个运维团队,也许是一个实习生通过Tower运行它,手动将vlan_view_name输入到表格或其他东西中怎么办?第30行的问题对他们没有帮助。你说,加注解!嗯,是。我可以在代码中写一些草图来帮助下周或下个月的开发人员。这对运行代码的人没有帮助,他们的“工作”刚刚失败,当然对业务也没有帮助。请记住,我们现在是无所不能的。我们在写代码或者跳写代码的时候,都是站在实力和知识的立场上的。我们花了几个小时,甚至几天,研究文档、现实、其他错误、其他问题,我们留下了代码、评论,甚至可能是文档。我们写代码是为了分享成功,而成功是我们的用户想要的。但是这样的学习也有很多失败的地方,那些也可以不去管。在代码中留下“第30行有错误”对任何人都没有帮助。至少,我可以用更好的错误消息来处理明显的错误情况:-名称:如果返回零个vlan视图失败则失败:消息:“从搜索VLAN视图{{vlan_parent_view_name}}中获得0个结果。请验证其他内容是否存在,并且是可通过服务帐户访问。”时间:_otherthing_search_result|length==0在这四行代码中(没有额外考虑),我为下一个人——那个无助的Ops团队成员,或者更可能是一个月后的我——留下了具体的、有用的建议——这是关于现实世界的问题,而不是真的关于代码。如果有人发现了一个简单的复制/粘贴错误,或者日志系统发生了变化,那么这条消息可能会引起注意。无需了解Ansible,无需在凌晨3点给开发人员发短信“查看第30行”。可是等等!还有更多!在学习其他东西的过程中,我了解到它在一个关键方面有点愚蠢。它的许多记录类型(如果不是全部)没有唯一性约束,并且可能存在多个相同的记录。VLAN视图被定义为具有名称、开始ID和结束ID;其他记录类型同样简单,显然这应该是一个唯一的元组——基于现实和数据库规范化的抽象。但是其他一些东西允许重复的元组,尽管从概念上讲这是不可能的。在我的实验室里,我很乐意尝试并记住不要这样做。在企业生产环境中,我可能会写一个策略。无论哪种方式,经验告诉我,系统会被打破,它们会在经济不景气时被打破,而且这些问题可能需要很长时间才能演变成一个问题。对于“第30行错误”,经验丰富的Ansible开发人员可能会认识到它是“未找到记录”并且不知道其他任何足以解决问题的方法。但是,如果_otherthing_search_result[0]只是有时是正确的vlan_view_ref,那就更糟了,它会让整个世界无声无息地崩溃。并且该错误可能完全在其他地方出现,也许六个月后的安全审计会将其标记为不一致的记录保存,并且通过多种工具和人工访问,可能需要数天或数周才能发现这个特定的代码错误的事实.我在研究API的几天里了解到了这一点。我不是在寻找问题,如果它被记录在案,我就看不到它。所以我来到这篇文章的重点。我没有因为这是一个实验室而忽略不可能性,修复它,然后继续前进,而是花了两分钟时间离开_code_——不是评论,不是心理笔记,不是文档——而是始终运行的代码,涵盖了这个不可能的情况:-名称:如果>1个视图返回失败,则失败:消息:“从搜索VLAN视图{{vlan_parent_view_name}}得到{{_otherthing_search_result|length}}结果。其他允许这样做,但此代码不处理。”时间:_otherthing_search_result|length>1我手动创建了失败条件,因此我可以手动测试该条件。我希望它永远不会在实际使用中起作用,但我认为它会起作用。如果(何时)在生产中发生此错误,有人可以决定该怎么做。我希望他们修复坏数据。如果它经常发生,我希望他们能追踪到另一个损坏的系统。如果他们要求删除这段代码,而这段代码做了未定义和错误的事情,那是他们的特权,那是我不想工作的地方。代码并不完美,但它是完整的。这是工匠的作品。现实世界中的自动化是一个迭代过程,它与不完美的系统作斗争并平等地使用它们。它从不处理所有特殊情况。它甚至可能无法处理所有正常情况。通过lint、代码审查和验收测试的工作代码是处理安全和所需路径的代码。稍加努力,您不仅可以绘制安全路径,还可以留下您发现的危险警告,从而帮助下一个人。