<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Hasan Alkhatib - DevOps Engineer]]></title><description><![CDATA[Hasan Alkhatib - DevOps Engineer]]></description><link>https://blog.alkhatib.tech</link><generator>RSS for Node</generator><lastBuildDate>Thu, 21 May 2026 18:55:31 GMT</lastBuildDate><atom:link href="https://blog.alkhatib.tech/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Controlling RGB LEDs with Go and Arduino over WiFi]]></title><description><![CDATA[Sometimes, the best ideas come from playing around with simple projects. I recently set up an Arduino Nano RP2040 Connect to control an RGB LED ring via a web server written in Go. It turned out to be a fun and educational dive into IoT and web progr...]]></description><link>https://blog.alkhatib.tech/controlling-an-arduino-ring-using-a-go-web-server</link><guid isPermaLink="true">https://blog.alkhatib.tech/controlling-an-arduino-ring-using-a-go-web-server</guid><category><![CDATA[iot]]></category><category><![CDATA[arduino]]></category><category><![CDATA[Go Language]]></category><dc:creator><![CDATA[Hasan Alkhatib]]></dc:creator><pubDate>Thu, 02 Jan 2025 16:16:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747821704948/02c21de7-1d8e-492a-ae02-22705b37ad75.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sometimes, the best ideas come from playing around with simple projects. I recently set up an Arduino Nano RP2040 Connect to control an RGB LED ring via a web server written in Go. It turned out to be a fun and educational dive into IoT and web programming.</p>
<p>In this blog, I’ll walk you through the setup, share the code, and reflect on what I learned.</p>
<hr />
<h2 id="heading-what-well-build">What We'll Build!</h2>
<p>Control an RGB LED Ring using an Arduino Nano RP2040 Connect by fetching color values from a Go-based web server.</p>
<h3 id="heading-componenets">Componenets:</h3>
<ul>
<li><p><strong>Arduino Nano RP2040 Connect</strong> (with built-in WiFi).</p>
</li>
<li><p><strong>NeoPixel/WS2812 LED Ring</strong>.</p>
</li>
<li><p>A simple web server in Go.</p>
</li>
</ul>
<h3 id="heading-how-it-works">How it works:</h3>
<ol>
<li><p>The Arduino connects to WiFi and polls the web server every 3 seconds for RGB values.</p>
</li>
<li><p>The web server responds with JSON data containing the current RGB values.</p>
</li>
<li><p>The Arduino updates the LED ring to match the received colors.</p>
</li>
</ol>
<h2 id="heading-arduino-code-breakdown">Arduino Code Breakdown</h2>
<p>Let’s dive into the Arduino code:</p>
<ol>
<li><strong>WiFi Connection</strong>: The <code>WiFiNINA</code> library handles WiFi connectivity. Replace ssid and password with your network credentials.</li>
</ol>
<pre><code class="lang-cpp"><span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* ssid = <span class="hljs-string">"your_wifi_ssid"</span>;
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* password = <span class="hljs-string">"your_wifi_password"</span>;
</code></pre>
<ol start="2">
<li>HTTP Communication</li>
</ol>
<pre><code class="lang-cpp">httpClient.get(<span class="hljs-string">"/rgb"</span>);
</code></pre>
<ol start="3">
<li>LED Control: The <code>Adafruit_NeoPixel</code> library manages the LED ring. Each color value (Red, Green, Blue) is applied to all LEDs.</li>
</ol>
<pre><code class="lang-cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; strip.numPixels(); i++) {
    strip.setPixelColor(i, strip.Color(red, green, blue));
}
strip.show();
</code></pre>
<ol start="4">
<li>JSON Parsing</li>
</ol>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">parseRGB</span><span class="hljs-params">(String json, <span class="hljs-keyword">int</span> &amp;red, <span class="hljs-keyword">int</span> &amp;green, <span class="hljs-keyword">int</span> &amp;blue)</span> </span>{
    <span class="hljs-keyword">int</span> redIndex = json.indexOf(<span class="hljs-string">"\"red\":"</span>) + <span class="hljs-number">6</span>;
    <span class="hljs-keyword">int</span> greenIndex = json.indexOf(<span class="hljs-string">"\"green\":"</span>) + <span class="hljs-number">8</span>;
    <span class="hljs-keyword">int</span> blueIndex = json.indexOf(<span class="hljs-string">"\"blue\":"</span>) + <span class="hljs-number">7</span>;
    ...
}
</code></pre>
<h3 id="heading-full-code">Full Code</h3>
<pre><code class="lang-cpp"><span class="hljs-comment">/*
 * Setup:
 * - RGB LED Ring (WS2812/NeoPixel compatible) connected to D2
 * - Arduino Nano RP2040 Connect with built-in WiFi

 * - Ensure the web server is running at the specified IP and port.
 */</span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;ArduinoHttpClient.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;WiFiNINA.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;Wire.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;Adafruit_NeoPixel.h&gt;</span></span>

<span class="hljs-comment">// WiFi credentials</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* ssid = <span class="hljs-string">"your_wifi_ssid"</span>;
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* password = <span class="hljs-string">"your_wifi_password"</span>;

<span class="hljs-comment">// Server details (ipconfig getifaddr en0)</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* serverAddress = <span class="hljs-string">"web_server_ip"</span>;
<span class="hljs-keyword">const</span> <span class="hljs-keyword">int</span> port = web_server_port;

WiFiClient wifiClient;
HttpClient httpClient = HttpClient(wifiClient, serverAddress, port);

<span class="hljs-comment">// LED setup</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> LED_PIN 25</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> LED_COUNT 24</span>

<span class="hljs-function">Adafruit_NeoPixel <span class="hljs-title">strip</span><span class="hljs-params">(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800)</span></span>;

<span class="hljs-comment">// Function prototypes</span>
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">connectToWiFi</span><span class="hljs-params">()</span></span>;
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">fetchAndSetRGB</span><span class="hljs-params">()</span></span>;
<span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">parseRGB</span><span class="hljs-params">(String json, <span class="hljs-keyword">int</span> &amp;red, <span class="hljs-keyword">int</span> &amp;green, <span class="hljs-keyword">int</span> &amp;blue)</span></span>;

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">setup</span><span class="hljs-params">()</span> </span>{
  Serial.begin(<span class="hljs-number">9600</span>);

  strip.begin();
  strip.show();
  strip.setBrightness(<span class="hljs-number">50</span>);

  connectToWiFi();
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">loop</span><span class="hljs-params">()</span> </span>{
  fetchAndSetRGB();
  delay(<span class="hljs-number">3000</span>); <span class="hljs-comment">// Fetch every 3 seconds</span>
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">connectToWiFi</span><span class="hljs-params">()</span> </span>{
  Serial.print(<span class="hljs-string">"Connecting to WiFi..."</span>);
  <span class="hljs-keyword">while</span> (WiFi.begin(ssid, password) != WL_CONNECTED) {
    delay(<span class="hljs-number">1000</span>);
    Serial.print(<span class="hljs-string">"."</span>);
  }
  Serial.println(<span class="hljs-string">"Connected!"</span>);
}

<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">fetchAndSetRGB</span><span class="hljs-params">()</span> </span>{
  Serial.println(<span class="hljs-string">"Fetching RGB values..."</span>);
  httpClient.get(<span class="hljs-string">"/rgb"</span>);
  <span class="hljs-keyword">int</span> statusCode = httpClient.responseStatusCode();
  <span class="hljs-keyword">if</span> (statusCode != <span class="hljs-number">200</span>) {
    Serial.print(<span class="hljs-string">"Failed to fetch RGB values. Status code: "</span>);
    Serial.println(statusCode);
    <span class="hljs-keyword">return</span>;
  }

  String response = httpClient.responseBody();
  Serial.print(<span class="hljs-string">"Response: "</span>);
  Serial.println(response);

  <span class="hljs-keyword">int</span> red, green, blue;
  <span class="hljs-keyword">if</span> (parseRGB(response, red, green, blue)) {
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;strip.numPixels(); i++) {
      strip.setPixelColor(i, strip.Color(red, green, blue));
    }
    strip.show();
    Serial.println(<span class="hljs-string">"RGB values set successfully."</span>);
    Serial.print(<span class="hljs-string">"Red: "</span>);
    Serial.print(red);
    Serial.print(<span class="hljs-string">", Green: "</span>);
    Serial.print(green);
    Serial.print(<span class="hljs-string">", Blue: "</span>);
    Serial.println(blue);
  } <span class="hljs-keyword">else</span> {
    Serial.println(<span class="hljs-string">"Failed to parse RGB values."</span>);
  }
}

<span class="hljs-function"><span class="hljs-keyword">bool</span> <span class="hljs-title">parseRGB</span><span class="hljs-params">(String json, <span class="hljs-keyword">int</span> &amp;red, <span class="hljs-keyword">int</span> &amp;green, <span class="hljs-keyword">int</span> &amp;blue)</span> </span>{
  <span class="hljs-keyword">int</span> redIndex = json.indexOf(<span class="hljs-string">"\"red\":"</span>) + <span class="hljs-number">6</span>;
  <span class="hljs-keyword">int</span> greenIndex = json.indexOf(<span class="hljs-string">"\"green\":"</span>) + <span class="hljs-number">8</span>;
  <span class="hljs-keyword">int</span> blueIndex = json.indexOf(<span class="hljs-string">"\"blue\":"</span>) + <span class="hljs-number">7</span>;

  <span class="hljs-keyword">if</span> (redIndex == <span class="hljs-number">-1</span> || greenIndex == <span class="hljs-number">-1</span> || blueIndex == <span class="hljs-number">-1</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

  red = json.substring(redIndex, json.indexOf(<span class="hljs-string">','</span>, redIndex)).toInt();
  green = json.substring(greenIndex, json.indexOf(<span class="hljs-string">','</span>, greenIndex)).toInt();
  blue = json.substring(blueIndex, json.indexOf(<span class="hljs-string">'}'</span>, blueIndex)).toInt();

  <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
</code></pre>
<hr />
<h2 id="heading-go-web-server">Go Web Server</h2>
<p>On the server side, we have a lightweight Go application to serve the RGB values.</p>
<h3 id="heading-key-features"><strong>Key Features</strong></h3>
<ol>
<li><p><strong>Random Initial Colors</strong>: The server starts with a random Palestinian flag color (red, green, or white).</p>
</li>
<li><p>2. <strong>Concurrency Handling</strong>: A sync.Mutex ensures thread-safe access to the RGB struct.</p>
</li>
<li><p><strong>Dual Control</strong>: You can update the RGB values either through a CLI or programmatically via HTTP GET requests.</p>
</li>
</ol>
<h3 id="heading-full-code-1"><strong>Full Code</strong></h3>
<pre><code class="lang-go"><span class="hljs-comment">// Usage:</span>
<span class="hljs-comment">// 1. Run the program: go run main.go</span>
<span class="hljs-comment">// 2. Web server starts on port 8080. Get RGB values with a GET request to http://localhost:8080/rgb.</span>
<span class="hljs-comment">// 3. Set new RGB values in the CLI using format R,G,B (e.g., 255,0,0 for red). Type 'exit' to quit.</span>

<span class="hljs-comment">// PS. get the server IP by running ipconfig getifaddr en0</span>
<span class="hljs-comment">// then access the server from another device using the IP and port 8080</span>
<span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"math/rand"</span>
    <span class="hljs-string">"net/http"</span>
    <span class="hljs-string">"os"</span>
    <span class="hljs-string">"strings"</span>
    <span class="hljs-string">"sync"</span>
    <span class="hljs-string">"time"</span>
)

<span class="hljs-keyword">type</span> RGB <span class="hljs-keyword">struct</span> {
    Red   <span class="hljs-keyword">int</span> <span class="hljs-string">`json:"red"`</span>
    Green <span class="hljs-keyword">int</span> <span class="hljs-string">`json:"green"`</span>
    Blue  <span class="hljs-keyword">int</span> <span class="hljs-string">`json:"blue"`</span>
}

<span class="hljs-keyword">var</span> (
    rgb RGB
    mu  sync.Mutex <span class="hljs-comment">// To handle concurrent access</span>
    rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-comment">// Set default RGB values to randomly pick one of the Palestinian flag colors, since, why not?</span>
    <span class="hljs-keyword">switch</span> rnd.Intn(<span class="hljs-number">3</span>) {
    <span class="hljs-keyword">case</span> <span class="hljs-number">0</span>:
        rgb = RGB{Red: <span class="hljs-number">0</span>, Green: <span class="hljs-number">100</span>, Blue: <span class="hljs-number">0</span>} <span class="hljs-comment">// Dark Green</span>
    <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
        rgb = RGB{Red: <span class="hljs-number">139</span>, Green: <span class="hljs-number">0</span>, Blue: <span class="hljs-number">0</span>} <span class="hljs-comment">// Dark Red</span>
    <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
        rgb = RGB{Red: <span class="hljs-number">255</span>, Green: <span class="hljs-number">255</span>, Blue: <span class="hljs-number">255</span>} <span class="hljs-comment">// White</span>
    }
    fmt.Println(<span class="hljs-string">"Setting the Palestinian flag colors, since, why not?"</span>)

    <span class="hljs-comment">// Start the web server in a separate goroutine</span>
    <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
        http.HandleFunc(<span class="hljs-string">"/rgb"</span>, handleRGB)
        fmt.Println(<span class="hljs-string">"Starting server on port 8080..."</span>)
        log.Fatal(http.ListenAndServe(<span class="hljs-string">":8080"</span>, <span class="hljs-literal">nil</span>))
    }()

    <span class="hljs-comment">// CLI loop for setting RGB values</span>
    reader := os.Stdin
    <span class="hljs-keyword">for</span> {
        fmt.Print(<span class="hljs-string">"Enter RGB values (format: R,G,B) or type 'exit' to quit: "</span>)
        <span class="hljs-keyword">var</span> input <span class="hljs-keyword">string</span>
        fmt.Fscanln(reader, &amp;input)
        input = strings.TrimSpace(input)

        <span class="hljs-keyword">if</span> strings.ToLower(input) == <span class="hljs-string">"exit"</span> {
            fmt.Println(<span class="hljs-string">"Exiting..."</span>)
            <span class="hljs-keyword">break</span>
        }

        <span class="hljs-keyword">if</span> setRGB(input) {
            fmt.Printf(<span class="hljs-string">"RGB updated to: %d, %d, %d\n"</span>, rgb.Red, rgb.Green, rgb.Blue)
        } <span class="hljs-keyword">else</span> {
            fmt.Println(<span class="hljs-string">"Invalid input. Use format R,G,B with values between 0 and 255."</span>)
        }
    }
}

<span class="hljs-comment">// Handle HTTP GET requests to /rgb</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">handleRGB</span><span class="hljs-params">(w http.ResponseWriter, r *http.Request)</span></span> {
    <span class="hljs-keyword">if</span> r.Method != http.MethodGet {
        http.Error(w, <span class="hljs-string">"Invalid request method"</span>, http.StatusMethodNotAllowed)
        <span class="hljs-keyword">return</span>
    }

    mu.Lock()
    <span class="hljs-keyword">defer</span> mu.Unlock()

    w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
    json.NewEncoder(w).Encode(rgb)
}

<span class="hljs-comment">// Set the RGB values based on CLI input</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">setRGB</span><span class="hljs-params">(input <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">bool</span></span> {
    parts := strings.Split(input, <span class="hljs-string">","</span>)
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(parts) != <span class="hljs-number">3</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }

    <span class="hljs-keyword">var</span> r, g, b <span class="hljs-keyword">int</span>
    _, err := fmt.Sscanf(input, <span class="hljs-string">"%d,%d,%d"</span>, &amp;r, &amp;g, &amp;b)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> || r &lt; <span class="hljs-number">0</span> || r &gt; <span class="hljs-number">255</span> || g &lt; <span class="hljs-number">0</span> || g &gt; <span class="hljs-number">255</span> || b &lt; <span class="hljs-number">0</span> || b &gt; <span class="hljs-number">255</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
    }

    mu.Lock()
    <span class="hljs-keyword">defer</span> mu.Unlock()
    rgb = RGB{Red: r, Green: g, Blue: b}
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
}
</code></pre>
<hr />
<h2 id="heading-putting-it-all-together">Putting it All Together</h2>
<ol>
<li><strong>Run the Web Server</strong>: Compile and run the Go program on your machine:</li>
</ol>
<pre><code class="lang-bash">go run main.go
</code></pre>
<ol start="2">
<li><p><strong>Connect the Arduino</strong>: Upload the code to your Arduino Nano RP2040 and monitor the serial output to ensure it connects to WiFi.</p>
</li>
<li><p><strong>Test the System</strong>: Open the RGB endpoint in your browser:</p>
</li>
</ol>
<pre><code class="lang-http"><span class="hljs-attribute">http://&lt;your_server_ip&gt;:8080/rgb</span>
</code></pre>
<hr />
<p>This project combines IoT and web programming in a fun way. Got questions or feedback? Drop a comment below or email me at <a target="_blank" href="mailto:hasan@alkhatib.tech">hasan@alkhatib.tech</a>.</p>
<p>🌐 <a target="_blank" href="https://alkhatib.tech/">alkhatib.tech</a></p>
]]></content:encoded></item><item><title><![CDATA[Shift-Left in the World of DevOps!]]></title><description><![CDATA[Dive into the core concept of "Shift Left" within the DevOps landscape. While this guide zeroes in on Java, Python, and Go configurations, the insights shared are valuable for developers across the board. Ready to explore? Let's jump in! 🚀

Pro Tip!...]]></description><link>https://blog.alkhatib.tech/shift-left-in-the-world-of-devops</link><guid isPermaLink="true">https://blog.alkhatib.tech/shift-left-in-the-world-of-devops</guid><category><![CDATA[Devops]]></category><category><![CDATA[Git]]></category><category><![CDATA[Security]]></category><category><![CDATA[bestpractice]]></category><category><![CDATA[shiftleft]]></category><dc:creator><![CDATA[Hasan Alkhatib]]></dc:creator><pubDate>Sun, 24 Sep 2023 09:08:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747821740106/30432b9d-100a-4b18-b2d1-834eaeabba04.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Dive into the core concept of "Shift Left" within the DevOps landscape. While this guide zeroes in on Java, Python, and Go configurations, the insights shared are valuable for developers across the board. Ready to explore? Let's jump in! 🚀</p>
<hr />
<h2 id="heading-pro-tip">Pro Tip! 🌟</h2>
<p>Before we dive deeper, here's a suggestion: Think about setting up a global pre-commit hook. This way, a bash script will run for every upcoming commit, ensuring your code undergoes all the essential checks and tests before it's locked in.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Create global git hooks directory and configure git</span>
mkdir -p ~/.git-hooks &amp;&amp; git config --global core.hooksPath ~/.git-hooks

<span class="hljs-comment"># Create the pre-commit hook</span>
cat &gt; ~/.git-hooks/pre-commit &lt;&lt; <span class="hljs-string">'EOF'</span>
<span class="hljs-comment">#!/bin/sh</span>

<span class="hljs-keyword">if</span> [ -f <span class="hljs-string">"build.gradle"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Running pre-commit checks for Java project..."</span>
    <span class="hljs-comment"># Run tests/checks for Java projects</span>
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"setup.py"</span> ] || [ -f <span class="hljs-string">"pyproject.toml"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Running pre-commit checks for Python project..."</span>
    <span class="hljs-comment"># Run tests/checks for Python projects</span>
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"go.mod"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Running pre-commit checks for GoLang project..."</span>
    <span class="hljs-comment"># Run tests/checks for Go projects</span>
<span class="hljs-keyword">else</span> 
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Unknown project type. Skipping pre-commit checks."</span>
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Check the exit status and abort the commit if tests fail</span>
<span class="hljs-keyword">if</span> [ $? -ne 0 ]; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"\nTests failed! Commit aborted.\n"</span>
    <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>

<span class="hljs-built_in">exit</span> 0
EOF

<span class="hljs-comment"># Make the pre-commit hook executable</span>
chmod +x ~/.git-hooks/pre-commit

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Global git hooks setup complete!"</span>
</code></pre>
<hr />
<h2 id="heading-1-local-build">1. Local Build! 🛠️</h2>
<p>Before pushing your code, always ensure it builds locally. Have you considered using a build tool? I'd recommend <a target="_blank" href="https://bazel.build/">Bazel</a>, a fast and reliable build tool.</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>
<span class="hljs-comment"># Same content for pre-commit file</span>

<span class="hljs-keyword">if</span> [ -f <span class="hljs-string">"build.gradle"</span> ]; <span class="hljs-keyword">then</span> 
    ./gradlew build
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"setup.py"</span> ] || [ -f <span class="hljs-string">"pyproject.toml"</span> ]; <span class="hljs-keyword">then</span> 
    python setup.py build
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"go.mod"</span> ]; <span class="hljs-keyword">then</span> 
    go build ./...
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"WORKSPACE"</span> ] || [ -f <span class="hljs-string">"WORKSPACE.bazel"</span> ]; <span class="hljs-keyword">then</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Building Bazel project..."</span>
    bazel build //...
<span class="hljs-keyword">else</span> 
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Unknown project type. Skipping."</span>
<span class="hljs-keyword">fi</span>
</code></pre>
<hr />
<h2 id="heading-2-static-code-analysis">2. Static Code Analysis 🔍</h2>
<p>There are many ways and different schools of thought on the specifics of code checks for a pre-commit. However, all will agree that static code analysis is a great way to catch those vulnerabilities and coding errors early on.</p>
<ul>
<li><p><strong>Java</strong>: Use <a target="_blank" href="https://www.sonarlint.org/">SonarLint</a> with Gradle.</p>
</li>
<li><p><strong>Python</strong>: Utilize <a target="_blank" href="https://flake8.pycqa.org/en/latest/">Flake8</a> for linting and <a target="_blank" href="https://black.readthedocs.io/en/stable/">Black</a> for code formatting.</p>
</li>
<li><p><strong>GoLang</strong>: Use <a target="_blank" href="https://github.com/golang/lint">golint</a> for linting.</p>
</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-comment"># same content from the pre-commit file</span>

<span class="hljs-keyword">if</span> [ -f <span class="hljs-string">"build.gradle"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-comment"># previous checks</span>
    <span class="hljs-comment"># Static Code Analysis checks for Java (gradle) projects</span>
    <span class="hljs-comment"># Assuming you have SonarLint CLI or SonarQube scanner set up</span>
    ./gradlew sonarqube
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"setup.py"</span> ] || [ -f <span class="hljs-string">"pyproject.toml"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-comment"># previous checks</span>
    <span class="hljs-comment"># Static Code Analysis for Python projects</span>
    flake8 . &amp;&amp; black --check .
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"go.mod"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-comment"># previous checks</span>
    <span class="hljs-comment"># Static Code Analysis for GoLang projects</span>
    golint ./...
<span class="hljs-keyword">else</span> 
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Unknown project type. Skipping."</span>
<span class="hljs-keyword">fi</span>
</code></pre>
<hr />
<h2 id="heading-3-unit-tests">3. Unit Tests 🧪</h2>
<p>Testing is the backbone of reliable software. Ensure you have unit tests in place:</p>
<ul>
<li><p><strong>Java</strong>: Use <a target="_blank" href="https://junit.org/junit5/">JUnit</a>.</p>
</li>
<li><p><strong>Python</strong>: Use <a target="_blank" href="https://docs.pytest.org/en/stable/">pytest</a>.</p>
</li>
<li><p><strong>GoLang</strong>: Go's <a target="_blank" href="https://golang.org/pkg/testing/">built-in testing package</a> is your friend.</p>
</li>
</ul>
<hr />
<h2 id="heading-4-vulnerable-dependencies-check">4. Vulnerable Dependencies Check 🔐</h2>
<p>More often than not, vulnerabilities creep into your codebase due to third-party code injected as dependencies. It's crucial to ensure that these dependencies are not only up-to-date but also secure.</p>
<ul>
<li><p><strong>Java</strong>: Use the <a target="_blank" href="https://jeremylong.github.io/DependencyCheck/dependency-check-gradle/index.html">Dependency-Check Gradle plugin</a>.</p>
</li>
<li><p><strong>Python</strong>: <a target="_blank" href="https://pyup.io/safety/">safety</a> is a great tool for checking dependencies.</p>
</li>
<li><p><strong>GoLang</strong>: Use <code>go list -json -m all</code> to list modules.</p>
</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-comment"># same content from the pre-commit file</span>

<span class="hljs-keyword">if</span> [ -f <span class="hljs-string">"build.gralde"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-comment"># previous checks</span>
    <span class="hljs-comment"># build.gradle &gt; plugins { id 'org.owasp.dependencycheck' version 'x.x.x' }</span>
    <span class="hljs-comment"># configure dependency check plugin</span>
    ./gradlew dependencyCheckAnalyze
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"setup.py"</span> ] || [ -f <span class="hljs-string">"pyproject.toml"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-comment"># previous checks</span>
    <span class="hljs-comment"># pip install safety</span>
    safety check
<span class="hljs-keyword">elif</span> [ -f <span class="hljs-string">"go.mod"</span> ]; <span class="hljs-keyword">then</span> 
    <span class="hljs-comment"># previous checks</span>
    <span class="hljs-comment"># go get github.com/securego/gosec/v2/cmd/gosec</span>
    gosec ./...
<span class="hljs-keyword">else</span> 
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Unknown project type. Skipping."</span>
<span class="hljs-keyword">fi</span>
</code></pre>
<hr />
<p>🚨 <strong>Disclaimer</strong>: Remember, every team and project is unique. It's essential to tailor your pre-commit hooks and other practices to best fit your team's needs and the nature of your project. Always strive for a balance between thorough checks and developer productivity.</p>
<hr />
<p>I hope this guide helps you in your DevOps journey. Feel free to share, comment, and let me know if you have any questions or suggestions! 🙌</p>
<p>🌐 <a target="_blank" href="https://alkhatib.tech/">alkhatib.tech</a></p>
]]></content:encoded></item><item><title><![CDATA[Spring Boot & Jaeger in Action!]]></title><description><![CDATA[In the DevOps space, Observability is crucial to maintain a healthy and reliable solution. With logs, metrics, and traces, you can implement a setup that takes you from fixing your code issues on production to foreseeing issues before they even happe...]]></description><link>https://blog.alkhatib.tech/spring-boot-jaeger-in-action</link><guid isPermaLink="true">https://blog.alkhatib.tech/spring-boot-jaeger-in-action</guid><category><![CDATA[Springboot]]></category><category><![CDATA[jaeger]]></category><category><![CDATA[Devops]]></category><category><![CDATA[observability]]></category><category><![CDATA[Java]]></category><dc:creator><![CDATA[Hasan Alkhatib]]></dc:creator><pubDate>Mon, 07 Nov 2022 18:34:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747821813257/d7083479-4320-4dc9-b790-c5dcc7751770.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the DevOps space, Observability is crucial to maintain a healthy and reliable solution. With logs, metrics, and traces, you can implement a setup that takes you from fixing your code issues on production to foreseeing issues before they even happen.</p>
<p>I developed a small Spring Boot microservice for this showcase that consumes data from two external APIs. In front of this service, I implemented a simple API-Gateway to accept and authenticate requests. Both services communicate with each other and produce traces to be visualized later on via our observability setup (Jaeger UI).</p>
<h2 id="heading-prerequisites-and-external-dependencies">Prerequisites and external dependencies</h2>
<ul>
<li><p><a target="_blank" href="https://openjdk.org/projects/jdk/17/">JDK17</a> &amp; Gradle 7.5+</p>
</li>
<li><p>Docker &amp; Docker-compose</p>
</li>
<li><p>rapidapi.com API key (<a target="_blank" href="https://rapidapi.com/developer/security/default-application_4204327">Developer dashboard</a>)</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667899348187/3GNXZ_nOc.png" alt="c5673b2-Key_Rotation.png" /></p>
<h2 id="heading-setting-up-spring-with-opentracing">Setting up Spring with OpenTracing</h2>
<p>Java with Spring Boot provides a solid base to make it among the easiest technologies to instrument traces and visualize them using any UI of your choice. In this case, it will be Jaeger!</p>
<ul>
<li>For starters, pick your instrumentation and add it as a dependency:</li>
</ul>
<pre><code class="lang-plaintext">implementation 'io.opentracing.contrib:opentracing-spring-jaeger-cloud-starter:3.3.1'
</code></pre>
<ul>
<li>In this case, we will have out-of-the-box support to get traces for all requests to the API Gateway. For other services, add these beans:</li>
</ul>
<pre><code class="lang-java">    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> RestTemplateBuilder <span class="hljs-title">restTemplateBuilder</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> RestTemplateBuilder();
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> RestTemplate <span class="hljs-title">restTemplate</span><span class="hljs-params">(RestTemplateBuilder builder)</span></span>{
        <span class="hljs-keyword">return</span> builder.build();
    }
</code></pre>
<ul>
<li>Now to the cherry on top, taking into consideration that you have your Jaeger instance up and running, you will need to add Opentracing configuration to your application.yaml</li>
</ul>
<pre><code class="lang-yaml"><span class="hljs-attr">opentracing:</span>
  <span class="hljs-attr">jaeger:</span>
    <span class="hljs-attr">http-sender:</span>
      <span class="hljs-attr">url:</span> <span class="hljs-string">${JAEGER_URI:http://localhost:14268/api/traces}</span>
</code></pre>
<h2 id="heading-run-a-full-example">Run a full example</h2>
<p>To get everything up and running, you will need the Rapidapi API Key that we mentioned as a prerequisite here. Then you need to subscribe to these two APIs:</p>
<ul>
<li><p><a target="_blank" href="https://rapidapi.com/meme-generator-api-meme-generator-api-default/api/meme-generator">Meme Generator</a></p>
</li>
<li><p><a target="_blank" href="https://rapidapi.com/KegenGuyll/api/dad-jokes">Dad Jokes</a></p>
</li>
</ul>
<p>Then, here is an ad-hoc <a target="_blank" href="https://gist.github.com/HasanKhatib/406a06c709a54d9588f2a4d52ab00d4a">docker-compose file</a> to run the full example locally.</p>
<pre><code class="lang-plaintext">export RAPIDAPI_KEY=YOUR_KEY_HERE
docker-compose up
</code></pre>
<p>Now, call the api-gateway:</p>
<pre><code class="lang-plaintext">curl --location --request GET 'localhost:8081/random-meme/' \
--header 'Authorization: Basic YWRtaW46cGFzcw=='
</code></pre>
<h2 id="heading-summary">Summary</h2>
<p>Throughout this showcase, we utilized Spring framework to develop a reactive-web microservice and an API-Gateway. Following that, we dockerized these services and orchestrated them to have a running example. Finally, here is what to expect on JaegerUI after calling the services.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1667900050171/Bi9kJfp5K.jpg" alt="springboot1.jpg" /></p>
<h2 id="heading-resources">Resources</h2>
<p>To get a closer look at both services, the Spring Boot memes service and the API Gateway, follow these two links:</p>
<ul>
<li><p>%[https://github.com/HasanKhatib/random-meme]</p>
</li>
<li><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/HasanKhatib/spring-gateway">https://github.com/HasanKhatib/spring-gateway</a></div>
<p> </p>
</li>
</ul>
<p>🌐 <a target="_blank" href="https://alkhatib.tech/">alkhatib.tech</a></p>
]]></content:encoded></item></channel></rss>