<?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[Rama Blog]]></title><description><![CDATA[All About tech including coding, networking, and cloud computing]]></description><link>https://blog.ramadlana.my.id</link><generator>RSS for Node</generator><lastBuildDate>Wed, 13 May 2026 19:27:33 GMT</lastBuildDate><atom:link href="https://blog.ramadlana.my.id/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why STP prefer lower priority but VRRP prefer higher priority]]></title><description><![CDATA[At the beginning of my journey as a network engineer, I was always confused when configuring STP. I often had to double-check and re-read the documentation over and over again. It wasn’t the command syntax that was difficult, commands are easy to rem...]]></description><link>https://blog.ramadlana.my.id/why-stp-prefer-lower-priority-but-vrrp-prefer-higher-priority</link><guid isPermaLink="true">https://blog.ramadlana.my.id/why-stp-prefer-lower-priority-but-vrrp-prefer-higher-priority</guid><category><![CDATA[vrrp]]></category><category><![CDATA[networking]]></category><category><![CDATA[spanning tree]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Mon, 13 Jan 2025 17:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/40XgDxBfYXM/upload/2f188113f4baf83b5b82d0b7de65193a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>At the beginning of my journey as a network engineer, I was always confused when configuring STP. I often had to double-check and re-read the documentation over and over again. It wasn’t the command syntax that was difficult, commands are easy to remember naturally since we type them repeatedly. What I kept forgetting was:<br /><em>"Hmm, should I set a lower or higher priority for this bridge? Okay, let's Google it… and try to remember it."</em></p>
<p>Then, a few months later, when I had to configure STP priority again, I’d do the same thing all over again. 😆</p>
<p>One day, someone told me;<br /><em>"A lower value means higher priority."</em></p>
<p>That made sense—after all, if something is <strong>#1 priority</strong>, it means it's the <strong>top priority</strong>, right? But then, I suddenly realized:<br /><em>"Wait, what about VRRP? In VRRP, a</em> <strong><em>higher</em></strong> <em>priority value is preferred!"</em></p>
<p>That contradiction got me thinking. So, I started digging through IEEE documentation and finally found something that cleared up my confusion:</p>
<blockquote>
<p><strong>IEEE 802.1D Standard:</strong> The IEEE 802.1D standard specifies that the root bridge is the switch with the lowest Bridge ID, which is a combination of bridge priority and MAC address. This ensures a deterministic and consistent selection process.</p>
</blockquote>
<p>I couldn’t find the exact document again while writing this—maybe the link got moved—but you can search for it. The key takeaway here is <strong>"deterministic and consistent selection process."</strong></p>
<p>This makes perfect sense. The default STP priority is <strong>32768</strong>, and if we don’t explicitly configure it, the switch with the <strong>lowest MAC address</strong> becomes the root bridge.</p>
<h3 id="heading-why-does-using-the-lowest-value-make-stp-more-consistent">Why does using the lowest value make STP more consistent?</h3>
<p>Because hardware vendors <strong>increment</strong> MAC addresses over time as they manufacture new products. If we buy switches from the same vendor, rack them, and leave the priority at default, the <strong>root bridge will remain unchanged</strong>. This means we <strong>avoid unnecessary recalculations</strong> of the STP topology—no sudden changes in root ports, designated ports, or blocked ports.</p>
<p>Now, imagine if STP used the <strong>highest MAC address</strong> instead. Every time we added a <strong>newer switch</strong>, the root bridge would change (unless we manually set the priority). That would be a complete disaster!</p>
<h3 id="heading-what-about-vrrp">What about VRRP?</h3>
<p>VRRP, on the other hand, prefers <strong>higher priority values</strong> because a higher number <strong>represents greater capability</strong>, better specs, and so on. If there’s a tie, VRRP uses the <strong>highest IP address</strong> as the tiebreaker. This makes sense because <strong>we can assign IP addresses manually</strong>, meaning we control the outcome during the <strong>design phase</strong>.</p>
<p>This is different from STP, which relies on MAC addresses <strong>pre-assigned by hardware vendors</strong>. Yes, we can change a MAC address, but in practice, we usually don’t.</p>
<h3 id="heading-other-protocols-that-follow-the-higher-is-preferred-rule">Other Protocols That Follow the "Higher is Preferred" Rule</h3>
<p>The same logic applies to:</p>
<ul>
<li><p><strong>OSPF DR (Designated Router) Election</strong></p>
</li>
<li><p><strong>PIM DR (Designated Router) Election</strong></p>
</li>
<li><p><strong>IS-IS DIS (Designated Intermediate System) Election</strong></p>
</li>
</ul>
<p>All of these protocols prefer <strong>higher values</strong>, just like VRRP, because priority and IP addresses can be set during <strong>design</strong>, rather than relying on factory-assigned MAC addresses.</p>
<p>Understanding why STP selects the lowest priority while protocols like VRRP prefer the highest helps eliminate confusion and makes network design more intuitive. STP relies on MAC addresses, which are fixed by hardware vendors, ensuring a stable and predictable root bridge selection. On the other hand, VRRP and other protocols prioritize higher values because they allow manual control over election processes.</p>
<p>By remembering these distinctions, we can make better design choices and avoid unexpected behavior in our networks. So, next time you configure STP or VRRP, you won’t need to Google it again—you’ll already know why! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[Lifelong Learning: Adapting, Overcoming, and Growing]]></title><description><![CDATA[In both personal and professional life, recognizing weaknesses, bouncing back from failures, and staying adaptable are essential for continuous growth. Learning never stops—it’s not a destination but an ongoing process of improvement and self-reflect...]]></description><link>https://blog.ramadlana.my.id/embrace-growth-mastering-weaknesses-resilience-and-adaptability-for-lifelong-learning</link><guid isPermaLink="true">https://blog.ramadlana.my.id/embrace-growth-mastering-weaknesses-resilience-and-adaptability-for-lifelong-learning</guid><category><![CDATA[personal development]]></category><category><![CDATA[#growth]]></category><category><![CDATA[growth mindset,]]></category><category><![CDATA[Self Improvement ]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Sun, 11 Aug 2024 08:39:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/1E6vgtfLkLA/upload/f29e61ef4e1e82e5baa04f35a4745f2a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In both personal and professional life, recognizing weaknesses, bouncing back from failures, and staying adaptable are essential for continuous growth. <strong>Learning never stops</strong>—it’s not a destination but an ongoing process of improvement and self-reflection. Understanding this makes it easier to handle challenges and move forward with confidence.</p>
<hr />
<h3 id="heading-my-journey-in-tech">🚀 My Journey in Tech</h3>
<p>Over the past nine years, I’ve worked as a <strong>network engineer, software engineer, and cloud engineer</strong>. In this field, <strong>change is constant</strong>, and to keep up, I’ve had to learn new skills quickly. Whether through online courses like <strong>Udemy and Coursera</strong>, YouTube tutorials, or official technical documentation, <strong>continuous learning has been a necessity</strong>.</p>
<p>Technology moves fast, and businesses must keep up to stay competitive. That means professionals in IT need to be <strong>proactive</strong> about updating their knowledge. For example, when a <strong>new programming language</strong> or <strong>cloud service</strong> becomes popular, learning it keeps you relevant in the job market. Cybersecurity, automation, and cloud computing trends are <strong>constantly evolving</strong>, and staying informed gives an edge in career growth.</p>
<p>Throughout my career, I’ve faced situations where I had to learn new technologies quickly to meet deadlines or solve complex problems. These experiences reinforced <strong>three key principles</strong> I always follow:</p>
<p>✅ <strong>Know Your Weaknesses</strong><br />✅ <strong>Bounce Back from Failures</strong><br />✅ <strong>Stay Adaptable</strong></p>
<hr />
<h3 id="heading-1-know-your-weaknesses">🎯 1. Know Your Weaknesses</h3>
<p>Acknowledging weaknesses is one of the hardest but most rewarding aspects of self-improvement. It requires <strong>honesty and self-awareness</strong>, which can be uncomfortable but necessary for growth. <strong>Weaknesses are not flaws; they highlight areas for development.</strong></p>
<p>For example, if someone struggles with <strong>public speaking</strong>, avoiding presentations won’t help. Instead, acknowledging the weakness and working on it—<strong>taking courses, practicing, and getting feedback</strong>—turns it into a strength.</p>
<p>🔹 <strong>Identify weak areas</strong><br />🔹 <strong>Set specific goals</strong><br />🔹 <strong>Actively improve</strong></p>
<hr />
<h3 id="heading-2-bounce-back-from-failures">🔥 2. Bounce Back from Failures</h3>
<p><strong>Resilience</strong> is about recovering from setbacks. <strong>Failures are part of the journey.</strong> What matters is how you respond.</p>
<p>Successful people don’t see failures as the end; they see them as <strong>learning experiences</strong>. For example, if an engineer’s solution doesn’t work, they analyze what went wrong, adjust, and try again. <strong>Entrepreneurs who fail in their first business use that experience to build something better.</strong></p>
<p>🔹 <strong>Maintain a positive mindset</strong><br />🔹 <strong>Learn from mistakes</strong><br />🔹 <strong>Stay motivated even in tough times</strong></p>
<p>💡 <strong>Failures aren’t roadblocks—they’re stepping stones.</strong></p>
<hr />
<h3 id="heading-3-stay-adaptable">🌟 3. Stay Adaptable</h3>
<p><strong>Change is constant</strong>, and adaptability is what keeps professionals relevant. Being adaptable means being <strong>open to new ideas, technologies, and ways of thinking</strong>.</p>
<p>Adaptability isn’t just reacting to change—it’s <strong>actively seeking opportunities for growth</strong>. This could mean learning a <strong>new programming language</strong>, staying updated with <strong>industry trends</strong>, or experimenting with <strong>new tools</strong>.</p>
<p>For example, a <strong>software engineer</strong> who continuously learns new frameworks stays competitive in the industry. Similarly, a <strong>network engineer</strong> who explores <strong>automation tools like Python or Ansible</strong> gains an advantage in modern networking environments.</p>
<p>🔹 <strong>Stay curious</strong><br />🔹 <strong>Keep learning</strong><br />🔹 <strong>Embrace change</strong></p>
<hr />
<h3 id="heading-the-mindset-of-lifelong-learning">🧠 The Mindset of Lifelong Learning</h3>
<p>Embracing lifelong learning means continuously improving, <strong>setting goals, and staying curious</strong>. Learning isn’t just about <strong>formal education</strong>—it’s about <strong>everyday experiences, problem-solving, and self-reflection</strong>.</p>
<p>This journey requires <strong>patience and persistence</strong> but leads to <strong>professional success and personal fulfillment</strong>.</p>
<hr />
<h3 id="heading-conclusion">🎯 Conclusion</h3>
<p>Lifelong learning is built on <strong>three principles</strong>:</p>
<p>🔹 <strong>Know Your Weaknesses</strong> – Identify areas for growth and work on them.<br />🔹 <strong>Bounce Back from Failures</strong> – Learn from setbacks and keep moving forward.<br />🔹 <strong>Stay Adaptable</strong> – Embrace change and new opportunities.</p>
<p>By following these principles, we can develop a <strong>mindset that promotes continuous growth</strong>. The journey never ends, but <strong>each step forward brings us closer to becoming the best version of ourselves</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[Network Multicast Explained: Protocols and Implementations Guide]]></title><description><![CDATA[Understanding IGMP and PIM in Multicast Networking
In the realm of multicast networking, two essential protocols play distinct but complementary roles: IGMP (Internet Group Management Protocol) and PIM (Protocol Independent Multicast). Understanding ...]]></description><link>https://blog.ramadlana.my.id/network-multicast-explained-protocols-and-implementations-guide</link><guid isPermaLink="true">https://blog.ramadlana.my.id/network-multicast-explained-protocols-and-implementations-guide</guid><category><![CDATA[multicast]]></category><category><![CDATA[igmp]]></category><category><![CDATA[pim]]></category><category><![CDATA[networking]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Sun, 11 Aug 2024 05:39:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/m_HRfLhgABo/upload/5e92e8d0032f3e4cc3ccd3f5cc978ad1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-understanding-igmp-and-pim-in-multicast-networking">Understanding IGMP and PIM in Multicast Networking</h3>
<p>In the realm of multicast networking, two essential protocols play distinct but complementary roles: IGMP (Internet Group Management Protocol) and PIM (Protocol Independent Multicast). Understanding how these protocols work together is crucial for managing multicast traffic effectively across networks.</p>
<h4 id="heading-the-role-of-igmp">The Role of IGMP</h4>
<p><strong>IGMP</strong> is a protocol used for managing multicast group memberships within a local network. It allows devices to signal their interest in receiving multicast traffic, ensuring that multicast data is only sent to devices that have explicitly requested it. IGMP operates within a single network segment or subnet, making it highly effective for managing multicast traffic locally. <strong>Key Functions of IGMP:</strong></p>
<ul>
<li><p><strong>Group Membership Management:</strong> IGMP helps routers and switches determine which devices (hosts) are part of a multicast group.</p>
</li>
<li><p><strong>Efficient Multicast Distribution:</strong> By informing network devices of which groups are active, IGMP helps to minimize unnecessary multicast traffic and optimize bandwidth usage.</p>
</li>
</ul>
<h4 id="heading-the-role-of-pim">The Role of PIM</h4>
<p><strong>PIM</strong> is designed to extend multicast traffic beyond the boundaries of a single local network. While IGMP handles group membership within a network, PIM is responsible for routing multicast traffic between different networks, enabling it to traverse routers and various network segments. <strong>Key Functions of PIM:</strong></p>
<ul>
<li><p><strong>Multicast Routing:</strong> PIM creates and maintains multicast distribution trees that span multiple networks, facilitating the delivery of multicast traffic to devices across different network segments.</p>
</li>
<li><p><strong>Protocol Independence:</strong> PIM operates independently of the underlying unicast routing protocol (e.g., OSPF, EIGRP, BGP), allowing it to work with various network setups.</p>
</li>
</ul>
<h4 id="heading-how-igmp-and-pim-work-together">How IGMP and PIM Work Together</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723354452617/da3179e6-cd58-4af0-9bd9-d9915924e1aa.png" alt class="image--center mx-auto" /></p>
<p>The interaction between IGMP and PIM is crucial for effective multicast communication. Within a local network, IGMP ensures that multicast traffic is only sent to interested devices. When multicast traffic needs to be sent to or from devices across different networks, PIM takes over, routing the traffic between networks and ensuring that it reaches its intended destination. In summary:</p>
<ul>
<li><p><strong>IGMP</strong> is essential for managing multicast group memberships locally, ensuring efficient multicast traffic distribution within a single network segment.</p>
</li>
<li><p><strong>PIM</strong> complements IGMP by enabling multicast traffic to traverse multiple networks, allowing multicast communication to extend beyond local boundaries.</p>
</li>
</ul>
<h3 id="heading-multicast-pim-neighbor-discovery">Multicast PIM - Neighbor discovery</h3>
<p>In a PIM domain, each PIM interface on a router periodically multicasts PIM hello messages to all other PIM routers (identified by the address 224.0.0.13) on the local subnet. Through the exchanging of hello messages, all PIM routers on the subnet determine their PIM neighbors, maintain PIM neighboring relationship with other routers, and build and maintain SPTs.</p>
<h3 id="heading-multicast-pim-reverse-path-forwarding-rpf">Multicast PIM - Reverse Path Forwarding (RPF)</h3>
<p>Reverse Path Forwarding (RPF) is a fundamental mechanism in multicast routing that ensures data packets are forwarded along the correct path back to the source. RPF uses the existing unicast routing table to determine the preferred path for incoming multicast packets, ensuring that data is only accepted and forwarded if it arrives on the expected interface. This mechanism prevents loops and ensures that multicast traffic is efficiently routed through the network.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723354502099/cfbe736f-8fb4-4f76-ad78-3d05191aedbc.png" alt class="image--center mx-auto" /></p>
<p>Image Source: <a target="_blank" href="https://support.hpe.com/techhub/eginfolib/networking/docs/switches/5510hi/5200-0071b_ip-multi_cg/content/471720261.htm">RPF check mechanism (</a><a target="_blank" href="http://hpe.com">hpe.com</a><a target="_blank" href="https://support.hpe.com/techhub/eginfolib/networking/docs/switches/5510hi/5200-0071b_ip-multi_cg/content/471720261.htm">)</a></p>
<p><strong>RPF Mechanism</strong> The RPF process works as follows:</p>
<ol>
<li><p>When a multicast packet arrives at a router, the router checks its unicast routing table to determine the preferred path to the packet's source.</p>
</li>
<li><p>If the packet arrives on the interface that matches the preferred path, it is accepted and forwarded to the next hop.</p>
</li>
<li><p>If the packet arrives on a different interface, it is discarded to prevent routing loops and inefficiencies. This mechanism ensures that multicast traffic flows along the most efficient path, leveraging the existing unicast routing infrastructure to maintain optimal performance. <strong>RPF Example</strong> Consider a multicast packet with a source IP address of 10.1.1.1 and a destination multicast address of 239.1.1.1. If this packet arrives at a router on both port1 and port2, the router uses the unicast routing table to determine the best path to reach 10.1.1.1. If the unicast route indicates that the preferred path to 10.1.1.1 is through port1, the packet arriving on port1 is accepted and forwarded, while the packet arriving on port2 is discarded. This ensures that the multicast traffic follows the most efficient route, minimizing unnecessary load on the network.</p>
</li>
</ol>
<h3 id="heading-pim-dense-mode-pim-dm">PIM Dense Mode (PIM-DM)</h3>
<p><strong>Characteristics of PIM-DM</strong> PIM Dense Mode (PIM-DM) is a multicast routing protocol that operates under the assumption that multicast receivers are densely distributed throughout the network. In PIM-DM, multicast traffic is initially flooded to all PIM-enabled routers. This approach ensures that all potential receivers have access to the multicast data, but it can result in significant overhead if many routers do not have interested receivers. <strong>Flood and Prune Mechanism</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723354569016/6d8cab89-cf1e-45c6-a48d-8eeeb415153a.png" alt class="image--center mx-auto" /></p>
<p><strong>PIM-DM Flooding</strong>: When multicast traffic is first introduced into the network, it is flooded to all PIM-enabled routers. This ensures that all potential receivers receive the multicast data. <strong>PIM-DM Pruning</strong>: Routers that do not have any interested multicast receivers send a prune message upstream, instructing the upstream router to stop sending multicast traffic to them. This process continues until multicast traffic is only sent to routers with interested receivers. This mechanism helps to reduce unnecessary traffic and optimize the use of network resources, but it can be inefficient in networks with sparse multicast receivers. <strong>PIM-DM Draft</strong> is used to facilitate the process of rejoining a multicast group that was previously pruned. When a network segment or router has been pruned (i.e., multicast traffic was stopped), if a new receiver expresses interest in that multicast group, the network needs a way to handle this rejoining. <strong>Benefits and Drawbacks of PIM-DM</strong> <strong>Benefits</strong>:</p>
<ul>
<li><p>Simple to implement and configure.</p>
</li>
<li><p>Ensures all potential receivers initially receive the multicast data. <strong>Drawbacks</strong>:</p>
</li>
<li><p>Inefficient in networks with sparse receivers, leading to excessive flooding and pruning.</p>
</li>
<li><p>Higher bandwidth consumption due to initial flooding.</p>
</li>
</ul>
<h3 id="heading-pim-sparse-mode-pim-sm">PIM Sparse Mode (PIM-SM)</h3>
<p><strong>Characteristics of PIM-SM</strong> PIM Sparse Mode (PIM-SM) operates under the assumption that multicast receivers are sparsely distributed throughout the network. Unlike PIM-DM, PIM-SM uses a more controlled approach to multicast traffic distribution, relying on a central Rendezvous Point (RP) to manage group memberships and traffic forwarding.</p>
<p><strong>Shared Tree (RPT)</strong> In PIM-SM, the initial multicast traffic is sent to a Rendezvous Point (RP), which maintains a shared tree (RPT) connecting all routers with interested receivers. The steps are as follows:</p>
<ul>
<li><p>A router interested in receiving multicast traffic for a group sends a join message towards the RP.</p>
</li>
<li><p>The RP builds a shared tree connecting all receivers.</p>
</li>
<li><p>Multicast traffic from the source is sent to the RP, then distributed to all receivers via the shared tree. <strong>Source Tree (SPT)</strong> After the initial multicast traffic is delivered via the shared tree, routers can transition to a Source Tree or Short Path Tree (SPT) for more efficient delivery. The steps are as follows:</p>
</li>
<li><p>Once a receiver router receives multicast traffic from the RP, it learns the source's IP address.</p>
</li>
<li><p>If there is a more efficient path to the source, the router builds a source tree specific to that source.</p>
</li>
<li><p>Future multicast traffic is received directly from the source via the source tree, optimizing the delivery path.</p>
</li>
</ul>
<p>PIM Sparse Mode use Register and Register Stop to handle multicast source registration <strong>PIM Register:</strong> Used to inform the RP about the source and to forward multicast traffic to the RP. <strong>PIM Register-Stop:</strong> Tells the local router to stop sending Register messages once the RP confirms there are interested receivers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723354607638/b148c21a-3b94-4e68-99ce-ef1f7196fe52.png" alt class="image--center mx-auto" /></p>
<p><strong>Transition from Shared Tree to Source Tree</strong> This transition from the shared tree to the source tree enhances efficiency by ensuring that multicast traffic follows the shortest possible path to each receiver. This reduces latency and conserves bandwidth, particularly in large networks with diverse multicast sources and receivers.</p>
<h3 id="heading-pim-sparse-mode-auto-rp">PIM Sparse Mode Auto-RP</h3>
<p>In PIM multicast routing, the Rendezvous Point (RP) is a crucial component that facilitates the distribution of multicast traffic to receivers. Auto-RP automates the process of discovering and advertising RP information, making it easier to deploy and manage multicast routing. Note: <strong>Auto-RP</strong> is applicable only to <strong>PIM-SM</strong>.</p>
<p><strong>Mapping Agents:</strong> These are routers that listen for RP announcements and distribute RP information to the rest of the network.<br /><strong>Candidate RPs:</strong> These are routers that volunteer to act as RPs and advertise their willingness to serve as an RP to the network.</p>
<p><strong>Auto-RP Components</strong>: <strong>Candidate RP (CRP):</strong> A router that wants to be an RP will use Auto-RP to advertise itself as a candidate. This advertisement includes information such as the multicast groups it is willing to support. <strong>Mapping Agent (MA):</strong> A router that listens for Candidate RP advertisements and distributes RP information throughout the network. <strong>Rendezvous Point (RP):</strong> Once elected, the RP is responsible for managing multicast groups and forwarding multicast traffic.</p>
<h3 id="heading-pim-source-specific-multicast-pim-ssm">PIM Source-Specific Multicast (PIM-SSM)</h3>
<p><strong>Overview of PIM-SSM</strong> PIM Source-Specific Multicast (PIM-SSM) is a variant of PIM designed to enhance the efficiency and security of multicast traffic delivery. In PIM-SSM, multicast receivers specify both the source and the group they are interested in, allowing for more precise and efficient routing of multicast traffic. <strong>Notes</strong>:</p>
<ul>
<li><p>Its <strong>Required IGMPv3</strong> enabled within networks. PIM SSM relies on the capability of IGMPv3 to handle source-specific multicast group memberships. IGMPv3 enables the receiver to explicitly specify the source addresses it wants to receive traffic from, which is a fundamental requirement for PIM SSM.</p>
</li>
<li><p>(*;G) are not exist on PIM-SSM</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723354657591/72cd14d4-0225-4de2-860f-7efe820f7923.png" alt class="image--center mx-auto" /></p>
<p>  <strong>Advantages of PIM-SSM</strong></p>
</li>
<li><p><strong>Increased Security</strong>: By allowing receivers to specify the source, PIM-SSM reduces the risk of unwanted or malicious multicast traffic.</p>
</li>
<li><p><strong>Improved Efficiency</strong>: PIM-SSM optimizes the delivery of multicast traffic by ensuring it only flows from the specified source to interested receivers, reducing unnecessary traffic.</p>
</li>
<li><p><strong>Simplified Management</strong>: PIM-SSM simplifies the management of multicast groups by reducing the complexity of group membership and traffic forwarding.</p>
</li>
</ul>
<h3 id="heading-pim-bidirectional-pim-bidr">PIM Bidirectional (PIM-BIDR)</h3>
<p><strong>Overview of PIM-BIDR</strong> In PIM BIDIR, the RP serves as the central point through which all multicast traffic is exchanged. It plays a key role in bidirectional multicast communication, ensuring that multicast traffic can flow in both directions—between sources and receivers. Multiple RPs can be manually configured. The network can be set alternate RP if the primary RP fails.</p>
<p>PIM BIDIR is a variant of PIM-SM, similar to SSM, and is particularly useful when most receivers are also senders, such as in videoconferencing scenarios. In PIM BiDir, all participants join a single distribution tree rooted at the RP. Unlike the unidirectional trees in PIM-SM, BiDir allows traffic to flow both up and down the tree. When a source sends multicast packets, they travel up to the RP and then down to all receivers.</p>
<p>To establish the bidirectional tree, PIM elects <strong>Designated Forwarders (DFs)</strong> for each link. The DF is selected based on the shortest metric to the RP, similar to the PIM Assert procedure. PIM Assert Procedure is Mechanism that optimizes multicast traffic by stopping the forwarding of multicast traffic on specific interfaces where there are no interested receivers. DFs are the only routers allowed to forward traffic upstream towards the RP.</p>
<p>Each router in a PIM BIDIR network maintains a (*, G) state for each bidirectional group, with an Outgoing Interface List (OIL) based on PIM Join messages from neighbors, representing the downstream part of the tree.</p>
<p>PIM BIDIR does not use the PIM Register/Register-Stop mechanism for source registration. Sources can start sending multicast traffic at any time; packets will travel upward to the RP and then be either dropped if there are no receivers or forwarded down the BIDIR tree. The RP cannot instruct the source to stop sending traffic.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723354712853/1f0f0b97-00ce-4660-8df2-af4d2223d460.png" alt class="image--center mx-auto" /></p>
<p><strong>Use Cases for PIM-BIDR</strong></p>
<ul>
<li><p><strong>Video Conferencing</strong>: PIM-BIDR is ideal for video conferencing applications where participants need to send and receive video streams simultaneously.</p>
</li>
<li><p><strong>Collaborative Work</strong>: In collaborative environments, PIM-BIDR allows for efficient sharing of data and resources among multiple users.</p>
</li>
</ul>
<h3 id="heading-comparing-pim-modes">Comparing PIM Modes</h3>
<p><strong>PIM-DM vs PIM-SM</strong></p>
<ul>
<li><p><strong>PIM-DM</strong>: Suitable for networks with densely distributed receivers, but can result in excessive flooding and pruning.</p>
</li>
<li><p><strong>PIM-SM</strong>: More efficient for networks with sparsely distributed receivers, using a central RP to manage group memberships and traffic.</p>
</li>
</ul>
<p><strong>PIM-SSM vs PIM-BIDR</strong></p>
<ul>
<li><p><strong>PIM-SSM</strong>: Focuses on source-specific multicast traffic, enhancing security and efficiency by allowing receivers to specify both the source and the group.</p>
</li>
<li><p><strong>PIM-BIDR</strong>: Optimized for bidirectional traffic flows, ideal for applications requiring simultaneous send and receive capabilities.</p>
</li>
</ul>
<h3 id="heading-implementing-pim-in-networks">Implementing PIM in Networks</h3>
<p><strong>PIM Configuration Steps</strong></p>
<ol>
<li><p><strong>Enable PIM on Interfaces</strong>: Configure PIM on the interfaces of routers that will participate in multicast routing.</p>
</li>
<li><p><strong>Configure Rendezvous Points (RP)</strong>: For PIM-SM, designate and configure RPs to manage group memberships and traffic forwarding.</p>
</li>
<li><p><strong>Establish Multicast Routing Policies</strong>: Define policies to control the flow of multicast traffic and manage group memberships. <strong>Common Challenges and Solutions</strong></p>
</li>
</ol>
<ul>
<li><p><strong>Challenge</strong>: Managing multicast group memberships in large networks. <strong>Solution</strong>: Use automated tools and protocols like IGMP to simplify membership management.</p>
</li>
<li><p><strong>Challenge</strong>: Ensuring efficient routing of multicast traffic. <strong>Solution</strong>: Leverage RPF checks and transition to source trees for optimized delivery.</p>
</li>
</ul>
<h3 id="heading-use-cases-and-applications-of-pim">Use Cases and Applications of PIM</h3>
<p><strong>Real-World Examples</strong></p>
<ul>
<li><p><strong>Live Streaming</strong>: PIM is used to efficiently distribute live video streams to large audiences. Live streaming mean user stream the video at same time without have any control to video playback such as Forward, Backward, Timestamp slider and so on.</p>
</li>
<li><p><strong>Online Gaming</strong>: Multicast traffic optimizes the delivery of real-time game data to multiple players.</p>
</li>
</ul>
<p><strong>Industry Applications</strong></p>
<ul>
<li><p><strong>Finance</strong>: Real-time stock ticker updates and financial news distribution.</p>
</li>
<li><p><strong>Education</strong>: Distance learning and virtual classrooms benefit from efficient multicast traffic delivery.</p>
</li>
</ul>
<h3 id="heading-switch-role-as-igmp-snoop">Switch Role as IGMP Snoop</h3>
<p>Snoop Multicast Information between host and router. <strong>Overview of IGMP Snooping</strong> IGMP (Internet Group Management Protocol) Snooping is a network switch feature that allows the switch to listen in on IGMP conversations between hosts and routers. By doing so, the switch can intelligently forward multicast traffic only to ports that are part of the multicast group, preventing unnecessary traffic from being sent to all ports. <strong>Benefits of IGMP Snooping</strong></p>
<ul>
<li><p><strong>Traffic Optimization</strong>: IGMP Snooping significantly reduces multicast traffic by ensuring that multicast packets are only sent to ports with interested receivers.</p>
</li>
<li><p><strong>Enhanced Performance</strong>: By limiting unnecessary traffic, IGMP Snooping improves the overall performance and efficiency of the network.</p>
</li>
<li><p><strong>Bandwidth Conservation</strong>: By preventing multicast packets from flooding the entire network, IGMP Snooping conserves valuable bandwidth, particularly in large and complex networks.</p>
</li>
</ul>
<h3 id="heading-faqs-on-protocol-independent-multicast-pim">FAQs on Protocol Independent Multicast (PIM)</h3>
<p>What is Protocol Independent Multicast (PIM)? PIM is a multicast routing protocol that operates independently of specific unicast routing protocols, enabling efficient distribution of multicast traffic across IP networks.</p>
<p>How does Reverse Path Forwarding (RPF) work? RPF ensures that multicast packets are accepted only if they arrive on the correct interface, as determined by the unicast routing table, preventing loops and optimizing traffic flow.</p>
<p>What are the differences between PIM-DM and PIM-SM? PIM-DM assumes densely distributed receivers and uses a flood and prune mechanism, while PIM-SM assumes sparsely distributed receivers and uses a Rendezvous Point to manage traffic.</p>
<p>What is the purpose of PIM-SSM? PIM-SSM allows receivers to specify both the source and the group for multicast traffic, enhancing security and efficiency by reducing unnecessary traffic.</p>
<p>When is PIM Bidirectional (PIM-BIDR) used? PIM-BIDR is used in scenarios with bidirectional traffic flows, such as video conferencing and collaborative work, enabling efficient routing in both directions.</p>
<p>What are the benefits of multicast routing? Multicast routing optimizes bandwidth use, improves scalability, and enhances network performance by delivering data to multiple recipients simultaneously.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p><strong>Summary of Key Points</strong> Protocol Independent Multicast (PIM) is a versatile and efficient multicast routing protocol that operates independently of specific unicast routing protocols. It offers various modes, including PIM-DM, PIM-SM, PIM-SSM, and PIM-BIDR, each suited to different network environments and requirements. Understanding and implementing PIM can significantly enhance the efficiency and performance of multicast traffic in IP networks. <strong>Final Thoughts on PIM</strong> PIM remains a critical component of modern IP networks, providing the scalability, efficiency, and flexibility needed to support a wide range of multicast applications. As networks continue to evolve, the ongoing development and integration of PIM with emerging technologies will ensure its relevance and effectiveness in meeting future multicast routing challenges.</p>
]]></content:encoded></item><item><title><![CDATA[How to Migrate Compute Instances Between Google Cloud Projects]]></title><description><![CDATA[Migrating virtual machines (VMs) across Google Cloud projects can simplify your infrastructure management and resource allocation. In this guide, we'll show you how to create, snapshot, and migrate VMs using Google Cloud's command-line tool gcloud. T...]]></description><link>https://blog.ramadlana.my.id/how-to-migrate-compute-instances-between-google-cloud-projects</link><guid isPermaLink="true">https://blog.ramadlana.my.id/how-to-migrate-compute-instances-between-google-cloud-projects</guid><category><![CDATA[google cloud]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Sun, 11 Aug 2024 05:27:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/TKAg3WignSw/upload/d8a0b8eed61db3dff859b677f23dab46.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Migrating virtual machines (VMs) across Google Cloud projects can simplify your infrastructure management and resource allocation. In this guide, we'll show you how to create, snapshot, and migrate VMs using Google Cloud's command-line tool <code>gcloud</code>. This will help you move VMs between projects and ensure a smooth transition.</p>
<h3 id="heading-1-creating-a-new-vm-instance"><strong>1. Creating a New VM Instance</strong></h3>
<p>To start, create a new VM instance in your destination project. Here’s how:</p>
<pre><code class="lang-bash">gcloud compute instances create rama_test_vm_move \
    --image-project rama_lab \
    --image machine-images-sf-sa \
    --subnet default
</code></pre>
<p>In this command:</p>
<ul>
<li><p><code>rama_test_vm_move</code> is the name of the new VM instance.</p>
</li>
<li><p><code>--image-project</code> specifies the project where the image is located.</p>
</li>
<li><p><code>--image</code> indicates the name of the image to use.</p>
</li>
<li><p><code>--subnet</code> assigns the instance to a subnet (in this case, the default subnet).</p>
</li>
</ul>
<p>For consistency, if you need to create another instance with similar parameters, you can use:</p>
<pre><code class="lang-bash">gcloud compute instances create ramatestvmmove \
    --image-project rama-lab \
    --image machine-images-sf-sa \
    --subnet default
</code></pre>
<h3 id="heading-2-creating-and-managing-snapshots"><strong>2. Creating and Managing Snapshots</strong></h3>
<p><strong>Source Project:</strong></p>
<ol>
<li><p><strong>Create a Snapshot:</strong> To snapshot a disk from a VM in your source project, use:</p>
<pre><code class="lang-bash"> gcloud compute snapshots create sasnapshoot \
     --source-disk instance-2 \
     --snapshot-type STANDARD \
     --source-disk-zone asia-southeast2<span class="hljs-_">-a</span>
</code></pre>
<ul>
<li><p><code>sasnapshoot</code> is the name of the snapshot.</p>
</li>
<li><p><code>--source-disk</code> specifies the disk you want to snapshot.</p>
</li>
<li><p><code>--snapshot-type</code> defines the type of snapshot (STANDARD).</p>
</li>
<li><p><code>--source-disk-zone</code> is the zone where the source disk is located.</p>
</li>
</ul>
</li>
<li><p><strong>Create an Image from the Snapshot:</strong></p>
<p> After creating the snapshot, convert it into an image:</p>
<pre><code class="lang-bash"> gcloud compute images create serviceassuranceimages \
     --source-snapshot=sasnapshoot
</code></pre>
<ul>
<li><code>serviceassuranceimages</code> is the name of the new image created from the snapshot.</li>
</ul>
</li>
<li><p><strong>Grant Access to the Image:</strong></p>
<p> Ensure that the new user or project has the necessary permissions to access the image. Assign the <code>user.image</code> role via IAM.</p>
</li>
</ol>
<h3 id="heading-3-creating-vm-instances-in-the-destination-project"><strong>3. Creating VM Instances in the Destination Project</strong></h3>
<p><strong>Destination Project:</strong></p>
<p>To create a VM instance in a new project using the image from the source project:</p>
<pre><code class="lang-bash">gcloud compute instances create ramatest \
    --image-project rama-lab \
    --image serviceassuranceimages
</code></pre>
<p>In this command:</p>
<ul>
<li><p><code>ramatest</code> is the name of the new VM instance.</p>
</li>
<li><p><code>--image-project</code> specifies the project where the image is stored.</p>
</li>
<li><p><code>--image</code> refers to the image created from the snapshot.</p>
</li>
</ul>
<h3 id="heading-4-example-implementation-a-full-migration"><strong>4. Example Implementation: A Full Migration</strong></h3>
<p>Here’s a complete example of migrating a VM from one project to another:</p>
<p><strong>Source Project:</strong></p>
<ol>
<li><p><strong>Create Snapshot:</strong></p>
<pre><code class="lang-bash"> gcloud compute snapshots create exportedsnapshoot \
     --source-disk newvmsa-instance \
     --snapshot-type STANDARD \
     --source-disk-zone asia-southeast2<span class="hljs-_">-a</span>
</code></pre>
</li>
<li><p><strong>Create Image from Snapshot:</strong></p>
<pre><code class="lang-bash"> gcloud compute images create exportedserviceassuranceimages \
     --source-snapshot=exportedsnapshoot
</code></pre>
</li>
</ol>
<p><strong>Destination Project:</strong></p>
<ol>
<li><p><strong>Create VM Instance:</strong></p>
<pre><code class="lang-bash"> gcloud compute instances create serviceassurancevm \
     --image-project zeta-crossbar-371709 \
     --image exportedserviceassuranceimages
</code></pre>
</li>
</ol>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Migrating VMs across Google Cloud projects involves creating snapshots, converting them to images, and deploying new VM instances using these images. By following these steps, you can efficiently manage and transfer your VMs while ensuring they retain their configurations and data. This process is essential for maintaining a flexible and scalable cloud infrastructure, allowing you to optimize resource utilization and project management.</p>
]]></content:encoded></item><item><title><![CDATA[Steps to Build Your Own Ansible Module]]></title><description><![CDATA[Ansible modules allow you to automate various network management tasks, and creating a custom module can significantly boost your automation capabilities. This blog post will guide you through the process of creating a custom Ansible module to intera...]]></description><link>https://blog.ramadlana.my.id/steps-to-build-your-own-ansible-module</link><guid isPermaLink="true">https://blog.ramadlana.my.id/steps-to-build-your-own-ansible-module</guid><category><![CDATA[ansible]]></category><category><![CDATA[Python]]></category><category><![CDATA[networking]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Sun, 11 Aug 2024 05:24:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/XJXWbfSo2f0/upload/27d9be40da632f59408491021b95dda0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ansible modules allow you to automate various network management tasks, and creating a custom module can significantly boost your automation capabilities. This blog post will guide you through the process of creating a custom Ansible module to interact with Huawei VRP (Versatile Routing Platform) devices. Specifically, we will create a module to execute the <code>display ip routing-table</code> command and handle the output.</p>
<h2 id="heading-step-1-creating-the-custom-ansible-module"><strong>Step 1: Creating the Custom Ansible Module</strong></h2>
<p>We'll start by creating a Python script for our custom Ansible module. This module will interact with Huawei devices to show the IP routing table.</p>
<p><strong>Script:</strong> <code>yourorganization_module_huawei_display_ip_routing_</code><a target="_blank" href="http://table.py"><code>table.py</code></a></p>
<pre><code class="lang-python"><span class="hljs-comment">#!/usr/bin/python3</span>

<span class="hljs-comment"># Copyright: (c) 2021, Hidayah Ramadlana &lt;hidayah.ramadalana@org.com&gt;</span>
<span class="hljs-comment"># GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)</span>

<span class="hljs-keyword">from</span> __future__ <span class="hljs-keyword">import</span> (absolute_import, division, print_function)
__metaclass__ = type

<span class="hljs-keyword">from</span> ansible.module_utils.basic <span class="hljs-keyword">import</span> AnsibleModule

<span class="hljs-comment"># all logic function</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_module</span>():</span>
    <span class="hljs-comment"># SOP:1 Change this: </span>
    <span class="hljs-comment"># param input</span>
    module_args = dict(
        command=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">True</span>),
        ansible_host=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_network_os=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_user=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_ssh_pass=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_platform=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
    )

    <span class="hljs-comment"># SOP: 2 Change this</span>
    <span class="hljs-comment"># result prototype</span>
    result = dict(
        changed=<span class="hljs-literal">False</span>,
        return_from_devices=<span class="hljs-string">""</span>
    )

    <span class="hljs-comment"># [do not change] create new AnsibleModule instance called (module)</span>
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=<span class="hljs-literal">True</span>
    )

    <span class="hljs-comment"># [do not change] checkmode if true, only return the result immediately, all bellow code after this block cannot executed</span>
    <span class="hljs-keyword">if</span> module.check_mode:
        result[<span class="hljs-string">'message_from_user'</span>] = <span class="hljs-string">"this is check mode enable message"</span>
        module.exit_json(**result)

    <span class="hljs-comment"># SOP: 3 Change this</span>
    <span class="hljs-comment"># ALL LOGIC FOR RETURN MESSAGE IS DO IN HERE</span>
    <span class="hljs-comment"># change result value using module params or bussiness logic</span>
    <span class="hljs-keyword">from</span> netmiko <span class="hljs-keyword">import</span> ConnectHandler

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">call_huawei</span>(<span class="hljs-params">command,device_type, device_ip, device_username, device_password, device_port</span>):</span>
        <span class="hljs-comment"># all platform or device_type can be see in here:</span>
        <span class="hljs-comment"># https://github.com/ktbyers/netmiko/blob/develop/PLATFORMS.md</span>

        huawei = {
        <span class="hljs-string">'device_type'</span>: device_type,
        <span class="hljs-string">'host'</span>:   device_ip,
        <span class="hljs-string">'username'</span>: device_username,
        <span class="hljs-string">'password'</span>: device_password,
        <span class="hljs-string">'port'</span> : device_port
        }

        net_connect = ConnectHandler(**huawei)
        <span class="hljs-keyword">return</span> net_connect.send_command(command)

    proposed_args = {
        <span class="hljs-string">'command'</span>: module.params[<span class="hljs-string">'command'</span>],
        <span class="hljs-string">'device_type'</span>: module.params[<span class="hljs-string">'ansible_network_os'</span>],
        <span class="hljs-string">'device_ip'</span>:   module.params[<span class="hljs-string">'ansible_host'</span>],
        <span class="hljs-string">'device_username'</span>: module.params[<span class="hljs-string">'ansible_user'</span>],
        <span class="hljs-string">'device_password'</span>: module.params[<span class="hljs-string">'ansible_ssh_pass'</span>],
        <span class="hljs-comment"># hardcode port</span>
        <span class="hljs-string">'device_port'</span>: <span class="hljs-number">22</span>
    }
    device_cli_output = call_huawei(**proposed_args)

    <span class="hljs-comment"># ~~~~~~~~~~~~~~~~~~~~~~~~~~~ NTC TEMPLATE PARSER ~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
    <span class="hljs-string">"""ntc_templates.parse."""</span>
    <span class="hljs-keyword">import</span> os

    <span class="hljs-keyword">try</span>:
        <span class="hljs-keyword">from</span> textfsm <span class="hljs-keyword">import</span> clitable

        HAS_CLITABLE = <span class="hljs-literal">True</span>
    <span class="hljs-keyword">except</span> ImportError:
        HAS_CLITABLE = <span class="hljs-literal">False</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_get_template_dir</span>():</span>
        template_dir = os.environ.get(<span class="hljs-string">"NTC_TEMPLATES_DIR"</span>)
        <span class="hljs-keyword">if</span> template_dir <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            package_dir = os.path.dirname(__file__)
            template_dir = os.path.join(package_dir, <span class="hljs-string">"templates"</span>)
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> os.path.isdir(template_dir):
                project_dir = os.path.dirname(os.path.dirname(os.path.dirname(template_dir)))
                template_dir = os.path.join(project_dir, <span class="hljs-string">"templates"</span>)

        <span class="hljs-keyword">return</span> template_dir


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_clitable_to_dict</span>(<span class="hljs-params">cli_table</span>):</span>
        <span class="hljs-string">"""Convert TextFSM cli_table object to list of dictionaries."""</span>
        objs = []
        <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> cli_table:
            temp_dict = {}
            <span class="hljs-keyword">for</span> index, element <span class="hljs-keyword">in</span> enumerate(row):
                temp_dict[cli_table.header[index].lower()] = element
            objs.append(temp_dict)

        <span class="hljs-keyword">return</span> objs


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">parse_output</span>(<span class="hljs-params">platform=None, command=None, data=None</span>):</span>
        <span class="hljs-string">"""Return the structured data based on the output from a network device."""</span>

        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> HAS_CLITABLE:
            msg = <span class="hljs-string">"""
    The TextFSM library is not currently supported on Windows. If you are NOT using Windows
    you should be able to 'pip install textfsm' to fix this issue. If you are using Windows
    then you will need to install the patch referenced here:

    https://github.com/google/textfsm/pull/82

    """</span>
            <span class="hljs-keyword">raise</span> ImportError(msg)

        template_dir = _get_template_dir()
        cli_table = clitable.CliTable(<span class="hljs-string">"index"</span>, template_dir)

        attrs = {<span class="hljs-string">"Command"</span>: command, <span class="hljs-string">"Platform"</span>: platform}
        <span class="hljs-keyword">try</span>:
            cli_table.ParseCmd(data, attrs)
            structured_data = _clitable_to_dict(cli_table)
        <span class="hljs-keyword">except</span> clitable.CliTableError <span class="hljs-keyword">as</span> e:
            <span class="hljs-keyword">raise</span> Exception(
                <span class="hljs-string">'Unable to parse command "{0}" on platform {1} - {2}'</span>.format(
                    command, platform, str(e)
                )
            )
            <span class="hljs-comment"># Invalid or Missing template</span>
            <span class="hljs-comment"># module.fail_json(msg='parsing error', error=str(e))</span>
            <span class="hljs-comment"># rather than fail, fallback to return raw text</span>
            <span class="hljs-comment"># structured_data = [data]</span>

        <span class="hljs-keyword">return</span> structured_data

    <span class="hljs-comment"># ~~~~~~~~~~~~~~~~~~~~~~~~~~~ END OF TEMPLATE PARSER ~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>

    <span class="hljs-comment"># NTC TEMPLATE LOCATION PLEASE CHANGE THIS TO UPDATED NTC TEMPLATES DIRECTORY</span>
    os.environ[<span class="hljs-string">"NTC_TEMPLATES_DIR"</span>] = <span class="hljs-string">"/opt/ntc-templates/ntc_templates/templates"</span>


    parsed = parse_output(platform=module.params[<span class="hljs-string">'ansible_platform'</span>], command=module.params[<span class="hljs-string">'command'</span>], data=device_cli_output)

    <span class="hljs-comment"># RESULT MODIFICATION</span>
    result[<span class="hljs-string">'return_from_devices'</span>] = parsed

    <span class="hljs-comment"># SOP: 3 END OF LOGIC FOR RETURN MESSAGE </span>

    <span class="hljs-comment"># [do not change] is Changed Logic</span>
    <span class="hljs-comment"># if its True, then changed will be true with yellow text</span>
    <span class="hljs-comment"># result['changed'] = True</span>

    <span class="hljs-comment"># [do not change] Fail Condition Logic</span>
    <span class="hljs-keyword">if</span> module.params[<span class="hljs-string">'command'</span>] == <span class="hljs-string">'fail me'</span>:
        module.fail_json(msg=<span class="hljs-string">'You requested this to fail'</span>, **result)

    <span class="hljs-comment"># [do not change]in the event of a successful module execution</span>
    module.exit_json(**result)


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    run_module()


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    main()
</code></pre>
<p>Dont worry about that long script, We'll break down the module into its three primary functional components: <strong>Input</strong>, <strong>Process</strong>, and <strong>Output</strong>.</p>
<h4 id="heading-input-handling-module-arguments"><strong>Input: Handling Module Arguments</strong></h4>
<p>The <strong>input</strong> function is responsible for receiving and validating arguments passed to the module. It defines the parameters that the module will use to interact with the network device.</p>
<p><strong>Code Snippet: Input Handling</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_module</span>():</span>
    <span class="hljs-comment"># Define module arguments</span>
    module_args = dict(
        command=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">True</span>),
        ansible_host=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_network_os=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_user=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_ssh_pass=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
        ansible_platform=dict(type=<span class="hljs-string">'str'</span>, required=<span class="hljs-literal">False</span>),
    )

    <span class="hljs-comment"># Initialize result prototype</span>
    result = dict(
        changed=<span class="hljs-literal">False</span>,
        return_from_devices=<span class="hljs-string">""</span>
    )

    <span class="hljs-comment"># Create AnsibleModule instance</span>
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=<span class="hljs-literal">True</span>
    )

    <span class="hljs-comment"># Handle check mode</span>
    <span class="hljs-keyword">if</span> module.check_mode:
        result[<span class="hljs-string">'message_from_user'</span>] = <span class="hljs-string">"Check mode enabled."</span>
        module.exit_json(**result)
</code></pre>
<p>In this section, we define the module's expected parameters using the <code>module_args</code> dictionary. This includes the command to execute, device details, and authentication credentials. We also initialize the result dictionary to hold the output of the command.</p>
<h4 id="heading-process-interacting-with-the-device"><strong>Process: Interacting with the Device</strong></h4>
<p>The <strong>process</strong> function handles the actual interaction with the network device. It uses the parameters provided in the input to connect to the device, execute commands, and parse the results.</p>
<p><strong>Code Snippet: Processing and Parsing</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> netmiko <span class="hljs-keyword">import</span> ConnectHandler
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">from</span> textfsm <span class="hljs-keyword">import</span> clitable

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">call_huawei</span>(<span class="hljs-params">command, device_type, device_ip, device_username, device_password, device_port</span>):</span>
    huawei = {
        <span class="hljs-string">'device_type'</span>: device_type,
        <span class="hljs-string">'host'</span>: device_ip,
        <span class="hljs-string">'username'</span>: device_username,
        <span class="hljs-string">'password'</span>: device_password,
        <span class="hljs-string">'port'</span>: device_port
    }
    net_connect = ConnectHandler(**huawei)
    <span class="hljs-keyword">return</span> net_connect.send_command(command)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">parse_output</span>(<span class="hljs-params">platform=None, command=None, data=None</span>):</span>
    template_dir = os.getenv(<span class="hljs-string">"NTC_TEMPLATES_DIR"</span>, <span class="hljs-string">"/opt/ntc-templates/ntc_templates/templates"</span>)
    cli_table = clitable.CliTable(<span class="hljs-string">"index"</span>, template_dir)

    attrs = {<span class="hljs-string">"Command"</span>: command, <span class="hljs-string">"Platform"</span>: platform}
    <span class="hljs-keyword">try</span>:
        cli_table.ParseCmd(data, attrs)
        structured_data = _clitable_to_dict(cli_table)
    <span class="hljs-keyword">except</span> clitable.CliTableError <span class="hljs-keyword">as</span> e:
        <span class="hljs-keyword">raise</span> Exception(
            <span class="hljs-string">'Unable to parse command "{}" on platform {} - {}'</span>.format(
                command, platform, str(e)
            )
        )
    <span class="hljs-keyword">return</span> structured_data
</code></pre>
<p>Here, the <code>call_huawei</code> function connects to the Huawei device using Netmiko and executes the specified command. The <code>parse_output</code> function handles the parsing of the command output using TextFSM. This function ensures that the raw data is converted into a structured format suitable for further processing.</p>
<h4 id="heading-output-delivering-results">Output: Delivering Results</h4>
<p>The <strong>output</strong> function formats the results and sends them back to the Ansible playbook. It ensures that the output is presented in a way that is easy for users to understand and utilize.</p>
<p><strong>Code Snippet: Output Handling</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_module</span>():</span>
    <span class="hljs-comment"># (Previous code remains unchanged)</span>

    <span class="hljs-comment"># Process and Parse</span>
    device_cli_output = call_huawei(**proposed_args)
    parsed = parse_output(platform=module.params[<span class="hljs-string">'ansible_platform'</span>], command=module.params[<span class="hljs-string">'command'</span>], data=device_cli_output)

    <span class="hljs-comment"># Set Result</span>
    result[<span class="hljs-string">'return_from_devices'</span>] = parsed

    <span class="hljs-comment"># Handle Result</span>
    module.exit_json(**result)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    run_module()

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    main()
</code></pre>
<p>In the output handling section, we call the <code>call_huawei</code> and <code>parse_output</code> functions to retrieve and format the data. We then update the result dictionary and use <code>module.exit_json()</code> to return the structured data to the Ansible playbook.</p>
<h2 id="heading-step-2-placement-and-usage"><strong>Step 2: Placement and Usage</strong></h2>
<p><strong>In development,</strong> We can create modules on <code>/usr/share/ansible/plugins/modules</code> and call from playbook using <code>yourorganization_module_huawei_display_ip_routing_table:</code></p>
<p><strong>In Production</strong> And then, after being finished, we create our own collection in</p>
<pre><code class="lang-plaintext">/usr/share/ansible/collections/ansible_collections/yourorganization/vrp/plugins/modules
</code></pre>
<ul>
<li><p><code>yourorganization</code> for workspace name</p>
</li>
<li><p><code>vrp</code> for OS for system name</p>
</li>
<li><p>and put modules on plugins or modules</p>
</li>
</ul>
<p>and call on playbook and put module using this format <code>yourorganization.vrp.display_ip_routing_table:</code></p>
<p>Example:</p>
<pre><code class="lang-plaintext">mv multipolar_module_huawei_display_ip_routing_table.py /usr/share/ansible/collections/ansible_collections/yourorganization/vrp/plugins/modules/display_ip_routing_table.py

ansible-playbook -i inventory_host_huawei.yml playbook_for_module_huawei_display_ip_routing_table_using_collection.yml
</code></pre>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Creating and managing custom Ansible modules allows you to tailor automation to your specific network needs. By following these steps, you can efficiently manage Huawei VRP devices and integrate their functionalities into your Ansible automation workflows. This guide should provide a solid foundation for developing and deploying your custom network modules.</p>
]]></content:encoded></item><item><title><![CDATA[Automatically Generating API Call Type Definitions in TypeScript.]]></title><description><![CDATA[It's time to stop creating tedious type definitions manually for API responses.
In the past, whenever I made API calls in TypeScript, whether on the frontend or backend, I would painstakingly create type definitions by hand. This process involved exa...]]></description><link>https://blog.ramadlana.my.id/automatically-generating-api-call-type-definitions-in-typescript</link><guid isPermaLink="true">https://blog.ramadlana.my.id/automatically-generating-api-call-type-definitions-in-typescript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[fetch API]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Sat, 18 Feb 2023 09:57:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/xkBaqlcqeb4/upload/499cf4ebda0343e6c3a390441f1860d0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It's time to stop creating tedious type definitions manually for API responses.</p>
<p>In the past, whenever I made API calls in TypeScript, whether on the frontend or backend, I would painstakingly create type definitions by hand. This process involved examining the structure of the API response and then writing out the corresponding TypeScript types. For instance, if the response looked like this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"John Doe"</span>,
  <span class="hljs-attr">"email"</span>: <span class="hljs-string">"john.doe@example.com"</span>
}
</code></pre>
<p>I would manually define a TypeScript interface to match this response:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">interface</span> User {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>This manual approach was not only time-consuming but also prone to errors, especially when dealing with complex or nested data structures. Additionally, any changes in the API response required updating the type definitions, which could easily be overlooked, leading to potential bugs and inconsistencies in the codebase.</p>
<p>Fortunately, there are now tools and libraries available that can automate this process, generating type definitions directly from the API responses. This not only saves time but also ensures that the types are always in sync with the actual data being returned by the API. By leveraging these tools, developers can focus more on building features and less on the repetitive task of writing type definitions.:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"products"</span>: [
        {
          <span class="hljs-attr">"id"</span>: <span class="hljs-number">59</span>,
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Spring and summershoes"</span>,
        },
        {
          <span class="hljs-attr">"id"</span>: <span class="hljs-number">88</span>,
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"TC Reusable Silicone Magic Washing Gloves"</span>,
        }
}
</code></pre>
<p>then sure, I will create definitions like this way:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> IProduct {
    <span class="hljs-string">"products"</span>: <span class="hljs-built_in">Array</span>&lt;{
        id: <span class="hljs-built_in">number</span>;
        title: <span class="hljs-built_in">string</span>;     
    }&gt;
}
</code></pre>
<p>okay, it's easy because the return of the JSON string from the API Server is not complex enough. but how about this:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"products"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">7</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Samsung Galaxy Book"</span>,
      <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Samsung Galaxy Book S (2020) Laptop With Intel Lakefield Chip, 8GB of RAM Launched"</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">1499</span>,
      <span class="hljs-attr">"discountPercentage"</span>: <span class="hljs-number">4.15</span>,
      <span class="hljs-attr">"rating"</span>: <span class="hljs-number">4.25</span>,
      <span class="hljs-attr">"stock"</span>: <span class="hljs-number">50</span>,
      <span class="hljs-attr">"brand"</span>: <span class="hljs-string">"Samsung"</span>,
      <span class="hljs-attr">"category"</span>: <span class="hljs-string">"laptops"</span>,
      <span class="hljs-attr">"thumbnail"</span>: <span class="hljs-string">"https://i.dummyjson.com/data/products/7/thumbnail.jpg"</span>,
      <span class="hljs-attr">"images"</span>: [
        <span class="hljs-string">"https://i.dummyjson.com/data/products/7/1.jpg"</span>,
        <span class="hljs-string">"https://i.dummyjson.com/data/products/7/2.jpg"</span>,
        <span class="hljs-string">"https://i.dummyjson.com/data/products/7/3.jpg"</span>,
        <span class="hljs-string">"https://i.dummyjson.com/data/products/7/thumbnail.jpg"</span>
      ]
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">8</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Microsoft Surface Laptop 4"</span>,
      <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Style and speed. Stand out on HD video calls backed by Studio Mics. Capture ideas on the vibrant touchscreen."</span>,
      <span class="hljs-attr">"price"</span>: <span class="hljs-number">1499</span>,
      <span class="hljs-attr">"discountPercentage"</span>: <span class="hljs-number">10.23</span>,
      <span class="hljs-attr">"rating"</span>: <span class="hljs-number">4.43</span>,
      <span class="hljs-attr">"stock"</span>: <span class="hljs-number">68</span>,
      <span class="hljs-attr">"brand"</span>: <span class="hljs-string">"Microsoft Surface"</span>,
      <span class="hljs-attr">"category"</span>: <span class="hljs-string">"laptops"</span>,
      <span class="hljs-attr">"thumbnail"</span>: <span class="hljs-string">"https://i.dummyjson.com/data/products/8/thumbnail.jpg"</span>,
      <span class="hljs-attr">"images"</span>: [
        <span class="hljs-string">"https://i.dummyjson.com/data/products/8/1.jpg"</span>,
        <span class="hljs-string">"https://i.dummyjson.com/data/products/8/2.jpg"</span>,
        <span class="hljs-string">"https://i.dummyjson.com/data/products/8/3.jpg"</span>,
        <span class="hljs-string">"https://i.dummyjson.com/data/products/8/4.jpg"</span>,
        <span class="hljs-string">"https://i.dummyjson.com/data/products/8/thumbnail.jpg"</span>
      ]
    },
... and thousands more
}
</code></pre>
<p>Maybe you can manually type that definition, but what if maybe the API response is more complex than above ? or maybe you have hundreds of API endpoints with different structures?</p>
<h3 id="heading-create-it-automatically">Create it automatically</h3>
<p>To save your precious time and effort, I recommend using a tool called Thunder Client, which is available as a free extension for VS Code. Thunder Client is my favorite alternative to Postman and Insomnia because it is lightweight, fast, and easy to use. One of its standout features is its ability to generate code and types automatically, which can be a huge time-saver, especially when dealing with complex API responses or multiple API endpoints with different structures.</p>
<p>Let's go ahead and install Thunder Client and give it a try:</p>
<ol>
<li><p>Open VS Code and navigate to the Extensions view by clicking on the Extensions icon in the Activity Bar on the side of the window.</p>
</li>
<li><p>In the search bar, type "Thunder Client" and press Enter.</p>
</li>
<li><p>Click the Install button next to the Thunder Client extension.</p>
</li>
<li><p>Once installed, you can open Thunder Client by clicking on its icon in the Activity Bar.</p>
</li>
</ol>
<p>With Thunder Client, you can easily create and manage your API requests, and it will automatically generate the necessary code and types for you. This makes it an invaluable tool for developers who need to work with APIs efficiently.</p>
<p>URL endpoints: <code>https://dummyjson.com/products/search?q=Laptop</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676713549421/a931ddea-4f8e-45ae-9f68-ccf29f387661.png" alt class="image--center mx-auto" /></p>
<p>Then in the right upper corner, we can see small {} bracket icons. click it</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676713734282/510125e7-ee5b-4df9-b58b-229deb1fef70.png" alt class="image--center mx-auto" /></p>
<p>Now we got fetch the javascript code, and the next step is to click generate Types</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676713899423/0302da8f-2098-499e-aaa9-6df142c2e780.png" alt class="image--center mx-auto" /></p>
<p>Viola! now we have a typescript interface definition without manually creating it.</p>
]]></content:encoded></item><item><title><![CDATA[Add External Javascript Library for Svelte or SvelteKit]]></title><description><![CDATA[When we work with Javascript frameworks chances are we need to import external javascript for example importing template built-in js or maybe any legacy external javascript that you need to use on your App
Here are a few ways to import external js on...]]></description><link>https://blog.ramadlana.my.id/add-external-javascript-library-for-svelte-or-sveltekit</link><guid isPermaLink="true">https://blog.ramadlana.my.id/add-external-javascript-library-for-svelte-or-sveltekit</guid><category><![CDATA[Svelte]]></category><category><![CDATA[Sveltekit]]></category><category><![CDATA[javascript framework]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Sat, 18 Feb 2023 04:31:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/g5jpH62pwes/upload/a8e9c7cd44c966659326fc6c60e63859.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When we work with Javascript frameworks chances are we need to import external javascript for example importing template built-in js or maybe any legacy external javascript that you need to use on your App</p>
<p>Here are a few ways to import external js on SvelteKit</p>
<h3 id="heading-using-html-decorator">Using {@html} decorator</h3>
<p>For me, it's commonly used to import js template files and put them on <code>+layout.svelte</code></p>
<pre><code class="lang-javascript">&lt;/div&gt;
...
    {@html <span class="hljs-string">'&lt;script src="/tabler.min.js"&gt;&lt;/script&gt;'</span>}
...
&lt;/div&gt;
</code></pre>
<h3 id="heading-using-svelte-head">Using svelte head</h3>
<p>its mainly used if we want to import external js files and we wanna call a function after these external js loaded to DOM</p>
<p>First let see what our code if we code using vanilla js</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Form</span>
&lt;form id=<span class="hljs-string">"payment-form"</span>&gt;
     ... your form things
&lt;/form&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://js.stripe.com/v3/"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
<span class="hljs-comment">// Create a Stripe client.</span>
<span class="hljs-keyword">var</span> stripe = Stripe(<span class="hljs-string">'ourkeysecret1234567789zzz'</span>);

<span class="hljs-comment">// Create an instance of Elements.</span>
<span class="hljs-keyword">var</span> elements = stripe.elements();
</code></pre>
<p>lets convert that to SvelteKit Components.</p>
<pre><code class="lang-javascript">&lt;script&gt;
    <span class="hljs-keyword">import</span> { onMount } <span class="hljs-keyword">from</span> <span class="hljs-string">'svelte'</span>;
        <span class="hljs-keyword">let</span> stripeReady = <span class="hljs-literal">false</span>;
        <span class="hljs-keyword">let</span> mounted = <span class="hljs-literal">false</span>;

        onMount(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-comment">// onMount always call after Components mounted.</span>
            mounted = <span class="hljs-literal">true</span>;
            <span class="hljs-comment">// if stripe altready mounted load stripe element imediately</span>
            <span class="hljs-keyword">if</span> (stripeReady) {
                loadStripeElements();
            }
        });

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stripeLoaded</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-comment">// if stripeReady -&gt; load Stripe Element.</span>
            stripeReady = <span class="hljs-literal">true</span>;
            <span class="hljs-keyword">if</span> (mounted) {
                loadStripeElements();
            }
        }

        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadStripeElements</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-comment">// create stripe elements</span>
            <span class="hljs-keyword">const</span> stripe = tripe(<span class="hljs-string">'ourkeysecret1234567789zzz'</span>);
            <span class="hljs-keyword">var</span> elements = stripe.elements();
            <span class="hljs-comment">// etc..</span>
        }
    }
&lt;/script&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">svelte:head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://js.stripe.com/v3/"</span> <span class="hljs-attr">on:load</span>=<span class="hljs-string">{stripeLoaded}</span>&lt;/<span class="hljs-attr">script</span>&gt;</span><span class="xml">
<span class="hljs-tag">&lt;/<span class="hljs-name">svelte:head</span>&gt;</span></span></span>

<span class="xml"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"payment-form"</span>&gt;</span>
         ... your form things
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span></span>
</code></pre>
<p>That is. we successfully added an external (legacy) JS library into our Svelte Components.</p>
]]></content:encoded></item><item><title><![CDATA[How to Set Up Your Own Systemd Custom Service in Linux]]></title><description><![CDATA[Systemd is the init system used by many modern Linux distributions to manage system processes and services. Creating a systemd service allows you to run background tasks, manage system daemons, and ensure that your services start automatically at boo...]]></description><link>https://blog.ramadlana.my.id/how-to-set-up-your-own-systemd-custom-service-in-linux</link><guid isPermaLink="true">https://blog.ramadlana.my.id/how-to-set-up-your-own-systemd-custom-service-in-linux</guid><category><![CDATA[Linux]]></category><category><![CDATA[Scripting]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Hidayah Ramadlana]]></dc:creator><pubDate>Fri, 17 Feb 2023 06:53:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Tjbk79TARiE/upload/470d7caa0ad1cc5ef63cd027808f04ba.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Systemd is the init system used by many modern Linux distributions to manage system processes and services. Creating a systemd service allows you to run background tasks, manage system daemons, and ensure that your services start automatically at boot. In this guide, we’ll walk through the steps to create a systemd service, specifically using an example of a Metabase daemon. Follow these steps to set up your own systemd service:</p>
<h3 id="heading-step-1-locate-user-defined-services"><strong>Step 1: Locate User-Defined Services</strong></h3>
<p>Systemd services are typically stored in specific directories based on their scope. For user-defined services, you’ll usually work within <code>/etc/systemd/system/</code> on Ubuntu. This directory is where you should place your custom service files.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /etc/systemd/system/
</code></pre>
<h3 id="heading-step-2-create-your-service-file"><strong>Step 2: Create Your Service File</strong></h3>
<p>Using your preferred text editor, create a new service file. You can name this file anything you like, but it must end with <code>.service</code>. For example, let’s name it <code>metabase.service</code>.</p>
<pre><code class="lang-bash">sudo nano whatever_you_want.service
</code></pre>
<h3 id="heading-step-3-define-your-service-configuration"><strong>Step 3: Define Your Service Configuration</strong></h3>
<p>Add the following template to your service file. This configuration is designed for a hypothetical Metabase daemon, but you can customize it for any service you need.</p>
<pre><code class="lang-ini"><span class="hljs-section">[Unit]</span>
<span class="hljs-attr">Description</span>=Metabase Daemon

<span class="hljs-section">[Service]</span>
<span class="hljs-attr">PIDFile</span>=/var/tmp/metabase.pid
<span class="hljs-attr">WorkingDirectory</span>=/usr/local/bin/metabase/
<span class="hljs-attr">User</span>=ubuntu
<span class="hljs-attr">Group</span>=ubuntu

<span class="hljs-comment"># Run command here</span>
<span class="hljs-attr">ExecStart</span>=/usr/bin/java -jar -Xmx512m /usr/local/bin/metabase/metabase.jar

<span class="hljs-attr">Restart</span>=<span class="hljs-literal">on</span>-failure
<span class="hljs-attr">RestartSec</span>=<span class="hljs-number">30</span>
<span class="hljs-attr">PrivateTmp</span>=<span class="hljs-literal">true</span>

<span class="hljs-attr">StandardOutput</span>=metabase
<span class="hljs-attr">StandardError</span>=metabase_err
<span class="hljs-attr">SyslogIdentifier</span>=metabase

<span class="hljs-section">[Install]</span>
<span class="hljs-attr">WantedBy</span>=multi-user.target
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><strong>[Unit]:</strong> Provides metadata about the service, including its description.</p>
</li>
<li><p><strong>[Service]:</strong> Defines how the service runs, including the command to start it (<code>ExecStart</code>), user and group under which it runs, and how to handle failures.</p>
</li>
<li><p><strong>[Install]:</strong> Configures how the service should be installed and started.</p>
</li>
</ul>
<h3 id="heading-step-4-manage-your-service"><strong>Step 4: Manage Your Service</strong></h3>
<p>Once you’ve created and saved your service file, you need to reload systemd to recognize your new service and then manage it using <code>systemctl</code>.</p>
<p><strong>Start the Service:</strong></p>
<pre><code class="lang-bash">sudo systemctl start whatever_you_want.service
</code></pre>
<p><strong>Enable Auto-Start at Boot:</strong></p>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> whatever_you_want.service
</code></pre>
<p><strong>Disable Auto-Start:</strong></p>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">disable</span> whatever_you_want.service
</code></pre>
<p><strong>Stop the Service:</strong></p>
<pre><code class="lang-bash">sudo systemctl stop whatever_you_want.service
</code></pre>
<p><strong>Restart the Service:</strong></p>
<pre><code class="lang-bash">sudo systemctl restart whatever_you_want.service
</code></pre>
<p><strong>View Service Logs:</strong></p>
<pre><code class="lang-bash">journalctl -e -u whatever_you_want.service
</code></pre>
<p>This command shows the most recent log entries for your service, which is useful for troubleshooting and monitoring.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Creating and managing a systemd service on Linux is a powerful way to handle background tasks and system daemons. By following these steps, you can easily set up your services to run automatically at boot and manage them with simple commands. Whether you’re running a web application, a background process, or any other service, systemd provides the tools you need to keep things running smoothly and efficiently.</p>
]]></content:encoded></item></channel></rss>