{"id":8276,"date":"2020-01-03T23:07:07","date_gmt":"2020-01-03T23:07:07","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=8276"},"modified":"2022-11-27T20:25:39","modified_gmt":"2022-11-27T20:25:39","slug":"understanding-a-chef-cookbook-anatomy-with-example","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/understanding-a-chef-cookbook-anatomy-with-example\/","title":{"rendered":"Chef Tutorials: Understanding a Chef Cookbook Anatomy with Example"},"content":{"rendered":"\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.devopsschool.com\/blog\/understand-the-chefignore-file\/\">Understanding the chef cookbook&#8217;s chefignore file<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.devopsschool.com\/blog\/berkshelf-in-chef-explained\/\">Understanding the chef cookbook&#8217;s Berkshelf file<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.devopsschool.com\/blog\/what-is-the-significance-of-the-default-directory-under-chef-cookbook-templates\/\">What is the significance of the default directory under chef cookbook \/templates?<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.devopsschool.com\/blog\/chef-documenting-cookbooks-automatically\/\">Understanding the chef cookbook&#8217;s README file<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.devopsschool.com\/blog\/know-about-metadata-rb-and-metadata-json-in-chef\/\">Understanding the chef cookbook&#8217;s metadata.rb and metadata.json file<\/a><\/li>\n<\/ul>\n\n\n\n<p>Following Reference Has been taken out from this <a href=\"https:\/\/www.thegeekstuff.com\/2016\/06\/chef-cookbook-directory-structure\/\" target=\"_blank\" rel=\"noopener\">url <\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Attributes<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Sometimes you might use hard-coded values (for example, directory name, filename, username, etc.) at multiple locations inside your recipes. Later when you want to change this value, it becomes a tedious process, as you have to browse through all the recipes that contains this value and change them accordingly.<\/li>\n\n\n\n<li>Instead, you can define the hard-code value as variable inside an attribute file, and use the attribute name inside the recipe. This way when you want to change the value, you are changing only at one place in the attribute file.<\/li>\n\n\n\n<li>These are the different attribute types available: default, force_default, normal, override, force_override, automatic<\/li>\n\n\n\n<li>Inside your cookbook, for most situations, you\u2019ll be using the default attribute type.<\/li>\n\n\n\n<li>The following is a sample attribute file, where I\u2019ve defined mysql related hard-coded values that I need to eventually use in multiple recipes. In this example, the attribute file was created under ~\/chef-repo\/cookbooks\/thegeekstuff\/attributes directory.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">default<\/span>&#91;<span class=\"hljs-string\">'mysql'<\/span>]&#91;<span class=\"hljs-string\">'dir'<\/span>] = <span class=\"hljs-string\">'\/data\/mysql'<\/span>\n<span class=\"hljs-keyword\">default<\/span>&#91;<span class=\"hljs-string\">'mysql'<\/span>]&#91;<span class=\"hljs-string\">'username'<\/span>] = <span class=\"hljs-string\">'dbadmin'<\/span>\n<span class=\"hljs-keyword\">default<\/span>&#91;<span class=\"hljs-string\">'mysql'<\/span>]&#91;<span class=\"hljs-string\">'dbname'<\/span>] = \u2018devdb\u2019<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Resources<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You\u2019ll see the resources directory only from Chef 12.5 version and above.<\/li>\n\n\n\n<li>Chef provides several built in resources for you to use. For example, using chef\u2019s built-in resource you can manage packages, services, files, directories on your system.<\/li>\n\n\n\n<li>But, if you have a complex requirement that is specific to your application or tool, you can create your own custom resource, and place them under the resources directory. Once you place your custom resource under this directory, you can use them in your recipes just like how you would use any other chef\u2019s build-in recipes.<\/li>\n\n\n\n<li>The following is a simple custom resource example. This file was created under ~\/chef-repo\/cookbooks\/thegeekstuff\/resources directory.<\/li>\n\n\n\n<li>There are three parts to this example: 1) Declare custom properties in the beginning 2) Load current property values 3) Create action blocks for this custom resource.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">property :myapp_name, String, <span class=\"hljs-keyword\">default<\/span>: <span class=\"hljs-string\">'Default Name for My App'<\/span>\n\nload_current_value <span class=\"hljs-keyword\">do<\/span>\n  <span class=\"hljs-comment\"># write code to load the current value for your properties<\/span>\nend\n\naction :create <span class=\"hljs-keyword\">do<\/span>\n  file <span class=\"hljs-string\">'\/home\/tomcat\/myapp\/config.cfg'<\/span> <span class=\"hljs-keyword\">do<\/span>\n    content <span class=\"hljs-string\">'location=west'<\/span>\n  end\n  <span class=\"hljs-comment\"># Write additional code to define other aspects of your app creation<\/span>\nend\n\naction :delete <span class=\"hljs-keyword\">do<\/span>\n  <span class=\"hljs-comment\">#write code to delete your application<\/span>\nend <\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Definition<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If you are using chef-client 12.5 or above, Chef recommends that you don\u2019t use definitions anymore, and use the custom resources (which is explained above). Definition might be deprecated in future version.<\/li>\n\n\n\n<li>Definition is similar to a compile-time macros that can be used in multiple recipes.<\/li>\n\n\n\n<li>Definitions are processed when the resources are compiled, and these are not same as resources as definition don\u2019t support properties like only_if, not_if, etc.<\/li>\n\n\n\n<li>The following is a simple definition example. In this example, app_config is the definition resource name. This definition file was created under ~\/chef-repo\/cookbooks\/thegeekstuff\/definitions directory.<\/li>\n\n\n\n<li><\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">define :app_config <span class=\"hljs-keyword\">do<\/span>\n  file <span class=\"hljs-string\">'\/home\/tomcat\/myapp\/config.cfg'<\/span> <span class=\"hljs-keyword\">do<\/span>\n    content <span class=\"hljs-string\">'location=west'<\/span>\n  end\nend<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Files<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If you want certain files to be copied over to all your remote nodes as part of Chef deployment, you can copy those files over to \u201cfiles\u201d directory under your cookbook.<\/li>\n\n\n\n<li>A particular file that is located under the files directory can be copied over to one or more remote nodes using cookbook_file resource.<\/li>\n\n\n\n<li>In the following example, I want to copy the dblogin.php file to the remote server. In this case, I might create a recipe using cookbook_file resource as shown below.<\/li>\n\n\n\n<li>First, make sure you copy the file mentioned in the source property (i.e dblogin.php) in the following recipe to your ~\/chef-repo\/cookbooks\/{your-cookbook-name}\/files directory.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">cookbook_file <span class=\"hljs-string\">'\/home\/tomcat\/myapp\/login\/dblogin.php'<\/span> <span class=\"hljs-keyword\">do<\/span>\n  source <span class=\"hljs-string\">'dblogin.php'<\/span>\n  owner <span class=\"hljs-string\">'tomcat'<\/span>\n  group <span class=\"hljs-string\">'tomcat'<\/span>\n  mode <span class=\"hljs-string\">'0755'<\/span>\n  <span class=\"hljs-attr\">action<\/span> :create\nend<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Libraries<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>All custom library files that you create for a specific cookbook should be placed under the \u201clibraries\u201d directory.<\/li>\n\n\n\n<li>Library files should be written in ruby language.<\/li>\n\n\n\n<li>You can write a library code that can either change the behavior of some of the existing chef functionality, or to create a new functionality that is not currently satisfied by any of the existing chef resources.<\/li>\n\n\n\n<li>Basically you\u2019ll use libraries to create a custom chef resource that will solve some specific problem based on your requirement.<\/li>\n\n\n\n<li>You can start a brand new library without extending an existing library by simply starting your library code (for example: MyCustomLibrary) with this line at the beginning: class MyCustomLibrary<\/li>\n\n\n\n<li>If you are existing an existing Chef functionality, you should extend those appropriate Chef classes. In the following example, we are extending Chef database resource. This is just the first few lines of a custom library code that shows how you start the library file definition.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">class<\/span> <span class=\"hljs-selector-tag\">Chef<\/span>\n  <span class=\"hljs-selector-tag\">class<\/span> <span class=\"hljs-selector-tag\">Resource<\/span>\n    <span class=\"hljs-selector-tag\">class<\/span> <span class=\"hljs-selector-tag\">MyDBResource<\/span> &lt; <span class=\"hljs-selector-tag\">Chef<\/span><span class=\"hljs-selector-pseudo\">::Resource<\/span><span class=\"hljs-selector-pseudo\">::Database<\/span>\n..<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Providers<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>All the providers that you write for your particular custom requirement should go under providers directory.<\/li>\n\n\n\n<li>You\u2019ll use custom providers when you want to inform chef-client how to manage a specific action. You can define multiple actions for your custom provider, and inform chef-client how to manage those actions.<\/li>\n\n\n\n<li>You\u2019ll typically use custom provider when you are using LWRP (lightweight resource providers), in which case, you\u2019ll first define a custom resource with your own set of actions, and then you\u2019ll write custom providers, where you\u2019ll write ruby code to tell chef-client what exactly needs to be done for those actions.<\/li>\n\n\n\n<li>For example, a custom provider ( dbcluster.rb ) file located under \u201cproviders\u201d directory might have few custom actions defined as shown below.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">action :check <span class=\"hljs-keyword\">do<\/span>\n..\nend\n\n<span class=\"hljs-attr\">action<\/span> :setmaster <span class=\"hljs-keyword\">do<\/span>\n..\nend<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Recipes<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Chef recipe is the heart and soul of Chef functionality. This is where you\u2019ll specify all configurations and setups that you want to be executed on your remote servers (nodes).<\/li>\n\n\n\n<li>Recipe are written in Ruby language. Recipe will be stored inside a cookbook.<\/li>\n\n\n\n<li>You can have multiple recipes (which is recommended for complex system configuration) inside one cookbook.<\/li>\n\n\n\n<li>You can also include an existing recipe in your current recipe. This way you can create a new recipe that is dependent on another recipe.<\/li>\n\n\n\n<li>In simple terms, recipes are bunch of Chef resources that you\u2019ll call to setup a configuration. For every resource that you include in your recipe, you can specify what actions from that resource you want to be executed, and you can also set appropriate attribute values, etc.<\/li>\n\n\n\n<li>You can also write your own custom logic using Ruby inside the Chef recipe for a specific resources that you are calling.<\/li>\n\n\n\n<li>Everything that you write inside a recipe is executed sequentially.<\/li>\n\n\n\n<li>When you have multiple recipes inside a cookbook, the order in which these recipes will be executed can be specified using a run-list.<\/li>\n\n\n\n<li>The following is a simple recipe example file ( mysetup.rb ) that can be placed under \u201crecipes\u201d directory which will install the given packages and start the httpd services on a remote node where this recipe is executed.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">package &#91;\u2018httpd\u2019, <span class=\"hljs-string\">'gcc'<\/span>, <span class=\"hljs-string\">'gcc-c++'<\/span>, <span class=\"hljs-string\">'nfs-utils'<\/span>] <span class=\"hljs-keyword\">do<\/span>\n  <span class=\"hljs-attr\">action<\/span> :install\nend\n\nservice <span class=\"hljs-string\">'httpd'<\/span> <span class=\"hljs-keyword\">do<\/span>\n  action &#91;:enable, :start]\nend<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Templates<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Template is similar to files, but the major difference is that using template we can dynamically generate static text files.<\/li>\n\n\n\n<li>Inside template we can have ruby programming language statements, which can then be used to generate some content dynamically.<\/li>\n\n\n\n<li>Chef templates are just an ERB, which is embedded ruby template.<\/li>\n\n\n\n<li>To use a template, first create the template files using ERB and place it under the \u201ctemplates\u201d directory.<\/li>\n\n\n\n<li>Also, inside the cookbook recipe we should use template resource to call our template.<\/li>\n\n\n\n<li>For example, place the following index.html.erb template file under ~\/chef-repo\/cookbooks\/{your-cookbook-name}\/templates\/default\/ directory.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Hello world on <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">%=<\/span> <span class=\"hljs-attr\">node<\/span>&#91;<span class=\"hljs-attr\">:fqdn<\/span>] %&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Cookbook Doc Files<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When you create cookbook, it creates these two documentation files the top-level of your cookbook directory: 1) README.md 2) CHANGELOG.md<\/li>\n\n\n\n<li>Maintaining these two files are very important when multiple people are working on your cookbook.<\/li>\n\n\n\n<li>The first file README.md is where you\u2019ll document everything about your cookbook. By default, when a cookbook is created, it already gives an excellent template inside the README.md file for you to start your documentation.<\/li>\n\n\n\n<li>Once you\u2019ve deployed a cookbook on production, as a best practice, any changes that you make to your cookbook after that should have a updated new version number. Inside the CHANGELOG.md file, you\u2019ll document specifically what changes were done in each and every version of your cookbook.<\/li>\n\n\n\n<li>Both README.md and CHANGELOG.md file uses the Markdown template format.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Cookbook Metadata File<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>As the name suggests, metadata.rb file is used to store certain metadata information about your cookbook. This metadata.rb file is located at the top-level of the cookbook directory. I.e ~\/chef-repo\/cookbooks\/{your-cookbook-name}\/metadata.rb<\/li>\n\n\n\n<li>The information inside the metadata file is used by the chef server to make sure it deploys the correct cookbook versions on the individual remote nodes.<\/li>\n\n\n\n<li>When you upload your cookbook to the Chef server, the metadata file is compiled and stored in the Chef server as JSON file.<\/li>\n\n\n\n<li>By default when you create a cookbook using knife command, it generates the metadata.rb file.<\/li>\n\n\n\n<li>There are certain metadata parameters that you can use inside this file. For example, you can specify the current version number of your cookbook. You can also specify which chef-client versions will be supported by this cookbook, etc. The following example shows a partial metadata.rb file.<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">name <span class=\"hljs-string\">'devdb'<\/span>\nmaintainer_email <span class=\"hljs-string\">'ramesh@thegeekstuff.com'<\/span>\ndescription <span class=\"hljs-string\">'Setup the Development DB server'<\/span>\nversion <span class=\"hljs-string\">'2.5.1'<\/span>\nchef_version <span class=\"hljs-string\">\"&gt;= 12.9\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div class=\"epyt-gallery\" data-currpage=\"1\" id=\"epyt_gallery_36293\"><figure class=\"wp-block-embed wp-block-embed-youtube is-type-video is-provider-youtube epyt-figure\"><div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\"  id=\"_ytid_92869\"  width=\"760\" height=\"427\"  data-origwidth=\"760\" data-origheight=\"427\" src=\"https:\/\/www.youtube.com\/embed\/?enablejsapi=1&#038;autoplay=0&#038;cc_load_policy=0&#038;cc_lang_pref=&#038;iv_load_policy=1&#038;loop=0&#038;rel=1&#038;fs=1&#038;playsinline=0&#038;autohide=2&#038;theme=dark&#038;color=red&#038;controls=1&#038;disablekb=0&#038;\" class=\"__youtube_prefs__  no-lazyload\" title=\"YouTube player\"  data-epytgalleryid=\"epyt_gallery_36293\"  allow=\"fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen data-no-lazy=\"1\" data-skipgform_ajax_framebjll=\"\"><\/iframe><\/div><\/figure><div class=\"epyt-gallery-list\"><div>Sorry, there was a YouTube error.<\/div><\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>Following Reference Has been taken out from this url Attributes Resources Definition Files Libraries Providers Recipes Templates Cookbook Doc Files Cookbook Metadata File<\/p>\n","protected":false},"author":1,"featured_media":8311,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_joinchat":[],"footnotes":""},"categories":[88],"tags":[5604,407,1050,519,213],"class_list":["post-8276","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-chef","tag-anatomy","tag-chef","tag-cookbooks","tag-example","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/8276","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=8276"}],"version-history":[{"count":4,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/8276\/revisions"}],"predecessor-version":[{"id":31948,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/8276\/revisions\/31948"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/8311"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=8276"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=8276"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=8276"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}