Sagar's Bloghttps://sagargiri.com/2025-01-20T19:30:00+09:00<pre>$ cd /pub && more beer</pre>I transferred my domain to cloudflare2025-01-20T19:30:00+09:002025-01-20T19:30:00+09:00Sagar Giritag:sagargiri.com,2025-01-20:/i-transferred-my-domain-to-cloudflare<p>I transferred my domain to cloudflare</p><p>The domain <code>sagargiri.com</code> was registered with <code>namecheap.com</code> and I was using <code>namecheap.com</code>'s nameservers to manage the domain. I decided to transfer the domain to <code>cloudflare.com</code> for better security and performance.</p> <p>I followed the steps mentioned in this YouTube Video</p> <iframe width="560" height="315" src="https://www.youtube.com/embed/zkA1oZz3GUo?si=7HqhxEf9QKhB9ir4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> <p>Following above steps to the tee, I successfully transferred the domain to <code>cloudflare.com</code>.</p>Three-step guide to set up custom domain for your github.io pages2021-11-27T23:08:00+09:002021-11-27T23:08:00+09:00Sagar Giritag:sagargiri.com,2021-11-27:/custom-domain-for-github-pages<p>In this blog post , I will show you how to set up custom domain for any github.io pages.</p><blockquote> <p>Assumption: For this tutorial, I am assuming you already have bought a domain name from any domain name provider and you already have a github.io pages setup like this <a href="https://girisagar46.github.io">girisagar46.github.io</a>. Also in this post, I'm using <a href="https://www.namecheap.com">namecheap</a> and setting up Apex domain name.</p> </blockquote> <p>This blog is hosted in <a href="https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages">GitHub pages</a>. When you visit <a href="https://sagargiri.com">sagargiri.com</a>, the web pages that you see are actually hosted in github.io, and you can see the source code of this blog <a href="https://github.com/girisagar46/girisagar46.github.io/">here</a>. But, how does my domain <code>sagargiri.com</code> is pointing to <code>girisagar46.github.io</code> ? How do we configure such settings? All of these questions are answered in this blog post.</p> <h2>Step-by-step guide to use custom domain for github.io pages</h2> <h3>Step 1: Buy the domain name.</h3> <p>If you do not have a domain name yet, you can use any of the domain name providers. For example, you can use <a href="https://www.namecheap.com">namecheap</a>, <a href="https://www.godaddy.com">godaddy</a> or <a href="https://domains.google">domains.google</a>. I bought mine from <a href="https://www.namecheap.com">namecheap</a> during black friday sale.</p> <p>Now that you have bought the domain name, you need to set up the DNS records. Which we'll do in second step.</p> <h3>Step 2: Set up DNS records.</h3> <p>In your domain name provider page you'll have an option to set up DNS records. In the case of namecheap, you'll first have to click the <code>MANAGE</code> button in the <code>Domain List</code> page as shown in screenshot below.</p> <p><img alt="image" src="../images/setup-domain-github-pages/manage.png"></p> <p>Then click the <code>Advanced DNS</code> button as shown in screenshot below.</p> <p><img alt="image" src="../images/setup-domain-github-pages/advanced-dns.png"></p> <p>In the <code>HOST RECORDS</code> section, you need to add the following DNS records as shown in screenshot below.</p> <p><img alt="image" src="../images/setup-domain-github-pages/host-record.png"></p> <p>Here are the IP addresses list for <code>A</code> record for you to copy and paste.</p> <div class="highlight"><pre><span></span><code><span class="mf">185.199.108.153</span> <span class="mf">185.199.109.153</span> <span class="mf">185.199.110.153</span> <span class="mf">185.199.111.153</span> </code></pre></div> <p>Also DO NOT forget to add the <code>CNAME</code> record as shown in screenshot. You need to add your own github.io domain name.</p> <p>Once you have added the DNS records, you can now go to your GitHub page settings to actually map the CNAME.</p> <h3>Step 3. Configure your USERNAME.github.io page settings</h3> <p>Go to your github.io repository settings and click on the <code>Settings</code> button and then click on the <code>Pages</code> button as shown in screenshot below.</p> <p><img alt="image" src="../images/setup-domain-github-pages/github-settings.png"></p> <p>This will lead you to the GitHub.io settings for GitHub pages.</p> <p>In the <code>Pages</code> section, you need to add the following domain name as shown in screenshot below.</p> <p><img alt="image" src="../images/setup-domain-github-pages/custom-domain.png"></p> <p>This will commit a new file called <code>CNAME</code> to your github.io repository. You can verify that later on. Also do not forget to check the <code>Enforce HTTPS</code> checkbox. This will provide you SSL certificate for your domain name. Once you see the green tick mark in your domain name in the <code>Pages</code> section, you're good tpo go.</p> <p>But, be aware that the DNS propagation takes some time. Take rest, drink a cup of coffee, browse other articles in this website and wait for a while.</p> <p>After some time, you can visit your domain name, and you will see the github.io pages are mapped to your domain name.</p> <p>You can also verify all this is working using the <code>dig</code> command</p> <div class="highlight"><pre><span></span><code>╰─$ dig sagargiri.com +noall +answer -t A ; &lt;&lt;&gt;&gt; DiG 9.10.6 &lt;&lt;&gt;&gt; sagargiri.com +noall +answer -t A ;; global options: +cmd sagargiri.com. 1799 IN A 185.199.109.153 sagargiri.com. 1799 IN A 185.199.110.153 sagargiri.com. 1799 IN A 185.199.111.153 sagargiri.com. 1799 IN A 185.199.108.153 </code></pre></div> <p>Here you can see that my domain is pointing to the A records that we have set up in the Step 2.</p> <p>References:</p> <p><a href="https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages">https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages</a> <a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site">https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site</a></p>Tools and technology I use for my day-to-day work2021-07-17T13:17:00+09:002021-07-17T13:17:00+09:00Sagar Giritag:sagargiri.com,2021-07-17:/tools-and-technology-i-use-for-my-day-to-day-work<p>In this blog post, I'll be sharing some tools that I use in my day-to-day work.</p><p>I am a professional software engineer working for a Japan-based company <a href="http://www.bebit.co.jp/">beBit.inc</a> building a flagship SAAS application called <a href="http://www.bebit.co.jp/usergram/">USERGRAM</a>. In my day-to-day work, I use lots of tools and technologies to get my job done and to make me productive. Here's the list of it:</p> <h3>1. PyCharm and Intellij IDEA</h3> <p>I mostly code in Python and Java and the above two are my go-to IDE if I have to work on any of these languages. I use the Kubernetes plugin in my IntelliJ IDEA to validate YAML configurations for k8s and it's such a handy tool.</p> <h3>2. github.com</h3> <p>GitHub is where we host all our source code for USERGRAM, and I use it for my personal pet projects as well. GitHub action amazing CI/CD integration in GitHub and my company and personally I love it. The PR review system is fantastic. Besides, all that, I also follow many developers' and programmers' profiles to see what they are working on, technology trends and also star some cool projects on GitHub. There isn't a single day (except some weekends) when I do not visit github.com</p> <h3>3. 1password</h3> <p>I can't emphasize enough about 1password. This is my de-facto password management tool. My company uses it and I use it. I have to say, this is the best investment I made. 100% worth it.</p> <h3>4. Firefox and Brave</h3> <p>Firefox and Brave browsers are my browser choices. I use Brave for official work and use Firefox for personal stuff such as social media. This is because I do not want to mix up my personal and official work.</p> <h3>5. Docker</h3> <p>Everything is dockerized at work and having Docker is absolutely necessary. But, while running a heavy stack, it sometimes slows down my laptop. </p> <h3>6. CleanMyMac X</h3> <p>I purchased this software to make my laptop faster by cleaning up junk files and freeing my RAM. It does more than that like finding large files, malware protection, etc. </p> <h3>7. iTerm2</h3> <p>This is my default terminal emulator for my mac. I installed ZSH shell as a default shell and I have to say iTerm2 and ZSH go hand in hand, no doubt.</p> <h3>8. Slack, Zoom, Around</h3> <p>These are the communication tools we use in our company to communicate. After the pandemic hit, we've been connected more with Slack, Zoom, and Around. We recently started to use Around in our team and it's really nice. </p> <h3>9. Skitch</h3> <p>In my day-to-day work, I have to screenshot and annotate screenshots a lot. I used to use mac's default screenshot tool in combination with some other 3rd party tools to screenshot stuff. That all got replaced when I found about Skitch. Now it's been my default and go-to tool for screenshots and annotations.</p> <h3>Honorable mentions</h3> <p>WebStorm (IDE for FrontEnd)</p> <p>ExpressVPN (My Favourite VPN service)</p> <p>Keybase</p> <p>Spectacle </p> <p>Atlassian JIRA and Confluence</p> <p>Archbee (The app I use to write this blog)</p> <p>Dropbox and Google Drive</p> <p>G-suit</p> <p>AWS</p> <p>k8s</p> <p>Terraform</p> <p>Visual Studio Code</p> <p>Draw.io</p> <blockquote> <p>PS. I'll be adding more to this list later on.</p> </blockquote>How to resolve "Unable to validate the following destination configurations" while adding event notification to your S3 bucket?2021-02-25T22:11:00+09:002021-02-25T22:11:00+09:00Sagar Giritag:sagargiri.com,2021-02-25:/s3-event-notification-issue<p>In this small article, I'll demonstrate how I resolved the lambda issue while adding S3 event notification.</p><h1>Problem</h1> <p>I have an existing S3 bucket and I wanted to add an S3 event notification to invoke my lambda function's dev alias. I read the <code>s3api</code> <a href="https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-notification-configuration.html">put-bucket-notification-configuration</a> documentation and prepare the <code>notification.json</code> file like this:</p> <div class="highlight"><pre><span></span><code><span class="p">{</span> <span class="w"> </span><span class="nt">&quot;LambdaFunctionConfigurations&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span> <span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="nt">&quot;Id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;ToInvokeMyLambdaFunction&quot;</span><span class="p">,</span> <span class="w"> </span><span class="nt">&quot;LambdaFunctionArn&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;arn:aws:lambda:ap-northeast-1:123456789101:function:TestFunc:dev&quot;</span><span class="p">,</span> <span class="w"> </span><span class="nt">&quot;Events&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span> <span class="w"> </span><span class="s2">&quot;s3:ObjectCreated:Put&quot;</span> <span class="w"> </span><span class="p">],</span> <span class="w"> </span><span class="nt">&quot;Filter&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="nt">&quot;Key&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="nt">&quot;FilterRules&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span> <span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="nt">&quot;Name&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;suffix&quot;</span><span class="p">,</span> <span class="w"> </span><span class="nt">&quot;Value&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;awesome_data.csv&quot;</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">]</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">]</span> <span class="p">}</span> </code></pre></div> <p>Then I execute the <code>s3api</code> command:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>aws<span class="w"> </span>s3api<span class="w"> </span>put-bucket-notification-configuration<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--bucket<span class="w"> </span>MyAwesomeBucket<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--notification-configuration<span class="w"> </span>file://notification.json </code></pre></div> <p>I got an error that said:</p> <div class="highlight"><pre><span></span><code>An<span class="w"> </span>error<span class="w"> </span>occurred<span class="w"> </span><span class="o">(</span>InvalidArgument<span class="o">)</span><span class="w"> </span>when<span class="w"> </span>calling<span class="w"> </span>the<span class="w"> </span>PutBucketNotificationConfiguration<span class="w"> </span>operation:<span class="w"> </span>Unable<span class="w"> </span>to<span class="w"> </span>validate<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>destination<span class="w"> </span>configurations </code></pre></div> <p>I checked my <code>aws-cli</code> version, it was the recommended one:</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>aws<span class="w"> </span>--version aws-cli/2.0.12<span class="w"> </span>Python/3.7.4<span class="w"> </span>Darwin/20.3.0<span class="w"> </span>botocore/2.0.0dev16 </code></pre></div> <p><em>But... It works when I do it from the S3 console...</em></p> <p><img alt="cat" src="https://media.giphy.com/media/xT0GqtpF1NWd9VbstO/giphy.gif"></p> <p>I tried executing the same <code>aws s3api</code> command again now with the <code>--debug</code> flag. And in the middle of the long debug output, I see this:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>aws<span class="w"> </span>s3api<span class="w"> </span>put-bucket-notification-configuration<span class="w"> </span>\ <span class="w"> </span>--bucket<span class="w"> </span>MyAwesomeBucket<span class="w"> </span>\ <span class="w"> </span>--notification-configuration<span class="w"> </span>file://notification.json<span class="w"> </span>\ <span class="w"> </span>--debug ... 2021-02-25<span class="w"> </span>21:39:13,902<span class="w"> </span>-<span class="w"> </span>MainThread<span class="w"> </span>-<span class="w"> </span>botocore.parsers<span class="w"> </span>-<span class="w"> </span>DEBUG<span class="w"> </span>-<span class="w"> </span>Response<span class="w"> </span>body: b&#39;<span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span>\n<span class="nt">&lt;Error&gt;&lt;Code&gt;</span>InvalidArgument<span class="nt">&lt;/Code&gt;&lt;Message&gt;</span>Unable<span class="w"> </span>to<span class="w"> </span>validate<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>destination<span class="w"> </span>configurations<span class="nt">&lt;/Message&gt;&lt;ArgumentName1&gt;</span>arn:aws:lambda:ap-northeast-1:123456789101:function:TestFunc:dev,<span class="w"> </span>null<span class="nt">&lt;/ArgumentName1&gt;&lt;ArgumentValue1&gt;</span>Not<span class="w"> </span>authorized<span class="w"> </span>to<span class="w"> </span>invoke<span class="w"> </span>function<span class="w"> </span>[arn:aws:lambda:ap-northeast-1:123456789101:function:TestFunc:dev]<span class="nt">&lt;/ArgumentValue1&gt;&lt;RequestId&gt;</span>2B8705F2FD8848F2<span class="nt">&lt;/RequestId&gt;&lt;HostId&gt;</span>bj9ahrqPxN3emWnZ008dtkVmVR9VVxfFjAJAw9hKvhoa4vtdHXaGi/x4a4Okki3oJhbaeHe0Ppk=<span class="nt">&lt;/HostId&gt;&lt;/Error&gt;</span>&#39; ... </code></pre></div> <p>The gist of it is <code>Not authorized to invoke function [arn:aws:lambda:ap-northeast-1:123456789101:function:TestFunc:dev]</code></p> <p>So the problem was with the lambda permission. :thinking:</p> <h1>Solution</h1> <p>Digging around the internet I find <a href="https://forums.aws.amazon.com/thread.jspa?threadID=182758">this</a> And the solution is to give your lambda a permission to being invoked by S3 first. Which can be done like this:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>aws<span class="w"> </span>lambda<span class="w"> </span>add-permission<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--function-name<span class="w"> </span>TestFunc:dev<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--profile<span class="w"> </span>default<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--statement-id<span class="w"> </span>AllowToBeInvoked<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--action<span class="w"> </span><span class="s2">&quot;lambda:InvokeFunction&quot;</span><span class="w"> </span><span class="se">\</span> <span class="w"> </span>--principal<span class="w"> </span>s3.amazonaws.com<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--source-arn<span class="w"> </span><span class="s2">&quot;arn:aws:s3:::MyAwesomeBucket&quot;</span><span class="w"> </span><span class="se">\</span> <span class="w"> </span>--source-account<span class="w"> </span><span class="m">123456789101</span> </code></pre></div> <p>I got the output like this:</p> <div class="highlight"><pre><span></span><code><span class="o">{</span> <span class="w"> </span><span class="s2">&quot;Statement&quot;</span>:<span class="w"> </span><span class="s2">&quot;{\&quot;Sid\&quot;:\&quot;AllowToBeInvoked\&quot;,\&quot;Effect\&quot;:\&quot;Allow\&quot;,\&quot;Principal\&quot;:{\&quot;Service\&quot;:\&quot;s3.amazonaws.com\&quot;},\&quot;Action\&quot;:\&quot;lambda:InvokeFunction\&quot;,\&quot;Resource\&quot;:\&quot;arn:aws:lambda:ap-northeast-1:123456789101:function:TestFunc:dev\&quot;,\&quot;Condition\&quot;:{\&quot;StringEquals\&quot;:{\&quot;AWS:SourceAccount\&quot;:\&quot;123456789101\&quot;},\&quot;ArnLike\&quot;:{\&quot;AWS:SourceArn\&quot;:\&quot;arn:aws:s3:::MyAwesomeBucket\&quot;}}}&quot;</span> <span class="o">}</span> </code></pre></div> <p>Finally, executing the <code>aws s3api</code> command, I was able to put S3 event notification on <code>MyAwesomeBucket</code></p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>aws<span class="w"> </span>s3api<span class="w"> </span>put-bucket-notification-configuration<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--bucket<span class="w"> </span>MyAwesomeBucket<span class="w"> </span><span class="se">\</span> <span class="w"> </span>--notification-configuration<span class="w"> </span>file://notification.json </code></pre></div> <p>I checked my lambda console and I can verify the S3 trigger is applied. :confetti_ball: <img alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1104077/1013252b-7ede-d418-a023-4a7052031a4d.png"></p> <p>References:</p> <ol> <li>https://forums.aws.amazon.com/thread.jspa?threadID=182758</li> <li>https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html</li> <li>https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-notification-configuration.html</li> </ol>Terraform: Getting Started from Zero2021-01-17T21:32:00+09:002021-01-17T21:32:00+09:00Sagar Giritag:sagargiri.com,2021-01-17:/straight-up-Terraform<p>This is the very detailed introduction to getting started with Terraform</p><blockquote> <p>Terraform is an open-source infrastructure as code software tool that enables you to safely and predictably create, change, and improve infrastructure. - www.Terraform.io</p> </blockquote> <!--toc--> <ul> <li><a href="#chapter-1-introduction-to-iac">Chapter 1: Introduction to IaC</a><ul> <li><a href="#11-begin-with-a-look-back">1.1 Begin with a look back</a></li> <li><a href="#12-why-infrastructure-as-code">1.2 Why infrastructure as code?</a></li> <li><a href="#13-terminology">1.3 Terminology</a></li> <li><a href="#14-explore-approaches-to-iac">1.4 Explore approaches to IaC</a></li> </ul> </li> <li><a href="#chapter-2-terraform">Chapter 2: Terraform</a><ul> <li><a href="#21-what-is-terraform">2.1 What is Terraform?</a></li> <li><a href="#22-install-terraform">2.2 Install Terraform</a></li> <li><a href="#23-terraform-tour">2.3 Terraform Tour</a></li> <li><a href="#24-the-very-basics-of-terraform">2.4 The very "Basics of Terraform"</a></li> </ul> </li> <li><a href="#chapter-3-learning-hcl">Chapter 3: Learning HCL</a><ul> <li><a href="#31-overview-of-hcl-structure">3.1 Overview of HCL structure</a></li> <li><a href="#32-terraform-data-sources-and-resources">3.2 Terraform data sources and resources</a></li> <li><a href="#33-terraform-outputs">3.3 Terraform Outputs</a></li> <li><a href="#34-interpolation-in-hcl">3.4 Interpolation in HCL</a></li> <li><a href="#35-dependencies-in-terraform">3.5 Dependencies in Terraform</a></li> <li><a href="#36-variables-and-locals">3.6 Variables and Locals</a></li> <li><a href="#37-conditionals-and-the-count-property">3.7 Conditionals and the Count property</a></li> <li><a href="#38-data-types-and-operators">3.8 Data types and operators</a></li> <li><a href="#39-functions">3.9 Functions</a></li> <li><a href="#310-iterations-in-collections">3.10 Iterations in collections</a></li> <li><a href="#311-directives-and-heredocs">3.11 Directives and heredocs</a></li> <li><a href="#312-clean-up">3.12 Clean up</a></li> </ul> </li> <li><a href="#chapter-4-code-re-use-for-applying-dry">Chapter 4: Code Re-Use for applying DRY</a><ul> <li><a href="#41-understanding-terraform-modules">4.1 Understanding Terraform Modules</a></li> <li><a href="#42-distributing-modules">4.2 Distributing modules</a></li> </ul> </li> <li><a href="#chapter-5-collaboration-with-terraform">Chapter 5: Collaboration with Terraform</a><ul> <li><a href="#51-terraform-backends">5.1 Terraform backends</a></li> <li><a href="#52-terraform-workspaces">5.2 Terraform workspaces</a></li> </ul> </li> </ul> <h1>Chapter 1: Introduction to IaC</h1> <h2>1.1 Begin with a look back</h2> <ul> <li>[1960-1970] - Mainframe Computers<ul> <li>Big machines</li> <li>Big facilities and using fork-lifts to move machines</li> <li>Automation was not that critical in this era</li> </ul> </li> <li>[1980-1990] - Client/Server World<ul> <li>Things started to get little more complicated</li> <li>UNIX or PC servers running various OS</li> <li>These machines serve users using networking</li> </ul> </li> <li>[Mid 90's-2000] - Virtualization<ul> <li>Software defines infrastructures</li> <li>Hardware were virtualized</li> <li>Clients do not have any hardware debt</li> </ul> </li> <li>Cloud Era<ul> <li>No hardware to manage</li> <li>It's all software management problem</li> <li>All these things could be managed by API's, Scripts</li> <li>Manage all the infrastructures by the code</li> </ul> </li> </ul> <h2>1.2 Why infrastructure as code?</h2> <ul> <li>Repeatability<ul> <li>We can deploy the same thing over and over again</li> <li>We'll have a backup</li> <li>We can have multiple environments (dev, stage, prod)</li> </ul> </li> <li>Auditability<ul> <li>We can see what changed, who changed and impact of change</li> <li>We can detect the problems easily</li> </ul> </li> <li>Change control<ul> <li>Allows us to use VCS to control what to change</li> </ul> </li> <li>Collaboration<ul> <li>Multiple people can work together on the same code base</li> <li>Example: Use GitHub to propose a change</li> </ul> </li> </ul> <h2>1.3 Terminology</h2> <ul> <li><strong>IaC</strong> - Infrastructure as Code</li> <li><strong>CM</strong> - Configuration Management (Example: Ansible, Puppet, etc)</li> <li><strong>IaaS</strong> - Infrastructure as a Service (Example: AWS, GoogleCloud, Azure)</li> <li><strong>PaaS</strong> - Platform as a Service (Example: Heroku, AWS EBS)</li> <li><strong>VCS</strong> - Version Control System</li> <li><strong>CI/CD</strong> - Continuous Integration/ Continuous Deployment (Delivery)</li> <li><strong>SDLC</strong> - Software Development Life Cycle</li> <li><strong>Declarative</strong> - Declare what you want</li> <li><strong>Imperative</strong> - How to get the desired state</li> </ul> <h2>1.4 Explore approaches to IaC</h2> <ul> <li>Imperative Approach<ul> <li>Procedural Approach</li> <li>Answers How?</li> <li>Example Tools: AWS Cli, Python/Boto3</li> </ul> </li> <li>Declarative Approach<ul> <li>Answers What?</li> <li>Example Tools: AWS CloudFormation, Terraform</li> <li>We can change things easily for example AWS instance type</li> <li>Tool does everything for us</li> </ul> </li> </ul> <h1>Chapter 2: Terraform</h1> <h2>2.1 What is Terraform?</h2> <ul> <li>Terraform is a cross-platform command line tool</li> <li>Declarative IaC tool<ul> <li>We define what we want and Terraform will create it for us</li> </ul> </li> <li>Also, an Online Service<ul> <li>Provided through Terraform Cloud</li> <li>Remote execution, Secret Storage</li> </ul> </li> <li>Terraform consists<ul> <li><strong>Configuration</strong>: Configuration files to define what we want</li> <li><strong>State</strong>: Like a Database which stores the current state and can be stored anywhere like in local PC, S3, GCS, Google Drive, etc<ul> <li>State is the Terraform view of the world</li> <li>Terraform looks here instead of cloud provider</li> <li>Terraform compares <strong>Config and State</strong> to create-destroy resource</li> </ul> </li> </ul> </li> </ul> <h2>2.2 Install Terraform</h2> <p><a href="https://www.Terraform.io/downloads.html">https://www.Terraform.io/downloads.html</a></p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>-version Terraform<span class="w"> </span>v0.14.4 </code></pre></div> <h2>2.3 Terraform Tour</h2> <p>Initialize Terraform</p> <div class="highlight"><pre><span></span><code>╭─sagar-giri@PCN-489<span class="w"> </span>~/IdeaProjects/HelloTerraform ╰─$<span class="w"> </span>terraform<span class="w"> </span>init Terraform<span class="w"> </span>initialized<span class="w"> </span><span class="k">in</span><span class="w"> </span>an<span class="w"> </span>empty<span class="w"> </span>directory! The<span class="w"> </span>directory<span class="w"> </span>has<span class="w"> </span>no<span class="w"> </span>Terraform<span class="w"> </span>configuration<span class="w"> </span>files.<span class="w"> </span>You<span class="w"> </span>may<span class="w"> </span>begin<span class="w"> </span>working with<span class="w"> </span>Terraform<span class="w"> </span>immediately<span class="w"> </span>by<span class="w"> </span>creating<span class="w"> </span>Terraform<span class="w"> </span>configuration<span class="w"> </span>files. </code></pre></div> <p>Plan Terraform</p> <div class="highlight"><pre><span></span><code>╭─sagar-giri@PCN-489<span class="w"> </span>~/IdeaProjects/HelloTerraform ╰─$<span class="w"> </span>terraform<span class="w"> </span>plan Error:<span class="w"> </span>No<span class="w"> </span>configuration<span class="w"> </span>files Plan<span class="w"> </span>requires<span class="w"> </span>configuration<span class="w"> </span>to<span class="w"> </span>be<span class="w"> </span>present.<span class="w"> </span>Planning<span class="w"> </span>without<span class="w"> </span>a<span class="w"> </span>configuration would<span class="w"> </span>mark<span class="w"> </span>everything<span class="w"> </span><span class="k">for</span><span class="w"> </span>destruction,<span class="w"> </span>which<span class="w"> </span>is<span class="w"> </span>normally<span class="w"> </span>not<span class="w"> </span>what<span class="w"> </span>is<span class="w"> </span>desired. If<span class="w"> </span>you<span class="w"> </span>would<span class="w"> </span>like<span class="w"> </span>to<span class="w"> </span>destroy<span class="w"> </span>everything,<span class="w"> </span>run<span class="w"> </span>plan<span class="w"> </span>with<span class="w"> </span>the<span class="w"> </span>-destroy<span class="w"> </span>option. Otherwise,<span class="w"> </span>create<span class="w"> </span>a<span class="w"> </span>Terraform<span class="w"> </span>configuration<span class="w"> </span>file<span class="w"> </span><span class="o">(</span>.tf<span class="w"> </span>file<span class="o">)</span><span class="w"> </span>and<span class="w"> </span>try<span class="w"> </span>again. </code></pre></div> <p>Apply</p> <div class="highlight"><pre><span></span><code>╭─sagar-giri@PCN-489<span class="w"> </span>~/IdeaProjects/HelloTerraform ╰─$<span class="w"> </span>terraform<span class="w"> </span>apply<span class="w"> </span><span class="m">1</span><span class="w"> </span>↵ Error:<span class="w"> </span>No<span class="w"> </span>configuration<span class="w"> </span>files Apply<span class="w"> </span>requires<span class="w"> </span>configuration<span class="w"> </span>to<span class="w"> </span>be<span class="w"> </span>present.<span class="w"> </span>Applying<span class="w"> </span>without<span class="w"> </span>a<span class="w"> </span>configuration would<span class="w"> </span>mark<span class="w"> </span>everything<span class="w"> </span><span class="k">for</span><span class="w"> </span>destruction,<span class="w"> </span>which<span class="w"> </span>is<span class="w"> </span>normally<span class="w"> </span>not<span class="w"> </span>what<span class="w"> </span>is<span class="w"> </span>desired. If<span class="w"> </span>you<span class="w"> </span>would<span class="w"> </span>like<span class="w"> </span>to<span class="w"> </span>destroy<span class="w"> </span>everything,<span class="w"> </span>run<span class="w"> </span><span class="s1">&#39;Terraform destroy&#39;</span><span class="w"> </span>instead. </code></pre></div> <p>Destroy</p> <div class="highlight"><pre><span></span><code>╭─sagar-giri@PCN-489<span class="w"> </span>~/IdeaProjects/HelloTerraform ╰─$<span class="w"> </span>terraform<span class="w"> </span>destroy Do<span class="w"> </span>you<span class="w"> </span>really<span class="w"> </span>want<span class="w"> </span>to<span class="w"> </span>destroy<span class="w"> </span>all<span class="w"> </span>resources? <span class="w"> </span>Terraform<span class="w"> </span>will<span class="w"> </span>destroy<span class="w"> </span>all<span class="w"> </span>your<span class="w"> </span>managed<span class="w"> </span>infrastructure,<span class="w"> </span>as<span class="w"> </span>shown<span class="w"> </span>above. <span class="w"> </span>There<span class="w"> </span>is<span class="w"> </span>no<span class="w"> </span>undo.<span class="w"> </span>Only<span class="w"> </span><span class="s1">&#39;yes&#39;</span><span class="w"> </span>will<span class="w"> </span>be<span class="w"> </span>accepted<span class="w"> </span>to<span class="w"> </span>confirm. <span class="w"> </span>Enter<span class="w"> </span>a<span class="w"> </span>value:<span class="w"> </span>no Destroy<span class="w"> </span>cancelled. ╭─sagar-giri@PCN-489<span class="w"> </span>~/IdeaProjects/HelloTerraform ╰─$<span class="w"> </span>terraform<span class="w"> </span>destroy<span class="w"> </span><span class="m">1</span><span class="w"> </span>↵ Do<span class="w"> </span>you<span class="w"> </span>really<span class="w"> </span>want<span class="w"> </span>to<span class="w"> </span>destroy<span class="w"> </span>all<span class="w"> </span>resources? <span class="w"> </span>Terraform<span class="w"> </span>will<span class="w"> </span>destroy<span class="w"> </span>all<span class="w"> </span>your<span class="w"> </span>managed<span class="w"> </span>infrastructure,<span class="w"> </span>as<span class="w"> </span>shown<span class="w"> </span>above. <span class="w"> </span>There<span class="w"> </span>is<span class="w"> </span>no<span class="w"> </span>undo.<span class="w"> </span>Only<span class="w"> </span><span class="s1">&#39;yes&#39;</span><span class="w"> </span>will<span class="w"> </span>be<span class="w"> </span>accepted<span class="w"> </span>to<span class="w"> </span>confirm. <span class="w"> </span>Enter<span class="w"> </span>a<span class="w"> </span>value:<span class="w"> </span>yes Destroy<span class="w"> </span>complete!<span class="w"> </span>Resources:<span class="w"> </span><span class="m">0</span><span class="w"> </span>destroyed. </code></pre></div> <p>Help (Look for the <em><strong>Main commands</strong></em> section)</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span><span class="nb">help</span> Usage:<span class="w"> </span>Terraform<span class="w"> </span><span class="o">[</span>global<span class="w"> </span>options<span class="o">]</span><span class="w"> </span>&lt;subcommand&gt;<span class="w"> </span><span class="o">[</span>args<span class="o">]</span> The<span class="w"> </span>available<span class="w"> </span>commands<span class="w"> </span><span class="k">for</span><span class="w"> </span>execution<span class="w"> </span>are<span class="w"> </span>listed<span class="w"> </span>below. The<span class="w"> </span>primary<span class="w"> </span>workflow<span class="w"> </span>commands<span class="w"> </span>are<span class="w"> </span>given<span class="w"> </span>first,<span class="w"> </span>followed<span class="w"> </span>by less<span class="w"> </span>common<span class="w"> </span>or<span class="w"> </span>more<span class="w"> </span>advanced<span class="w"> </span>commands. Main<span class="w"> </span>commands: <span class="w"> </span>init<span class="w"> </span>Prepare<span class="w"> </span>your<span class="w"> </span>working<span class="w"> </span>directory<span class="w"> </span><span class="k">for</span><span class="w"> </span>other<span class="w"> </span>commands <span class="w"> </span>validate<span class="w"> </span>Check<span class="w"> </span>whether<span class="w"> </span>the<span class="w"> </span>configuration<span class="w"> </span>is<span class="w"> </span>valid <span class="w"> </span>plan<span class="w"> </span>Show<span class="w"> </span>changes<span class="w"> </span>required<span class="w"> </span>by<span class="w"> </span>the<span class="w"> </span>current<span class="w"> </span>configuration <span class="w"> </span>apply<span class="w"> </span>Create<span class="w"> </span>or<span class="w"> </span>update<span class="w"> </span>infrastructure <span class="w"> </span>destroy<span class="w"> </span>Destroy<span class="w"> </span>previously-created<span class="w"> </span>infrastructure All<span class="w"> </span>other<span class="w"> </span>commands: <span class="w"> </span>console<span class="w"> </span>Try<span class="w"> </span>Terraform<span class="w"> </span>expressions<span class="w"> </span>at<span class="w"> </span>an<span class="w"> </span>interactive<span class="w"> </span><span class="nb">command</span><span class="w"> </span>prompt <span class="w"> </span>fmt<span class="w"> </span>Reformat<span class="w"> </span>your<span class="w"> </span>configuration<span class="w"> </span><span class="k">in</span><span class="w"> </span>the<span class="w"> </span>standard<span class="w"> </span>style <span class="w"> </span>force-unlock<span class="w"> </span>Release<span class="w"> </span>a<span class="w"> </span>stuck<span class="w"> </span>lock<span class="w"> </span>on<span class="w"> </span>the<span class="w"> </span>current<span class="w"> </span>workspace <span class="w"> </span>get<span class="w"> </span>Install<span class="w"> </span>or<span class="w"> </span>upgrade<span class="w"> </span>remote<span class="w"> </span>Terraform<span class="w"> </span>modules <span class="w"> </span>graph<span class="w"> </span>Generate<span class="w"> </span>a<span class="w"> </span>Graphviz<span class="w"> </span>graph<span class="w"> </span>of<span class="w"> </span>the<span class="w"> </span>steps<span class="w"> </span><span class="k">in</span><span class="w"> </span>an<span class="w"> </span>operation <span class="w"> </span>import<span class="w"> </span>Associate<span class="w"> </span>existing<span class="w"> </span>infrastructure<span class="w"> </span>with<span class="w"> </span>a<span class="w"> </span>Terraform<span class="w"> </span>resource <span class="w"> </span>login<span class="w"> </span>Obtain<span class="w"> </span>and<span class="w"> </span>save<span class="w"> </span>credentials<span class="w"> </span><span class="k">for</span><span class="w"> </span>a<span class="w"> </span>remote<span class="w"> </span>host <span class="w"> </span><span class="nb">logout</span><span class="w"> </span>Remove<span class="w"> </span>locally-stored<span class="w"> </span>credentials<span class="w"> </span><span class="k">for</span><span class="w"> </span>a<span class="w"> </span>remote<span class="w"> </span>host <span class="w"> </span>output<span class="w"> </span>Show<span class="w"> </span>output<span class="w"> </span>values<span class="w"> </span>from<span class="w"> </span>your<span class="w"> </span>root<span class="w"> </span>module <span class="w"> </span>providers<span class="w"> </span>Show<span class="w"> </span>the<span class="w"> </span>providers<span class="w"> </span>required<span class="w"> </span><span class="k">for</span><span class="w"> </span>this<span class="w"> </span>configuration <span class="w"> </span>refresh<span class="w"> </span>Update<span class="w"> </span>the<span class="w"> </span>state<span class="w"> </span>to<span class="w"> </span>match<span class="w"> </span>remote<span class="w"> </span>systems <span class="w"> </span>show<span class="w"> </span>Show<span class="w"> </span>the<span class="w"> </span>current<span class="w"> </span>state<span class="w"> </span>or<span class="w"> </span>a<span class="w"> </span>saved<span class="w"> </span>plan <span class="w"> </span>state<span class="w"> </span>Advanced<span class="w"> </span>state<span class="w"> </span>management <span class="w"> </span>taint<span class="w"> </span>Mark<span class="w"> </span>a<span class="w"> </span>resource<span class="w"> </span>instance<span class="w"> </span>as<span class="w"> </span>not<span class="w"> </span>fully<span class="w"> </span>functional <span class="w"> </span>untaint<span class="w"> </span>Remove<span class="w"> </span>the<span class="w"> </span><span class="s1">&#39;tainted&#39;</span><span class="w"> </span>state<span class="w"> </span>from<span class="w"> </span>a<span class="w"> </span>resource<span class="w"> </span>instance <span class="w"> </span>version<span class="w"> </span>Show<span class="w"> </span>the<span class="w"> </span>current<span class="w"> </span>Terraform<span class="w"> </span>version <span class="w"> </span>workspace<span class="w"> </span>Workspace<span class="w"> </span>management Global<span class="w"> </span>options<span class="w"> </span><span class="o">(</span>use<span class="w"> </span>these<span class="w"> </span>before<span class="w"> </span>the<span class="w"> </span>subcommand,<span class="w"> </span><span class="k">if</span><span class="w"> </span>any<span class="o">)</span>: <span class="w"> </span>-chdir<span class="o">=</span>DIR<span class="w"> </span>Switch<span class="w"> </span>to<span class="w"> </span>a<span class="w"> </span>different<span class="w"> </span>working<span class="w"> </span>directory<span class="w"> </span>before<span class="w"> </span>executing<span class="w"> </span>the <span class="w"> </span>given<span class="w"> </span>subcommand. <span class="w"> </span>-help<span class="w"> </span>Show<span class="w"> </span>this<span class="w"> </span><span class="nb">help</span><span class="w"> </span>output,<span class="w"> </span>or<span class="w"> </span>the<span class="w"> </span><span class="nb">help</span><span class="w"> </span><span class="k">for</span><span class="w"> </span>a<span class="w"> </span>specified<span class="w"> </span>subcommand. <span class="w"> </span>-version<span class="w"> </span>An<span class="w"> </span><span class="nb">alias</span><span class="w"> </span><span class="k">for</span><span class="w"> </span>the<span class="w"> </span><span class="s2">&quot;version&quot;</span><span class="w"> </span>subcommand. </code></pre></div> <p>Format the Terraform file</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>fmt </code></pre></div> <h2>2.4 The very "Basics of Terraform"</h2> <p>Terraform uses HCL (<a href="https://github.com/hashicorp">HashiCorp</a> Configuration Language)</p> <p>The extension of file ends with <code>.tf</code></p> <p>Create <code>main.tf</code> inside a directory</p> <div class="highlight"><pre><span></span><code><span class="s2">&quot;greeting&quot;</span><span class="w"> </span>{ <span class="w"> </span><span class="nv">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Hello Terraform.&quot;</span> <span class="w"> </span>} <span class="w"> </span><span class="nv">provider</span><span class="w"> </span><span class="s2">&quot;random&quot;</span><span class="w"> </span>{} </code></pre></div> <p>Initialize Terraform</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>init Initializing<span class="w"> </span>the<span class="w"> </span>backend... Initializing<span class="w"> </span>provider<span class="w"> </span>plugins... -<span class="w"> </span>Finding<span class="w"> </span>latest<span class="w"> </span>version<span class="w"> </span>of<span class="w"> </span>hashicorp/random... -<span class="w"> </span>Installing<span class="w"> </span>hashicorp/random<span class="w"> </span>v3.0.1... -<span class="w"> </span>Installed<span class="w"> </span>hashicorp/random<span class="w"> </span>v3.0.1<span class="w"> </span><span class="o">(</span>signed<span class="w"> </span>by<span class="w"> </span>HashiCorp<span class="o">)</span> Terraform<span class="w"> </span>has<span class="w"> </span>created<span class="w"> </span>a<span class="w"> </span>lock<span class="w"> </span>file<span class="w"> </span>.Terraform.lock.hcl<span class="w"> </span>to<span class="w"> </span>record<span class="w"> </span>the<span class="w"> </span>provider selections<span class="w"> </span>it<span class="w"> </span>made<span class="w"> </span>above.<span class="w"> </span>Include<span class="w"> </span>this<span class="w"> </span>file<span class="w"> </span><span class="k">in</span><span class="w"> </span>your<span class="w"> </span>version<span class="w"> </span>control<span class="w"> </span>repository so<span class="w"> </span>that<span class="w"> </span>Terraform<span class="w"> </span>can<span class="w"> </span>guarantee<span class="w"> </span>to<span class="w"> </span>make<span class="w"> </span>the<span class="w"> </span>same<span class="w"> </span>selections<span class="w"> </span>by<span class="w"> </span>default<span class="w"> </span>when you<span class="w"> </span>run<span class="w"> </span><span class="s2">&quot;Terraform init&quot;</span><span class="w"> </span><span class="k">in</span><span class="w"> </span>the<span class="w"> </span>future. Terraform<span class="w"> </span>has<span class="w"> </span>been<span class="w"> </span>successfully<span class="w"> </span>initialized! You<span class="w"> </span>may<span class="w"> </span>now<span class="w"> </span>begin<span class="w"> </span>working<span class="w"> </span>with<span class="w"> </span>Terraform.<span class="w"> </span>Try<span class="w"> </span>running<span class="w"> </span><span class="s2">&quot;terraform plan&quot;</span><span class="w"> </span>to<span class="w"> </span>see any<span class="w"> </span>changes<span class="w"> </span>that<span class="w"> </span>are<span class="w"> </span>required<span class="w"> </span><span class="k">for</span><span class="w"> </span>your<span class="w"> </span>infrastructure.<span class="w"> </span>All<span class="w"> </span>Terraform<span class="w"> </span>commands should<span class="w"> </span>now<span class="w"> </span>work. If<span class="w"> </span>you<span class="w"> </span>ever<span class="w"> </span><span class="nb">set</span><span class="w"> </span>or<span class="w"> </span>change<span class="w"> </span>modules<span class="w"> </span>or<span class="w"> </span>backend<span class="w"> </span>configuration<span class="w"> </span><span class="k">for</span><span class="w"> </span>Terraform, rerun<span class="w"> </span>this<span class="w"> </span><span class="nb">command</span><span class="w"> </span>to<span class="w"> </span>reinitialize<span class="w"> </span>your<span class="w"> </span>working<span class="w"> </span>directory.<span class="w"> </span>If<span class="w"> </span>you<span class="w"> </span>forget,<span class="w"> </span>other commands<span class="w"> </span>will<span class="w"> </span>detect<span class="w"> </span>it<span class="w"> </span>and<span class="w"> </span>remind<span class="w"> </span>you<span class="w"> </span>to<span class="w"> </span><span class="k">do</span><span class="w"> </span>so<span class="w"> </span><span class="k">if</span><span class="w"> </span>necessary. </code></pre></div> <p>Plan it</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>plan An<span class="w"> </span>execution<span class="w"> </span>plan<span class="w"> </span>has<span class="w"> </span>been<span class="w"> </span>generated<span class="w"> </span>and<span class="w"> </span>is<span class="w"> </span>shown<span class="w"> </span>below. Resource<span class="w"> </span>actions<span class="w"> </span>are<span class="w"> </span>indicated<span class="w"> </span>with<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>symbols: Terraform<span class="w"> </span>will<span class="w"> </span>perform<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>actions: Plan:<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>add,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>change,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>destroy. Changes<span class="w"> </span>to<span class="w"> </span>Outputs: <span class="w"> </span>+<span class="w"> </span><span class="nv">greeting</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Hello Terraform.&quot;</span> ------------------------------------------------------------------------ Note:<span class="w"> </span>You<span class="w"> </span>didn<span class="s1">&#39;t specify an &quot;-out&quot; parameter to save this plan, so Terraform</span> <span class="s1">can&#39;</span>t<span class="w"> </span>guarantee<span class="w"> </span>that<span class="w"> </span>exactly<span class="w"> </span>these<span class="w"> </span>actions<span class="w"> </span>will<span class="w"> </span>be<span class="w"> </span>performed<span class="w"> </span><span class="k">if</span> <span class="s2">&quot;Terraform apply&quot;</span><span class="w"> </span>is<span class="w"> </span>subsequently<span class="w"> </span>run. </code></pre></div> <p>Apply it. You might have to type <code>yes</code> in the middle of it.</p> <p>After applying it creates a <code>.tfstate</code> file, and you should not touch the <code>.tfstate</code> file.</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>apply An<span class="w"> </span>execution<span class="w"> </span>plan<span class="w"> </span>has<span class="w"> </span>been<span class="w"> </span>generated<span class="w"> </span>and<span class="w"> </span>is<span class="w"> </span>shown<span class="w"> </span>below. Resource<span class="w"> </span>actions<span class="w"> </span>are<span class="w"> </span>indicated<span class="w"> </span>with<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>symbols: Terraform<span class="w"> </span>will<span class="w"> </span>perform<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>actions: Plan:<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>add,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>change,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>destroy. Changes<span class="w"> </span>to<span class="w"> </span>Outputs: <span class="w"> </span>+<span class="w"> </span><span class="nv">greeting</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Hello Terraform.&quot;</span> Do<span class="w"> </span>you<span class="w"> </span>want<span class="w"> </span>to<span class="w"> </span>perform<span class="w"> </span>these<span class="w"> </span>actions? <span class="w"> </span>Terraform<span class="w"> </span>will<span class="w"> </span>perform<span class="w"> </span>the<span class="w"> </span>actions<span class="w"> </span>described<span class="w"> </span>above. <span class="w"> </span>Only<span class="w"> </span><span class="s1">&#39;yes&#39;</span><span class="w"> </span>will<span class="w"> </span>be<span class="w"> </span>accepted<span class="w"> </span>to<span class="w"> </span>approve. <span class="w"> </span>Enter<span class="w"> </span>a<span class="w"> </span>value:<span class="w"> </span>yes Apply<span class="w"> </span>complete!<span class="w"> </span>Resources:<span class="w"> </span><span class="m">0</span><span class="w"> </span>added,<span class="w"> </span><span class="m">0</span><span class="w"> </span>changed,<span class="w"> </span><span class="m">0</span><span class="w"> </span>destroyed. Outputs: <span class="nv">greeting</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Hello Terraform.&quot;</span> </code></pre></div> <p>See the output</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>output <span class="nv">greeting</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Hello Terraform.&quot;</span> </code></pre></div> <p>Specify which output you want</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>output<span class="w"> </span>greeting <span class="s2">&quot;Hello Terraform.&quot;</span> </code></pre></div> <h1>Chapter 3: Learning HCL</h1> <h2>3.1 Overview of HCL structure</h2> <p>By conventions <code>main.tf</code> , <code>outputs.tf</code> and <code>variables.tf</code> are required files inside a directory</p> <p>Sometimes the <code>main.tf</code> file gets too big. In this case we use the submodules.</p> <p>Example <code>main.tf</code> with AWS as a provider:</p> <div class="highlight"><pre><span></span><code><span class="c1"># Terraform block is optional but it&#39;s a best practice to have it</span> <span class="nb">terraform</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # required_version is the Terraform version which we want to apply</span> <span class="w"> </span><span class="na">required_version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&gt;=0.14.0&quot;</span> <span class="p">}</span> <span class="c1"># Which cloud provider you want to use</span> <span class="kr">provider</span><span class="w"> </span><span class="nv">&quot;aws&quot;</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # region is required</span> <span class="w"> </span><span class="na">region</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;ap-northeast-1&quot;</span> <span class="c1"> # Since I am putting this file in GitHub I do not EVER put my AWS credentials here.</span> <span class="c1"> # Instead I use the environment variable or Terraform cloud or the ~/.aws/credentials file</span> <span class="c1"> #access_keys = &quot;my-access-key&quot;</span> <span class="c1"> #access_secret = &quot;my-secret-key&quot;</span> <span class="p">}</span> </code></pre></div> <h2>3.2 Terraform data sources and resources</h2> <ul> <li>Resources<ul> <li>Resource is any object that you want to manage with Terraform. For example: S3, AWS EKS, GKE, VM's.</li> <li>Resources are defined in the resource block</li> <li>Declaring a resource tells Terraform that it should CREATE and manage the Resource described.</li> <li>If the resource already exists, it must be imported into Terraform state.</li> <li>Example: <code>resource "aws_s3_bucket" "Terraform-bucket-2021" {}</code></li> <li>REF: <a href="https://www.Terraform.io/docs/configuration/blocks/resources/index.html">https://www.Terraform.io/docs/configuration/blocks/resources/index.html</a></li> </ul> </li> <li>Data sources<ul> <li>Data sources are resources that Terraform does not manage. For example: <em>Availability Zones, Account ID</em></li> <li>We can use data source to get the availability zones to place EC2 instances in multiple AZ's</li> <li>REF: <a href="https://www.Terraform.io/docs/configuration/data-sources.html">https://www.Terraform.io/docs/configuration/data-sources.html</a> Example:</li> </ul> </li> </ul> <p><strong>Create a S3 bucket in AWS using resource block.</strong></p> <div class="highlight"><pre><span></span><code><span class="nb">terraform</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">required_version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&gt;=0.14.0&quot;</span> <span class="p">}</span> <span class="kr">provider</span><span class="w"> </span><span class="nv">&quot;aws&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">region</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;ap-northeast-1&quot;</span> <span class="p">}</span> <span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;Terraform-bucket-2021&quot;</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # bucket name should be unique.</span> <span class="c1"> # If you don&#39;t provide any name, Terraform will create it for you and saves in outputs.tf file</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021&quot;</span> <span class="p">}</span> </code></pre></div> <p>Plan and save the output to a file using command: <code>terraform plan -out s3.tfplan</code> . This will create a file named <code>s3.tfplan</code> with following output:</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>plan<span class="w"> </span>-out<span class="w"> </span>example.tfplan An<span class="w"> </span>execution<span class="w"> </span>plan<span class="w"> </span>has<span class="w"> </span>been<span class="w"> </span>generated<span class="w"> </span>and<span class="w"> </span>is<span class="w"> </span>shown<span class="w"> </span>below. Resource<span class="w"> </span>actions<span class="w"> </span>are<span class="w"> </span>indicated<span class="w"> </span>with<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>symbols: <span class="w"> </span>+<span class="w"> </span>create Terraform<span class="w"> </span>will<span class="w"> </span>perform<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>actions: <span class="w"> </span><span class="c1"># aws_s3_bucket.Terraform-bucket-2021 will be created</span> <span class="w"> </span>+<span class="w"> </span>resource<span class="w"> </span><span class="s2">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021&quot;</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">acceleration_status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">acl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;private&quot;</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">arn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021&quot;</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">bucket_domain_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">bucket_regional_domain_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">force_destroy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">false</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">hosted_zone_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">region</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">request_payer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">website_domain</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">website_endpoint</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span>versioning<span class="w"> </span><span class="o">{</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">enabled</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">mfa_delete</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span><span class="o">}</span> <span class="w"> </span><span class="o">}</span> Plan:<span class="w"> </span><span class="m">1</span><span class="w"> </span>to<span class="w"> </span>add,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>change,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>destroy. ------------------------------------------------------------------------ This<span class="w"> </span>plan<span class="w"> </span>was<span class="w"> </span>saved<span class="w"> </span>to:<span class="w"> </span>example.tfplan To<span class="w"> </span>perform<span class="w"> </span>exactly<span class="w"> </span>these<span class="w"> </span>actions,<span class="w"> </span>run<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span><span class="nb">command</span><span class="w"> </span>to<span class="w"> </span>apply: <span class="w"> </span>Terraform<span class="w"> </span>apply<span class="w"> </span><span class="s2">&quot;example.tfplan&quot;</span> </code></pre></div> <p>Anything beginning with the <code>+</code> means Terraform will create this resource for us. In the output above, it's <code>+ create</code> which means the resource doesn't exist yet and Terraform will perform <code>create</code> operation on the resource.</p> <p>Now, apply the plan using command: <code>terraform apply s3.tfplan</code></p> <p>Once applied, following output will be seen:</p> <div class="highlight"><pre><span></span><code>╰─$ terraform apply example.tfplan aws_s3_bucket.Terraform-bucket-2021: Creating... aws_s3_bucket.Terraform-bucket-2021: Creation complete after 5s [id=Terraform-bucket-2021] Apply complete! Resources: 1 added, 0 changed, 0 destroyed. The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the <span class="sb">`terraform show`</span> command. State path: Terraform.tfstate </code></pre></div> <p>It means that the s3 bucket has been created.</p> <p>Verify if the bucket exist using <code>aws s3 ls</code> command</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>aws<span class="w"> </span>s3<span class="w"> </span>ls <span class="m">2021</span>-01-16<span class="w"> </span><span class="m">19</span>:42:52<span class="w"> </span>Terraform-bucket-2021 </code></pre></div> <p>Bucket is successfully created 🎉</p> <blockquote> <p><em>Note: In real world, you ought to share the plan with your colleagues and there's an agreement between collegues before applying it.</em></p> </blockquote> <h2>3.3 Terraform Outputs</h2> <p>When we don't define some value (bucket name for example), Terraform will create the bucket name for us, and we can know the bucket details using Terraform outputs.</p> <p>In above case, let's output the bucket information of <code>terraform-bucket-2021</code></p> <p>To do that we need to create a output block</p> <div class="highlight"><pre><span></span><code><span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;Terraform-bucket-2021&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021&quot;</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;bucket_info&quot;</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # &lt;syntax&gt; value = resource_type[.]label_name</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">aws_s3_bucket.Terraform-bucket-2021</span> <span class="p">}</span> </code></pre></div> <p>Now, plan it <code>terraform plan -out s3.tfplan</code> . Here, the previous filename <code>s3.tfplan</code> will be replaced with the new fresh file.</p> <p>Not apply the <code>s3.tfplan</code> using command <code>terraform apply s3.tfplan</code></p> <p>You'll see following output:</p> <div class="highlight"><pre><span></span><code>Apply<span class="w"> </span>complete!<span class="w"> </span>Resources:<span class="w"> </span><span class="m">0</span><span class="w"> </span>added,<span class="w"> </span><span class="m">0</span><span class="w"> </span>changed,<span class="w"> </span><span class="m">0</span><span class="w"> </span>destroyed. Outputs: <span class="nv">bucket_info</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span><span class="s2">&quot;acceleration_status&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&quot;</span> <span class="w"> </span><span class="s2">&quot;acl&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;private&quot;</span> <span class="w"> </span><span class="s2">&quot;arn&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;arn:aws:s3:::Terraform-bucket-2021&quot;</span> <span class="w"> </span><span class="s2">&quot;bucket&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021&quot;</span> <span class="w"> </span><span class="s2">&quot;bucket_domain_name&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021.s3.amazonaws.com&quot;</span> <span class="w"> </span><span class="s2">&quot;bucket_prefix&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tostring<span class="o">(</span>null<span class="o">)</span> <span class="w"> </span><span class="s2">&quot;bucket_regional_domain_name&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021.s3.ap-northeast-1.amazonaws.com&quot;</span> <span class="w"> </span><span class="s2">&quot;cors_rule&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;force_destroy&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">false</span> <span class="w"> </span><span class="s2">&quot;grant&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;hosted_zone_id&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Z2M4EHUR26P7ZW&quot;</span> <span class="w"> </span><span class="s2">&quot;id&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;Terraform-bucket-2021&quot;</span> <span class="w"> </span><span class="s2">&quot;lifecycle_rule&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;logging&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;object_lock_configuration&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;policy&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tostring<span class="o">(</span>null<span class="o">)</span> <span class="w"> </span><span class="s2">&quot;region&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;ap-northeast-1&quot;</span> <span class="w"> </span><span class="s2">&quot;replication_configuration&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;request_payer&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;BucketOwner&quot;</span> <span class="w"> </span><span class="s2">&quot;server_side_encryption_configuration&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;tags&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tomap<span class="o">({})</span> <span class="w"> </span><span class="s2">&quot;versioning&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([</span> <span class="w"> </span><span class="o">{</span> <span class="w"> </span><span class="s2">&quot;enabled&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">false</span> <span class="w"> </span><span class="s2">&quot;mfa_delete&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">false</span> <span class="w"> </span><span class="o">}</span>, <span class="w"> </span><span class="o">])</span> <span class="w"> </span><span class="s2">&quot;website&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([])</span> <span class="w"> </span><span class="s2">&quot;website_domain&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tostring<span class="o">(</span>null<span class="o">)</span> <span class="w"> </span><span class="s2">&quot;website_endpoint&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tostring<span class="o">(</span>null<span class="o">)</span> <span class="o">}</span> </code></pre></div> <p>As you can see <code>Apply complete! Resources: 0 added, 0 changed, 0 destroyed.</code> because no resources were created even though our <code>.tf</code> file has resource block.</p> <p>You can also get the output using <code>terraform output</code> command like this: <code>terraform output bucket_info</code></p> <p>Example:</p> <p><strong>List output of availability zones of region configured in your AWS configuration</strong></p> <p>First, create the data block because regions are not managed by Terraform and it's a data. And the output block. Since the output is from the data block, we define value as: <code>data.&lt;type&gt;.&lt;label&gt;</code></p> <div class="highlight"><pre><span></span><code><span class="kr">data</span><span class="w"> </span><span class="nc">&quot;aws_availability_zones&quot;</span><span class="w"> </span><span class="nv">&quot;available&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">state</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;available&quot;</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;aws_availability_zones&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">data.aws_availability_zones.available</span> <span class="p">}</span> </code></pre></div> <p>Now, plan it <code>terraform plan -out s3.tfplan</code> and apply <code>terraform apply s3.tfplan</code></p> <p>You'll see following output:</p> <div class="highlight"><pre><span></span><code>Apply<span class="w"> </span>complete!<span class="w"> </span>Resources:<span class="w"> </span><span class="m">0</span><span class="w"> </span>added,<span class="w"> </span><span class="m">0</span><span class="w"> </span>changed,<span class="w"> </span><span class="m">0</span><span class="w"> </span>destroyed. Outputs: <span class="nv">aws_availability_zones</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span><span class="s2">&quot;all_availability_zones&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tobool<span class="o">(</span>null<span class="o">)</span> <span class="w"> </span><span class="s2">&quot;blacklisted_names&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">(</span>null<span class="o">)</span><span class="w"> </span>/*<span class="w"> </span>of<span class="w"> </span>string<span class="w"> </span>*/ <span class="w"> </span><span class="s2">&quot;blacklisted_zone_ids&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">(</span>null<span class="o">)</span><span class="w"> </span>/*<span class="w"> </span>of<span class="w"> </span>string<span class="w"> </span>*/ <span class="w"> </span><span class="s2">&quot;exclude_names&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">(</span>null<span class="o">)</span><span class="w"> </span>/*<span class="w"> </span>of<span class="w"> </span>string<span class="w"> </span>*/ <span class="w"> </span><span class="s2">&quot;exclude_zone_ids&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">(</span>null<span class="o">)</span><span class="w"> </span>/*<span class="w"> </span>of<span class="w"> </span>string<span class="w"> </span>*/ <span class="w"> </span><span class="s2">&quot;filter&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">(</span>null<span class="o">)</span><span class="w"> </span>/*<span class="w"> </span>of<span class="w"> </span>object<span class="w"> </span>*/ <span class="w"> </span><span class="s2">&quot;group_names&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>toset<span class="o">([</span> <span class="w"> </span><span class="s2">&quot;ap-northeast-1&quot;</span>, <span class="w"> </span><span class="o">])</span> <span class="w"> </span><span class="s2">&quot;id&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;2021-01-16 10:53:54.916848 +0000 UTC&quot;</span> <span class="w"> </span><span class="s2">&quot;names&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([</span> <span class="w"> </span><span class="s2">&quot;ap-northeast-1a&quot;</span>, <span class="w"> </span><span class="s2">&quot;ap-northeast-1c&quot;</span>, <span class="w"> </span><span class="s2">&quot;ap-northeast-1d&quot;</span>, <span class="w"> </span><span class="o">])</span> <span class="w"> </span><span class="s2">&quot;state&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;available&quot;</span> <span class="w"> </span><span class="s2">&quot;zone_ids&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>tolist<span class="o">([</span> <span class="w"> </span><span class="s2">&quot;apne1-az4&quot;</span>, <span class="w"> </span><span class="s2">&quot;apne1-az1&quot;</span>, <span class="w"> </span><span class="s2">&quot;apne1-az2&quot;</span>, <span class="w"> </span><span class="o">])</span> <span class="o">}</span> </code></pre></div> <blockquote> <p>Note: The output of AZ's can be used later on if we want to provision EC2 instances in multiple regions. We can use this output to do it so.</p> </blockquote> <h2>3.4 Interpolation in HCL</h2> <p>Interpolation is just the means of concatenating different values to create one value. In case of S3 bucket the value of S3 bucket has to be globally unique. Hence, inorder to create a bucket with unique name, we can use interpolation.</p> <p>Example:</p> <p><strong>Create aws bucket which name has the </strong><strong><code>accountID</code></strong><strong> in it.</strong></p> <div class="highlight"><pre><span></span><code><span class="kr">data</span><span class="w"> </span><span class="nc">&quot;aws_caller_identity&quot;</span><span class="w"> </span><span class="nv">&quot;current&quot;</span><span class="w"> </span><span class="p">{}</span> <span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucket2&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${data.aws_caller_identity.current.account_id}-bucket2&quot;</span> <span class="p">}</span> </code></pre></div> <p>Here <code>data.aws_caller_identity.current.account_id</code> is interpolated which is <code>account_id + "-bucket2"</code> got from the data block <code>aws_caller_identity</code></p> <h2>3.5 Dependencies in Terraform</h2> <p>Terraform has the concept of <code>implicit</code> and <code>explicit</code> dependencies.</p> <p>Whe Terraform processes the HCL configs, it evaluates the dependency graph, and it'll create dependencies before it creates the dependent resource. If there is not any dependencies, Terraform will create resource in parallel which will give performance boost.</p> <p>Example:</p> <p>Implicit dependency resolve when the dependent resource already exists.</p> <div class="highlight"><pre><span></span><code><span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucket3&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${data.aws_caller_identity.current.account_id}-bucket3&quot;</span> <span class="w"> </span><span class="nb">tags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # I already have bucket2 available so this is implicit</span> <span class="w"> </span><span class="na">dependency</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">aws_s3_bucket.bucket2.arn</span> <span class="w"> </span><span class="p">}</span> <span class="p">}</span> </code></pre></div> <p>Explicit dependency when the dependent resource does not exist yet, and we need to wait for it to be created first. (analogy depends</p> <div class="highlight"><pre><span></span><code><span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucket4&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${data.aws_caller_identity.current.account_id}-bucket4&quot;</span> <span class="c1"> # Explicit</span> <span class="w"> </span><span class="na">depends_on</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span> <span class="w"> </span><span class="nv">aws_s3_bucket.bucket3</span> <span class="w"> </span><span class="p">]</span> <span class="p">}</span> </code></pre></div> <p>To see the dependencies, generate the <code>dot</code> file using <code>terraform graph &gt; graph.dot</code></p> <p>And paste the content in online tool <a href="https://dreampuf.github.io/GraphvizOnline/">https://dreampuf.github.io/GraphvizOnline/</a> to see the output.</p> <p>The <code>terraform graph</code> command is only used for debugging purpose.</p> <h2>3.6 Variables and Locals</h2> <p>Variables are ways to get input to the Terraform config</p> <p>Ways to provide variables:</p> <ul> <li>Using command line while applying</li> <li>Specify them in files such as <code>.tfvars</code> or <code>.auto.tfvars</code> for complex data types</li> <li>Using environment variables but all the environment variable name should have prefix of <code>TF_VAR_</code> In Terraform config, we use <code>variable</code> block to define expected variables.</li> </ul> <p>Example:</p> <p><strong>Create a S3 bucket, but the bucket name should be provided by the user</strong></p> <div class="highlight"><pre><span></span><code><span class="kr">variable</span><span class="w"> </span><span class="nv">&quot;bucket_name&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">string</span> <span class="c1"> # `default` is optional. If default is omitted, then value must be supplied</span> <span class="c1"> # default = &quot;My_Bucket1234&quot;</span> <span class="p">}</span> <span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucket5&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">var.bucket_name</span> <span class="p">}</span> </code></pre></div> <p>And when plan is executed, the bucket name is expected as an input value:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>terraform<span class="w"> </span>plan<span class="w"> </span>-out<span class="w"> </span>var.tfplan var.bucket_name <span class="w"> </span>Enter<span class="w"> </span>a<span class="w"> </span>value:<span class="w"> </span>MyPiBucket31415 An<span class="w"> </span>execution<span class="w"> </span>plan<span class="w"> </span>has<span class="w"> </span>been<span class="w"> </span>generated<span class="w"> </span>and<span class="w"> </span>is<span class="w"> </span>shown<span class="w"> </span>below. Resource<span class="w"> </span>actions<span class="w"> </span>are<span class="w"> </span>indicated<span class="w"> </span>with<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>symbols: <span class="w"> </span>+<span class="w"> </span>create Terraform<span class="w"> </span>will<span class="w"> </span>perform<span class="w"> </span>the<span class="w"> </span>following<span class="w"> </span>actions: <span class="w"> </span><span class="c1"># aws_s3_bucket.bucket5 will be created</span> <span class="w"> </span>+<span class="w"> </span>resource<span class="w"> </span><span class="s2">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="s2">&quot;bucket5&quot;</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">acceleration_status</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">acl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;private&quot;</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">arn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;MyPiBucket31415&quot;</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">bucket_domain_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">bucket_regional_domain_name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">force_destroy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">false</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">hosted_zone_id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">region</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">request_payer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">website_domain</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">website_endpoint</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span>versioning<span class="w"> </span><span class="o">{</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">enabled</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span>+<span class="w"> </span><span class="nv">mfa_delete</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">(</span>known<span class="w"> </span>after<span class="w"> </span>apply<span class="o">)</span> <span class="w"> </span><span class="o">}</span> <span class="w"> </span><span class="o">}</span> Plan:<span class="w"> </span><span class="m">1</span><span class="w"> </span>to<span class="w"> </span>add,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>change,<span class="w"> </span><span class="m">0</span><span class="w"> </span>to<span class="w"> </span>destroy. </code></pre></div> <p><strong>Local values</strong></p> <p>Local values make Terraform configs more readable.</p> <p>If we want to use same value multiple times in the code, it's better to save it as a local value.</p> <p>We can have multiple locals, but the names should be unique because names are global.</p> <p>Example:</p> <div class="highlight"><pre><span></span><code><span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">aws_account</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${data.aws_caller_identity.current.account_id}-${lower(data.aws_caller_identity.current.user_id)}&quot;</span> <span class="p">}</span> <span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucket6&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${local.aws_account}-bucket6&quot;</span> <span class="p">}</span> </code></pre></div> <blockquote> <p>Note: Here the <code>lower()</code> is a Terraform function. See more here: <a href="https://www.Terraform.io/docs/configuration/functions.html">https://www.Terraform.io/docs/configuration/functions.html</a></p> </blockquote> <h2>3.7 Conditionals and the Count property</h2> <p>Count is the meta attribute of Terraform</p> <p>Count means instead of creating 1 resource, you can define <code>n</code> number of count to replicate the same resource.</p> <p>Example:</p> <p><strong>Create 2 buckets</strong></p> <div class="highlight"><pre><span></span><code><span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucketX&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${local.aws_account}-bucket${count.index+7}&quot;</span> <span class="p">}</span> </code></pre></div> <p>Q. What happens when <code>count=0</code> ?</p> <p>Terraform will destroy all resource if created or not create anything if it's not created yet.</p> <p><strong>We can also replicate resources using </strong><strong><code>for_each</code></strong>** **</p> <div class="highlight"><pre><span></span><code><span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="nb">buckets</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">bucket101</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;mybucket101&quot;</span> <span class="w"> </span><span class="na">bucket102</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;mybucket102&quot;</span> <span class="w"> </span><span class="p">}</span> <span class="p">}</span> <span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucketIterator&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">for_each</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">local.buckets</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${local.aws_account}-${each.value}&quot;</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;bucketIterator&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">aws_s3_bucket.bucketIterator</span> <span class="p">}</span> </code></pre></div> <p>We can also define list instead of map:</p> <div class="highlight"><pre><span></span><code><span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">buckets</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span> <span class="w"> </span><span class="s2">&quot;mybucket101&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s2">&quot;mybucket102&quot;</span> <span class="w"> </span><span class="p">]</span> <span class="p">}</span> <span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;bucketIterator&quot;</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # Since buckets is a list, we need to convert to set using toset()</span> <span class="w"> </span><span class="na">for_each</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">toset</span><span class="p">(</span><span class="nv">local.buckets</span><span class="p">)</span> <span class="c1"> # Here we can use either .key or .value</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${local.aws_account}-${each.key}&quot;</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;bucketIterator&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">aws_s3_bucket.bucketIterator</span> <span class="p">}</span> </code></pre></div> <p><code>count</code> vs <code>for_each</code></p> <ul> <li> <p><code>count</code> is generally used for toggle switch when in development phase</p> </li> <li> <p><code>for_each</code> is more powerful, as we can use map in <code>for_each</code> hence, better to use <code>for_each</code> in prod</p> </li> </ul> <h2>3.8 Data types and operators</h2> <p>REF: <a href="https://www.Terraform.io/docs/configuration/expressions/types.html">https://www.Terraform.io/docs/configuration/expressions/types.html</a></p> <div class="highlight"><pre><span></span><code><span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">a_string</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;This is a String&quot;</span> <span class="w"> </span><span class="na">a_number</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">3.1415</span> <span class="w"> </span><span class="na">a_boolean</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">true</span> <span class="w"> </span><span class="na">a_list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span> <span class="w"> </span><span class="s2">&quot;element1&quot;</span><span class="p">,</span> <span class="w"> </span><span class="no">true</span><span class="p">,</span> <span class="w"> </span><span class="p">[</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="m">3</span><span class="p">]</span> <span class="w"> </span><span class="p">]</span> <span class="w"> </span><span class="nb">a_map</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;value&quot;</span> <span class="w"> </span><span class="na">nums</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="m">20</span><span class="p">,</span><span class="w"> </span><span class="m">30</span><span class="p">]</span> <span class="w"> </span><span class="na">is_active</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">true</span> <span class="w"> </span><span class="nb">configs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">instance_type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;t2.micro&quot;</span> <span class="w"> </span><span class="na">vpc_enabled</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">true</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">}</span> <span class="c1"> # Operators</span> <span class="w"> </span><span class="na">operators</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="m">3</span><span class="err">+</span><span class="m">3</span><span class="p">)</span><span class="err">-</span><span class="p">(</span><span class="m">3</span><span class="err">*</span><span class="m">3</span><span class="err">/</span><span class="m">3</span><span class="p">)</span> <span class="c1"> # Logical</span> <span class="w"> </span><span class="na">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">true</span><span class="w"> </span><span class="err">&amp;&amp;</span><span class="w"> </span><span class="no">true</span> <span class="w"> </span><span class="na">f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">true</span><span class="w"> </span><span class="err">||</span><span class="w"> </span><span class="no">false</span> <span class="c1"> # Comparison</span> <span class="w"> </span><span class="na">gt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="m">2</span> <span class="w"> </span><span class="na">lt</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="err">&lt;</span><span class="w"> </span><span class="m">9</span> <span class="w"> </span><span class="na">eq</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="na">4</span><span class="w"> </span><span class="o">=</span><span class="p">=</span><span class="w"> </span><span class="m">4</span> <span class="w"> </span><span class="na">neq</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="p">!=</span><span class="w"> </span><span class="m">5</span> <span class="p">}</span> </code></pre></div> <p>Example:</p> <p><strong>Terraform config to create </strong><strong><code>n</code></strong><strong> number of buckets where </strong><strong><code>n</code></strong><strong> not more than </strong><strong><code>5</code></strong>** **</p> <div class="highlight"><pre><span></span><code><span class="kr">variable</span><span class="w"> </span><span class="nv">&quot;bucket_count&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kt">number</span> <span class="p">}</span> <span class="kr">data</span><span class="w"> </span><span class="nc">&quot;aws_caller_identity&quot;</span><span class="w"> </span><span class="nv">&quot;current&quot;</span><span class="w"> </span><span class="p">{}</span> <span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">min_bucket_count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5</span> <span class="c1"> # Conditional operators similar to ternary operator</span> <span class="w"> </span><span class="na">num_buckets</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">var.bucket_count</span><span class="w"> </span><span class="err">&gt;</span><span class="w"> </span><span class="m">5</span><span class="w"> </span><span class="p">?</span><span class="w"> </span><span class="nv">local.min_bucket_count</span><span class="p">:</span><span class="w"> </span><span class="nv">var.bucket_count</span> <span class="w"> </span><span class="na">aws_account</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${data.aws_caller_identity.current.account_id}-${lower(data.aws_caller_identity.current.user_id)}&quot;</span> <span class="p">}</span> <span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;aws_s3_bucket&quot;</span><span class="w"> </span><span class="nv">&quot;buckets&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">local.num_buckets</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${local.aws_account}-buckets${count.index+7}&quot;</span> <span class="p">}</span> </code></pre></div> <h2>3.9 Functions</h2> <p>REF: <a href="https://www.Terraform.io/docs/configuration/functions.html">https[://www.Terraform.io/docs/configuration/functions.html](https://www.Terraform.io/docs/configuration/functions.html)</a></p> <p>Example:</p> <div class="highlight"><pre><span></span><code><span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">ts</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">timestamp</span><span class="p">()</span> <span class="w"> </span><span class="na">current_month</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">formatdate</span><span class="p">(</span><span class="s2">&quot;MMMM&quot;</span><span class="p">,</span><span class="w"> </span><span class="nv">local.ts</span><span class="p">)</span> <span class="w"> </span><span class="na">tomorrow</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">formatdate</span><span class="p">(</span><span class="s2">&quot;MMMM&quot;, timeadd(local.ts, &quot;24h&quot;</span><span class="p">))</span> <span class="w"> </span><span class="na">upper</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">upper</span><span class="p">(</span><span class="s2">&quot;lowercase&quot;</span><span class="p">)</span> <span class="w"> </span><span class="na">lower</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">lower</span><span class="p">(</span><span class="s2">&quot;UPPERCASE&quot;</span><span class="p">)</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;func&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;${local.ts} ${local.current_month} ${local.tomorrow} ${local.upper} ${local.lower}&quot;</span> <span class="p">}</span> </code></pre></div> <p>Output:</p> <div class="highlight"><pre><span></span><code>Apply<span class="w"> </span>complete!<span class="w"> </span>Resources:<span class="w"> </span><span class="m">0</span><span class="w"> </span>added,<span class="w"> </span><span class="m">0</span><span class="w"> </span>changed,<span class="w"> </span><span class="m">0</span><span class="w"> </span>destroyed. Outputs: <span class="nv">func</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;2021-01-16T15:36:41Z January January LOWERCASE uppercase&quot;</span> </code></pre></div> <h2>3.10 Iterations in collections</h2> <p>HCL uses <code>for</code> syntax dfor iterating over list values</p> <p>Example:</p> <div class="highlight"><pre><span></span><code><span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">my_list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;one&quot;, &quot;two&quot;, &quot;three&quot;</span><span class="p">]</span> <span class="w"> </span><span class="na">upper_list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="err">for</span><span class="w"> </span><span class="err">item</span><span class="w"> </span><span class="err">in</span><span class="w"> </span><span class="nv">local.my_list</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="nf">upper</span><span class="p">(</span><span class="err">item</span><span class="p">)]</span> <span class="w"> </span><span class="nb">upper_map</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="err">for</span><span class="w"> </span><span class="err">item</span><span class="w"> </span><span class="err">in</span><span class="w"> </span><span class="nv">local.my_list</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="na">item</span><span class="w"> </span><span class="o">=</span><span class="err">&gt;</span><span class="w"> </span><span class="nf">upper</span><span class="p">(</span><span class="err">item</span><span class="p">)</span><span class="w"> </span><span class="p">}</span> <span class="c1"> # Filtering</span> <span class="w"> </span><span class="na">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="m">4</span><span class="p">,</span><span class="w"> </span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="m">6</span><span class="p">,</span><span class="w"> </span><span class="m">7</span><span class="p">,</span><span class="w"> </span><span class="m">8</span><span class="p">,</span><span class="w"> </span><span class="m">9</span><span class="p">]</span> <span class="w"> </span><span class="na">evens</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="err">for</span><span class="w"> </span><span class="err">i</span><span class="w"> </span><span class="err">in</span><span class="w"> </span><span class="nv">local.n</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="err">i</span><span class="w"> </span><span class="err">if</span><span class="w"> </span><span class="err">i</span><span class="w"> </span><span class="err">%</span><span class="w"> </span><span class="na">2</span><span class="w"> </span><span class="o">=</span><span class="p">=</span><span class="w"> </span><span class="m">0</span><span class="p">]</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;my_list&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">local.my_list</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;upper_list&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">local.upper_list</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;upper_map&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">local.upper_map</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;evens&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">local.evens</span> <span class="p">}</span> </code></pre></div> <p>Output after apply:</p> <div class="highlight"><pre><span></span><code>Apply<span class="w"> </span>complete!<span class="w"> </span>Resources:<span class="w"> </span><span class="m">0</span><span class="w"> </span>added,<span class="w"> </span><span class="m">0</span><span class="w"> </span>changed,<span class="w"> </span><span class="m">0</span><span class="w"> </span>destroyed. Outputs: <span class="nv">evens</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[</span> <span class="w"> </span><span class="m">2</span>, <span class="w"> </span><span class="m">4</span>, <span class="w"> </span><span class="m">6</span>, <span class="w"> </span><span class="m">8</span>, <span class="o">]</span> <span class="nv">my_list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[</span> <span class="w"> </span><span class="s2">&quot;one&quot;</span>, <span class="w"> </span><span class="s2">&quot;two&quot;</span>, <span class="w"> </span><span class="s2">&quot;three&quot;</span>, <span class="o">]</span> <span class="nv">upper_list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">[</span> <span class="w"> </span><span class="s2">&quot;ONE&quot;</span>, <span class="w"> </span><span class="s2">&quot;TWO&quot;</span>, <span class="w"> </span><span class="s2">&quot;THREE&quot;</span>, <span class="o">]</span> <span class="nv">upper_map</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">{</span> <span class="w"> </span><span class="s2">&quot;one&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;ONE&quot;</span> <span class="w"> </span><span class="s2">&quot;three&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;THREE&quot;</span> <span class="w"> </span><span class="s2">&quot;two&quot;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;TWO&quot;</span> <span class="o">}</span> </code></pre></div> <h2>3.11 Directives and heredocs</h2> <ul> <li><code>heredocs</code><ul> <li>is a multiline string that is used to create an inline JSON documents</li> <li>They are used in outputs, variables description and inline documents Example:</li> </ul> </li> </ul> <div class="highlight"><pre><span></span><code><span class="nb">locals</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">count</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0</span> <span class="w"> </span><span class="na">nums</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="m">3</span><span class="p">]</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;heredocs&quot;</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # EOT means EOF</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&lt;&lt;-</span><span class="dl">EOT</span> <span class="sh"> This is the `heredoc`.</span> <span class="sh"> This is multiline String.</span> <span class="sh"> Used for writing documentations.</span> <span class="dl"> EOT</span> <span class="c1"> # Dont forget EOT at the end</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;directive&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&lt;&lt;-</span><span class="dl">EOT</span> <span class="sh"> We can use directive in heredoc.</span> <span class="sh"> %{if local.count == 0}</span> <span class="sh"> The count is 0, destroying everything...</span> <span class="sh"> %{else}</span> <span class="sh"> The count is ${local.count}</span> <span class="sh"> %{endif}</span> <span class="dl"> EOT</span> <span class="p">}</span> <span class="kr">output</span><span class="w"> </span><span class="nv">&quot;iterated-directive&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&lt;&lt;-</span><span class="dl">EOT</span> <span class="sh"> Directive can also be iterated.</span> <span class="sh"> %{for num in local.nums}</span> <span class="sh"> ${num}</span> <span class="sh"> %{endfor}</span> <span class="dl"> EOT</span> <span class="p">}</span> </code></pre></div> <p>Output after apply:</p> <div class="highlight"><pre><span></span><code>Apply<span class="w"> </span>complete!<span class="w"> </span>Resources:<span class="w"> </span><span class="m">0</span><span class="w"> </span>added,<span class="w"> </span><span class="m">0</span><span class="w"> </span>changed,<span class="w"> </span><span class="m">0</span><span class="w"> </span>destroyed. Outputs: <span class="nv">directive</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&lt;&lt;EOT</span> <span class="s">We can use directive in heredoc.</span> <span class="s">The count is 0, destroying everything...</span> <span class="s">EOT</span> <span class="nv">heredocs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&lt;&lt;EOT</span> <span class="s">This is the `heredoc`.</span> <span class="s">This is multiline String.</span> <span class="s">Used for writing documentations.</span> <span class="s">EOT</span> iterated-directive<span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&lt;&lt;EOT</span> <span class="s">Directive can also be iterated.</span> <span class="s">1</span> <span class="s">2</span> <span class="s">3</span> <span class="s">EOT</span> </code></pre></div> <h2>3.12 Clean up</h2> <p>Since we created multiple buckets and all, it's time to clean up.</p> <p>Even though the buckets don't cost any, it's wise to clean up since we're just playing with Terraform in development mode.</p> <p>First look for states that's tracked by Terraform using <code>terraform state list</code> . If it shows bunch of outputs of your bucket, execute <code>terraform destroy</code> which will destroy all resources that were created.</p> <h1>Chapter 4: Code Re-Use for applying DRY</h1> <h2>4.1 Understanding Terraform Modules</h2> <p>What is a module in Terraform?</p> <ul> <li>All Terraform is in a module. The top level module is called the Root module</li> <li>Modules are just a directory that contains Terraform file, and they can be nested</li> <li>Modules can be imported which are already available</li> <li>Modules written by others can be get here <a href="https://registry.Terraform.io">https://registry.Terraform.io</a></li> <li>Module helps in implementing DRY principle</li> <li>Module naming convention (if you want to publish to Terraform registry)<ul> <li><code>terraform-&lt;PROVIDER&gt;-&lt;NAME&gt;</code></li> <li><code>&lt;NAME&gt;</code> can contain hyphens Module layout</li> </ul> </li> </ul> <div class="highlight"><pre><span></span><code>├──<span class="w"> </span>Terraform-aws-s3 │<span class="w">   </span>├──<span class="w"> </span>README.md │<span class="w">   </span>├──<span class="w"> </span>datas.tf │<span class="w">   </span>├──<span class="w"> </span>locals.tf │<span class="w">   </span>├──<span class="w"> </span>main.tf │<span class="w">   </span>├──<span class="w"> </span>outputs.tf │<span class="w">   </span>├──<span class="w"> </span>variables.tf │<span class="w">   </span>└──<span class="w"> </span>versions.tf </code></pre></div> <p>You can use <a href="https://github.com/QuiNovas/cookiecutter-Terraform-module">https://github.com/QuiNovas/cookiecutter-Terraform-module</a> to automate the process of creating these files</p> <p>To use module</p> <div class="highlight"><pre><span></span><code><span class="c1"># Module located in local filesystem</span> <span class="k">module</span> <span class="s">&quot;local-module&quot;</span> { <span class="nb">source</span> = <span class="s">&quot;/path/to/module&quot;</span> } <span class="c1"># Module which is published</span> <span class="k">module</span> <span class="s">&quot;published-module&quot;</span> { <span class="nb">source</span> = <span class="s">&quot;rojopolis/Terraform-aws-lambda-python-archive&quot;</span> <span class="nb">version</span> = <span class="s">&quot;1.2.3&quot;</span> } <span class="c1"># Module which is in GitHub</span> <span class="k">module</span> <span class="s">&quot;github-module&quot;</span> { <span class="nb">source</span> = <span class="s">&quot;https://github.com/rojopolis/Terraform-aws-lambda-python-archive&quot;</span> } </code></pre></div> <p>Play with <a href="https://github.com/rojopolis/Terraform-aws-lambda-python-archive/">https://github.com/rojopolis/Terraform-aws-lambda-python-archive/</a> to know about modules.</p> <h2>4.2 Distributing modules</h2> <ul> <li>Name the module properly <code>terraform-&lt;PROVIDER&gt;-&lt;NAME&gt;</code></li> <li>Should be in public repository in GitHub.</li> <li>Should have license and examples</li> <li>Repo should be released with a tag</li> <li>Sign-in to <a href="https://registry.Terraform.io">https://registry.Terraform.io</a></li> <li>Select the repo which is named correctly</li> <li>Done 🎉</li> <li>Profit 🏦</li> </ul> <h1>Chapter 5: Collaboration with Terraform</h1> <h2>5.1 Terraform backends</h2> <ul> <li>Backend is a shared storage medium that stores state files</li> <li>Backends officially supports blocking</li> <li>Blocking is required inorder to prevent multiple user's updating resources at the same time</li> <li>Most of the providers support blocking</li> <li>We can use S3 as a backend provider</li> <li>Backend provider is not in Terraform Example:</li> </ul> <div class="highlight"><pre><span></span><code><span class="nb">terraform</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">required_version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;&gt;=0.14.0&quot;</span> <span class="w"> </span><span class="kr">backend</span><span class="w"> </span><span class="nv">&quot;s3&quot;</span><span class="w"> </span><span class="p">{</span> <span class="c1"> # bucket should already exist</span> <span class="w"> </span><span class="na">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;my-Terraform-backend&quot;</span> <span class="w"> </span><span class="na">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;sagar-Terraform-resources&quot;</span> <span class="w"> </span><span class="na">region</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;ap-northeast-1&quot;</span> <span class="c1"> # dynamo db table also should already exist</span> <span class="w"> </span><span class="na">dynamodb_table</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;sagar-Terraform-lock&quot;</span> <span class="w"> </span><span class="p">}</span> <span class="p">}</span> </code></pre></div> <p>You must <code>init</code> again inorder to change the backend.</p> <p>Locks are stored in dynamodb table. Whoever acquires the lock first has the precedence of getting the resource.</p> <p>We can also have remote backend</p> <div class="highlight"><pre><span></span><code><span class="w"> </span><span class="kr">backend</span><span class="w"> </span><span class="nv">&quot;remote&quot;</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">hostname</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;app.Terraform.io&quot;</span> <span class="w"> </span><span class="na">organization</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;beBit&quot;</span> <span class="w"> </span><span class="nb">workspace</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="na">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;hello-Terraform&quot;</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">}</span> </code></pre></div> <p>If we change the S3 backend to remote backend, we need to do <code>terraform init</code> again which will ask us if we'd like to move the state file from S3 to the remote backend.</p> <h2>5.2 Terraform workspaces</h2> <ul> <li>Workspace helps us to create different environment with the same sets of Terraform configurations.</li> <li>You can view the list of your Terraform workspaces using the command <code>terraform workspace list</code></li> <li>The default workspace name is called <code>default</code></li> <li>You can not delete the default workspace</li> <li>Execute <code>terraform workspace --help</code> to view the workspaces sub-commands</li> </ul> <p>Create a new workspace:</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>workspace<span class="w"> </span>new<span class="w"> </span>staging Created<span class="w"> </span>and<span class="w"> </span>switched<span class="w"> </span>to<span class="w"> </span>workspace<span class="w"> </span><span class="s2">&quot;staging&quot;</span>! You<span class="err">&#39;</span>re<span class="w"> </span>now<span class="w"> </span>on<span class="w"> </span>a<span class="w"> </span>new,<span class="w"> </span>empty<span class="w"> </span>workspace.<span class="w"> </span>Workspaces<span class="w"> </span>isolate<span class="w"> </span>their<span class="w"> </span>state, so<span class="w"> </span><span class="k">if</span><span class="w"> </span>you<span class="w"> </span>run<span class="w"> </span><span class="s2">&quot;terraform plan&quot;</span><span class="w"> </span>Terraform<span class="w"> </span>will<span class="w"> </span>not<span class="w"> </span>see<span class="w"> </span>any<span class="w"> </span>existing<span class="w"> </span>state <span class="k">for</span><span class="w"> </span>this<span class="w"> </span>configuration. </code></pre></div> <p>List the workspaces:</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>workspace<span class="w"> </span>list <span class="w"> </span>default *<span class="w"> </span>staging </code></pre></div> <p>Where the <code>*</code> is the current one, and we can also use <code>terraform workspace show</code> to get the current workspace.</p> <p>Switch the workspace back to <code>default</code></p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>workspace<span class="w"> </span><span class="k">select</span><span class="w"> </span>default<span class="w"> </span><span class="m">1</span><span class="w"> </span>↵ Switched<span class="w"> </span>to<span class="w"> </span>workspace<span class="w"> </span><span class="s2">&quot;default&quot;</span>. </code></pre></div> <p>Deleting the workspace:</p> <div class="highlight"><pre><span></span><code>╰─$<span class="w"> </span>terraform<span class="w"> </span>workspace<span class="w"> </span>delete<span class="w"> </span>staging Deleted<span class="w"> </span>workspace<span class="w"> </span><span class="s2">&quot;staging&quot;</span>! </code></pre></div> <blockquote> <p>Note: The workspace should be clean i.e. destroyed before deleting it. Learn more here: <a href="https://www.Terraform.io/docs/state/workspaces.html">https://www.Terraform.io/docs/state/workspaces.html</a></p> </blockquote>Instrument your Java Code with Micrometer, Prometheus, and Grafana.2020-12-31T15:33:00+09:002020-12-31T15:33:00+09:00Sagar Giritag:sagargiri.com,2020-12-31:/java-instrumentation-with-micrometer<p>In this blog tutorial, let's instrument your Java SE code with Prometheus using Micrometer</p><blockquote> <p>Micrometer provides a simple facade over the instrumentation clients for the most popular monitoring systems, allowing you to instrument your JVM-based application code without vendor lock-in. Think SLF4J, but for metrics. - https://micrometer.io/</p> </blockquote> <p>I'm assuming you have some Java code, and you'd like to instrument it (measure how well it's performing, what is the heap space in current state, are there any exceptions. etc)</p> <p>With this 3 steps, you'll be up and running in no time.</p> <h1>Step 1: Setup the development environment</h1> <p>Here I am using <a href="https://www.docker.com/">Docker</a> and <a href="https://docs.docker.com/compose/">Docker compose</a> to set up the environment for simplicity purposes. If you do not have these in your machine, I highly recommend you to install it so that you can follow along.</p> <blockquote> <p>The full source code is available here: https://github.com/girisagar46/prome-java</p> </blockquote> <p>First and foremost, I will set <a href="https://prometheus.io/">Prometheus</a> and <a href="https://grafana.com/">Grafana</a> in my <code>docker-compose.yml</code> file.</p> <p>The <code>docker-compose.yml</code> file looks like this:</p> <div class="highlight"><pre><span></span><code><span class="n">version</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;3.8&quot;</span> <span class="n">services</span><span class="p">:</span> <span class="w"> </span><span class="n">prometheus</span><span class="p">:</span> <span class="w"> </span><span class="n">image</span><span class="p">:</span><span class="w"> </span><span class="n">prom</span><span class="o">/</span><span class="n">prometheus</span> <span class="w"> </span><span class="n">container_name</span><span class="p">:</span><span class="w"> </span><span class="n">prometheus</span> <span class="w"> </span><span class="n">volumes</span><span class="p">:</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">./</span><span class="n">monitoring</span><span class="o">/</span><span class="n">prometheus</span><span class="o">.</span><span class="n">yml</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">prometheus</span><span class="o">/</span><span class="n">prometheus</span><span class="o">.</span><span class="n">yml</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">./</span><span class="n">data</span><span class="o">/</span><span class="n">prometheus</span><span class="p">:</span><span class="o">/</span><span class="n">data</span> <span class="w"> </span><span class="n">command</span><span class="p">:</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="s2">&quot;--config.file=/etc/prometheus/prometheus.yml&quot;</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="s2">&quot;--storage.tsdb.path=/data&quot;</span> <span class="w"> </span><span class="n">ports</span><span class="p">:</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="s2">&quot;9090:9090&quot;</span> <span class="w"> </span><span class="n">restart</span><span class="p">:</span><span class="w"> </span><span class="n">always</span> <span class="w"> </span><span class="n">grafana</span><span class="p">:</span> <span class="w"> </span><span class="n">image</span><span class="p">:</span><span class="w"> </span><span class="n">grafana</span><span class="o">/</span><span class="n">grafana</span> <span class="w"> </span><span class="n">volumes</span><span class="p">:</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">./</span><span class="n">grafana</span><span class="p">:</span><span class="o">/</span><span class="k">var</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">grafana</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">./</span><span class="n">grafana</span><span class="o">/</span><span class="n">datasources</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">grafana</span><span class="o">/</span><span class="n">datasources</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">./</span><span class="n">grafana</span><span class="o">/</span><span class="n">dashboards</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">grafana</span><span class="o">/</span><span class="n">dashboard</span> <span class="w"> </span><span class="n">ports</span><span class="p">:</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="s2">&quot;3000:3000&quot;</span> <span class="w"> </span><span class="n">restart</span><span class="p">:</span><span class="w"> </span><span class="n">always</span> <span class="w"> </span><span class="n">environment</span><span class="p">:</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">GF_SECURITY_ADMIN_USER</span><span class="o">=</span><span class="n">admin</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">GF_SECURITY_ADMIN_PASSWORD</span><span class="o">=</span><span class="n">admin</span> <span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">GF_USERS_ALLOW_SIGN_UP</span><span class="o">=</span><span class="bp">false</span> </code></pre></div> <p>Since we're mounting <code>/monitoring/prometheus.yml</code> into prometheus service, let's create the directory <code>monitoring</code> and create a file <code>prometheus.yml</code> inside the <code>monitoring</code> directory.</p> <p>The contents of the <code>prometheus.yml</code> looks like this:</p> <script src="https://gist.github.com/girisagar46/3f2327a403eb37f6b5cac0bf07aa592a.js"></script> <p>Once the <code>docker-compose.yml</code> is ready, start the services with <code>docker-compose up</code></p> <p>And when the services are up, visit <a href="http://localhost:9090/">http://localhost:9090/</a>. You'll see something like this: <img alt="Prometheus UI" src="../images/java-micrometer/prometheus-ui.png"></p> <p>And if you navigate to <a href="http://localhost:9090/targets">http://localhost:9090/targets</a> (<code>Status</code> dropdown -&gt; <code>Targets</code>), you'll see something like this: <img alt="Prometheus UI" src="../images/java-micrometer/prometheus-targets.png"></p> <p>As you can see there's an error message that says:</p> <div class="highlight"><pre><span></span><code><span class="nv">Get</span><span class="w"> </span><span class="s2">&quot;http://host.docker.internal:8080/metrics&quot;</span>:<span class="w"> </span><span class="nv">dial</span><span class="w"> </span><span class="nv">tcp</span><span class="w"> </span><span class="mi">192</span>.<span class="mi">168</span>.<span class="mi">65</span>.<span class="mi">2</span>:<span class="mi">8080</span>:<span class="w"> </span><span class="k">connect</span>:<span class="w"> </span><span class="nv">connection</span><span class="w"> </span><span class="nv">refused</span> </code></pre></div> <p>because our Java application is not running at the moment. We'll fix this a little letter.</p> <p>If you visit <a href="http://localhost:3000/">http://localhost:3000/</a>, you'll see the Grafana login page:</p> <p><img alt="Grafana Login" src="../images/java-micrometer/grafana-login.png"></p> <p>Use the default username: <code>admin</code> and password <code>admin</code> to get inside the Grafana dashboard. When asked to change password, skip it as it's just a local development environment. Obviously in production, this has to be more sure by enabling the login by Gmail or any other OAUTH mechanism.</p> <p>Now you need to add Prometheus data source so that our Grafana can get the piece of the metrics we're exposing. To add the datasource directly go to <a href="http://localhost:3000/datasources">http://localhost:3000/datasources</a></p> <p>Then click on <strong>Add data source</strong> button and fill up the form as shown in the screenshot below.</p> <p><img alt="grafana-datasource.png" src="../images/java-micrometer/grafana-datasource.png"></p> <h1>Step 2: Expose metrics from your Java application</h1> <ol> <li>Create <code>MetricService</code> class which will provide the singleton instance of <code>PrometheusMeterRegistry</code></li> </ol> <script src="https://gist.github.com/girisagar46/9ffa46b7f251301576a7df9bd4e59c00.js"></script> <ol> <li>Create HTTP metric endpoint where prometheus can go to scrape the metrics. As you can see in the <code>prometheus.yml</code> file we've defined <code>metrics_path: "/metrics"</code>. So, let's create HTTP endpoint. I'll add this in the <code>Actuator.java</code> file:</li> </ol> <script src="https://gist.github.com/girisagar46/2684a5443274bf19890a5c5224e4e2fc.js"></script> <ol> <li>Create the Main class (the entry point to our application)</li> </ol> <script src="https://gist.github.com/girisagar46/8a79f2433a238ab60dad71aec5235c12.js"></script> <p>At this point, the source code directory looks like this:</p> <p><img alt="project-structure.png" src="../images/java-micrometer/project-structure.png"></p> <p>Now if you run your application (Execute Main.java) and go to <a href="http://localhost:8080/metrics">http://localhost:8080/metrics</a>, you'll see following output:</p> <div class="highlight"><pre><span></span><code>... <span class="gh">#</span> HELP jvm_gc_live_data_size_bytes Size of long-lived heap memory pool after reclamation <span class="gh">#</span> TYPE jvm_gc_live_data_size_bytes gauge jvm_gc_live_data_size_bytes 0.0 <span class="gh">#</span> HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool <span class="gh">#</span> TYPE jvm_buffer_count_buffers gauge jvm_buffer_count_buffers{id=&quot;mapped - &#39;non-volatile memory&#39;&quot;,} 0.0 jvm_buffer_count_buffers{id=&quot;mapped&quot;,} 0.0 jvm_buffer_count_buffers{id=&quot;direct&quot;,} 2.0 <span class="gh">#</span> HELP jvm_memory_used_bytes The amount of used memory <span class="gh">#</span> TYPE jvm_memory_used_bytes gauge ... </code></pre></div> <p>Which means your Java application is exposing metrics for the Prometheus to grab.</p> <h1>Step 3: Visualize the exposed metrics in Grafana</h1> <p>Since, we're only exposing JVM metrics for now let's see those exposed metrics on Grafana through a sweet dashboard.</p> <p>Let's import the <a href="https://grafana.com/grafana/dashboards/4701">Micrometer grafana official dashboard</a>. The ID of the grafana dashboard is <code>4701</code>. So, let's import the dashboard to Grafana.</p> <p>Click on the <strong>Import</strong> button which is shown in the screenshot below.</p> <p><img alt="dashboard-import.png" src="../images/java-micrometer/dashboard-import.png"></p> <p>Type <code>4701</code> in the input field <code>Import via grafana.com</code> and click <strong>Load</strong> button.</p> <p><img alt="import-4701.png" src="../images/java-micrometer/import-4701.png"></p> <p>Once, you click load, you'll see this page. Follow the 3 steps shown in the screenshot.</p> <p><img alt="import-dashboard.png" src="../images/java-micrometer/import-dashboard.png"></p> <p>Now your dashboard is imported, change the date range to view recent data.</p> <p><img alt="dashboard-range.png" src="../images/java-micrometer/dashboard-range.png"></p> <p>Congratulations!! your dashboard is fully functional and ready to use.</p> <p><img alt="full-dashboard.png" src="../images/java-micrometer/full-dashboard.png"></p> <p>You can play with Prometheus and Grafana as much as you like because everything is running in local. Try creating some alerts, Prometheus rules, write some PROMQL and expose some other metrics with Micrometer.</p> <p>If you want to take this to production, you can do it in various ways. Using K8s, using 3rd party service, hosting your own, using AWS managed service, etc. There are plethora of options, and you can choose any depending on your cost and requirements.</p> <h1>Going further</h1> <p>Now the basic setup is done, the metrics world does not stop here. It's a vast ocean. Here are some further additional resources which will help you to go forward.</p> <ol> <li><a href="https://micrometer.io/docs/concepts">https://micrometer.io/docs/concepts</a></li> <li><a href="https://prometheus.io/docs/prometheus/latest/getting_started/">https://prometheus.io/docs/prometheus/latest/getting_started/</a></li> <li><a href="https://prometheus.io/docs/prometheus/latest/querying/basics/">https://prometheus.io/docs/prometheus/latest/querying/basics/</a></li> <li><a href="https://www.youtube.com/watch?v=hTjHuoWxsks">Video: PromQL for Mere Mortals</a></li> <li><a href="https://www.youtube.com/watch?v=nJMRmhbY5hY">Video: The 4 Types Of Prometheus Metrics</a></li> <li><a href="https://www.robustperception.io/blog">https://www.robustperception.io/blog</a></li> <li><a href="https://grafana.com/tutorials/">https://grafana.com/tutorials/</a></li> <li><a href="https://github.com/prometheus/client_java">https://github.com/prometheus/client_java</a></li> <li><a href="https://www.reddit.com/r/PrometheusMonitoring">https://www.reddit.com/r/PrometheusMonitoring</a> -&gt; Reddit community</li> <li><a href="https://www.reddit.com/r/grafana">https://www.reddit.com/r/grafana</a> -&gt; Reddit community</li> <li><a href="https://slofile.com/slack/micrometer-metrics">https://slofile.com/slack/micrometer-metrics</a> -&gt; Official Slack channel for Micrometer (Join and ask any questions related to Prometheus, Grafana and Micrometer)</li> </ol>The Insides of Kubernetes and how it actually works.2019-09-06T14:30:00+09:002019-09-06T14:30:00+09:00Sagar Giritag:sagargiri.com,2019-09-06:/k8s-in-out<p>In this article, you'll learn about the REST objects in kubernetes (pods, replication controller, deployments, service)</p><blockquote> <p>"It groups containers that make up an application into logical units for easy management and discovery. Kubernetes builds upon 15 years of experience of running production workloads at Google, combined with best-of-breed ideas and practices from the community." — Kubernetes, Production-Grade Container Orchestration</p> </blockquote> <h3>What is Kubernetes?</h3> <p>In a typical micro service architecture using k8s, we have these things:</p> <p><img alt="Cover" src="../images/k8s/architecture.jpg"></p> <ul> <li>In a simple term, k8s is composed of Nodes and Pods.</li> <li>Combination of nodes creates a cluster aka kubernetes cluster.</li> <li>You can consider nodes as a physical or virtual server.</li> <li>There are two kinds of nodes:<ol> <li>Master node (Controls what's going on)</li> <li>Node aka Minions (That does the actual work)</li> </ol> </li> <li>Each node has pods.</li> <li>Each pods have one or more container running inside it.</li> </ul> <p><strong>In the birds eye view, Kubernetes architecture can be viewed as:</strong></p> <p><img alt="Birds-eye" src="../images/k8s/birds-eye.jpg"></p> <h3>Nodes:</h3> <p>A node is a worker machine in Kubernetes. Learn more <a href="https://lmgtfy.com/?q=kubernetes+nodes">here</a></p> <p>There are two types of nodes:</p> <ol> <li>Master node</li> <li>Worker node</li> </ol> <h4>Master Node</h4> <ul> <li>There can be one or more master node in a k8s cluster.</li> <li>Best practice is to make master node free of workloads so that master node can only look after cluster.</li> <li>You can think master node as a shepherd who who tends and rears sheep. (worker nodes)</li> </ul> <p><strong>What's inside a master node?</strong></p> <p><img alt="Master Node" src="../images/k8s/master-node.jpg"></p> <ul> <li>Remember a Node is a machine. So the base layer is the hardware layer. It can be bare metal, a virtual server, EC2 instance or even your personal laptop (if you are in local environment)</li> <li>Then the layer after that is OS layer. And remember, K8s only works in Linux OS. Kubernetes is platform agnostic in terms of hardware lever, but it needs Linux OS to operate.</li> </ul> <p><strong>Components of Master node:</strong></p> <ol> <li> <p>Scheduler: Watches for new pods and assign work to that pod.</p> </li> <li> <p>Controller: This watches for changes in the cluster</p> </li> <li> <p>Key Value Store: This is the persistent storage service. It uses <a href="https://etcd.io/">etcd</a> to maintain it's state. So in a master node, only this component is stateful.</p> </li> <li> <p>API server: This exposes the REST API for developers and clients to interact with k8s cluster. Developers deal directly with api server via command line tool provided by kubernetes called <code>kubectl</code>. API server can also be linked with authentication service to provide extra layer of security for k8s cluster.</p> </li> </ol> <h4>Worker Node</h4> <p>Worker node (also used to be called as minion) are also a machine that does the actual work. For example, updating a shopping cart or authenticating a user in your web application.</p> <p><strong>What's inside a worker node?</strong></p> <p><img alt="Worker Node" src="../images/k8s/worker-node.jpg"></p> <ol> <li> <p>Kubelet: They are main k8s agent They instantiate pod, register node with a cluster and operate on port 10255 Kubelet just report back to master node if a container dies. The endpoint provied by kubelet are: <code>/spec</code>, <code>/healtz</code> , <code>/pods</code></p> </li> <li> <p>Container Engine: They do container management (pulling image, running container)</p> </li> <li> <p>Kube Proxy Responsible for K8s networking This makes sure that each pod get unique IP address for network communication If more than 1 container is running inside a pod, then all pod share the same IP address but the port is different This also does load balancing across all pods in a service (#service section)</p> </li> </ol> <h3>Declarative model and Desired state</h3> <p>Kubernetes work in declarative model. Which basically means that we provide the APIServer (which is inside the master node) some specification to describe the desired state. The specification is written in JSON or YAML format. Once we provide the specification <strong>declaration</strong>, then it's the responsibility of Kubernetes to maintain the <em>desired</em> state.</p> <h4>Declarative Model</h4> <p>We give manifest to do something. For example: At each time, there must be 5 containers running.</p> <h4>Desired State</h4> <p>This is done by k8s internally. For example: Since we declared to run 5 replicas, but at a particular instant of time, if only 4 are running (which don't match with declaration), then k8s kicks in and tries to maintain the desired state from the declaration manifest (written in YAML or JSON which is provided to master node)</p> <h3>Pods</h3> <ul> <li>Pods are atomic unit of deployment in k8s world and they exists inside a node</li> <li>Containers always runs inside a pod</li> <li>Pods can have multiple containers (only in advanced cases, but ideally one)</li> <li>If two containers are running inside a same pod, then they share same memory space and volumes. This running more than one containers are useful if we want tightly coupled architecture.</li> </ul> <p><img alt="Pod Multi" src="../images/k8s/pod-multi.jpg"></p> <p>Here in above figure, these two containers share the same DB and also same file system and also the same IP address.</p> <p>In detail:</p> <p><img alt="Pod Multi" src="../images/k8s/pod-multi-detail.jpg"></p> <p>Containers inside the pod share the same IP address of the pod, but the port of each container is different. Intra container communication happens inside the pods by localhost.</p> <p>For loosely coupled system, the containers from two different pods can talk to each other through network communication.</p> <p><img alt="Pod Multi Container multi" src="../images/k8s/pod-multi-container-multi.jpg"></p> <ul> <li>Pods are also the unit of scaling in kubernetes world. We scale pods up and down (add or remove pods) while scaling.</li> <li>Pods are <em>atomic</em>. Which means we just create replicas of pods. We don't wait for the containers to be up before creating a pod. We just create create replicas of already up and running pods.</li> <li>Pod lifecycle is: <strong>pending -&gt; running -&gt; success or failed -&gt; die</strong></li> <li>There is no half (partially up) pod. Either it's up or not.</li> <li>Ideally 1 pod gets scheduled to one node</li> </ul> <p>Pod Lifecycle:</p> <p><img alt="Pod lifecycle" src="../images/k8s/pod-lifecycle.png"></p> <ol> <li>First we provide the manifest file to API server in k8s master node</li> <li>API server receives manifest file and tries to run container and pod goes to pending mode</li> <li>In pending mode, image is downloaded</li> <li>Then container inside the pods are run</li> <li>Then it goes to running mode</li> <li>And if the purpose of pod is full filled, then when pod is gracefully stopped, it goes to succeed state</li> </ol> <p>Note: If for some whatever reason, if some problem arises in pending mode, then the pod goes to failed mode.</p> <h3>Replication Controller</h3> <p>But, in real world, we really don't work with pods directly. We use ReplicationController to work with pods. ReplicationController sits on top of pod and it instantiating the pod(s)</p> <p><img alt="Replication Controller" src="../images/k8s/rc.png"></p> <h3>Services</h3> <ul> <li>Pods are volatile. They are not persistent.</li> <li>Pods go alive and die rapidly. When they die and generate their IP address changes rapidly. If pods die or new pods are added it's very difficult to manage the IP address and connection between these pods. To address this issue, we make use of service.</li> <li>Service sits between pods layer and manages the network connection between the pods</li> <li>They also do load balancing tasks</li> <li>It's the job of service to send traffic to healthy pods and it uses TCP protocol by default</li> <li>When our app is deployed in Kubernetes, we want it to be used by public. Hence, Service also helps to expose our application to public world (in the internet)</li> <li>Service gets single DNS, static IP, and never changing port.</li> <li>Services are stateful and they never change once defined.</li> <li>Services and pods are tied together by label</li> <li>Our client can talk to service in-order to get access to the application hosted in the pods</li> </ul> <p><img alt="Service" src="../images/k8s/service.png"></p> <h3>Deployments</h3> <p><img alt="Deployments" src="../images/k8s/deployment.png"></p> <ul> <li>These are the one which we interact the most</li> <li>They sit above the replication controller. And in the world of k8s deployment, replication sets are called replica set</li> <li>Deployments are:</li> <li>Self documenting</li> <li>Write spec once, deploy many</li> <li>Versioned</li> <li>Simple rolling updates and rollbacks</li> <li>Proper first class REST objects in k8s api</li> <li>Defined in standard manifest file</li> <li>Deployed via API server (in master node)</li> <li>Add features to replication controller</li> </ul>Build AWS CodePipeline CI/CD for your Django Application2019-02-15T22:50:00+09:002019-02-15T22:50:00+09:00Sagar Giritag:sagargiri.com,2019-02-15:/build-aws-codepipeline-for-cicd<p>In this article, you'll learn how to setup AWS CodePipeline for Continuous Integration and Continuous Delivery (CI/CD) pipeline for your Django Application.</p><blockquote> <p>Assumption: For this tutorial, I am assuming you already have an EC2 instance where you've configured and deploy a Django application.</p> </blockquote> <p>In <a href="https://girisagar46.github.io/from-bitbucket-pipeline-to-aws-codecommit">previous tutorial</a>, you learnt about syncing your BitBucket repository to AWS CodeCommit. Now, since your source code is already into AWS CodeCommit, you can now setup AWS CodePipeline for CI/CD.</p> <p><img alt="Cover" src="../images/codepipeline/cover.png"></p> <p>This tutorial will be a little bit long and I will guide you to setup AWS CodePipeline for your Django application step by step with no step skipped.</p> <p>Okay, Let's begin!</p> <h2>Step 0 (True programmer starts counting from zero ;) )</h2> <ul> <li>Go to AWS Console and select AWS CodePipeline which is under the <strong>Developer Tools</strong> section. Or you can also search for AWS CodePipeline by typing the name under <strong>Find Services</strong></li> </ul> <p><img alt="AWS Console" src="../images/codepipeline/console.png"></p> <p><em>AWS Console</em></p> <h2>Step 1</h2> <ul> <li>Once you are in AWS CodePipeline click on <strong>Create pipeline</strong> button. You'll be then redirected to <strong>Choose pipeline settings</strong></li> </ul> <p><img alt="Choose pipeline settings" src="../images/codepipeline/Step-1.png"></p> <ul> <li>Give yor pipeline a name under the <strong>Pipeline name</strong> input field.</li> <li>Select <strong>New service role</strong> under the <strong>Service role</strong> section.</li> <li>Under <strong>Role name</strong> section, you'll be provided a default role name. But, you may wish to give a proper name which you can remember. In that case, provide your own <strong>Role name</strong>.</li> <li>Check the checkbox that says <em>Allow AWS CodePipeline to create a service role so it can be used with this new pipeline</em></li> <li>Under <strong>Artifact store</strong>, select <strong>Custom location</strong>. And here's a tricky part. Artifacts are files that is generated after the CI part is completed. These artifacts need to be stored somewhere. In CodePipeline's case, it's the S3 bucket. If you choose <strong>Default location</strong>, your artifacts will be stored in the S3 location defined by the CodePipeline itself. In my case, I choose to store my artifacts in my own S3 bucket. Here's a <a href="#">tutorial</a> if you don't know how to create a S3 bucket.</li> <li>After filling up this form, click the <strong>Next</strong> button.</li> </ul> <h2>Step 2</h2> <ul> <li>After clicking <strong>Next</strong> at the end of <strong>Step 1</strong>, you'll see another form where you'll <strong>Add source</strong></li> </ul> <p><img alt="Add Source stage" src="../images/codepipeline/Step-2.png"></p> <ul> <li>Select <strong>Source provider</strong>. In this case, I am selecting <strong>AWS CodeCommit</strong> because I've already <a href="https://girisagar46.github.io/from-bitbucket-pipeline-to-aws-codecommit">synced my BitBucket repository to AWS CodeCommit</a>.</li> <li>Select your <strong>Repository name</strong> from the drop down option.</li> <li>Select the <strong>Branch name</strong> from the dropdown option. This <strong>Branch name</strong> indicates triggering of CI when a commit is made to this branch.</li> <li>On <strong>Change detection options</strong> select the recommended option <strong>Amazon CloudWatch Events</strong></li> <li>Click <strong>Next</strong> and start <strong>Step 3</strong></li> </ul> <h2>Step 3</h2> <p><img alt="Add build stage" src="../images/codepipeline/Step-3.png"></p> <ul> <li>Select <strong>Build provider</strong> as <strong>AWS CodeBuild</strong></li> <li>Now, you need to setup a <strong>Project</strong> for AWS CodeBuild. Click on <strong>Create project</strong> button as shown in the picture.</li> <li>When you click that <strong>Create project</strong>, a new window will open where you will setup a CodeBuild project. Let's call it <strong>Step 4</strong> for now. Now, let's jump to <strong>Step 4</strong></li> </ul> <h2>Step 4</h2> <p>I'll be breaking down this step into small chunks.</p> <h3>Step 4-1 (Create build project)</h3> <p><img alt="Create build project" src="../images/codepipeline/Step-4-1.png"></p> <ul> <li>Give your project a name under <strong>Project name</strong> input field.</li> <li>Give a project <strong>Description</strong> if you like. It's totally optional but it's a good practice to describe what it does.</li> <li>You can add tags to your project but, I am leaving it blank for now.</li> </ul> <h3>Step 4-2 (Environment)</h3> <p><img alt="Environment" src="../images/codepipeline/Step-4-2.png"></p> <ul> <li>Just below <strong>Create build project</strong>, you'll see <strong>Environment</strong> configuration</li> <li>Select <strong>Managed image</strong> under <strong>Environment image</strong> section</li> <li>Select <strong>Operating system</strong> as <strong>Ubuntu</strong></li> <li>Runtime <strong>Python</strong> (Remember, we are doing CI for Django application)</li> <li><strong>aws/codebuild/python:3.6.5</strong> as <strong>Runtime version</strong></li> <li>Select <strong>Always use the latest image for this runtime version</strong> under the <strong>Image version</strong> section</li> <li>I am not selecting <strong>Privileged</strong> option. It's description is self explanatory. If you want more details, see the AWS CodeBuild official documentation</li> <li>Choose <strong>New service role</strong> under the <strong>Service role</strong> section. We are selecting <strong>New service role</strong> because we haven't created any role yet for the code build from IAM. So, we'll just create a new one.</li> <li>Give a proper <strong>Role name</strong> so that you can remember and if you see it in the IAM console, you'll just instantly recognize that this is a role or AWS CodeBuild</li> <li>I am leaving <strong>Additional configuration</strong> as empty. This is where you set up Environment variables, system configuration and so on. You can setup some <strong>Additional configuration</strong> if you like</li> </ul> <h3>Step 4-3 (Buildspec)</h3> <p><img alt="Buildspec" src="../images/codepipeline/Step-4-3.png"></p> <ul> <li>Select <strong>Use a buildspec file</strong> under <strong>Build specifications</strong></li> <li>Under the <strong>Buildspec name</strong> section, you can add your own custom name if you have custom buildspec yml file but that's completely optional</li> <li>Fill out the <strong>Logs</strong> section. Your build logs are all streamed to <strong>AWS CloudWatch</strong> if you want. You can also use S3 to store your logs. In my case, I chose <strong>AWS CloudWatch</strong> and gave a <strong>Group name</strong> and <strong>Stream name</strong></li> <li>Now click on <strong>Continue to CodePipeline</strong> button and you will be redirected to that page (<strong>Step 3</strong>)</li> </ul> <h2>Step 5</h2> <ul> <li>After <strong>Step 4-3</strong>, you'll be redirected to that <strong>Add build stage</strong> page and you'll see your newly created build project. If you don't see it there, then just refresh the page.</li> </ul> <p><img alt="Project in build stage" src="../images/codepipeline/Step-5.png"></p> <ul> <li>Now, click the <strong>Next</strong> button.</li> </ul> <h2>Step 6</h2> <p><img alt="Add deploy stage" src="../images/codepipeline/Step-6.png"></p> <ul> <li>This step is called <strong>Add deploy stage</strong></li> <li>First, choose the deploy provider. Select <strong>AWS CodeDeploy</strong></li> <li>Under the <strong>Application name</strong> section, you should choose the CodeDeploy application. Since, we haven't yet created the CodeDeploy application, let's just create one. Don't close this browser tab. Just open new browser tab and go to <strong>Step 7</strong></li> </ul> <h2>Step 7</h2> <ul> <li>To create the <strong>AWS CodeDeploy</strong> application, first go to the <strong>CodeDeploy</strong> section from AWS Console and click on the <strong>Create application</strong> button. You'll then see <strong>Application configuration</strong> form. Give your application a name <strong>Application name</strong> and choose the <strong>Compute platform</strong> as <strong>EC2/On-premises</strong> since we are deploying our application on our EC2 server.</li> </ul> <p><img alt="Create code deploy application" src="../images/codepipeline/Step-7.png"></p> <ul> <li>After you create the CodeDeploy application, we need to divert a little bit to setup a <strong>New service IAM Role</strong> and a <strong>Deployment group</strong>. We'll continue from <strong>Step 6</strong> after setting up the deployment group. For now, let's go to step 8. We'll revisit <strong>Step 6</strong> after this.</li> </ul> <h2>Step 8 (Create New service IAM Role for CodeDeploy)</h2> <ul> <li>Go to the <strong>AWS IAM Console</strong> <img alt="IAM Roles" src="../images/codepipeline/Step-8.png"></li> <li>Click on <strong>Roles</strong> on the sidebar menu</li> <li> <p>Then click on <strong>Create role</strong> button.</p> </li> <li> <p>Select <strong>CodeDeploy</strong> and also <strong>CodeDeploy</strong> under <strong>Select your use case</strong> <img alt="Code deploy selection" src="../images/codepipeline/Step-9.png"></p> </li> <li>You'll see something like this:</li> </ul> <p><img alt="Attached permissions policies" src="../images/codepipeline/Step-10.png"></p> <ul> <li>Click <strong>Next: Tags</strong></li> <li> <p>Give your role a tag with <strong>Name</strong> and <strong>Value</strong> if you like <img alt="Role tags" src="../images/codepipeline/Step-11.png"></p> </li> <li> <p>Click <strong>Next: Review</strong> button <img alt="Role Review" src="../images/codepipeline/Step-12.png"></p> </li> <li> <p>Give your role a name. We'll be using this role while creating deployment group.</p> </li> <li>Then click on <strong>Create role</strong> button</li> </ul> <h2>Step 9 (Create deployment group)</h2> <ul> <li>Under <strong>CodeDeploy</strong> &gt; <strong>Application</strong> section, you'll see the <strong>CodeDeploy</strong> application name <em>hello-world-codedeploy-application</em> that you just created in <strong>Step 7</strong></li> <li>Click on the application link and under the <strong>Deployment groups</strong> tab, you'll see a button that says <strong>Create deployment group</strong>. Click that.</li> <li>You'll see a form like this:</li> </ul> <p><img alt="Deployment group creation form" src="../images/codepipeline/Step-13.png"></p> <ul> <li> <p>Under the <strong>Service role</strong> section, select the service role that you just created on <strong>Step 9</strong></p> </li> <li> <p>Under <strong>Environment configuration</strong> section, select <strong>Amazon EC2 instances</strong>. Then add tags. These tags are actually the EC2 instance tag that you've already setup for Django application deployment</p> </li> <li> <p>Fill out the form and click <strong>Create deployment group</strong> button</p> </li> <li>Your deployment group will be created and you'll see a page just like this:</li> </ul> <p><img alt="Deployment group creation complete" src="../images/codepipeline/Step-14.png"></p> <h2>Step 10</h2> <ul> <li>Now go to <strong>Step 6</strong> where you've left off. Since, we've just created <strong>CodeDeploy application</strong> and <strong>Deployment group</strong>. Select those values in specific fields. If they are not populated under the select dropdown, just refresh the page and you'll be fine. <img alt="Code deploy stage" src="../images/codepipeline/Step-15.png"></li> <li>Click <strong>Next</strong> button and go to <strong>Step 11</strong></li> </ul> <h2>Step 11</h2> <ul> <li>This is probably the last step of our code pipeline setup. After clicking the <strong>Next</strong> button from <strong>Step 10</strong>, you'll see a <strong>CodePipeline Review</strong> page.</li> </ul> <p><img alt="CodePipeline review" src="../images/codepipeline/Step-16.png"></p> <ul> <li>Just go through it and check if everything is setup correctly</li> <li>If you need to change something, go to previous section. And if you think everything is fine, click on <strong>Create pipeline</strong> button</li> </ul> <h2>Step 12</h2> <ul> <li>You'll see a success page something like this.</li> </ul> <p><img alt="CodePipeline complete" src="../images/codepipeline/Step-17.png"></p> <h2>Step 13 (Create buildspec.yml file)</h2> <p>At this point, your pipeline will obviously fail in the <strong>Build</strong> section because we haven't setup the <code>buildspec.yml</code> file.</p> <p>Here's a <code>buildspec.yml</code> file that I setup for my django project pipeline. Take a reference and change accordingly.</p> <script src="https://gist.github.com/girisagar46/6e351be212e94e98dbc159e57795a0cc.js"></script> <p>**I'll be writing a separate post on what's going inside the <code>buildspec.yml</code> file. But, for now just copy-paste this in your <code>buildspec.yml</code> file and push it to your repository.</p> <h2>Step 14 (Create appspec.yml file)</h2> <p>Your CodePipeline will still fail on <strong>Deploy</strong> part because we haven't still setup an <code>appspec.yml</code> file yet. This file is used by the CodeDeploy to deploy our application to the EC2 instance.</p> <p>Here's the configuration for my <code>appspec.yml</code> file that I setup for my django project pipeline. Take a reference and change it accordingly.</p> <script src="https://gist.github.com/girisagar46/b6f6e3f80b1fc32561ebece6fdaa465d.js"></script> <p><strong>After this, your CodePipeline should be Green.</strong></p>From Bitbucket Pipeline to AWS CodeCommit2019-02-08T22:08:00+09:002019-02-08T22:08:00+09:00Sagar Giritag:sagargiri.com,2019-02-08:/from-bitbucket-pipeline-to-aws-codecommit<p>In this article you'll ne learning how to sync your BitBucket repository to AWS CodeCommit. Once your AWS CodeCommit is synced with your BitBucket repo you can use AWS CodeCommit for many AWS services like CodePipeline, CodeBuild, CodeDeploy etc.</p><h2>Setup codecommit IAM user</h2> <ul> <li> <p>Create new user from AWS IAM console</p> </li> <li> <p>Give two permission to that new codecommit user: </p> <ul> <li><code>AWSCodeCommitFullAccess</code> and </li> <li><code>AmazonS3FullAccess</code></li> </ul> </li> <li> <p>Open that new user from IAM console. Under user's section and go to <strong>Security Credentials</strong> tab</p> </li> <li> <p>Under <strong>SSH keys for AWS CodeCommit</strong> upload new SSH public key. </p> </li> <li> <p>To do this open up your terminal and add following commands:</p> <ul> <li><code>$ ssh-keygen -f ~/.ssh/codecommit_rsa</code></li> <li>And inside <strong>.ssh</strong> folder you’ll find <code>codecommit_rsa</code> and <code>codecommit_rsa.pub</code> file</li> <li>Open <code>codecommit_rsa.pub</code> in your editor and copy the contents</li> <li>Click <strong>Upload SSH public Key</strong> button and in the popup and paste the contents of <code>codecommit_rsa.pub</code> file and click Upload <strong>SSH public Key</strong></li> </ul> </li> </ul> <p><img alt="Upload SSH public Key" src="../images/cicd/upload-ssh-aws.png"></p> <p>After uploading this, you’ll get the “SSH key ID”</p> <p><img alt="The SSH KEY ID" src="../images/cicd/ssh-key-id.png"></p> <ul> <li>Open your terminal and edit this file: <code>~/.ssh/config</code> </li> <li>Set the values as described below and save the file.</li> </ul> <div class="highlight"><pre><span></span><code>Host git-codecommit.*.amazonaws.com User Your-IAM-SSH-Key-ID-Here IdentityFile ~/.ssh/codecommit_rsa </code></pre></div> <ul> <li>Now, create new codecommit repository:<ul> <li><code>AWS Console</code> &gt; <code>Code Commit</code> &gt; <code>Getting started</code> &gt; <code>Create repository</code></li> <li>Give your repository a name and description and hit the <code>create</code> button.</li> </ul> </li> </ul> <h2>Setup BitbucketPipeline</h2> <ul> <li>Open your repository in BitBucket on which you want to setup pipeline. [Note: You must have admin access to that repository]</li> <li> <p>After opening your repository go to <code>settings</code> &gt; <code>Pipeline Settings</code> &gt; <code>Enable Pipeline</code> </p> </li> <li> <p>Then go to <code>Pipeline</code> &gt; <code>Settings</code> -&gt; <code>Repository variables</code> and set these values:</p> </li> </ul> <p><img alt="BitBucket pipeline repository variables" src="../images/cicd/repo-vars.png"></p> <h4>Description of each of these variables:</h4> <ol> <li> <p><code>CodeCommitConfig</code> -&gt; 64 bit encoded version of the contents inside your <code>~/.ssh/config</code> file. Generate this by doing: <code>bash $ base64 ~/.ssh/config</code> And copy the output to the value field of <code>CodeCommitConfig</code></p> </li> <li> <p><code>CodeCommitHost</code>: your AWS codecommit host. Blurred part is the AWS region</p> </li> <li> <p><code>CodeCommitKey</code>: 64 bit encoded version of the contents inside your private key at <code>~/.ssh/codecommit_rsa</code>. Generate this by doing:</p> <p><code>bash $ base64 ~/.ssh/codecommit_rsa</code> And copy the output to the value field of <code>CodeCommitKey</code></p> </li> <li> <p><code>CodeCommitRepo</code>: The link of repository that you just created</p> </li> <li> <p><code>CodeCommitUser</code>: Your-IAM-SSH-Key-ID</p> </li> </ol> <h4>Create bitbucket-pipelines.yml</h4> <p>Create <code>bitbucket-pipelines.yml</code> file with following contents:</p> <div class="highlight"><pre><span></span><code><span class="nt">pipelines</span><span class="p">:</span> <span class="w"> </span><span class="nt">default</span><span class="p">:</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">step</span><span class="p">:</span> <span class="w"> </span><span class="nt">script</span><span class="p">:</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">echo $CodeCommitKey &gt; ~/.ssh/codecommit_rsa.tmp</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">base64 -d ~/.ssh/codecommit_rsa.tmp &gt; ~/.ssh/codecommit_rsa</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">chmod 400 ~/.ssh/codecommit_rsa</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">echo $CodeCommitConfig &gt; ~/.ssh/config.tmp</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">base64 -d ~/.ssh/config.tmp &gt; ~/.ssh/config</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">set +e</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ssh -o StrictHostKeyChecking=no $CodeCommitHost</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">set -e</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">git remote set-url origin ssh://$CodeCommitRepo</span> <span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">git push origin $BITBUCKET_BRANCH</span> </code></pre></div> <ul> <li> <p>Make sure your indention are correct. You can use yml validator (<a href="https://jsonformatter.org/yaml-validator">https://jsonformatter.org/yaml-validator</a>) to do this.</p> </li> <li> <p>Push the <code>bitbucket-pipelines.yml</code> to any branch, then your pipeline will run and sync the changes to AWS Codecommit repository</p> </li> </ul>Docker 101 (Part 1)2018-12-02T00:01:00+09:002018-12-02T00:01:00+09:00Sagar Giritag:sagargiri.com,2018-12-02:/docker-101<p>I don't have any prior experience with docker. To everyone who is reading, this post is just my experience and as well as a kind of personal note for me for future reference. :)</p><h2>Step 1: Install Docker</h2> <p>Docker can be installed in pretty much any OS platform, be it Windows, Mac or Linux. Since I use a Linux machine this whole article is based on the Linux system. For installing docker in Windows and Mac, refer the official documentation.</p> <p>Ok, enough talk. Let's get started.</p> <p>Docker is a company as well as a software. And docker is released every month which is called edge release. And every quarter, a stable version of docker is released. </p> <p>One of the ways to install docker on a Linux machine is by using the apt package manager but, the problem with this is approach is that you'll not get the current release of docker which sucks IMO because in every new release new features are baked in. So, I advise you to not install via the apt package manager (if you are in Debian ubuntu variant of Linux) or any other package manager for other Linux distributions.</p> <p>There are two versions of docker available to download and install. One being free aka Community Edition and another paid version Enterprise Edition. For learning purpose, we'll install Community Edition docker. Hey! who does not like free software? ;)</p> <p>Okay, to install the latest and greatest version of community edition docker, fire up your terminal and execute the following command:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>wget<span class="w"> </span>-qO-<span class="w"> </span>https://get.docker.io/<span class="w"> </span><span class="p">|</span><span class="w"> </span>sh </code></pre></div> <p>What this command does is that it pulls the installation script from the <a href="https://get.docker.io/">https://get.docker.io/</a> and execute as a shell command. After the installation is complete, check the version of docker that is installed in your system by:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>docker<span class="w"> </span>--version </code></pre></div> <p>You'll see that the current stable release of the docker has been installed.</p> <div class="highlight"><pre><span></span><code>Docker<span class="w"> </span>version<span class="w"> </span><span class="m">18</span>.09.0,<span class="w"> </span>build<span class="w"> </span>4d60db4 </code></pre></div> <h2>Step 2: Configure Docker</h2> <p>Couple of things you need to configure after installing Docker. At the time of installation, docker is attached to the root user and every time you need to execute a docker command, you have to pass the sudo command. This situation is not idle for many cases. To fix this, we should bind docker to another user. Execute the following command to attach docker to another user:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>usermod<span class="w"> </span>-aG<span class="w"> </span>docker<span class="w"> </span>ubuntu </code></pre></div> <p><em>Note: Replace ubuntu with your username</em></p> <p>After this, install docker machine. Docker machine should also be the latest version. For Windows and Mac user, docker machine is already installed while installing Docker. To install docker machine, head over to this link <a href="https://github.com/docker/machine/release">https://github.com/docker/machine/release</a>. You'll see the command which is like this...</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>curl<span class="w"> </span>-L<span class="w"> </span>https://github.com/docker/machine/releases/download/v0.16.0/docker-machine-<span class="sb">`</span>uname<span class="w"> </span>-s<span class="sb">`</span>-<span class="sb">`</span>uname<span class="w"> </span>-m<span class="sb">`</span><span class="w"> </span>&gt;/tmp/docker-machine<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>chmod<span class="w"> </span>+x<span class="w"> </span>/tmp/docker-machine<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>sudo<span class="w"> </span>cp<span class="w"> </span>/tmp/docker-machine<span class="w"> </span>/usr/local/bin/docker-machine </code></pre></div> <p>Execute the above command and check if docker machine is installed or not by executing</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>docker-machine<span class="w"> </span>version docker-machine<span class="w"> </span>version<span class="w"> </span><span class="m">0</span>.16.0,<span class="w"> </span>build<span class="w"> </span>702c267f </code></pre></div> <p>Now, install docker compose.</p> <p>Head over to this link <a href="https://github.com/docker/compose/release">https://github.com/docker/compose/release</a>. You'll see the command which is like this...</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>curl<span class="w"> </span>-L<span class="w"> </span>https://github.com/docker/compose/releases/download/1.23.2/docker-compose-<span class="sb">`</span>uname<span class="w"> </span>-s<span class="sb">`</span>-<span class="sb">`</span>uname<span class="w"> </span>-m<span class="sb">`</span><span class="w"> </span>-o<span class="w"> </span>/usr/local/bin/docker-compose $<span class="w"> </span>chmod<span class="w"> </span>+x<span class="w"> </span>/usr/local/bin/docker-compose </code></pre></div> <p>Grab that command and execute it. Once complete, check if docker machine is installed or not by executing</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>docker-compose<span class="w"> </span>version docker-compose<span class="w"> </span>version<span class="w"> </span><span class="m">1</span>.23.2,<span class="w"> </span>build<span class="w"> </span>1110ad01 docker-py<span class="w"> </span>version:<span class="w"> </span><span class="m">3</span>.6.0 CPython<span class="w"> </span>version:<span class="w"> </span><span class="m">3</span>.6.7 OpenSSL<span class="w"> </span>version:<span class="w"> </span>OpenSSL<span class="w"> </span><span class="m">1</span>.1.0f<span class="w"> </span><span class="m">25</span><span class="w"> </span>May<span class="w"> </span><span class="m">2017</span> </code></pre></div> <p>That's pretty much it. Now you have docker installed in your Linux machine.</p> <p>PS. If you are using windows or MAC, visit the official docker website <a href="https://docs.docker.com/docker-for-windows/install/">https://docs.docker.com/docker-for-windows/install/</a> to get more details.</p> <p>In the next part, well dive deeper into the Docker world. </p>Installing Python3.6 in Ubuntu 16.04 LTS Instance Server2018-05-23T23:32:00+09:002018-05-23T23:32:00+09:00Sagar Giritag:sagargiri.com,2018-05-23:/installing-python3.6-in-ubuntu-server<p>Installing Python 3.6.3 in your freshly installed Ubuntu 16.04 Desktop, Linux Mint Desktop or even in AWS/Azure Ubuntu 16.04 server instance is pain in the a**. This article will teach you how to install Python 3.6.3 from source including the dependencies you need to install inorder to work it correctly.</p><p>Here is the step by step guide to install <code>Python 3.6.3</code> in your AWS EC2's Ubuntu 16.04 server instance or in your local machine with Ubuntu 16.04 LTS Desktop or in Linux Mint.</p> <p><strong>Note: If you are using Ubuntu 18.04 LTS, then it ships with Python 3.6.3 by default.</strong></p> <p>Check which Python version is pre-installed in the system by typing <code>$ python3 -V</code> in the terminal. Generally it is <code>Python 3.5.2</code> for Ubtuntu 16.04 LTS.</p> <h2>Pre-requisites</h2> <ol> <li> <p>First you need to upgrade and update your system.</p> <p><code>$ sudo apt update &amp;&amp; sudo apt -y upgrade</code></p> </li> <li> <p>Then you need to install <code>zlib1g-dev</code> package because of <a href="https://github.com/pypa/pip/issues/1919">this</a> issue. </p> <p><code>$ sudo apt -y install zlib1g-dev</code> To make sure it is installed correctly, type <code>$ cat /usr/include/zlib.h</code>. It'll show you the source of <code>zlib</code> header file.</p> </li> <li> <p>Because of <a href="https://stackoverflow.com/questions/893053/seeing-escape-characters-when-pressing-the-arrow-keys-in-python-shell">this</a> issue, you also have to install another package called <code>libreadline-dev</code></p> <p><code>$ sudo apt install libreadline-dev</code></p> </li> <li> <p>Now, install <code>build-essential</code> and other bunch of stuffs which is required by <code>Python 3.6.3</code> afterwards.</p> <p><code>$ sudo apt install build-essential checkinstall libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev</code></p> <p>These packages are needed for setting up SSL for downloading packages over PIP, for setting up <code>sqlite</code>, <code>g++</code> and so on.</p> </li> <li> <p>Export <code>LD_LIBRARY_PATH</code> for secure SSL connection.</p> <p><code>$ export LD_LIBRARY_PATH=/usr/local/ssl/lib/</code></p> </li> </ol> <h2>Begin installation of Python 3.6.3</h2> <ol> <li> <p>First, download tar zipped file from Python FTP server.</p> <p><code>wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tgz</code></p> </li> <li> <p>Extract the zipped file:</p> <p><code>$ tar zxvf Python-3.6.3.tgz</code></p> </li> <li> <p>Move Python3.6.3 directory to <code>/opt/</code> directory and <code>cd</code> into it.</p> <p><code>$ sudo mv Python-3.6.3 /opt/</code></p> <p><code>$ cd /opt/Python-3.6.3/</code></p> </li> <li> <p>Configure Python directory.</p> <p><code>$./configure --enable-optimizations</code></p> </li> <li> <p>Make it:</p> <p><code>$ make</code></p> </li> <li> <p>Test the Make if you want (this is optional)</p> <p><code>$ make test</code></p> </li> <li> <p>Install it via Make:</p> <p><code>sudo make install</code></p> </li> <li> <p>Verify that Python 3.6.3 is installed in your system by typing</p> <p><code>$ python3</code></p> <p>If it again shows Python 3.5.2 then type <code>$ python3.6</code>. To make things easier, set up an alias. To set up alias do the following:</p> <p>Edit <code>.bashrc</code> file located in your home directory.</p> <p><code>$ nano ~/.bashrc</code></p> <p>Add following line at the end</p> <p><code>alias python3=/usr/local/bin/python3.6</code></p> </li> </ol> <p><em>At this point, Python 3.6.3 is correctly installed in your system</em></p> <h2>Further steps:</h2> <ol> <li> <p>Make sure yout PIP is correct. In Python2 is <code>pip</code> and in Python3 its <code>pip3</code></p> <p><code>$ pip3 -V</code> shows you which Python it is pointing to.</p> </li> <li> <p>If you are using <code>pyodbc</code> then you need to install <code>unixodbc-dev</code></p> <p><code>$ sudo apt -f install unixodbc-dev</code></p> <p>Then you can insall <code>pyodbc</code> with:</p> <p><code>$ pip3 install pyodbc</code></p> </li> </ol>Be a self taught Python programmer in 2018.2018-03-11T22:38:00+09:002018-03-11T22:38:00+09:00Sagar Giritag:sagargiri.com,2018-03-11:/teach-yourself-python-2018<p>Internet is a fountain of knowledge. You can teach yourself anything via resources that are available online in the Internet. In this post I'll be sharing some tips, MOOC and resources so that you can teach yourself Python programming language in 2018. This post is solely based on my experince.</p><blockquote> <p>Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. - The Zen of Python, by Tim Peters</p> </blockquote> <p>I am not writing this post to tell you what is Python? You can find what it is just by doing a simple Google search on <strong>"What is Python?"</strong></p> <hr> <p>An StackOverflow post <a href="https://stackoverflow.blog/2017/09/06/incredible-growth-python/">The Incredible Growth of Python</a> quotes <strong>"Python has a solid claim to being the fastest-growing major programming language"</strong> and it is absolutely true. This blog post also claims that <strong>"Python was the most visited tag on Stack Overflow within high-income nations"</strong>. And these are not just a random quotes by a random blogger. This facts is based on year long data dump in StackOverflow website.</p> <p>Just look at this graph which tells the future trend of Python programming language. Isn't is beautiful?</p> <p><img alt="StackOverflow trend" src="https://zgab33vy595fw5zq-zippykid.netdna-ssl.com/wp-content/uploads/2017/09/growth_major_languages-1-1024x878.png"> <em>source:<a href="https://stackoverflow.blog/2017/09/06/incredible-growth-python/">https://stackoverflow.blog/2017/09/06/incredible-growth-python/</a></em></p> <p>Now, let me tell something about myself. I am a self taught Python programmer. I started learning Python in 2015 when I was a third semester student. I've not taken any formal course on programming in Python except that one time when our college conducted four classes on Python programming language with one class being of approximately 2-3 hours. But, I had already completed the Python basics before so, it wasn't fruitfull for me. But, I kept on taking the class because "ATTENDANCE" was a must.</p> <p>So, inorder to gain more knowledge in Python, I started learning from online resources. And over the course of time, I think I've gained enough (but, not enough) knowledge in Python. So, Here's the MOOC you can follow (which I followed) to be a self taught Python programmer.</p> <ul> <li> <p>Start with Python3. Because, Python2 is <a href="http://pythonclock.org/">retiring</a> and Python3 is the future. However, back in 2015 I started with Python 2.7 (Irony). Now, I code almost everything in Python 3.6.3.</p> </li> <li> <p>Learn the basics. Some resources where you can start are:</p> <ul> <li>If you want to learn interactively and online. You may want to try <a href="https://www.codecademy.com/learn/learn-python">Codecademy Python</a></li> <li> <p>If you are a learner through video tutorials, follow these online courses:</p> <ul> <li><a href="https://www.udemy.com/python-for-absolute-beginners-u/">Udemy</a></li> <li><a href="https://www.udacity.com/course/programming-foundations-with-python--ud036">Udacity</a></li> <li><a href="https://www.coursera.org/learn/python4">Coursera</a></li> <li><a href="https://pythonprogramming.net/">pythonprogramming.net</a></li> </ul> </li> <li> <p>Youtube is also also an enormous library of video tutorials. Here are some channels and playlist where you can learn Python from the basics.</p> <ul> <li><a href="https://www.youtube.com/watch?v=HBxCHonP6Ro&amp;list=PL6gx4Cwl9DGAcbMi1sH6oAMk4JHw91mC_">Python 3.4 Programming Tutorials</a></li> <li><a href="https://www.youtube.com/watch?v=oVp1vrfL_w4&amp;list=PLQVvvaa0QuDe8XSftW-RAxdo6OmaeL85M">Python 3 Basics Tutorial Series</a></li> </ul> </li> <li> <p>If you are learner by reading books, then are are few books that I recommend and are also free. </p> <ul> <li> <p>Here is the huge collection of online of books: <a href="https://pythonbooks.revolunet.com/">https://pythonbooks.revolunet.com/</a>. However, the ones I like are:</p> <ul> <li><a href="http://interactivepython.org/runestone/static/thinkcspy/index.html">Think Like a Computer Scientist</a></li> <li><a href="https://automatetheboringstuff.com/">Automate the Boring Stuff</a></li> </ul> <p><strong>Pro Tip: Follow just one book. Don't ramble.</strong></p> </li> </ul> </li> </ul> </li> </ul> <h4>Here is my <a href="https://github.com/girisagar46/PythonTrainingClass">GitHub repository</a> which I've prepared while teaching Python programming language in Deerwalk. This covers basic Python course if you are interested. Please give a star if you like this and contributers are welcome.</h4> <ul> <li> <p>Make a habit of reading and understanding the core python documentation. <a href="https://docs.python.org/3/">Python3 Docs</a></p> </li> <li> <p>If you get stuck, do not hesitate to ask questions in <a href="https://stackoverflow.com/">StackOverflow</a> with tag <strong>#Python3</strong>. But, be formal while asking questions in StackOverflow. Follow this guide <a href="https://stackoverflow.com/help/how-to-ask">How do I ask a good question?</a></p> </li> <li> <p>After completing basics, try learning advance stuffs. You can do this by following some of the python blogs:</p> <ul> <li><a href="https://talkpython.fm/">https://talkpython.fm/</a></li> <li><a href="https://realpython.com/">https://realpython.com/</a></li> <li><a href="https://www.fullstackpython.com/blog.html">https://www.fullstackpython.com/blog.html</a></li> <li>More here: <a href="https://pythontips.com/2013/07/31/10-python-blogs-worth-following/">https://pythontips.com/2013/07/31/10-python-blogs-worth-following/</a></li> </ul> <p><em>PS. This are some of the blogs that I follow. Or else, I simply do a Google search.</em></p> </li> <li> <p>Don't be afraid to do Google search if you get stuck while solving a problem or while trying to learn some concepts like decorators, generators, design patterns, etc. </p> </li> </ul> <p><strong>Pro Tip: Try solving any problem by yourself first. That's the only way to learn it. If you can't, then ask questions.</strong></p> <ul> <li> <p>While writing code, always follow the protocols of good coding styles in Python. Learn about python coding ethics here: <a href="http://pep8.org/">http://pep8.org/</a></p> </li> <li> <p>Make maximum use of code editors and IDE like: PyCharm, VsCode, SublimeText</p> </li> <li> <p>Projects, Projects, Projects (Obviously)</p> </li> <li> <p>There's no need to do advance commercial projects, but make sure you implement the basic python core concepts.</p> </li> <li> <p>Try to implememt core libraries that comes within the Python package like json, csv, urllib3, etc. And also try to use third package libraries.</p> </li> <li> <p>If you are searching for project topics and ideas, here is a good resource to follow:</p> <ul> <li> <p><a href="https://knightlab.northwestern.edu/2014/06/05/five-mini-programming-projects-for-the-python-beginner/">https://knightlab.northwestern.edu/2014/06/05/five-mini-programming-projects-for-the-python-beginner/</a></p> </li> <li> <p><a href="http://www.practicepython.org/">http://www.practicepython.org/</a></p> </li> </ul> </li> <li> <p>Create your <a href="https://github.com/">GitHub</a> account. Push the projects you've done to your GitHub repository. If you don't know how to use Git and GitHub learn it <a href="http://try.github.io/">http://try.github.io/</a>. And trust me, you won't regret of learning how to use Git and Github.</p> </li> </ul> <blockquote> <p>Trust me, GitHub is your new resume now a days</p> </blockquote> <ul> <li> <p>Follow Python groups in Facebook. I am saying the real groups with huge number of members. You can find them just by searching. Why follow these groups? because there are some good fellow members that share awesome blog posts and projects that they've done.</p> </li> <li> <p>Practice Practice Practice</p> </li> <li> <p>Follow, star the open source projects in Github. Here's the curated list of Open source python projects. <a href="https://awesome-python.com/">https://awesome-python.com/</a></p> </li> <li> <p>Learn about tools:</p> <ul> <li><a href="http://docs.python-guide.org/en/latest/dev/virtualenvs/">Virtual Environment</a></li> <li><a href="http://www.pythonforbeginners.com/basics/python-pip-usage">PIP Package Manager</a></li> </ul> </li> <li> <p>Now, you are confident in basics, try learning to use libraries and web frameworks like:</p> <ul> <li>Django</li> <li>Flask</li> <li>Data Science Libraries</li> </ul> </li> </ul> <p><em>Links to each libraries can be found here: <a href="https://awesome-python.com/">https://awesome-python.com/</a></em></p> <ul> <li> <p>Do small projects with the framework and libraries that you've learned and push your code to GitHub.</p> </li> <li> <p>Learn new topic everyday. <em>P.S. I learned about Python enums today :)</em> </p> </li> <li> <p>After this you can try applying for Python dev jobs. Here is an interesting <a href="https://www.toptal.com/python#hiring-guide">Toptal article</a> about what recruiters expect in Python dev. </p> </li> </ul>Download Youtube Videos in Ubuntu for FREE!2017-02-22T22:21:00+09:002017-02-22T22:21:00+09:00Sagar Giritag:sagargiri.com,2017-02-22:/download-youtube-videos-in-ubuntu<p>There are some free as well as paid online tool for downloading Youtube videos but youtube-dl is free, opensource, geeky and awesome command line tool to download videos from Youtube.</p><p><a href="https://rg3.github.io/youtube-dl/">youtube-dl</a> is a command-line program to download videos from YouTube.com and a few more sites like vimeo, 9gag, Dailymotion, <a href="https://rg3.github.io/youtube-dl/supportedsites.html">etc</a>. </p> <p>It is purely build in Python and requires the Python interpreter (2.6, 2.7, or 3.2+) to use it and it is not platform specific. There's also a <a href="https://yt-dl.org/latest/youtube-dl.exe">Windows executable</a> for Windows user. And the most cool thing about youtube-dl is that it's opensource and released to the public domain.</p> <p>This tutorial illustrates how to install and use it in Ubuntu. But to use this free software you need Python installed in your system.</p> <h2>Step 1: Install youtube-dl</h2> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>youtube-dl </code></pre></div> <p>or, install via <a href="https://girisagar46.github.io/install-python-pip-package-management-system-in-ubuntu">PIP</a></p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>youtube-dl </code></pre></div> <h2>Step 2 : Use it for free</h2> <p>Fire up your terminal. And type</p> <p><code>$ youtube-dl [URL for video]</code></p> <p>eg. <code>$ youtube-dl https://www.youtube.com/watch?v=KWZGAExj-es</code></p> <h3>Choosing the quality:</h3> <p>youtube-dl gives option to download videos of different quality. To download videos of high quality, type the commands provided below:</p> <p><code>$ youtube-dl -F https://www.youtube.com/watch?v=KWZGAExj-es</code></p> <p>This command gives the information of the video. </p> <div class="highlight"><pre><span></span><code>linuxsagar@ubuntu:~<span class="w"> </span>$<span class="w"> </span>youtube-dl<span class="w"> </span>-F<span class="w"> </span>https://www.youtube.com/watch?v<span class="o">=</span>KWZGAExj-es <span class="o">[</span>youtube<span class="o">]</span><span class="w"> </span>KWZGAExj-es:<span class="w"> </span>Downloading<span class="w"> </span>webpage <span class="o">[</span>youtube<span class="o">]</span><span class="w"> </span>KWZGAExj-es:<span class="w"> </span>Downloading<span class="w"> </span>video<span class="w"> </span>info<span class="w"> </span>webpage <span class="o">[</span>youtube<span class="o">]</span><span class="w"> </span>KWZGAExj-es:<span class="w"> </span>Extracting<span class="w"> </span>video<span class="w"> </span>information <span class="o">[</span>info<span class="o">]</span><span class="w"> </span>Available<span class="w"> </span>formats<span class="w"> </span><span class="k">for</span><span class="w"> </span>KWZGAExj-es: format<span class="w"> </span>code<span class="w"> </span>extension<span class="w"> </span>resolution<span class="w"> </span>note <span class="m">249</span><span class="w"> </span>webm<span class="w"> </span>audio<span class="w"> </span>only<span class="w"> </span>DASH<span class="w"> </span>audio<span class="w"> </span>53k<span class="w"> </span>,<span class="w"> </span>opus<span class="w"> </span>@<span class="w"> </span>50k,<span class="w"> </span><span class="m">1</span>.81MiB <span class="m">250</span><span class="w"> </span>webm<span class="w"> </span>audio<span class="w"> </span>only<span class="w"> </span>DASH<span class="w"> </span>audio<span class="w"> </span>73k<span class="w"> </span>,<span class="w"> </span>opus<span class="w"> </span>@<span class="w"> </span>70k,<span class="w"> </span><span class="m">2</span>.35MiB <span class="m">140</span><span class="w"> </span>m4a<span class="w"> </span>audio<span class="w"> </span>only<span class="w"> </span>DASH<span class="w"> </span>audio<span class="w"> </span>128k<span class="w"> </span>,<span class="w"> </span>m4a_dash<span class="w"> </span>container,<span class="w"> </span>mp4a.40.2@128k,<span class="w"> </span><span class="m">4</span>.65MiB <span class="m">171</span><span class="w"> </span>webm<span class="w"> </span>audio<span class="w"> </span>only<span class="w"> </span>DASH<span class="w"> </span>audio<span class="w"> </span>137k<span class="w"> </span>,<span class="w"> </span>vorbis@128k,<span class="w"> </span><span class="m">4</span>.44MiB <span class="m">251</span><span class="w"> </span>webm<span class="w"> </span>audio<span class="w"> </span>only<span class="w"> </span>DASH<span class="w"> </span>audio<span class="w"> </span>174k<span class="w"> </span>,<span class="w"> </span>opus<span class="w"> </span>@160k,<span class="w"> </span><span class="m">5</span>.84MiB <span class="m">278</span><span class="w"> </span>webm<span class="w"> </span>256x144<span class="w"> </span>144p<span class="w"> </span>92k<span class="w"> </span>,<span class="w"> </span>webm<span class="w"> </span>container,<span class="w"> </span>vp9,<span class="w"> </span>12fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">2</span>.60MiB <span class="m">160</span><span class="w"> </span>mp4<span class="w"> </span>256x144<span class="w"> </span>144p<span class="w"> </span>111k<span class="w"> </span>,<span class="w"> </span>avc1.4d400c,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">3</span>.86MiB <span class="m">242</span><span class="w"> </span>webm<span class="w"> </span>426x240<span class="w"> </span>240p<span class="w"> </span>223k<span class="w"> </span>,<span class="w"> </span>vp9,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">6</span>.27MiB <span class="m">133</span><span class="w"> </span>mp4<span class="w"> </span>426x240<span class="w"> </span>240p<span class="w"> </span>243k<span class="w"> </span>,<span class="w"> </span>avc1.4d4015,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">8</span>.57MiB <span class="m">243</span><span class="w"> </span>webm<span class="w"> </span>640x360<span class="w"> </span>360p<span class="w"> </span>420k<span class="w"> </span>,<span class="w"> </span>vp9,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">11</span>.11MiB <span class="m">134</span><span class="w"> </span>mp4<span class="w"> </span>640x360<span class="w"> </span>360p<span class="w"> </span>517k<span class="w"> </span>,<span class="w"> </span>avc1.4d401e,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">11</span>.36MiB <span class="m">244</span><span class="w"> </span>webm<span class="w"> </span>854x480<span class="w"> </span>480p<span class="w"> </span>715k<span class="w"> </span>,<span class="w"> </span>vp9,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">17</span>.63MiB <span class="m">135</span><span class="w"> </span>mp4<span class="w"> </span>854x480<span class="w"> </span>480p<span class="w"> </span>970k<span class="w"> </span>,<span class="w"> </span>avc1.4d401e,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">21</span>.71MiB <span class="m">247</span><span class="w"> </span>webm<span class="w"> </span>1280x720<span class="w"> </span>720p<span class="w"> </span>1499k<span class="w"> </span>,<span class="w"> </span>vp9,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">32</span>.43MiB <span class="m">136</span><span class="w"> </span>mp4<span class="w"> </span>1280x720<span class="w"> </span>720p<span class="w"> </span>1666k<span class="w"> </span>,<span class="w"> </span>avc1.4d401f,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">39</span>.95MiB <span class="m">248</span><span class="w"> </span>webm<span class="w"> </span>1920x1080<span class="w"> </span>1080p<span class="w"> </span>2744k<span class="w"> </span>,<span class="w"> </span>vp9,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">55</span>.46MiB <span class="m">137</span><span class="w"> </span>mp4<span class="w"> </span>1920x1080<span class="w"> </span>1080p<span class="w"> </span>2752k<span class="w"> </span>,<span class="w"> </span>avc1.640028,<span class="w"> </span>24fps,<span class="w"> </span>video<span class="w"> </span>only,<span class="w"> </span><span class="m">71</span>.87MiB <span class="m">17</span><span class="w"> </span>3gp<span class="w"> </span>176x144<span class="w"> </span>small<span class="w"> </span>,<span class="w"> </span>mp4v.20.3,<span class="w"> </span>mp4a.40.2@<span class="w"> </span>24k <span class="m">36</span><span class="w"> </span>3gp<span class="w"> </span>320x180<span class="w"> </span>small<span class="w"> </span>,<span class="w"> </span>mp4v.20.3,<span class="w"> </span>mp4a.40.2 <span class="m">43</span><span class="w"> </span>webm<span class="w"> </span>640x360<span class="w"> </span>medium<span class="w"> </span>,<span class="w"> </span>vp8.0,<span class="w"> </span>vorbis@128k <span class="m">18</span><span class="w"> </span>mp4<span class="w"> </span>640x360<span class="w"> </span>medium<span class="w"> </span>,<span class="w"> </span>avc1.42001E,<span class="w"> </span>mp4a.40.2@<span class="w"> </span>96k <span class="m">22</span><span class="w"> </span>mp4<span class="w"> </span>1280x720<span class="w"> </span>hd720<span class="w"> </span>,<span class="w"> </span>avc1.64001F,<span class="w"> </span>mp4a.40.2@192k<span class="w"> </span><span class="o">(</span>best<span class="o">)</span> </code></pre></div> <p>Notice the format column in the output above? Yes, that's what you need. Also, remember capital F in the above command (-F) gives the format information.</p> <p>Now, lets download a 720p mp4 file with format code <em>136</em>.</p> <p><code>$ youtube-dl -f 136 https://www.youtube.com/watch?v=KWZGAExj-es</code></p> <h2>You only want the audio of a file? No problem, youtube-dl got your back</h2> <p><code>youtube-dl --extract-audio --audio-format mp3 https://www.youtube.com/watch?v=5dKGK81z4js</code></p> <p>That's it. Similarly, you will be able to download videos/ audio from any site using youtube-dl tool from command line interface.</p> <p>This opensource project has been hosted in GitHub. You can checkout the source code from here: <a href="https://github.com/rg3/youtube-dl">https://github.com/rg3/youtube-dl</a></p>UI Change For Stackoverflow and Github2017-02-14T19:25:00+09:002017-02-14T19:25:00+09:00Sagar Giritag:sagargiri.com,2017-02-14:/ui-change-for-stackoverflow-and-github<p>GitHub and Stack Overflow are the most visited and popular website among aspiring and vetran developers/ programmers. Recently UI of both websites have been changed.</p><p><a href="https://github.com">GitHub</a> and <a href="http://stackoverflow.com/">Stack Overflow</a> both of these websites have updated their UI. As far as I have seen, mainly the header part or the main navigation menu has been modified.</p> <p>GitHub has changed it's header color from old silverish background to full black background. </p> <p><img alt="Github" src="images/GitHub.png"></p> <p>Similarly, <a href="http://stackoverflow.com/">Stack Overflow</a> also has updated it's navbar UI. I totally liked these new navbar interface and I'm totally digging it.</p> <p><img alt="Stack Overflow" src="images/Stack_Overflow.png"></p> <p>Recently wired.com has also published a news about how Linkedin is changing it's interface and making it look like facebookish. More at: <a href="https://www.wired.com/2017/01/new-linkedin-looks-just-like-facebook-smart-move/">https://www.wired.com/2017/01/new-linkedin-looks-just-like-facebook-smart-move/</a></p>Top Websites That Computer Science Students Must Visit.2017-02-13T21:34:00+09:002017-02-13T21:34:00+09:00Sagar Giritag:sagargiri.com,2017-02-13:/top-website-that-cs-student-should-visit<p>Are you a computer science student? If yes, then this might be a right article for you.</p><script> $(function() { $('a[href]').attr('target', '_blank'); }); </script> <blockquote> <p>Develop a passion for learning. If you do, you will never cease to grow. - Anthony J. D'Angelo</p> </blockquote> <p>I was going through Quora feeds and my eye caught one particular question, "What are the top websites computer science students must visit?" This question had more than 3k followers. I immediately opened the question link and bookmarked it. </p> <p>Different users had given many answers and some of the links that I really liked are as follows:</p> <ul> <li><a href="http://stackoverflow.com/">Stack Overflow</a></li> <li><a href="https://github.com/">GitHub</a></li> <li><a href="http://ocw.mit.edu/courses/#electrical-engineering-and-computer-science">MIT OpenCourseWare</a></li> <li><a href="http://cs50.tv/2011/fall">Harvard Extension School/ Hardvard CS50</a></li> <li><a href="http://www.udacity.com/">Udacity</a></li> <li><a href="http://www.khanacademy.org/#computer-science">Khan Academy</a></li> <li><a href="http://www.tutorialspoint.com/">Tutorials Point</a></li> <li><a href="https://www.quora.com/">Quora</a></li> <li><a href="https://www.coursera.org/">Coursera</a></li> <li><a href="https://www.hackerrank.com/">HackerRank</a></li> <li><a href="http://academicearth.org/subjects/computerscience">Academic Earth</a></li> <li><a href="http://www.open.edu/itunes">The Open University</a></li> <li><a href="http://programming-motherfucker.com/">Programming Motherfu***r</a></li> <li><a href="http://www.virtualhosting.com/blog/2008/50-killer-online-resources-for-computer-science-students/">50+ Killer Resources for Computer Science Students</a></li> <li><a href="http://www.cs4fn.org/">Computer Science for Fun</a></li> <li><a href="http://code.tutsplus.com/">Code.tutsplus.com</a></li> <li><a href="http://www.smartscholar.com/computer-science-guide/">Computer Science Education Resource Guide</a></li> </ul> <p>These are some of the links I really liked. But, this isn't the limit. Go through this answer in Quora by yourself. <a href="https://www.quora.com/What-are-the-top-websites-computer-science-students-must-visit">https://www.quora.com/What-are-the-top-websites-computer-science-students-must-visit</a></p> <p>And, now some of my personal favorites are:</p> <ul> <li><a href="http://dataschool.io/">Data School</a> - If you are intersted in data science. </li> <li><a href="http://bigdatauniversity.com/">Big Data University</a> - If you are really into big data, machine learning, spark.</li> <li><a href="http://machinelearningmastery.com">Machinelearning Mastery</a> - Great place to start your machine learning career.</li> <li><a href="http://www.datasciencecentral.com/">Data Science Central</a> - Awesome blog about machine learning and data science.</li> <li><a href="http://ohshitgit.com/">Oh shit, git!</a> - How to not screw up your git repo.</li> <li><a href="https://www.edx.org/">Edx</a> - Quality education for everyone, everywhere for Free!</li> <li><a href="https://github.com/girisagar46/how-to-contribute-to-open-source">How to contribute to Open Source</a> - Get started to contribute to opensource projects.</li> <li><a href="http://egghead.io/">Egghead.io</a> - Bite-size video tutorials for badass web developers</li> <li><a href="http://www.javatpoint.com/">Javatpoint</a> - Get started with any popular programming language you like.</li> <li><a href="https://www.freecodecamp.com/">Free Code Camp</a> - Open source community that helps you learn to code. (Nepali version coming soon)</li> <li><a href="https://medium.com/tag/computer-science">Medium Blog for CS</a> </li> <li><a href="https://www.reddit.com/r/algorithms/">Algorithms Subreddit</a></li> <li><a href="https://www.liveedu.tv/">Live Edu</a> - Watch professionals code in real time. Visit website, meet coders and learn programming.</li> <li><a href="http://www.idiotinside.com/topics/python/">Idiot Inside</a> - Python and others</li> <li><a href="https://awesome-python.com/">Awesome Python</a> - Info about different Python libraries.</li> <li><a href="http://javascriptissexy.com/">javascriptissexy.com</a> - Indeed JS is sexy. Awesome blog only and about JS.</li> </ul> <p>Many of the links that are mentioned above are related to programming but, Computer Science is not only about coding/programming. A competent computer science students should be able to design new algorithms, reduce complexity of the problem set and algorithms, or design a new programming language, implement a compiler or an interpreter, etc. But, without strong knowledge of programming, nothing is possible.</p> <p>If you have some cool links, do share it in the comment section below. :) </p>The One Stop CSIT Guide2017-02-06T18:44:00+09:002017-02-06T18:44:00+09:00Sagar Giritag:sagargiri.com,2017-02-06:/the-csit-guide<p>The one-stop bundle for all the resources for 4 years B.Sc. CSIT study.</p><blockquote> <p>Warning: This is a challenging task. DMCA might take down some repo. Let's see.</p> </blockquote> <p>The main problem I faced while studying CSIT was that I had to stumble upon networks of hyperlinks to find the exact resource or course material that I needed to do my assignments/reports. Whenever I find something interesting or something that I need, I immediately downloaded that. And that resulted a vast collection of the resource that might be helpful for the students who are studying B.Sc. CSIT.</p> <p>To distribute these resources, I tried zipping the folder and uploading to GitHub, but GitHub didn't accept files more than 100MiB. Hence, I had to upload each folder separately. In Order to do that I created a GitHub organization called <a href="https://github.com/CSIT-GUIDE">CSIT-GUIDE</a>.</p> <p>All these repositories inside <a href="https://github.com/CSIT-GUIDE">CSIT-GUIDE</a> has subject wise notes, books, guides, question papers, lab works and other resources. All these were collected by me on 4 years of studying B.Sc. CSIT. I'm just trying to help all other students who are studying CSIT course.</p> <p>The organization <a href="https://github.com/CSIT-GUIDE">CSIT-GUIDE</a> has eight repositories which are (semester wise) .</p> <p>** NOTE: These repositories has the subjects that I was taught. The elective courses I was taught might not be taught to you. **</p> <p>If you find anything missing, or you have some extra notes, you can always contribute.</p> <p>You can contribute by:</p> <ol> <li>Forking the repo you want to contribute.</li> <li>Adding your resource and pushing to your forked repo.</li> <li>Sending a new pull request.</li> </ol> <p>DIRECT LINKS:</p> <p><a href="https://github.com/CSIT-GUIDE/FIRST_SEMESTER">FIRST SEMESTER</a></p> <p><a href="https://github.com/CSIT-GUIDE/SECOND_SEMESTER">SECOND SEMESTER</a></p> <p><a href="https://github.com/CSIT-GUIDE/THIRD_SEMESTER">THIRD SEMESTER</a></p> <p><a href="https://github.com/CSIT-GUIDE/FOURTH_SEMESTER">FOURTH SEMESTER</a></p> <p><a href="https://github.com/CSIT-GUIDE/FIFTH_SEMESTER">FIFTH SEMESTER</a></p> <p><a href="https://github.com/CSIT-GUIDE/SIXTH_SEMESTER">SIXTH SEMESTER</a></p> <p><a href="https://github.com/CSIT-GUIDE/SEVENTH_SEMESTER">SEVENTH SEMESTER</a></p> <p><a href="https://github.com/CSIT-GUIDE/EIGHTH_SEMESTER">EIGHTH SEMESTER</a></p> <p>If you want to be a part of <a href="https://github.com/CSIT-GUIDE">CSIT-GUIDE</a>, just email me your GitHub username at <code>[email protected]</code>.</p> <p>P.S. The DMCA laws might block these repos. This is just an experiment. If it goes haywire, I'll be sharing these via Google Drive. :-)</p>Installing Git Version Control System2017-02-01T19:01:00+09:002017-02-01T19:01:00+09:00Sagar Giritag:sagargiri.com,2017-02-01:/installing-git-version-control-system<p>Git is most widely used modern (VCS) version control system. Git is an open source project and originally developed to maintain code for Linux kernel and developed in 2005 by <a href="https://en.wikipedia.org/wiki/Linus_Torvalds">Linus Torvalds</a>.</p><blockquote> <p>"Software is like sex: it's better when it's free." - Linus Torvalds</p> </blockquote> <p>Git is available for all platforms Linux, Mac OS X and Windows.</p> <h1>Install Git on Mac OS X</h1> <p>There are different ways to install Git on a Mac. If you've installed XCode (or it's Command Line Tools), Git may already be installed. To find out, open a terminal and enter <code>git --version</code>. Inorder to install a newer version of Git, use one of these methods:</p> <h2>Git for Mac Installer</h2> <p>The easiest way to install Git on a Mac is via the stand-alone installer:</p> <ol> <li>Download the latest <a href="https://sourceforge.net/projects/git-osx-installer/files/">Git for Mac</a> installer.</li> <li>Follow the prompts to install Git.</li> <li>Open a terminal and verify the installation was successful by typing <code>git --version</code></li> <li>Configure your Git username and email using the following command</li> </ol> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>user.name<span class="w"> </span><span class="s2">&quot;Your Name&quot;</span><span class="w"> </span> $<span class="w"> </span>git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>user.email<span class="w"> </span><span class="s2">&quot;[email protected]&quot;</span> </code></pre></div> <h2>Git for Windows stand-alone installer</h2> <ol> <li>Download the latest Git for Windows <a href="https://git-for-windows.github.io/">installer</a>.</li> <li>Execute the installer, finish the Git Setup wizard screen with default options.</li> <li>Open a Command Prompt or Git Bash (search git in all programs).</li> <li>Run the following commands to configure your Git username and email using the following command. These details will be associated with any commits that you create:</li> </ol> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>user.name<span class="w"> </span><span class="s2">&quot;Your Name&quot;</span> $<span class="w"> </span>git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>user.email<span class="w"> </span><span class="s2">&quot;[email protected]&quot;</span> </code></pre></div> <h2>Git for Linux (Debian/ Ubuntu)</h2> <p>1 From your shell, install Git using apt-get (Ubuntu 14.04) or apt (Ubuntu 16.04 or later):</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>update $<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>git </code></pre></div> <ol> <li>Verify the installation was successful by typing git --version:</li> </ol> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>--version git<span class="w"> </span>version<span class="w"> </span><span class="m">2</span>.9.2 </code></pre></div> <ol> <li>Configure your Git username and email using the following command. These details will be associated with any commits that you create:</li> </ol> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>user.name<span class="w"> </span><span class="s2">&quot;Your Name&quot;</span> $<span class="w"> </span>git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>user.email<span class="w"> </span><span class="s2">&quot;[email protected]&quot;</span> </code></pre></div> <p>source: <a href="https://www.atlassian.com/git/tutorials/install-git">https://www.atlassian.com/git/tutorials/install-git</a></p>Install Python pip package management system in Ubuntu2017-01-31T19:21:00+09:002017-01-31T19:21:00+09:00Sagar Giritag:sagargiri.com,2017-01-31:/install-python-pip-package-management-system-in-ubuntu<p>pip is a package management system used to install and manage software packages written in Python.</p><p><code>pip</code> is the replacement for the <code>easy_install</code> python package management tool. </p> <p>If you're running Python 2.7.9+ or Python 3.4+ pip is already installed in the bundle.</p> <p>If you are below Python 2.7.9 then these are the steps you need to follow to install PIP.</p> <h1>For Ubuntu</h1> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>update $<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>-y<span class="w"> </span>install<span class="w"> </span>python-pip </code></pre></div> <p>But, even if you are running python 3.4+ version, and pip is not available in the sytem, you can install by:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>python3-pip </code></pre></div> <h1>For Mac OS</h1> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>easy_install<span class="w"> </span>pip </code></pre></div> <p>or</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>brew<span class="w"> </span>install<span class="w"> </span>python </code></pre></div> <h1>For Windows</h1> <p>You can install pip via installer. </p> <p>Download, <a href="http://download.sjsoft.com/opensource/pip-1.1.win32.exe">pip-1.1.win32.exe</a> and run setup.</p> <h1>Verify the pip setup</h1> <p>Check version of the pip via from command line.</p> <div class="highlight"><pre><span></span><code>pip<span class="w"> </span>-V </code></pre></div> <h1>pip usage</h1> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>some-package-name </code></pre></div> <p>Users can also easily remove the package:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>pip<span class="w"> </span>uninstall<span class="w"> </span>some-package-name </code></pre></div> <p>pip has a feature to manage full lists of packages and corresponding version numbers, possible through a "requirements" file. And is mainly used for <code>virtual enviromnent</code></p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>requirements.txt </code></pre></div> <p>Sources:</p> <ol> <li><a href="http://stackoverflow.com/questions/17271319/how-to-install-pip-on-mac-os-x">http://stackoverflow.com/questions/17271319/how-to-install-pip-on-mac-os-x</a></li> <li><a href="http://stackoverflow.com/questions/4750806/how-do-i-install-pip-on-windows">http://stackoverflow.com/questions/4750806/how-do-i-install-pip-on-windows</a></li> <li><a href="https://www.liquidweb.com/kb/how-to-install-pip-on-ubuntu-14-04-lts/">https://www.liquidweb.com/kb/how-to-install-pip-on-ubuntu-14-04-lts/</a></li> <li><a href="https://en.wikipedia.org/wiki/Pip_(package_manager)">https://en.wikipedia.org/wiki/Pip_(package_manager)</a></li> </ol>Integrating Disqus Comment Section In Pelican Blog2017-01-30T21:51:00+09:002017-01-30T21:51:00+09:00Sagar Giritag:sagargiri.com,2017-01-30:/integrate-disqus-in-a-post<p>Disqus is a worldwide blog comment hosting service for web sites and online communities that uses a networked platform.<sup>[<a href="https://en.wikipedia.org/wiki/Disqus">1</a>]</sup> And integrating Disqus comments in Pelican is straight forward and easy.</p><p>After you write a blog post, you expect people to comment in your post. Commenting is necessary because it can increase reader engagement and help build relationship among author and reader. </p> <p>Many Pelican themes support Disqus commenting natively. All you need to have is a Disqus account. Go to <a href="https://disqus.com/">disqus.com</a> and quickly create an account for yourself.</p> <p>Now, lets integrate Disqus to our each and every blog posts.</p> <h2>Steps</h2> <ul> <li>While logged in to your Disqus account, head over to <a href="https://disqus.com/admin/create/">admin create panel</a>. </li> <li>You'll see a form. Fill up that form</li> <li>Click <strong>Create Site</strong> button.</li> <li>Now on the top left side of the page, you'll see your disqus site. Click on the link. <em>[refer picture below]</em></li> </ul> <p><img alt="Disqus preview" class="img-center" src="images/disqus1.png"></p> <ul> <li>Now headover to <em>setting</em> menu. <em>[refer picture below]</em></li> </ul> <p><img alt="Disqus setting" class="img-center" src="images/disqus2.png"></p> <ul> <li>In the setting page, you'll see the <strong>Shortname</strong> of youtr site as shown below.</li> </ul> <p><img alt="shortname" class="img-center" src="images/disqus3.png"></p> <ul> <li> <p>Copy that <strong>shortname</strong></p> </li> <li> <p>Now open your <code>pelicanconf.py</code> file. On that file, add the following lines:</p> </li> </ul> <p><code>DISQUS_SITENAME = 'your-site-name'</code></p> <ul> <li> <p>Reserve your page via <code>$ fab reserve</code></p> </li> <li> <p>Browse the page and you'll see Disqus has been integrated to your blog post.</p> </li> </ul> <p><img alt="disqus implemented" src="images/disqus4.png"></p> <hr> <p>If you're confused, see how I configured Disqus comments in my blog from <a href="https://github.com/girisagar46/girisagar46.github.io/blob/source/pelicanconf.py">here</a></p>Building a static site and hosting in Github (part 2)2017-01-28T17:00:00+09:002017-01-28T17:00:00+09:00Sagar Giritag:sagargiri.com,2017-01-28:/pelican-github-part2<p>In <a href="https://girisagar46.github.io/pelican-github-part1">Part 1</a>, we just got started with our Pelican blog. In this part, we'll be hacking our blog to make it awesome.</p><blockquote> <p>In <a href="https://girisagar46.github.io/pelican-github-part1">Part 1</a> we've setup our github.io website and kick started out [Pelican] blog. Now, in this second tutorial, we'll configure Fabric and Pelican configuration and when it's all done, we'll create a blog post. And push it to github <code>source</code> branch and generated HTML to <code>master</code> branch.</p> </blockquote> <h1>First, let's setup our blog theme.</h1> <p>Pelican has tons of themes. All themes can be previewed at <a href="http://www.pelicanthemes.com/">pelicanthemes.com</a>. You can pick any themes you like. And, if you are not satisfied with the existing themes, you can also create your <a href="http://docs.getpelican.com/en/3.1.1/themes.html">own theme</a>. For this tutorial, we'll be using a theme called <a href="https://github.com/alexandrevicenzi/flex">Flex</a> by <a href="https://www.alexandrevicenzi.com/">Alexandre Vicenzi</a>. </p> <p>To setup a theme, create folder inside your <code>username.github.io</code> directory and name it <code>themes</code>. Now <code>cd</code> into that directory and clone the <a href="https://github.com/alexandrevicenzi/Flex.git">Flex</a> repository.</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/alexandrevicenzi/Flex.git </code></pre></div> <p>You can setup plugins in same way as the themes. The official repository for the plugins is <a href="https://github.com/getpelican/pelican-plugins">pelican-plugins</a>. We won't setup plugins in this tutorial. You can read the documentation by yourself to setup the plugins or I'll be posting a seperate tutorial post on how to setup plugins shortly*.</p> <h1>Configuration</h1> <p>We have our Flex theme inside our theme directory. Our theme needs a site logo. Site logo should be placed in a images directory. So, create an <code>images</code> folder inside the <code>content</code> folder. Paste an image in that folder. If you don't have any, default image will be rendered.</p> <p>For the configuration, we'll be working on <code>pelicanconf.py</code>, <code>publishconf.py</code> and <code>fabfile.py</code>.</p> <p>First let's look at <code>pelicanconf.py</code>. Open it in a text editor and update it as described in the snippet below. See the comments beginning with <code>#</code> to know what's happening.</p> <div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">unicode_literals</span> <span class="n">AUTHOR</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">&#39;Your Name&#39;</span> <span class="n">SITENAME</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">&#39;Your Blog Name&#39;</span> <span class="n">SITEURL</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">&#39;http://localhost:8000&#39;</span> <span class="c1">#used for local build and preview</span> <span class="n">SITETITLE</span> <span class="o">=</span> <span class="n">AUTHOR</span> <span class="n">SITESUBTITLE</span> <span class="o">=</span> <span class="s1">&#39;Your own text&#39;</span> <span class="c1">#needed for theme</span> <span class="n">SITEDESCRIPTION</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">&#39;your site description&#39;</span> <span class="c1">#used for meta tag for SEO purposes</span> <span class="n">PATH</span> <span class="o">=</span> <span class="s1">&#39;content&#39;</span> <span class="c1"># location to where your articles/posts are located</span> <span class="n">TIMEZONE</span> <span class="o">=</span> <span class="s1">&#39;Asia/Kathmandu&#39;</span> <span class="c1"># Your current time zone</span> <span class="n">DEFAULT_LANG</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">&#39;en&#39;</span> <span class="n">DATE_FORMATS</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">&#39;en&#39;</span><span class="p">:</span> <span class="s1">&#39;%B </span><span class="si">%d</span><span class="s1">, %Y&#39;</span><span class="p">,</span> <span class="p">}</span> <span class="n">USE_FOLDER_AS_CATEGORY</span> <span class="o">=</span> <span class="kc">False</span> <span class="n">COPYRIGHT_YEAR</span> <span class="o">=</span> <span class="mi">2017</span> <span class="n">DEFAULT_PAGINATION</span> <span class="o">=</span> <span class="mi">7</span> <span class="c1"># Theme Settings</span> <span class="n">SITELOGO</span> <span class="o">=</span> <span class="s1">&#39;/images/Your picture&#39;</span> <span class="c1">#your site logo</span> <span class="n">FAVICON</span> <span class="o">=</span> <span class="s1">&#39;/images/favicon.png&#39;</span> <span class="c1">#your favicon</span> <span class="n">THEME</span> <span class="o">=</span> <span class="s1">&#39;themes/Flex&#39;</span> <span class="c1">#path to your theme</span> <span class="n">BROWSER_COLOR</span> <span class="o">=</span> <span class="s1">&#39;#333333&#39;</span> <span class="n">PYGMENTS_STYLE</span> <span class="o">=</span> <span class="s1">&#39;default&#39;</span> <span class="c1">#for code highlighting</span> <span class="c1"># Blogroll</span> <span class="c1"># if you want to link to external page</span> <span class="n">LINKS</span> <span class="o">=</span> <span class="p">((</span><span class="s1">&#39;link1&#39;</span><span class="p">,</span> <span class="s1">&#39;Your link&#39;</span><span class="p">),)</span> <span class="c1"># Social widget</span> <span class="c1"># You can add your own links for facebook, twitter</span> <span class="n">SOCIAL</span> <span class="o">=</span> <span class="p">((</span><span class="s1">&#39;Facebook&#39;</span><span class="p">,</span> <span class="s1">&#39;Your facebook link&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s1">&#39;Twitter&#39;</span><span class="p">,</span> <span class="s1">&#39;#&#39;</span><span class="p">),)</span> <span class="n">DEFAULT_PAGINATION</span> <span class="o">=</span> <span class="mi">10</span> </code></pre></div> <p>If you want to know more details about the configuration, go <a href="https://github.com/alexandrevicenzi/Flex/wiki/Configuration-example">here</a>.</p> <p>Next, open <code>publishconf.py</code> file and modify these lines:</p> <div class="highlight"><pre><span></span><code><span class="o">...</span> <span class="n">SITEURL</span> <span class="o">=</span> <span class="s1">&#39;https://your_username.github.io&#39;</span> <span class="n">RELATIVE_URLS</span> <span class="o">=</span> <span class="kc">False</span> <span class="o">...</span> </code></pre></div> <h1>Our first post</h1> <p><code>cd</code> to your <code>content</code> directory and create a folder called <code>articles</code>. Inside that <code>articles</code> folder create a new file called <code>FirstPost.md</code>. Open that <code>FirstPost.md</code> file in a text editor and paste the lines as shown below:</p> <div class="highlight"><pre><span></span><code><span class="n">Title</span><span class="o">:</span><span class="w"> </span><span class="n">My</span><span class="w"> </span><span class="kd">super</span><span class="w"> </span><span class="n">title</span> <span class="n">Date</span><span class="o">:</span><span class="w"> </span><span class="mi">2010</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">03</span><span class="w"> </span><span class="mi">10</span><span class="o">:</span><span class="mi">20</span> <span class="n">Modified</span><span class="o">:</span><span class="w"> </span><span class="mi">2010</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">05</span><span class="w"> </span><span class="mi">19</span><span class="o">:</span><span class="mi">30</span> <span class="n">Category</span><span class="o">:</span><span class="w"> </span><span class="n">abc</span> <span class="n">Tags</span><span class="o">:</span><span class="w"> </span><span class="n">abc</span><span class="o">,</span><span class="w"> </span><span class="n">xyz</span> <span class="n">Slug</span><span class="o">:</span><span class="w"> </span><span class="n">my</span><span class="o">-</span><span class="kd">super</span><span class="o">-</span><span class="n">post</span> <span class="n">Authors</span><span class="o">:</span><span class="w"> </span><span class="n">Your</span><span class="w"> </span><span class="n">name</span> <span class="n">Summary</span><span class="o">:</span><span class="w"> </span><span class="n">Short</span><span class="w"> </span><span class="n">description</span> <span class="n">This</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">content</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">my</span><span class="w"> </span><span class="kd">super</span><span class="w"> </span><span class="n">blog</span><span class="w"> </span><span class="n">post</span><span class="o">.</span> </code></pre></div> <p>To know more, read the official <a href="http://docs.getpelican.com/en/stable/content.html">documentation</a>.</p> <h1>Generate HTML</h1> <p>Go to the root directory of the project or simple do <code>$ cd ..</code> in the terminal, and type </p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>fab<span class="w"> </span>clean<span class="p">;</span><span class="w"> </span>fab<span class="w"> </span>build<span class="p">;</span><span class="w"> </span>fab<span class="w"> </span>serve<span class="p">;</span> </code></pre></div> <p>and browse to <code>http://localhost:8000</code>. You'll see new shining blog with new design.</p> <h1>Commit and push to Github</h1> <p>** First, let's push our source code.**</p> <p>Type these commands one by one.</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span><span class="nb">source</span> $<span class="w"> </span>git<span class="w"> </span>add<span class="w"> </span>. $<span class="w"> </span>git<span class="w"> </span>commit<span class="w"> </span>-m<span class="w"> </span><span class="s2">&quot;Configuration, themes and first post&quot;</span> $<span class="w"> </span>git<span class="w"> </span>push </code></pre></div> <p>** Push the HTML contents in the <code>master</code> branch.**</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>ghp-import<span class="w"> </span>-m<span class="w"> </span><span class="s1">&#39;First push to github.io&#39;</span><span class="w"> </span>-b<span class="w"> </span>master<span class="w"> </span>output<span class="s2">&quot;</span> $<span class="s2"> git push -u origin master</span> </code></pre></div> <p>Now, redirect your browser to 'https://your_username.github.io' to view your online blog.</p> <p>Upto this you have your blog hosted in github pages and is available to public viewing. Next, I'll be posting some small tutorials on how to add <a href="https://disqus.com">disqus</a> comments, google analytics, automate publish using Fabric API, adding and configuring plugins and many more.</p> <p>Keep visiting my <a href="https://girisagar46.github.io">website</a>.</p>Building a static site and hosting in Github (part 1)2017-01-28T13:00:00+09:002017-01-28T13:00:00+09:00Sagar Giritag:sagargiri.com,2017-01-28:/pelican-github-part1<p>The contents that you are seeing right now is the static website built using Pelican. This tutorial series gives you every details on how to create a static blog using pelican and host it to the github server for FREE!</p><blockquote> <p>For this tutorial series, I'm assuming that you are working in a Linux environment. If not, you can use <a href="http://docs.python-guide.org/en/latest/dev/virtualenvs/">virtualenv</a> for Windows or Mac.</p> </blockquote> <h1>Getting started</h1> <p>First the big question, "What is <a href="#">Pelican</a>?"</p> <p>In short, Pelican is a static site generator that supports Markdown and reST syntax. Powered by Python. For more visit, <a href="http://getpelican.com/">getpelican.com</a></p> <p>For this tutorial, you only need to understand basic Git push/pull and branching command and as well as some basic <a href="https://guides.github.com/features/mastering-markdown/">Markdown</a> syntax. If you are a noob, no worries I'll cover each and every topics in detail.</p> <h2>Prerequisits:</h2> <ul> <li><a href="https://girisagar46.github.io/installing-git-version-control-system">Install Git VCS</a></li> <li><a href="#">Install Python</a></li> <li><a href="#">Install Markdown</a></li> <li><a href="#">Setup Github account</a></li> <li><a href="https://pages.github.com/">Setup github.io</a></li> <li><a href="#">A code editor</a></li> </ul> <h2>Setup Github page</h2> <p>First you need to have a <a href="https://pages.github.com/">github.io</a> page. Noew, clone your github.io repository and <code>cd</code> into it.</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/username/username.github.io $<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>username.github.io/ </code></pre></div> <p>Create a new Git branch called <code>source</code> or your any custom name. This new branch only holds your source code. The HTML generated by Pelican will be pushed to master branch which are then rendered in the website. We'll do Git push shortly. But, first let's create a new branch.</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>-b<span class="w"> </span><span class="nb">source</span> </code></pre></div> <p>Push the new branch on Github:</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>push<span class="w"> </span>origin<span class="w"> </span><span class="nb">source</span> </code></pre></div> <p>You are now working on the <code>source</code> branch.</p> <h2>Setup Pelican</h2> <p>Let's start with installing Pelican at the first place. Pelican, Pelican-Plugins and Pelican-Themes are dependent on different python modules and installing them one by one is a pain in the butt. Hence, for the simplicity, create a new file called <code>requirements.txt</code>. </p> <p>Open <code>requirements.txt</code> file in a <code>notepad</code> or <code>gedit</code> and paste the lines given below and save it.</p> <div class="highlight"><pre><span></span><code>appdirs==1.4.0 beautifulsoup4==4.5.1 blinker==1.4 bs4==0.0.1 docutils==0.12 ecdsa==0.13 Fabric==1.12.0 feedgenerator==1.9 ghp-import==0.4.1 Jinja2==2.8 Markdown==2.6.7 MarkupSafe==0.23 packaging==16.8 paramiko==1.17.2 pelican==3.6.3 pycrypto==2.6.1 Pygments==2.1.3 pyparsing==2.1.10 python-dateutil==2.5.3 pytz==2016.7 six==1.10.0 Unidecode==0.4.19 </code></pre></div> <p>These are the modules that we need to get started with the Pelican static website generation.</p> <p>To install the modules which are inside <code>requirements.txt</code>, type the following command in the terminal.</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>requirements.txt </code></pre></div> <p>If you don't know what is pip and how to install it, go <a href="https://girisagar46/install-python-pip-package-management-system-in-ubuntu">here</a>.</p> <p>Upto this step you've setup a github.io blog and installed Pelican and it's dependencies.</p> <h2>Pelican Quick Start</h2> <p>After installing pelican, you can leverage the command <code>$ pelican-quickstart</code> from the command line.</p> <h3>Quick Setup</h3> <ol> <li><code>cd</code> into your <code>username.github.io</code> repository that you cloned earlier. <code>$ cd username.github.io</code></li> <li>Save this <a href="https://raw.githubusercontent.com/girisagar46/girisagar46.github.io/source/.gitignore">.gitignore</a> file in your directory. It's needed to make your Github repo clean.</li> <li>Run <code>$ pelican-quickstart</code> in the terminal</li> </ol> <p>The quickstart will ask you various questions, which you can answer in turn. Here are some specific answers you should give:</p> <div class="highlight"><pre><span></span><code><span class="o">&gt;</span><span class="w"> </span><span class="k">Where</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">create</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="o">[</span><span class="n">.</span><span class="o">]</span><span class="w"> </span><span class="p">(</span><span class="n">hit</span><span class="w"> </span><span class="n">enter</span><span class="p">)</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">What</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">title</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="n">My</span><span class="w"> </span><span class="n">Awesome</span><span class="w"> </span><span class="n">Blog</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Who</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">author</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">Your</span><span class="w"> </span><span class="k">Full</span><span class="w"> </span><span class="n">Name</span><span class="p">)</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">What</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="k">language</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="o">[</span><span class="n">en</span><span class="o">]</span><span class="w"> </span><span class="p">(</span><span class="n">hit</span><span class="w"> </span><span class="n">enter</span><span class="p">)</span><span class="w"> </span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">specify</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">URL</span><span class="w"> </span><span class="k">prefix</span><span class="vm">?</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">g</span><span class="p">.,</span><span class="w"> </span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="n">example</span><span class="p">.</span><span class="n">com</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="n">Y</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">What</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">URL</span><span class="w"> </span><span class="k">prefix</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">see</span><span class="w"> </span><span class="n">above</span><span class="w"> </span><span class="n">example</span><span class="p">;</span><span class="w"> </span><span class="k">no</span><span class="w"> </span><span class="k">trailing</span><span class="w"> </span><span class="n">slash</span><span class="p">)</span><span class="w"> </span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="n">your_username</span><span class="p">.</span><span class="n">github</span><span class="p">.</span><span class="n">io</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">enable</span><span class="w"> </span><span class="n">article</span><span class="w"> </span><span class="n">pagination</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="n">Y</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">How</span><span class="w"> </span><span class="n">many</span><span class="w"> </span><span class="n">articles</span><span class="w"> </span><span class="n">per</span><span class="w"> </span><span class="n">page</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="vm">?</span><span class="w"> </span><span class="o">[</span><span class="n">10</span><span class="o">]</span><span class="w"> </span><span class="mi">10</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">What</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="nc">time</span><span class="w"> </span><span class="k">zone</span><span class="vm">?</span><span class="w"> </span><span class="o">[</span><span class="n">Europe/Paris</span><span class="o">]</span><span class="w"> </span><span class="n">Asia</span><span class="o">/</span><span class="n">Kathmandu</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">generate</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">Fabfile</span><span class="o">/</span><span class="n">Makefile</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">automate</span><span class="w"> </span><span class="n">generation</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">publishing</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="n">Y</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">auto</span><span class="o">-</span><span class="n">reload</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">simpleHTTP</span><span class="w"> </span><span class="n">script</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">assist</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="n">theme</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">development</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="n">Y</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">FTP</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span><span class="n">N</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">SSH</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span><span class="n">N</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">Dropbox</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span><span class="n">N</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">S3</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span><span class="n">N</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">Rackspace</span><span class="w"> </span><span class="n">Cloud</span><span class="w"> </span><span class="n">Files</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span><span class="n">N</span> <span class="o">&gt;</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">GitHub</span><span class="w"> </span><span class="n">Pages</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span><span class="n">Y</span> <span class="o">&gt;</span><span class="w"> </span><span class="k">Is</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">personal</span><span class="w"> </span><span class="n">page</span><span class="w"> </span><span class="p">(</span><span class="n">username</span><span class="p">.</span><span class="n">github</span><span class="p">.</span><span class="n">io</span><span class="p">)</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span><span class="n">Y</span> <span class="n">Done</span><span class="p">.</span><span class="w"> </span><span class="n">Your</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">project</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">available</span><span class="w"> </span><span class="k">at</span><span class="w"> </span><span class="o">/&lt;</span><span class="k">path</span><span class="o">&gt;/</span><span class="n">your_username</span><span class="p">.</span><span class="n">github</span><span class="p">.</span><span class="n">io</span> </code></pre></div> <p>That's it. Now you have the basic structure of your Pelican blog. The tree structure of the pelican blog is:</p> <div class="highlight"><pre><span></span><code>. ├── content ├── develop_server.sh ├── fabfile.py ├── Makefile ├── output ├── pelicanconf.py └── publishconf.py 2 directories, 5 files </code></pre></div> <p>Here, each files and folder have a specefic meaning. I'll discuss more on it later. </p> <h3>Build and serve</h3> <p>Generate HTML. All HTML files are generated in the <code>output</code> directory.</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>fab<span class="w"> </span>build </code></pre></div> <p>Here <code>fab</code> is a build tool that comes with <code>Fabric</code> module. Now, serve the HTML.</p> <div class="highlight"><pre><span></span><code>$<span class="w"> </span>fab<span class="w"> </span>serve </code></pre></div> <p>And redirect your browser to <code>http://localhost:8000</code>. You'll see the result.</p> <p><img alt="Website preview" src="images/pelican_quickstart.png"></p> <p>** Note: The website generated is only visible in local environment. We haven't pushed anything to Github yet. It'll be done after all configurations have been setup correctly.**</p> <p>Now, just sitback, relax and observe every files inside the directory. If you understood nothing, maybe learn some <a href="https://guides.github.com/features/mastering-markdown/">Markdown</a>.</p> <p>In <a href="https://girisagar46.github.io/pelican-github-part2#pelican-github-part2">Part 2</a> we'll write our first blog post, configure and fabricate pelican, and our first commit to the github.</p>