{"id":295,"date":"2015-03-16T21:56:33","date_gmt":"2015-03-17T01:56:33","guid":{"rendered":"http:\/\/ryepup.unwashedmeme.com\/blog\/?p=295"},"modified":"2015-03-16T21:56:33","modified_gmt":"2015-03-17T01:56:33","slug":"writing-saltstack-formulas","status":"publish","type":"post","link":"http:\/\/ryepup.unwashedmeme.com\/blog\/2015\/03\/16\/writing-saltstack-formulas\/","title":{"rendered":"writing saltstack formulas"},"content":{"rendered":"<p><a href=\"http:\/\/saltstack.com\/\">SaltStack<\/a> is a great open-source, cross-platform automation system. It lets you configure servers using declarative yaml files and python. You can create custom &#8220;states&#8221; during yaml\/python, and then say &#8220;make server X have state Y&#8221;. There&#8217;s a lot of plumbing involved which I&#8217;m not going to delve into, but it&#8217;s pretty neat stuff and doesn&#8217;t require punching holes in firewalls.<\/p>\n<p><a href=\"http:\/\/saltstack.com\/\">SaltStack<\/a> provides a lot of different mechanisms to re-use configuration, and recently I&#8217;ve been working a lot with <a href=\"http:\/\/docs.saltstack.com\/en\/latest\/topics\/development\/conventions\/formulas.html\">salt formulas<\/a> as a mechanism to create and re-use custom states.<\/p>\n<p>From the docs:<\/p>\n<blockquote><p>\n  Formulas are pre-written Salt States. They are as open-ended as Salt States themselves and can be used for tasks such as installing a package, configuring, and starting a service, setting up users or permissions, and many other common tasks.\n<\/p><\/blockquote>\n<p>These are implemented as a git repository with one formula in it, and then there are a variety of ways to reference a formula. It&#8217;s common to customize the configuration using salt&#8217;s <a href=\"http:\/\/docs.saltstack.com\/en\/latest\/topics\/pillar\/\">pillar<\/a> mechanism (yaml again)<\/p>\n<p>Some thoughts on writing formulas:<\/p>\n<ul>\n<li>the <code>pillar.example<\/code> file should show an in-depth example of what pillar customizations are available<\/li>\n<li>this community has settled on restructured text over markdown<\/li>\n<li><code>map.jinja<\/code> files are used to set defaults and switch options based on OS\n<ul>\n<li>these defaults should match what&#8217;s in <code>pillar.example<\/code>, which is annoying to maintain by hand<\/li>\n<\/ul>\n<\/li>\n<li>there are a million formulas on github, but the nature of salt states lends to writing really opinionated states that are super-specific to one&#8217;s infrastructure. It&#8217;s really hard to make a formula generic enough or sufficiently customizable, unless you&#8217;re doing something so trivial that it&#8217;s likely not worth a formula. There&#8217;s just too many choices that need to be made. For example, a formula to install <a href=\"http:\/\/www.cacti.net\/\">cacti<\/a> has a ton of choices:\n<ul>\n<li>install from source, or from a package manager?<\/li>\n<li>apache or nginx?<\/li>\n<li>any cacti plugins?<\/li>\n<li>which poller, spine or cmd.php?<\/li>\n<li>install the non-free snmp MIBs, or stick with the free (as-in-everything) option?<\/li>\n<\/ul>\n<\/li>\n<li>if you find a repo on github, you should fork it and reference your fork, even if it&#8217;s perfect the way it is. If you reference someone else&#8217;s formula directly, then you might have problems if they make breaking changes, or security issues if someone slips a backdoor into the formula. Each formula is third-party code running (usually as <code>root<\/code>!) on your systems, so you need to be careful to read and understand every formula<\/li>\n<li>I found myself forking an existing formula that&#8217;s close to what I want, and then thoroughly gutting it until it&#8217;s customized for my specific infrastructure. This is due to insufficient configuration options, not sharing my opinions on how to set something up, or being too specific to the creator&#8217;s infrastructure<\/li>\n<li>after writing a formula, it seems like it should be subdivided into many smaller formulas so they each do one thing, but managing dependencies between formulas is an <a href=\"https:\/\/github.com\/saltstack\/salt\/issues\/12179\">open issue<\/a>. If you split it up in a way that feels right, your install instructions get way longer. Instead of &#8220;fork and install my formula and <code>salt-call state.sls my-formula<\/code>&#8220;, it&#8217;s &#8220;fork and install these N formulas, then <code>salt-call<\/code>&#8220;<\/li>\n<li>if you start a formula from scratch, fork the <a href=\"https:\/\/github.com\/saltstack-formulas\/template-formula\">template-formula<\/a><\/li>\n<li><a href=\"http:\/\/jinja.pocoo.org\/\">jinja<\/a> has some powerful abstraction mechanisms via macros and imports. It&#8217;s tempting to write a custom salt module in python, but a lot can be done just right in <a href=\"http:\/\/jinja.pocoo.org\/\">jinja<\/a>. This is a <a href=\"http:\/\/docs.saltstack.com\/en\/latest\/topics\/development\/conventions\/formulas.html#easy-on-the-jinja\">double-edged sword<\/a><\/li>\n<li>there are a ton of helpful examples in the official <a href=\"https:\/\/github.com\/saltstack-formulas\">saltstack-formulas<\/a><\/li>\n<\/ul>\n<p>Happy formulating!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>SaltStack is a great open-source, cross-platform automation system. It lets you configure servers using declarative yaml files and python. You can create custom &#8220;states&#8221; during yaml\/python, and then say &#8220;make server X have state Y&#8221;. There&#8217;s a lot of plumbing involved which I&#8217;m not going to delve into, but it&#8217;s pretty neat stuff and doesn&#8217;t [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,25,49,51,50],"tags":[],"class_list":["post-295","post","type-post","status-publish","format-standard","hentry","category-open-source","category-python","category-ramble","category-saltstack","category-sysadmin"],"_links":{"self":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/295","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/comments?post=295"}],"version-history":[{"count":1,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/295\/revisions"}],"predecessor-version":[{"id":296,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/295\/revisions\/296"}],"wp:attachment":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/media?parent=295"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/categories?post=295"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/tags?post=295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}