<?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[CloudNativeFolks Community]]></title><description><![CDATA[CloudNativeFolks is non profit community that empower and educate about cloud native technology !]]></description><link>https://blog.cloudnativefolks.org</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1672284823339/TW3-rXvqg.png</url><title>CloudNativeFolks Community</title><link>https://blog.cloudnativefolks.org</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 05 Sep 2026 12:40:51 GMT</lastBuildDate><atom:link href="https://blog.cloudnativefolks.org/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Beyond Tokens: Why the Future of Software Security is Capability Computing]]></title><description><![CDATA[Over the past few decades, we've fundamentally changed how software is built. We moved from assembly to high-level languages, from monolithic applications to containers, and now from human-written cod]]></description><link>https://blog.cloudnativefolks.org/beyond-tokens-why-the-future-of-software-security-is-capability-computing</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/beyond-tokens-why-the-future-of-software-security-is-capability-computing</guid><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Wed, 05 Aug 2026 21:44:43 GMT</pubDate><content:encoded><![CDATA[<img src="https://cdn.hashnode.com/uploads/covers/5f11da35657b2838c7bf9bc6/c8176b03-b792-4fae-9e61-8c9306d1b47b.png" alt="" style="display:block;margin:0 auto" />

<p>Over the past few decades, we've fundamentally changed how software is built. We moved from assembly to high-level languages, from monolithic applications to containers, and now from human-written code to AI-generated software.</p>
<p>Yet one question remains surprisingly unanswered:</p>
<blockquote>
<p><strong>What is this software actually capable of doing?</strong></p>
</blockquote>
<p>Today's compilers optimize programs for speed, size, and correctness. Runtime security platforms monitor behavior after deployment. Policy engines decide who can access what. But there is no unified system that understands software capabilities as a first-class concept during compilation.</p>
<p>I believe the next evolution is <strong>Capability Computing</strong>.</p>
<p>Imagine a compiler that doesn't just understand instructions like <code>load</code>, <code>store</code>, or <code>call</code>, but instead reasons about higher-level capabilities:</p>
<ul>
<li><p>Filesystem.Read</p>
</li>
<li><p>Network.Send</p>
</li>
<li><p>Process.Execute</p>
</li>
<li><p>Secret.Read</p>
</li>
<li><p>Cloud.Create</p>
</li>
<li><p>AI.Tool.Invoke</p>
</li>
</ul>
<p>Instead of optimizing only machine code, the compiler builds a <strong>Capability Graph</strong> that represents what a program is permitted to do. Security policies can then be verified before deployment, producing deterministic decisions:</p>
<ul>
<li><p><strong>ALLOW</strong></p>
</li>
<li><p><strong>DENY</strong></p>
</li>
<li><p><strong>ESCALATE</strong></p>
</li>
</ul>
<p>The output is not only a binary, but also a signed capability manifest that any runtime—whether a microVM, WebAssembly runtime, or cloud platform—can enforce.</p>
<p>This shifts security from reactive monitoring to proactive verification.</p>
<p>More importantly, this approach is independent of how software is created. Whether code is written by a developer, generated by an AI model, or produced by another compiler, the verification process remains the same because it operates on <strong>capabilities</strong>, not tokens.</p>
<p>In this vision, LLVM, MLIR, WebAssembly, and future compiler infrastructures become frontends. Different sandbox technologies become runtimes. The stable abstraction in the middle is <strong>Capability IR</strong>.</p>
<p>Just as LLVM standardized compiler infrastructure and Kubernetes standardized application orchestration, I believe there is an opportunity to standardize <strong>Capability Verification</strong>.</p>
<p>The long-term goal isn't another security product.</p>
<p>It's a new layer of computing where every piece of software can answer a simple question before it ever runs:</p>
<blockquote>
<p><strong>"What am I capable of doing, and can I prove that I'm allowed to do it?"</strong></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[AWS Lambda Deployment with Terraform (In-Depth Guide)]]></title><description><![CDATA[Introduction
Deploying and managing AWS Lambda functions can get complicated, especially when you need to orchestrate several components like IAM roles, event triggers, monitoring, and deployment pipelines. That's where Terraform shines—it allows you...]]></description><link>https://blog.cloudnativefolks.org/aws-lambda-deployment-with-terraform-in-depth-guide</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/aws-lambda-deployment-with-terraform-in-depth-guide</guid><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Thu, 16 Jan 2025 17:57:51 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>Deploying and managing AWS Lambda functions can get complicated, especially when you need to orchestrate several components like IAM roles, event triggers, monitoring, and deployment pipelines. That's where Terraform shines—it allows you to manage all of this through code, providing automation, consistency, and scalability.</p>
<p>In this detailed guide, we’ll explore how to create and manage AWS Lambda functions using Terraform. We’ll go beyond the basics and discuss advanced topics like packaging code, using remote state, integrating with services like API Gateway and S3, and best practices for building reusable Terraform modules.</p>
<hr />
<h3 id="heading-why-terraform-for-aws-lambda">Why Terraform for AWS Lambda?</h3>
<p>AWS Lambda is a great service for running code without provisioning or managing servers, but managing multiple Lambda functions manually can become overwhelming. Terraform lets you:</p>
<ul>
<li><p><strong>Automate Deployments</strong>: Define infrastructure as code to automate deployments and updates.</p>
</li>
<li><p><strong>Ensure Consistency</strong>: By codifying your Lambda configurations, you can be sure they’re consistent across environments (dev, staging, production).</p>
</li>
<li><p><strong>Version Control Everything</strong>: With Terraform, you can put your infrastructure in version control, just like your codebase, making it easy to roll back or collaborate with teams.</p>
</li>
<li><p><strong>Simplify Management</strong>: You can manage your entire AWS infrastructure, not just Lambda, through a single tool like Terraform.</p>
</li>
</ul>
<p>Now, let's go deeper into how to build, deploy, and manage AWS Lambda functions using Terraform.</p>
<hr />
<p>login to stackgen - <a target="_blank" href="https://cloud.stackgen.com/">https://cloud.stackgen.com/</a> for Generative Infrastructure from code</p>
<p>Lets create a blank appstack using stackgen we are going to generate terraform</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728034699782/4c34e2b8-2d9f-453b-a873-6419fbf4e6e0.png" alt class="image--center mx-auto" /></p>
<p>click on New appStack</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728035016474/da999b79-9077-4233-8e7f-5acd0b323667.png" alt class="image--center mx-auto" /></p>
<p>lets create appStack from scratch and play around aws lambda and terraform</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728035073986/265da3a5-f708-4669-bf97-1109882ef78f.png" alt class="image--center mx-auto" /></p>
<p>Click on Proceed</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728035242228/a24e55ba-94d6-4b88-bead-623b1430ccf8.png" alt class="image--center mx-auto" /></p>
<p>StackGen by Default apply all best security policies by framework so generated if will be more secure</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728035556100/3b24073c-0fb0-4262-be08-c411cc35b2c9.png" alt class="image--center mx-auto" /></p>
<p>create appstacks</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728036895907/dd516ec7-2699-41f1-8f2d-5f578b145903.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-setting-up-aws-lambda-in-terraform">Setting Up AWS Lambda in Terraform</h2>
<h3 id="heading-aws-provider-configuration">AWS Provider Configuration</h3>
<p>Terraform requires an AWS provider block that specifies which AWS account and region you're deploying to.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728036966663/1570086b-bcf2-4ee9-ade2-967dd40171cf.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext">provider "aws" {
  region = "us-west-2"  # Adjust region as needed
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728038160685/826c08ec-6ec0-4b2e-9f7f-100aa62d1986.png" alt class="image--center mx-auto" /></p>
<p>drag and drop and bring cloud services and give required field</p>
<p>To go a step further, you can configure <strong>credentials</strong> securely using the AWS CLI, or IAM roles attached to the instance you're running Terraform from (if using EC2 or other AWS services):</p>
<pre><code class="lang-bash">aws configure
</code></pre>
<p>This sets up the <code>~/.aws/credentials</code> file with your access and secret keys.</p>
<p>If you're running Terraform from an EC2 instance, you can configure an instance role with proper permissions, so there’s no need to use static credentials.</p>
<h3 id="heading-using-profiles">Using Profiles</h3>
<p>If you manage multiple AWS accounts or regions, you can configure the provider to use specific profiles:</p>
<pre><code class="lang-plaintext">provider "aws" {
  profile = "dev"  # This profile should match the one in your AWS credentials
  region  = "us-west-2"
}
</code></pre>
<hr />
<h2 id="heading-defining-aws-lambda-function-in-terraform">Defining AWS Lambda Function in Terraform</h2>
<p>The main resource for creating a Lambda function in Terraform is <code>aws_lambda_function</code>. At a minimum, you need to define the <strong>runtime</strong>, <strong>handler</strong>, <strong>role</strong>, and <strong>deployment package</strong> (either a local ZIP or an S3 object).</p>
<h3 id="heading-lambda-function-definition">Lambda Function Definition</h3>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  function_name = "my_lambda"
  runtime       = "python3.8"
  handler       = "lambda_function.lambda_handler"
  role          = aws_iam_role.lambda_role.arn
  filename      = "lambda_function.zip"
  memory_size   = 128
  timeout       = 10

  environment {
    variables = {
      ENV_VAR_1 = "value1"
    }
  }
}
</code></pre>
<h4 id="heading-above-code-explained"><strong>above code explained :</strong></h4>
<ul>
<li><p><code>function_name</code>: The name of your Lambda function. It's important to note that Lambda function names must be unique within an AWS region.</p>
</li>
<li><p><code>runtime</code>: Specifies the runtime environment for the function. AWS supports several runtimes like Python, Node.js, Java, Go, and custom runtimes via containers.</p>
</li>
<li><p><code>handler</code>: This is the entry point of your code. For Python, it's typically <code>&lt;filename&gt;.&lt;function_name&gt;</code> (e.g., <code>lambda_function.lambda_handler</code>), where <code>lambda_</code><a target="_blank" href="http://function.py"><code>function.py</code></a> contains the function <code>lambda_handler</code>.</p>
</li>
<li><p><code>filename</code>: The ZIP file containing the Lambda deployment package.</p>
</li>
<li><p><code>memory_size</code>: Memory allocated to the function, ranging from 128 MB to 10,240 MB. Lambda allocates CPU power linearly in proportion to the memory.</p>
</li>
<li><p><code>timeout</code>: The maximum amount of time (in seconds) a function is allowed to run. If your function exceeds this, it will be terminated.</p>
</li>
<li><p><code>environment</code>: You can pass environment variables to the Lambda function.</p>
</li>
</ul>
<p>Lets do same using StackGen topology - add new resource - aws lambda</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728038598681/a451979a-41c5-46f6-ad66-9de9996ac4d2.png" alt class="image--center mx-auto" /></p>
<p>you will see its create IAM role and CloudWatch Log by default so generated tf is secured</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728038642404/95ffd3c1-478f-4c89-b582-8c4d25e75dcf.png" alt class="image--center mx-auto" /></p>
<p>you can see IaC is generated</p>
<h4 id="heading-advanced-configurations"><strong>Advanced Configurations:</strong></h4>
<ul>
<li><p><strong>Tags</strong>: You can tag Lambda functions to make it easier to track costs, permissions, and resources across AWS services.</p>
<pre><code class="lang-plaintext">  tags = {
    Environment = "dev"
    Project     = "MyProject"
  }
</code></pre>
</li>
<li><p><strong>Dead Letter Queues (DLQ)</strong>: If Lambda functions fail, you can use DLQs to capture and analyze failures by connecting to an SQS queue or SNS topic.</p>
<pre><code class="lang-plaintext">  dead_letter_config {
    target_arn = aws_sqs_queue.lambda_dlq.arn
  }
</code></pre>
</li>
</ul>
<hr />
<h2 id="heading-packaging-and-deploying-code">Packaging and Deploying Code</h2>
<p>AWS Lambda requires the function code to be packaged as a ZIP file. This can either be done manually or automatically using deployment pipelines.</p>
<h3 id="heading-option-1-local-zip-package">Option 1: Local ZIP Package</h3>
<p>When deploying code locally, you can package your Lambda function and pass the ZIP file to Terraform:</p>
<pre><code class="lang-plaintext">filename = "lambda_function.zip"
</code></pre>
<p>You can create this ZIP package manually or automate it with a script. Here's an example for Python:</p>
<pre><code class="lang-bash">zip lambda_function.zip lambda_function.py
</code></pre>
<h3 id="heading-option-2-s3-deployment">Option 2: S3 Deployment</h3>
<p>For larger functions or when working in a CI/CD pipeline, it's more efficient to store the Lambda package in an S3 bucket:</p>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  function_name = "my_lambda"
  runtime       = "python3.8"
  handler       = "lambda_function.lambda_handler"
  s3_bucket     = "lambda-deployment-bucket"
  s3_key        = "lambda_function.zip"
}
</code></pre>
<p>This way, your CI/CD system can upload new versions of your code to S3, and Terraform will use the new version when applying changes.</p>
<hr />
<h2 id="heading-adding-dependencies-with-lambda-layers">Adding Dependencies with Lambda Layers</h2>
<p>Lambda Layers allow you to package libraries and dependencies separately from your main Lambda code. This helps reduce code size, speeds up deployments, and makes managing shared code easier.</p>
<h3 id="heading-create-a-lambda-layer">Create a Lambda Layer</h3>
<pre><code class="lang-plaintext">resource "aws_lambda_layer_version" "common_dependencies" {
  layer_name          = "common_dependencies"
  filename            = "layer.zip"
  compatible_runtimes = ["python3.8"]
}
</code></pre>
<p>You can attach the layer to your Lambda function by referencing its ARN:</p>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  function_name = "my_lambda"
  runtime       = "python3.8"
  handler       = "lambda_function.lambda_handler"
  layers        = [aws_lambda_layer_version.common_dependencies.arn]
}
</code></pre>
<p>This example assumes you’ve packaged your dependencies (e.g., Python libraries) into <a target="_blank" href="http://layer.zip"><code>layer.zip</code></a>.</p>
<hr />
<h2 id="heading-iam-roles-and-permissions">IAM Roles and Permissions</h2>
<p>Lambda requires an IAM role that grants it the necessary permissions to execute. The minimal requirement is permission to write logs to CloudWatch.</p>
<h3 id="heading-basic-iam-role-for-lambda">Basic IAM Role for Lambda</h3>
<pre><code class="lang-plaintext">resource "aws_iam_role" "lambda_role" {
  name = "lambda_execution_role"
  assume_role_policy = &lt;&lt;EOF
  {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "Service": "lambda.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }
    ]
  }
  EOF
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728038878195/16596660-1182-42a4-a450-d715f0d4fb64.png" alt class="image--center mx-auto" /></p>
<p>if you click on the IAM rile you will find role policy which added</p>
<h3 id="heading-attaching-policies">Attaching Policies</h3>
<p>We’ll need to give the role basic execution permissions, like logging to CloudWatch:</p>
<pre><code class="lang-plaintext">resource "aws_iam_policy_attachment" "lambda_policy_attachment" {
  roles      = [aws_iam_role.lambda_role.name]
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
</code></pre>
<h3 id="heading-advanced-role-configurations">Advanced Role Configurations</h3>
<p>For more advanced use cases, like accessing other AWS services (S3, DynamoDB, etc.), you’ll need to attach additional permissions. For example, if your Lambda function needs to read from an S3 bucket:</p>
<pre><code class="lang-plaintext">data "aws_iam_policy_document" "lambda_s3_policy" {
  statement {
    actions   = ["s3:GetObject"]
    resources = ["arn:aws:s3:::mybucket/*"]
    effect    = "Allow"
  }
}

resource "aws_iam_role_policy" "lambda_s3_access" {
  name   = "lambda_s3_access"
  role   = aws_iam_role.lambda_role.id
  policy = data.aws_iam_policy_document.lambda_s3_policy.json
}
</code></pre>
<p>This allows your Lambda to access objects in the specified S3 bucket</p>
<p>lets see using StackGen lets add S3 cloud resources by drag and drop</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728039022393/47eaae38-02eb-4481-95ce-098a80005f45.png" alt class="image--center mx-auto" /></p>
<p>Connect lambda function to S3 and it will ask its IAM role and trigger configuration</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728039121579/5f0d69e3-307b-4147-a09b-799e94d8c2a1.png" alt class="image--center mx-auto" /></p>
<p>I will select IAM here and if you click on configuration you will see role type and policy accordingly added by StackGen . it’s smart enough to understand resource mapping and its depend cloud resources and add policy base on that also its allow you to edit or add customised .</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728039237988/3fe8aae1-1e46-4aa3-a3b3-6a27a95e421b.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-vpc-configuration">VPC Configuration</h2>
<p>Lambda functions can run inside a Virtual Private Cloud (VPC) to access private resources like databases or services that are not publicly available. To run your Lambda in a VPC, you need to specify the subnet IDs and security group IDs.</p>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  function_name = "my_vpc_lambda"
  vpc_config {
    subnet_ids         = ["subnet-12345", "subnet-67890"]
    security_group_ids = ["sg-123456"]
  }
}
</code></pre>
<p>Make sure that the subnet you choose has access to your required resources and allows outgoing traffic if necessary.</p>
<h3 id="heading-nat-gateway">NAT Gateway</h3>
<p>If your Lambda function needs to access the internet from inside a</p>
<p>VPC, you’ll need to configure a <strong>NAT Gateway</strong>. This allows outbound internet access for your function without exposing it publicly.</p>
<hr />
<h2 id="heading-event-sources-and-triggers">Event Sources and Triggers</h2>
<p>One of the key benefits of AWS Lambda is its ability to integrate with various AWS services to automatically trigger the function. Common event sources include S3 (when an object is created), DynamoDB Streams, API Gateway, and CloudWatch Events.</p>
<h3 id="heading-s3-event-trigger">S3 Event Trigger</h3>
<p>You can trigger a Lambda function when an object is created in an S3 bucket:</p>
<pre><code class="lang-plaintext">resource "aws_s3_bucket_notification" "example" {
  bucket = aws_s3_bucket.example.bucket

  lambda_function {
    lambda_function_arn = aws_lambda_function.example.arn
    events              = ["s3:ObjectCreated:*"]
  }
}
</code></pre>
<p>This will trigger the Lambda function whenever a new object is uploaded to the S3 bucket.</p>
<h3 id="heading-api-gateway-integration">API Gateway Integration</h3>
<p>To expose your Lambda function as a REST API, you can integrate it with API Gateway:</p>
<pre><code class="lang-plaintext">resource "aws_api_gateway_rest_api" "example" {
  name = "example_api"
}

resource "aws_lambda_permission" "api_gateway_invoke" {
  statement_id  = "AllowExecutionFromApiGateway"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.example.function_name
  principal     = "apigateway.amazonaws.com"
}
</code></pre>
<p>This grants API Gateway the permission to invoke the Lambda function.</p>
<hr />
<h2 id="heading-monitoring-and-logging-with-cloudwatch">Monitoring and Logging with CloudWatch</h2>
<p>By default, AWS Lambda logs output to CloudWatch. You can customize log retention, alarms, and even set up custom metrics.</p>
<h3 id="heading-cloudwatch-logs">CloudWatch Logs</h3>
<pre><code class="lang-plaintext">resource "aws_cloudwatch_log_group" "lambda_logs" {
  name              = "/aws/lambda/my_lambda"
  retention_in_days = 14
}
</code></pre>
<p>This will store the Lambda logs for 14 days in CloudWatch.</p>
<h3 id="heading-cloudwatch-alarms">CloudWatch Alarms</h3>
<p>You can also set up alarms to monitor key metrics like error rates, invocation durations, or throttling:</p>
<pre><code class="lang-plaintext">resource "aws_cloudwatch_metric_alarm" "lambda_error_alarm" {
  alarm_name          = "LambdaErrorAlarm"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  metric_name         = "Errors"
  namespace           = "AWS/Lambda"
  period              = 300
  statistic           = "Sum"
  threshold           = 1
  actions_enabled     = true
}
</code></pre>
<hr />
<h2 id="heading-reserved-concurrency">Reserved Concurrency</h2>
<p>Lambda functions can scale automatically, but if you want to control the number of concurrent executions (e.g., to avoid hitting downstream service limits), you can use <strong>reserved concurrency</strong>.</p>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  reserved_concurrent_executions = 5
}
</code></pre>
<p>This limits your function to a maximum of 5 concurrent invocations at any given time.</p>
<hr />
<h2 id="heading-best-practices-for-using-aws-lambda-with-terraform">Best Practices for Using AWS Lambda with Terraform</h2>
<h3 id="heading-1-version-control-your-deployment-packages">1. <strong>Version Control Your Deployment Packages</strong></h3>
<p>Always version your Lambda deployment packages. This way, you can easily roll back to a previous version if necessary. Use S3 versioning or CI/CD pipelines to manage different versions of your code.</p>
<h3 id="heading-2-use-terraform-modules-for-reusability">2. <strong>Use Terraform Modules for Reusability</strong></h3>
<p>Modularize your Terraform code to increase reusability and maintainability. For example, create separate modules for your Lambda function, IAM roles, API Gateway, and S3 configurations. This makes it easier to manage and reuse across different projects or environments.</p>
<h3 id="heading-3-remote-state">3. <strong>Remote State</strong></h3>
<p>In multi-team or multi-environment setups, use Terraform’s <strong>remote state</strong> to ensure that the same infrastructure code is applied consistently across different environments. This helps avoid state conflicts and maintains consistency.</p>
<pre><code class="lang-plaintext">terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "prod/terraform.tfstate"
    region = "us-west-2"
  }
}
</code></pre>
<h3 id="heading-4-environment-separation-continued">4. <strong>Environment Separation</strong> (continued)</h3>
<p>Using workspaces or separate Terraform state files for different environments (dev, staging, prod) can help prevent resource conflicts and ensure isolation between your environments. Here's an example of using Terraform workspaces to manage multiple environments:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a workspace for staging</span>
terraform workspace new staging

<span class="hljs-comment"># Create a workspace for production</span>
terraform workspace new production

<span class="hljs-comment"># Switch to the desired workspace</span>
terraform workspace select production
</code></pre>
<p>You can also adjust your resource configurations based on the workspace:</p>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  function_name = "my_lambda_${terraform.workspace}"
  runtime       = "python3.8"
  handler       = "lambda_function.lambda_handler"
  role          = aws_iam_role.lambda_role.arn
  filename      = "lambda_function.zip"
  memory_size   = 128
  timeout       = 10
}
</code></pre>
<p>This creates separate Lambda functions in each environment, keeping them isolated and configurable independently.</p>
<hr />
<h2 id="heading-advanced-aws-lambda-features-with-terraform">Advanced AWS Lambda Features with Terraform</h2>
<h3 id="heading-1-lambda-destinations">1. <strong>Lambda Destinations</strong></h3>
<p>Lambda destinations allow you to route the result of your Lambda execution to different AWS services based on success or failure. For example, you could send successful executions to an SNS topic and failed ones to an SQS queue for further processing or debugging.</p>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  function_name = "my_lambda"
  runtime       = "python3.8"
  handler       = "lambda_function.lambda_handler"
  role          = aws_iam_role.lambda_role.arn
  filename      = "lambda_function.zip"
  memory_size   = 128
  timeout       = 10

  environment {
    variables = {
      "ENV_VAR_1" = "value1"
    }
  }

  # Define Lambda destinations
  dead_letter_config {
    target_arn = aws_sqs_queue.lambda_dlq.arn
  }

  # Success destination (SNS)
  destination_config {
    on_success {
      destination = aws_sns_topic.success_topic.arn
    }
    on_failure {
      destination = aws_sqs_queue.failure_queue.arn
    }
  }
}
</code></pre>
<p>In this configuration, successful Lambda invocations are sent to an SNS topic, while failed executions are sent to an SQS queue.</p>
<h3 id="heading-2-provisioned-concurrency">2. <strong>Provisioned Concurrency</strong></h3>
<p>Lambda’s <strong>Provisioned Concurrency</strong> allows you to pre-allocate a certain number of concurrent executions for low-latency, high-throughput applications. This feature ensures that your function is "warm" and ready to respond to requests immediately, without the initial cold start.</p>
<pre><code class="lang-plaintext">resource "aws_lambda_provisioned_concurrency_config" "example" {
  function_name                 = aws_lambda_function.example.function_name
  qualifier                     = "$LATEST"
  provisioned_concurrent_executions = 10
}
</code></pre>
<p>By configuring provisioned concurrency, you can reduce the cold-start time of your function, ensuring a fast and consistent response time.</p>
<h3 id="heading-3-lambda-with-docker-containers">3. <strong>Lambda with Docker Containers</strong></h3>
<p>AWS Lambda now supports running containerized applications. Instead of zipping your code, you can package your Lambda as a Docker container image. This provides more flexibility in how you build and package your Lambda code, including running custom runtimes.</p>
<p>To deploy a containerized Lambda function with Terraform:</p>
<pre><code class="lang-plaintext">resource "aws_lambda_function" "my_lambda" {
  function_name = "my_container_lambda"
  package_type  = "Image"
  image_uri     = "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-lambda-image:latest"
  role          = aws_iam_role.lambda_role.arn
  memory_size   = 512
  timeout       = 30
}
</code></pre>
<p>You’ll need to build your Docker image locally or in your CI/CD pipeline and push it to Amazon Elastic Container Registry (ECR) before referencing it in Terraform.</p>
<h3 id="heading-4-cicd-with-terraform-and-aws-lambda">4. <strong>CI/CD with Terraform and AWS Lambda</strong></h3>
<p>To securely add AWS credentials for Terraform to use in a GitHub Actions workflow, you should use GitHub Secrets. This ensures that your AWS credentials are not exposed directly in your workflow YAML file.</p>
<p>Here’s how to do it:</p>
<h3 id="heading-step-1-add-aws-credentials-to-github-secrets">Step 1: Add AWS Credentials to GitHub Secrets</h3>
<ol>
<li><p>Go to your GitHub repository.</p>
</li>
<li><p>Click on <strong>Settings</strong>.</p>
</li>
<li><p>In the left sidebar, select <strong>Secrets and Variables</strong> &gt; <strong>Actions</strong>.</p>
</li>
<li><p>Click the <strong>New repository secret</strong> button.</p>
</li>
<li><p>Add the following secrets:</p>
<ul>
<li><p><code>AWS_ACCESS_KEY_ID</code></p>
</li>
<li><p><code>AWS_SECRET_ACCESS_KEY</code></p>
</li>
</ul>
</li>
</ol>
<p>Make sure these values are from an IAM user with the necessary permissions for Terraform to create resources (e.g., Lambda, S3, IAM).</p>
<h3 id="heading-step-2-update-github-actions-workflow-to-use-aws-credentials">Step 2: Update GitHub Actions Workflow to Use AWS Credentials</h3>
<p>Now, you need to modify your GitHub Actions workflow to use these secrets for AWS authentication.</p>
<p>Here’s your updated workflow YAML:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">Lambda</span> <span class="hljs-string">with</span> <span class="hljs-string">Terraform</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">terraform:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Configure</span> <span class="hljs-string">AWS</span> <span class="hljs-string">credentials</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">aws-actions/configure-aws-credentials@v2</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">aws-access-key-id:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_ACCESS_KEY_ID</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">aws-secret-access-key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_SECRET_ACCESS_KEY</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">aws-region:</span> <span class="hljs-string">us-west-2</span>  <span class="hljs-comment"># You can specify the region here</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Terraform</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">hashicorp/setup-terraform@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">terraform_version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Initialize</span> <span class="hljs-string">Terraform</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">terraform</span> <span class="hljs-string">init</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Plan</span> <span class="hljs-string">Terraform</span> <span class="hljs-string">changes</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">terraform</span> <span class="hljs-string">plan</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Apply</span> <span class="hljs-string">Terraform</span> <span class="hljs-string">changes</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">terraform</span> <span class="hljs-string">apply</span> <span class="hljs-string">-auto-approve</span>
</code></pre>
<h3 id="heading-breakdown-of-updates">Breakdown of Updates:</h3>
<ul>
<li><p><strong>AWS credentials configuration</strong>:</p>
<ul>
<li><p>The step <code>Configure AWS credentials</code> uses the GitHub action <code>aws-actions/configure-aws-credentials@v2</code> to set up the environment for Terraform to authenticate with AWS.</p>
</li>
<li><p>The <code>${{</code> <a target="_blank" href="http://secrets.AWS"><code>secrets.AWS</code></a><code>_ACCESS_KEY_ID }}</code> and <code>${{</code> <a target="_blank" href="http://secrets.AWS"><code>secrets.AWS</code></a><code>_SECRET_ACCESS_KEY }}</code> pull the secrets from the repository settings.</p>
</li>
</ul>
</li>
<li><p><strong>AWS Region</strong>:</p>
<ul>
<li>You can define the AWS region using the <code>aws-region</code> key (set to <code>us-west-2</code> in this example), but you can modify it to any region you need.</li>
</ul>
</li>
</ul>
<p>By following this process, you securely add AWS credentials to your GitHub Actions workflow, enabling Terraform to authenticate and interact with AWS.</p>
<h3 id="heading-5-cost-optimization-and-monitoring">5. <strong>Cost Optimization and Monitoring</strong></h3>
<p>Cost optimization is an essential part of managing Lambda functions, especially as usage scales up. Here are a few ways to optimize Lambda costs:</p>
<ul>
<li><p><strong>Monitor Duration</strong>: Reduce function execution time by optimizing the code to minimize processing delays.</p>
</li>
<li><p><strong>Optimize Memory</strong>: Use the minimum memory allocation that still allows the function to execute efficiently.</p>
</li>
<li><p><strong>Enable CloudWatch Alarms</strong>: Set up CloudWatch Alarms for function invocation counts, error rates, and duration metrics to keep an eye on function usage and identify cost anomalies.</p>
</li>
</ul>
<p>Terraform can also help automate the setup of these cost optimization tools:</p>
<pre><code class="lang-plaintext">resource "aws_cloudwatch_metric_alarm" "lambda_duration_alarm" {
  alarm_name          = "LambdaDurationExceeded"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 1
  metric_name         = "Duration"
  namespace           = "AWS/Lambda"
  period              = 60
  statistic           = "Average"
  threshold           = 3000  # 3 seconds
  actions_enabled     = true
}
</code></pre>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>AWS Lambda, combined with Terraform, offers an incredibly powerful platform for building serverless applications with infrastructure as code. By following the practices laid out in this guide, you can:</p>
<ul>
<li><p>Automate the deployment and management of Lambda functions.</p>
</li>
<li><p>Integrate seamlessly with other AWS services like S3, API Gateway, and CloudWatch.</p>
</li>
<li><p>Optimize your infrastructure for cost and performance.</p>
</li>
<li><p>Maintain flexibility and scalability as your applications grow.</p>
</li>
</ul>
<p>With Terraform, you can also scale your AWS Lambda deployment strategy to handle more complex setups involving multiple environments, reusable modules, and even containerized functions.</p>
<p>The possibilities are vast, but the key takeaway is that automation, consistency, and best practices with tools like Terraform will save time, reduce errors, and ensure that your AWS Lambda infrastructure is future-proof and scalable.</p>
]]></content:encoded></item><item><title><![CDATA[Infrastructure from Code (IfC): Overview and Role in Platform Engineering with StackGen]]></title><description><![CDATA[In our previous blog, we explored the concept of Infrastructure from Code (IfC) and how it automates the generation of infrastructure directly from application code. This approach eliminates the need for manually writing infrastructure as code (IaC) ...]]></description><link>https://blog.cloudnativefolks.org/infrastructure-from-code-ifc-overview-and-role-in-platform-engineering-with-stackgen</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/infrastructure-from-code-ifc-overview-and-role-in-platform-engineering-with-stackgen</guid><category><![CDATA[Platform Engineering ]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Security]]></category><category><![CDATA[Infrastructure as code]]></category><category><![CDATA[Infrastructure management]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Mon, 23 Sep 2024 14:26:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726887139423/6c16b973-85de-49af-9876-04ce9aba86b1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In our <a target="_blank" href="https://blog.cloudnativefolks.org/infrastructure-from-code-is-new-trend">previous blog</a>, we explored the concept of <strong>Infrastructure from Code (IfC)</strong> and how it automates the generation of infrastructure directly from application code. This approach eliminates the need for manually writing infrastructure as code (IaC) and ensures that best practices are applied automatically. But how can platform engineers adopt this game-changing practice? Are there tools that can make this transition easier?</p>
<p>In this blog, we’ll dive into the <strong>tools</strong> available to help you adopt IfC, focusing on how they can simplify your workflows, save time, and enhance infrastructure security and scalability. We'll also highlight the practical benefits of using these tools to accelerate your platform engineering processes.</p>
<h4 id="heading-introduction-to-infrastructure-from-code-ifc"><strong>Introduction to Infrastructure from Code (IfC)</strong></h4>
<p><strong>Infrastructure from Code (IfC)</strong> is a transformative approach to automating infrastructure provisioning by generating infrastructure configurations directly from application code. This reduces the need for manual infrastructure management and ensures consistency across different environments. In platform engineering, IfC enables teams to build and scale platforms quickly and efficiently.</p>
<p><strong>StackGen</strong> plays a crucial role in this process, simplifying infrastructure generation by automatically creating Infrastructure as Code (IaC) and applying best practice cloud policies. Even for those with limited IaC knowledge, StackGen makes it easy to review, enhance, and provide infrastructure to DevOps teams without writing any IaC from scratch.</p>
<h3 id="heading-how-stackgen-saves-time-for-platform-engineers"><strong>How StackGen Saves Time for Platform Engineers</strong></h3>
<p>When platform engineers manage infrastructure manually, they often face several time-consuming tasks:</p>
<ol>
<li><p><strong>Writing and Maintaining IaC</strong>: Manually writing IaC for services like Terraform, Helm, or CloudFormation requires extensive time and expertise.</p>
</li>
<li><p><strong>Applying Cloud Best Practices</strong>: Ensuring compliance and security requires knowledge of best practices, which involves time-consuming research and validation.</p>
</li>
<li><p><strong>Scaling Infrastructure</strong>: Manually managing infrastructure scaling in response to changing application needs requires constant monitoring and adjustment.</p>
</li>
<li><p><strong>Collaboration with DevOps Teams</strong>: Aligning IaC with DevOps practices and ensuring smooth deployment requires careful planning and review cycles.</p>
</li>
<li><p><strong>Security and Compliance</strong>: Ensuring infrastructure meets regulatory compliance (e.g., SOC 2, HIPAA, NIST-CSF, PCI, GDPR) and security standards can take weeks of manual effort.</p>
</li>
</ol>
<p>Using <strong>StackGen</strong> to generate Infrastructure from Code significantly reduces the time spent on these tasks. Below is a breakdown of how much time StackGen can save platform engineers:</p>
<h3 id="heading-1-writing-and-maintaining-iac"><strong>1. Writing and Maintaining IaC</strong></h3>
<ul>
<li><p><strong>Manual Process</strong>: Writing complex IaC from scratch for infrastructure components such as networking, load balancers, storage, and databases typically takes <strong>several days to weeks</strong> depending on the complexity of the application.</p>
</li>
<li><p><strong>With StackGen</strong>: StackGen automatically generates IaC within <strong>minutes to hours</strong> based on your application code, eliminating the need to manually write and maintain detailed configurations.</p>
</li>
<li><p><strong>Time Reduction</strong>: StackGen reduces time spent writing and maintaining IaC by up to <strong>90%</strong>, turning what could be a multi-week task into just a few hours.</p>
</li>
</ul>
<h3 id="heading-2-applying-cloud-best-practices"><strong>2. Applying Cloud Best Practices</strong></h3>
<ul>
<li><p><strong>Manual Process</strong>: Researching, implementing, and validating cloud best practices (such as security, compliance, and scaling configurations) can take <strong>several days</strong>. Engineers must ensure that the infrastructure follows the best practices for the chosen cloud provider.</p>
</li>
<li><p><strong>With StackGen</strong>: StackGen automatically applies pre-built best practice policies for AWS, Azure, and GCP, ensuring your infrastructure is compliant and secure without the need for manual intervention.</p>
</li>
<li><p><strong>Time Reduction</strong>: StackGen reduces this process by <strong>80-90%</strong>, saving platform engineers <strong>several days</strong> of manual configuration and testing.</p>
</li>
</ul>
<h3 id="heading-3-scaling-infrastructure"><strong>3. Scaling Infrastructure</strong></h3>
<ul>
<li><p><strong>Manual Process</strong>: Monitoring and manually adjusting infrastructure to scale with demand is a time-consuming task. Engineers may spend <strong>hours or even days each week</strong> configuring autoscaling policies and adjusting infrastructure as workloads fluctuate.</p>
</li>
<li><p><strong>With StackGen</strong>: StackGen generates Infrastructure as Code (IaC) that defines scaling parameters upfront, ensuring that infrastructure can be easily adjusted when needed. Instead of handling scaling in real time, StackGen allows engineers to set clear, predefined scaling policies through code, reducing the complexity and effort of manual adjustments.</p>
</li>
<li><p><strong>Time Savings</strong>: StackGen reduces the time spent on configuring and managing scaling by up to <strong>85%</strong>, as engineers can focus on defining infrastructure via IaC rather than manually adjusting resources on the fly. This approach significantly minimizes repetitive scaling tasks while maintaining flexibility.</p>
</li>
</ul>
<h3 id="heading-4-collaboration-with-devops-teams"><strong>4. Collaboration with DevOps Teams</strong></h3>
<ul>
<li><p><strong>Manual Process</strong>: Aligning infrastructure configurations with DevOps pipelines and ensuring smooth deployment often requires <strong>several review cycles and iterations</strong>, which can delay deployment timelines by <strong>days or weeks</strong>.</p>
</li>
<li><p><strong>With StackGen</strong>: StackGen integrates seamlessly with existing DevOps workflows, automatically generating infrastructure that is ready for deployment. Engineers can review and tweak the generated IaC before passing it to DevOps teams, streamlining the process.</p>
</li>
</ul>
<h3 id="heading-5-security-and-compliance"><strong>5. Security and Compliance</strong></h3>
<ul>
<li><p><strong>Manual Process</strong>: Ensuring that infrastructure is compliant with security regulations such as <strong>SOC 2, HIPAA, NIST-CSF, PCI, and GDPR</strong> requires significant manual effort. Platform engineers need to stay updated with the latest security guidelines, implement controls, and validate compliance—often a <strong>1-2 week process for each system</strong>.</p>
</li>
<li><p><strong>With StackGen</strong>: StackGen integrates automated security best practices into the generated IaC, ensuring compliance with all relevant security standards. This feature saves engineers from manually implementing these controls, reducing errors and ensuring that infrastructure is secure by design.</p>
</li>
<li><p><strong>Time Reduction</strong>: StackGen reduces the time spent on security and compliance by <strong>85-90%</strong>, transforming weeks of manual work into automated, built-in processes that engineers can trust.</p>
</li>
</ul>
<h3 id="heading-the-bigger-picture-time-savings-with-stackgen">The Bigger Picture: Time Savings with StackGen</h3>
<p>By automating these key areas, <strong>StackGen reduces the overall infrastructure management time by up to 70-90%</strong>. Below is a comparative example of time spent manually versus using StackGen for a typical platform engineering workflow:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Task</strong></td><td><strong>Manual Time</strong></td><td><strong>With StackGen</strong></td><td><strong>Time Saved</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Writing and Maintaining IaC</td><td>1-2 weeks</td><td>1-2 hours</td><td>~90%</td></tr>
<tr>
<td>Applying Cloud Best Practices</td><td>3-5 days</td><td>Built into generated IaC</td><td>~85-90%</td></tr>
<tr>
<td>Scaling Infrastructure</td><td>Ongoing (hours/week)</td><td>Predefined in IaC (adjustments required when needed)</td><td>~85% (hours/week)</td></tr>
<tr>
<td>Collaboration with DevOps Teams</td><td>3-7 days (review cycles)</td><td>1-2 days</td><td>~50-70%</td></tr>
<tr>
<td>Security Integration</td><td>1-2 weeks</td><td>Automated security best practices and compliance standards (SOC 2, HIPAA, NIST-CSF, PCI, GDPR) built into IaC</td><td>~85-90%</td></tr>
</tbody>
</table>
</div><blockquote>
<p>Get Started Now with StackGen - <a target="_blank" href="https://stackgen.com/developers">https://stackgen.com/developers</a></p>
</blockquote>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://stackgen.com">https://stackgen.com</a></div>
<p> </p>
<h3 id="heading-live-use-cases-of-stackgen-in-platform-engineering"><strong>Live Use Cases of StackGen in Platform Engineering</strong></h3>
<h4 id="heading-1-microservices-deployment-on-aws">1. <strong>Microservices Deployment on AWS</strong></h4>
<ul>
<li><p><strong>Scenario</strong>: A team building a microservices-based application on AWS.</p>
</li>
<li><p><strong>Manual Process</strong>: Writing Terraform or CloudFormation templates for provisioning AWS resources like VPCs, load balancers, and databases could take up to 2-3 weeks.</p>
</li>
<li><p><strong>With StackGen</strong>: The team connects their code repository to StackGen, specifies AWS as the target, and the necessary infrastructure is automatically generated in less than a day.</p>
</li>
<li><p><strong>Time Saved</strong>: ~2-3 weeks.</p>
</li>
</ul>
<h4 id="heading-2-kubernetes-based-platform-on-aws-cloud">2. <strong>Kubernetes-Based Platform on AWS Cloud</strong></h4>
<ul>
<li><p><strong>Scenario</strong>: A company using Kubernetes to manage containerised workloads on AWS Cloud.</p>
</li>
<li><p><strong>Manual Process</strong>: Provisioning EKS clusters, managing networking and storage, and ensuring best practices can take several days to weeks.</p>
</li>
<li><p><strong>With StackGen</strong>: The Kubernetes infrastructure is generated automatically within hours, complete with security and scaling best practices.</p>
</li>
<li><p><strong>Time Saved</strong>: ~1-2 weeks.</p>
</li>
</ul>
<h4 id="heading-3-serverless-application-on-aws-lambda">3. <strong>Serverless Application on AWS Lambda</strong></h4>
<ul>
<li><p><strong>Scenario</strong>: A startup deploying a serverless application on AWS Lambda.</p>
</li>
<li><p><strong>Manual Process</strong>: Configuring Lambda functions, API Gateway, and DynamoDB manually could take a few days to a week.</p>
</li>
<li><p><strong>With StackGen</strong>: The infrastructure is generated automatically within a few hours, fully optimized for serverless workloads.</p>
</li>
<li><p><strong>Time Saved</strong>: ~4-5 days.</p>
</li>
</ul>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>By leveraging <strong>StackGen</strong>, platform engineers can drastically reduce the time spent on infrastructure management—by as much as <strong>70-90%</strong>—while ensuring compliance with best practices. Whether it's deploying microservices, Kubernetes clusters, or serverless applications, StackGen automates complex processes, saving platform teams weeks of effort and enabling faster deployment cycles. This time-saving capability allows engineers to focus on innovation and scaling their platforms, rather than getting bogged down in manual IaC tasks.</p>
]]></content:encoded></item><item><title><![CDATA[From Serverless to Kubernetes Part - 1]]></title><description><![CDATA[Serverless has emerged as a popular way to deploy simple applications, making it easier for startups to build solutions with fewer resources. However, most serverless platforms are vendor-specific, which can limit their usefulness for modern cloud-na...]]></description><link>https://blog.cloudnativefolks.org/from-serverless-to-kubernetes-part-1</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/from-serverless-to-kubernetes-part-1</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[knative]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Tue, 10 Sep 2024 18:45:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725993877413/40d02718-3b9c-45f0-b1dd-221c03096317.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Serverless has emerged as a popular way to deploy simple applications, making it easier for startups to build solutions with fewer resources. However, most serverless platforms are vendor-specific, which can limit their usefulness for modern cloud-native and AI applications. This is where projects like Knative step in. Knative combines the power of serverless with Kubernetes, allowing developers to focus solely on writing serverless functions while benefiting from Kubernetes’ robust infrastructure.</p>
<p>In this blog, we’ll explore how to install Knative, understand its components, and deploy a simple Knative application on Kubernetes.</p>
<h3 id="heading-background-of-knative-project">Background of Knative Project</h3>
<p>Knative created originally by google with contributor from over 50 different companies , delivery an essential set of components to build and run serverless application on kubernetes . Knative is a <a target="_blank" href="https://www.cncf.io/">Cloud Native Computing Foundation</a> incubation project .</p>
<h3 id="heading-create-k8s-cluster-locally-with-kind">Create k8s Cluster Locally with Kind</h3>
<ol>
<li>Install kind locally</li>
</ol>
<ul>
<li><a target="_blank" href="https://kind.sigs.k8s.io">https://kind.sigs.k8s.io</a></li>
</ul>
<ol start="2">
<li><p>verify kind is installed or not</p>
<pre><code class="lang-plaintext"> kind --version
</code></pre>
</li>
<li><p>Kind ( Kubernetes in Docker ) use Docker to create Kubernetes Cluster</p>
<pre><code class="lang-plaintext"> Docker --version
</code></pre>
</li>
<li><p>here is Kubernetes manifest to create kind cluster which includes extraPortMapping we needed for kourier ingress later in installing Kourier</p>
</li>
</ol>
<pre><code class="lang-plaintext">kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  image: kindest/node:v1.31.0@sha256:53df588e04085fd41ae12de0c3fe4c72f7013bba32a20e7325357a1ac94ba865
  extraPortMappings:
  - containerPort: 31080  # expose port 31380 of the node to port 80 on the host, later to be use by kourier ingress
    hostPort: 80
  - containerPort: 31443
    hostPort: 443
</code></pre>
<p>save above manifest with name <code>kind-knative-cluster.yaml</code></p>
<pre><code class="lang-plaintext">kind create cluster --name knative-cluster --config kind-knative-cluster.yaml
</code></pre>
<p>if already cluster exist with that name <code>kind delete cluster -n knative-cluster</code></p>
<p>get cluster info and check if the context is pointing to the right cluster</p>
<pre><code class="lang-plaintext">kubectl cluster-info --context kind-knative-cluster
kubectl config get-contexts
</code></pre>
<h3 id="heading-install-knative-serving-component">Install Knative Serving Component</h3>
<pre><code class="lang-plaintext">kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.15.2/serving-crds.yaml
kubectl wait --for=condition=Established --all crd
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.15.2/serving-core.yaml
kubectl wait pod --timeout=-1s --for=condition=Ready -l '!job-name' -n knative-serving &gt; /dev/null
</code></pre>
<h3 id="heading-intall-kourier">Intall kourier</h3>
<pre><code class="lang-plaintext">kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v1.15.1/kourier.yaml
kubectl wait pod --timeout=-1s --for=condition=Ready -l '!job-name' -n kourier-system
kubectl wait pod --timeout=-1s --for=condition=Ready -l '!job-name' -n knative-serving
</code></pre>
<h3 id="heading-set-up-magic-dns">Set up Magic DNS</h3>
<pre><code class="lang-plaintext">EXTERNAL_IP="127.0.0.1"
KNATIVE_DOMAIN="$EXTERNAL_IP.nip.io"
echo KNATIVE_DOMAIN=$KNATIVE_DOMAIN
dig $KNATIVE_DOMAIN
kubectl patch configmap -n knative-serving config-domain -p "{\"data\": {\"$KNATIVE_DOMAIN\": \"\"}}"
</code></pre>
<h3 id="heading-check-the-config-domain-in-configmap">check the config domain in configmap</h3>
<pre><code class="lang-plaintext">kubectl describe configmaps config-domain -n knative-serving
</code></pre>
<h3 id="heading-set-kourier-as-the-default-networking-layer-for-knative-serving">set Kourier as the default networking layer for Knative Serving</h3>
<pre><code class="lang-plaintext">apiVersion: v1
kind: Service
metadata:
  name: kourier-ingress
  namespace: kourier-system
  labels:
    networking.knative.dev/ingress-provider: kourier
spec:
  type: NodePort
  selector:
    app: 3scale-kourier-gateway
  ports:
    - name: http2
      nodePort: 31080
      port: 80
      targetPort: 8080
    - name: https
      nodePort: 31443
      port: 443
      targetPort: 8443
</code></pre>
<p>Kourier is an Ingress for Knative Serving. Kourier is a lightweight alternative for the Istio ingress as its deployment consists only of an Envoy proxy and a control plane for it.</p>
<h1 id="heading-install-the-kourier-controller">install the Kourier controller</h1>
<pre><code class="lang-plaintext">kubectl apply -f kourier.yaml
</code></pre>
<h3 id="heading-configure-knative-serving-to-use-the-proper-ingressclass">Configure Knative Serving to use the proper "ingress.class"</h3>
<pre><code class="lang-plaintext">kubectl patch configmap/config-network   
--namespace knative-serving   
--type merge   
--patch '{"data":{"ingress.class":"kourier.ingress.networking.knative.dev"}}'
kubectl describe configmaps config-network -n knative-serving
</code></pre>
<h3 id="heading-check-pods-are-up-and-running">check pods are up and running</h3>
<pre><code class="lang-plaintext">kubectl get pods -n knative-serving
kubectl get pods -n kourier-system
kubectl get svc  -n kourier-system
</code></pre>
<h3 id="heading-install-kn-cli">Install Kn CLI</h3>
<pre><code class="lang-plaintext">brew install knative/client/kn
</code></pre>
<h3 id="heading-run-first-hello-world-serverless-function">Run first hello world serverless function</h3>
<pre><code class="lang-plaintext">kn service create hello   
--image gcr.io/knative-samples/helloworld-go   
--port 8080   
--env TARGET=Knative
</code></pre>
<h3 id="heading-get-service-url">Get Service URL</h3>
<pre><code class="lang-plaintext">SERVICE_URL=$(kubectl get ksvc hello -o jsonpath='{.status.url}')
echo $SERVICE_URL
</code></pre>
<p>Curl the URL in new Terminal</p>
<pre><code class="lang-plaintext">curl $SERVICE_URL
</code></pre>
<p>see the pod status</p>
<pre><code class="lang-plaintext">kubectl get pod -l serving.knative.dev/service=hello -w 
# NAME                                      READY   STATUS    RESTARTS   AGE

# hello-00001-deployment-659dfd67fb-5ps9x   2/2     Running   0          90s

# hello-00001-deployment-659dfd67fb-5ps9x   2/2     Terminating   0          2m25s

# hello-00001-deployment-659dfd67fb-5ps9x   1/2     Terminating   0          2m27s

# hello-00001-deployment-659dfd67fb-wgnkj   0/2     Pending       0          0s

# hello-00001-deployment-659dfd67fb-wgnkj   0/2     Pending       0          0s

# hello-00001-deployment-659dfd67fb-wgnkj   0/2     ContainerCreating   0          0s

# hello-00001-deployment-659dfd67fb-wgnkj   1/2     Running             0          1s

# hello-00001-deployment-659dfd67fb-wgnkj   2/2     Running             0          1s

# hello-00001-deployment-659dfd67fb-5ps9x   0/2     Terminating         0          2m55s

# hello-00001-deployment-659dfd67fb-5ps9x   0/2     Terminating         0          2m56s

# hello-00001-deployment-659dfd67fb-5ps9x   0/2     Terminating         0          2m56s

# NAME                                      READY   STATUS    RESTARTS   AGE

# hello-00001-deployment-659dfd67fb-5ps9x   2/2     Running   0          90s

# hello-00001-deployment-659dfd67fb-5ps9x   2/2     Terminating   0          2m25s

# hello-00001-deployment-659dfd67fb-5ps9x   1/2     Terminating   0          2m27s

# hello-00001-deployment-659dfd67fb-wgnkj   0/2     Pending       0          0s

# hello-00001-deployment-659dfd67fb-wgnkj   0/2     Pending       0          0s

# hello-00001-deployment-659dfd67fb-wgnkj   0/2     ContainerCreating   0          0s

# hello-00001-deployment-659dfd67fb-wgnkj   1/2     Running             0          1s

# hello-00001-deployment-659dfd67fb-wgnkj   2/2     Running             0          1s

# hello-00001-deployment-659dfd67fb-5ps9x   0/2     Terminating         0          2m55s

# hello-00001-deployment-659dfd67fb-5ps9x   0/2     Terminating         0          2m56s

# hello-00001-deployment-659dfd67fb-5ps9x   0/2     Terminating         0          2m56s

# hello-00001-deployment-659dfd67fb-wgnkj   2/2     Terminating         0          88s

# hello-00001-deployment-659dfd67fb-npmr5   0/2     Pending             0          0s

# hello-00001-deployment-659dfd67fb-npmr5   0/2     Pending             0          0s

# hello-00001-deployment-659dfd67fb-npmr5   0/2     ContainerCreating   0          0s

# hello-00001-deployment-659dfd67fb-npmr5   1/2     Running             0          2s

# hello-00001-deployment-659dfd67fb-npmr5   2/2     Running             0          2s

# hello-00001-deployment-659dfd67fb-wgnkj   1/2     Terminating         0          90s
</code></pre>
<p>if you see above pods if your accessing URL that time container creating in background instantly</p>
<blockquote>
<p>another way of installing Knative quickly</p>
<pre><code class="lang-plaintext">brew install knative-extensions/kn-plugins/quickstart
kn quickstart kind
</code></pre>
</blockquote>
<h3 id="heading-lets-build-our-newsfeed-knative-application">Lets build our newsfeed Knative application</h3>
<pre><code class="lang-plaintext">tree
.
├── README.md
├── service.yaml
├── servingcontainer
│   ├── Dockerfile
│   ├── go.mod
│   └── servingcontainer.go
└── sidecarcontainer
    ├── Dockerfile
    ├── go.mod
    ├── go.sum
    └── sidecarcontainer.go
</code></pre>
<p>here we have 2 functions on as <code>servingcontainer.go</code> and another <code>sidecarcontainer.go</code> with respecting dependencies and dockerfile</p>
<p>function 1 - servingcontainer</p>
<pre><code class="lang-plaintext"> tree
.
├── Dockerfile
├── go.mod
└── servingcontainer.go
</code></pre>
<pre><code class="lang-plaintext">
package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    log.Println("serving container received a request.")
    res, err := http.Get("http://127.0.0.1:8882")
    if err != nil {
        log.Fatal(err)
    }
    resp, err := io.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Fprintln(w, string(resp))
}

func main() {
    log.Print("serving container started...")
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8881", nil))
}
</code></pre>
<p>simple HTTP server that listens on port 8881 and forwards incoming requests to another service running at <a target="_blank" href="http://127.0.0.1:8882"><code>http://127.0.0.1:8882</code></a>. It retrieves the response from that service and returns it to the original client</p>
<p>here is Dockerfile</p>
<pre><code class="lang-plaintext">FROM golang:1.16 AS builder  
ARG TARGETOS
ARG TARGETARCH
# Create and change to the app directory.
WORKDIR /app
# Retrieve application dependencies using go modules.
COPY go.* ./
RUN go mod download
# Copy local code to the container image.
COPY . ./
# Build the binary.
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -mod=readonly -v -o servingcontainer
# Use the official Alpine image for a lean production container.
FROM alpine:3
RUN apk add --no-cache ca-certificates
# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/servingcontainer /servingcontainer
# Run the web service on container startup.
CMD ["/servingcontainer"]
</code></pre>
<p>Build Muti-arch images</p>
<pre><code class="lang-plaintext">docker buildx build --platform linux/arm64,linux/amd64 -t "sangam14/servingcontainer" --push .
[+] Building 72.9s (30/30) FINISHED                                                                                            docker:desktop-linux
 =&gt; [internal] load build definition from Dockerfile                                                                                           0.0s
 =&gt; =&gt; transferring dockerfile: 734B                                                                                                           0.0s
 =&gt; [linux/amd64 internal] load metadata for docker.io/library/alpine:3                                                                        3.8s
 =&gt; [linux/arm64 internal] load metadata for docker.io/library/alpine:3                                                                        3.8s
 =&gt; [linux/arm64 internal] load metadata for docker.io/library/golang:1.23                                                                     7.1s
 =&gt; [linux/amd64 internal] load metadata for docker.io/library/golang:1.23                                                                     6.6s
 =&gt; [auth] library/alpine:pull token for registry-1.docker.io                                                                                  0.0s
 =&gt; [auth] library/golang:pull token for registry-1.docker.io                                                                                  0.0s
 =&gt; [internal] load .dockerignore                                                                                                              0.0s
 =&gt; =&gt; transferring context: 2B                                                                                                                0.0s
 =&gt; [linux/arm64 builder 1/6] FROM docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e      33.0s
 =&gt; =&gt; resolve docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e                           0.0s
 =&gt; =&gt; sha256:83f1399aa9166438efeea4696812a3fa3f3397ff114492577a919f9b09f3c1ea 126B / 126B                                                     2.6s
 =&gt; =&gt; sha256:a355a3cac949bed5cda9c62103ceb0f004727cedcd2a17d7c9836aea1a452fda 70.62MB / 70.62MB                                               9.9s
 =&gt; =&gt; sha256:ecb27c98d5b9e78892d876693427ae0a01e3113b36989718360a5aa9e319fd80 86.29MB / 86.29MB                                              15.4s
 =&gt; =&gt; sha256:843b1d8321825bc8302752ae003026f13bd15c6eef2efe032f3ca1520c5bbc07 64.00MB / 64.00MB                                              11.9s
 =&gt; =&gt; sha256:364d19f59f69474a80c53fc78da91f85553e16e8ba6a28063cbebf259821119e 23.59MB / 23.59MB                                               5.9s
 =&gt; =&gt; sha256:56c9b9253ff98351db158cb6789848656b8d54f411c0037347bf2358efb18f39 49.59MB / 49.59MB                                               3.9s
 =&gt; =&gt; extracting sha256:56c9b9253ff98351db158cb6789848656b8d54f411c0037347bf2358efb18f39                                                      0.6s
 =&gt; =&gt; extracting sha256:364d19f59f69474a80c53fc78da91f85553e16e8ba6a28063cbebf259821119e                                                      0.2s
 =&gt; =&gt; extracting sha256:843b1d8321825bc8302752ae003026f13bd15c6eef2efe032f3ca1520c5bbc07                                                      0.7s
 =&gt; =&gt; extracting sha256:ecb27c98d5b9e78892d876693427ae0a01e3113b36989718360a5aa9e319fd80                                                      1.0s
 =&gt; =&gt; extracting sha256:a355a3cac949bed5cda9c62103ceb0f004727cedcd2a17d7c9836aea1a452fda                                                      1.6s
 =&gt; =&gt; extracting sha256:83f1399aa9166438efeea4696812a3fa3f3397ff114492577a919f9b09f3c1ea                                                      0.0s
 =&gt; =&gt; extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1                                                      0.0s
 =&gt; [linux/amd64 builder 1/6] FROM docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e      24.6s
 =&gt; =&gt; resolve docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e                           0.0s
 =&gt; =&gt; sha256:95c1ad979d054ab0c2824c196b59074e31870426326f3e359ca9ee12d0fcb999 127B / 127B                                                     1.1s
 =&gt; =&gt; sha256:e7bff916ab0c126c9d943f0c481a905f402e00f206a89248f257ef90beaabbd8 74.00MB / 74.00MB                                              16.9s
 =&gt; =&gt; sha256:627963ea2c8d5e7f344e68dce05f9013c8104d06e6e0d414fcbb261cc0b6bbde 92.26MB / 92.26MB                                              21.7s
 =&gt; =&gt; sha256:2e66a70da0bec13fb3d492fcdef60fd8a5ef0a1a65c4e8a4909e26742852f0f2 64.15MB / 64.15MB                                               5.4s
 =&gt; =&gt; sha256:2e6afa3f266c11e8960349e7866203a9df478a50362bb5488c45fe39d99b2707 24.05MB / 24.05MB                                              11.2s
 =&gt; =&gt; sha256:8cd46d290033f265db57fd808ac81c444ec5a5b3f189c3d6d85043b647336913 49.56MB / 49.56MB                                               7.1s
 =&gt; =&gt; extracting sha256:8cd46d290033f265db57fd808ac81c444ec5a5b3f189c3d6d85043b647336913                                                      0.5s
 =&gt; =&gt; extracting sha256:2e6afa3f266c11e8960349e7866203a9df478a50362bb5488c45fe39d99b2707                                                      0.2s
 =&gt; =&gt; extracting sha256:2e66a70da0bec13fb3d492fcdef60fd8a5ef0a1a65c4e8a4909e26742852f0f2                                                      0.7s
 =&gt; =&gt; extracting sha256:627963ea2c8d5e7f344e68dce05f9013c8104d06e6e0d414fcbb261cc0b6bbde                                                      0.9s
 =&gt; =&gt; extracting sha256:e7bff916ab0c126c9d943f0c481a905f402e00f206a89248f257ef90beaabbd8                                                      1.2s
 =&gt; =&gt; extracting sha256:95c1ad979d054ab0c2824c196b59074e31870426326f3e359ca9ee12d0fcb999                                                      0.0s
 =&gt; =&gt; extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1                                                      0.0s
 =&gt; [internal] load build context                                                                                                              0.0s
 =&gt; =&gt; transferring context: 798B                                                                                                              0.0s
 =&gt; [linux/amd64 stage-1 1/3] FROM docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d          0.8s
 =&gt; =&gt; resolve docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d                              0.0s
 =&gt; =&gt; sha256:43c4264eed91be63b206e17d93e75256a6097070ce643c5e8f0379998b44f170 2.10MB / 3.62MB                                                65.7s
 =&gt; =&gt; extracting sha256:43c4264eed91be63b206e17d93e75256a6097070ce643c5e8f0379998b44f170                                                      0.0s
 =&gt; [linux/arm64 stage-1 1/3] FROM docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d          0.8s
 =&gt; =&gt; resolve docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d                              0.0s
 =&gt; =&gt; sha256:cf04c63912e16506c4413937c7f4579018e4bb25c272d989789cfba77b12f951 4.09MB / 4.09MB                                                 0.7s
 =&gt; =&gt; extracting sha256:cf04c63912e16506c4413937c7f4579018e4bb25c272d989789cfba77b12f951                                                      0.1s
 =&gt; [linux/arm64 stage-1 2/3] RUN apk add --no-cache ca-certificates                                                                          36.3s
 =&gt; [linux/amd64 stage-1 2/3] RUN apk add --no-cache ca-certificates                                                                          32.1s
 =&gt; [linux/amd64 builder 2/6] WORKDIR /app                                                                                                     0.8s
 =&gt; [linux/amd64 builder 3/6] COPY go.* ./                                                                                                     0.0s
 =&gt; [linux/amd64 builder 4/6] RUN go mod download                                                                                              0.2s
 =&gt; [linux/amd64 builder 5/6] COPY . ./                                                                                                        0.0s
 =&gt; [linux/amd64 builder 6/6] RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod=readonly -v -o servingcontainer                         16.4s
 =&gt; [linux/arm64 builder 2/6] WORKDIR /app                                                                                                     0.1s
 =&gt; [linux/arm64 builder 3/6] COPY go.* ./                                                                                                     0.0s
 =&gt; [linux/arm64 builder 4/6] RUN go mod download                                                                                              0.1s
 =&gt; [linux/arm64 builder 5/6] COPY . ./                                                                                                        0.0s
 =&gt; [linux/arm64 builder 6/6] RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -mod=readonly -v -o servingcontainer                          3.7s
 =&gt; [linux/arm64 stage-1 3/3] COPY --from=builder /app/servingcontainer /servingcontainer                                                      0.0s
 =&gt; [linux/amd64 stage-1 3/3] COPY --from=builder /app/servingcontainer /servingcontainer                                                      0.0s
 =&gt; exporting to image                                                                                                                        11.7s
 =&gt; =&gt; exporting layers                                                                                                                        0.2s
 =&gt; =&gt; exporting manifest sha256:61709c4dd0e25684749ad68c5635b481f31f24574a603bc5b556ba5d15fe79a4                                              0.0s
 =&gt; =&gt; exporting config sha256:86aac9ead5bb472bc29b4f06c66655e7883bfdb248bd321885b257563a442929                                                0.0s
 =&gt; =&gt; exporting attestation manifest sha256:fabd107bc16cbbe43c3f163dc8c4e5cb51cbaf219d4da909d4364be8b2f80045                                  0.0s
 =&gt; =&gt; exporting manifest sha256:190a25dd92a3ff04983f4fd9ec8374f7560d2273f3481e5a57b32920b16cfff3                                              0.0s
 =&gt; =&gt; exporting config sha256:842a417114450ddfbca6dc5a5248c4b64950c445bfc7ff8b811c0a75eea1aa2b                                                0.0s
 =&gt; =&gt; exporting attestation manifest sha256:9471827b65703cafd008a1c28f65ada987dff64193299db1299906d8c1bfeb0e                                  0.0s
 =&gt; =&gt; exporting manifest list sha256:9b0071778eee4f9b87c7838d90689ad2c16dbecb7f85ec419edcf54f692d40e6                                         0.0s
 =&gt; =&gt; naming to docker.io/sangam14/servingcontainer:latest                                                                                    0.0s
 =&gt; =&gt; unpacking to docker.io/sangam14/servingcontainer:latest                                                                                 0.0s
 =&gt; =&gt; pushing layers                                                                                                                          7.9s
 =&gt; =&gt; pushing manifest for docker.io/sangam14/servingcontainer:latest@sha256:9b0071778eee4f9b87c7838d90689ad2c16dbecb7f85ec419edcf54f692d40e  3.4s
 =&gt; [auth] sangam14/servingcontainer:pull,push token for registry-1.docker.io                                                                  0.0s
 =&gt; pushing sangam14/servingcontainer with docker                                                                                              8.6s
 =&gt; =&gt; pushing layer cf04c63912e1                                                                                                              8.5s
 =&gt; =&gt; pushing layer c3d694a809a6                                                                                                              8.5s
 =&gt; =&gt; pushing layer e8a452786f60                                                                                                              8.5s
 =&gt; =&gt; pushing layer 854a7d49a717                                                                                                              8.5s
 =&gt; =&gt; pushing layer ce64efdaa908                                                                                                              8.5s
 =&gt; =&gt; pushing layer c8910dfd41a3                                                                                                              8.5s
 =&gt; =&gt; pushing layer 039108769e6b                                                                                                              8.5s
 =&gt; =&gt; pushing layer 43c4264eed91
</code></pre>
<p>function 2 - sidecarcontainer</p>
<pre><code class="lang-plaintext">tree
.
├── Dockerfile
├── go.mod
├── go.sum
└── sidecarcontainer.go
</code></pre>
<pre><code class="lang-plaintext">package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/mmcdole/gofeed"
)

func handler(w http.ResponseWriter, r *http.Request) {
    log.Println("sidecar container received a request.")

    // Parse the RSS feed
    fp := gofeed.NewParser()
    feed, err := fp.ParseURL("https://news.ycombinator.com/rss") // Replace with the desired RSS feed URL
    if err != nil {
        http.Error(w, "Failed to fetch newsfeed", http.StatusInternalServerError)
        log.Println("Failed to parse newsfeed:", err)
        return
    }

    // Display the feed title
    fmt.Fprintf(w, "Feed Title: %s\n\n", feed.Title)

    // Display the titles and links of the first few items
    for i, item := range feed.Items {
        if i &gt;= 10 { // Limit to first 5 items
            break
        }
        fmt.Fprintf(w, "Item %d: %s\nLink: %s\n\n", i+1, item.Title, item.Link)
    }

    fmt.Fprintln(w, "\nYay!! multi-container works")
}

func main() {
    log.Print("sidecar container started...")
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8882", nil))
}
</code></pre>
<p>a simple HTTP server in a Go-based sidecar container that fetches and parses an RSS feed (from Hacker News in this case) and serves the results. It uses the <code>gofeed</code> package to handle RSS parsing.</p>
<pre><code class="lang-plaintext"># Dockerfile

FROM golang:1.23 AS builder 

ARG TARGETOS
ARG TARGETARCH

# Create and change to the app directory
WORKDIR /app

# Retrieve application dependencies using go modules
COPY go.* ./
RUN go mod download

# Copy local code to the container image
COPY . ./

# Build the binary
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -mod=readonly -v -o sidecarcontainer

# Use the official Alpine image for a lean production container
FROM alpine:3
RUN apk add --no-cache ca-certificates

# Copy the binary to the production image from the builder stage
COPY --from=builder /app/sidecarcontainer /sidecarcontainer

# Run the web service on container startup
CMD ["/sidecarcontainer"]
</code></pre>
<p>Build Dockerfile</p>
<pre><code class="lang-plaintext">docker buildx build --platform linux/arm64,linux/amd64 -t "sangam14/sidecarcontainer" --push .
[+] Building 44.1s (29/29) FINISHED                                                                                            docker:desktop-linux
 =&gt; [internal] load build definition from Dockerfile                                                                                           0.0s
 =&gt; =&gt; transferring dockerfile: 741B                                                                                                           0.0s
 =&gt; [linux/amd64 internal] load metadata for docker.io/library/alpine:3                                                                        1.0s
 =&gt; [linux/arm64 internal] load metadata for docker.io/library/alpine:3                                                                        0.9s
 =&gt; [linux/amd64 internal] load metadata for docker.io/library/golang:1.23                                                                     1.0s
 =&gt; [linux/arm64 internal] load metadata for docker.io/library/golang:1.23                                                                     1.0s
 =&gt; [internal] load .dockerignore                                                                                                              0.0s
 =&gt; =&gt; transferring context: 2B                                                                                                                0.0s
 =&gt; [linux/arm64 builder 1/6] FROM docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e       0.0s
 =&gt; =&gt; resolve docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e                           0.0s
 =&gt; [linux/amd64 stage-1 1/3] FROM docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d          0.0s
 =&gt; =&gt; resolve docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d                              0.0s
 =&gt; [linux/arm64 stage-1 1/3] FROM docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d          0.0s
 =&gt; =&gt; resolve docker.io/library/alpine:3@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d                              0.0s
 =&gt; [internal] load build context                                                                                                              0.0s
 =&gt; =&gt; transferring context: 1.83kB                                                                                                            0.0s
 =&gt; [linux/amd64 builder 1/6] FROM docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e       0.0s
 =&gt; =&gt; resolve docker.io/library/golang:1.23@sha256:4a3c2bcd243d3dbb7b15237eecb0792db3614900037998c2cd6a579c46888c1e                           0.0s
 =&gt; CACHED [linux/amd64 stage-1 2/3] RUN apk add --no-cache ca-certificates                                                                    0.0s
 =&gt; CACHED [linux/arm64 stage-1 2/3] RUN apk add --no-cache ca-certificates                                                                    0.0s
 =&gt; CACHED [linux/arm64 builder 2/6] WORKDIR /app                                                                                              0.0s
 =&gt; [linux/arm64 builder 3/6] COPY go.* ./                                                                                                     0.0s
 =&gt; CACHED [linux/amd64 builder 2/6] WORKDIR /app                                                                                              0.0s
 =&gt; [linux/amd64 builder 3/6] COPY go.* ./                                                                                                     0.0s
 =&gt; [linux/arm64 builder 4/6] RUN go mod download                                                                                              4.5s
 =&gt; [linux/amd64 builder 4/6] RUN go mod download                                                                                              5.4s
 =&gt; [linux/arm64 builder 5/6] COPY . ./                                                                                                        0.0s
 =&gt; [linux/arm64 builder 6/6] RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -mod=readonly -v -o sidecarcontainer                          4.0s
 =&gt; [linux/amd64 builder 5/6] COPY . ./                                                                                                        0.0s
 =&gt; [linux/amd64 builder 6/6] RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod=readonly -v -o sidecarcontainer                         18.0s
 =&gt; [linux/arm64 stage-1 3/3] COPY --from=builder /app/sidecarcontainer /sidecarcontainer                                                      0.0s
 =&gt; [linux/amd64 stage-1 3/3] COPY --from=builder /app/sidecarcontainer /sidecarcontainer                                                      0.0s
 =&gt; exporting to image                                                                                                                        11.8s
 =&gt; =&gt; exporting layers                                                                                                                        0.3s
 =&gt; =&gt; exporting manifest sha256:743e5367746604219e7d8070490a9e49b78f8a41542f08f1d3fd683fc58cf7f0                                              0.0s
 =&gt; =&gt; exporting config sha256:c68b9afe107cf0ffdc9f2ae0eaf878de2431213bbc036891f36f3a9e2f619c5e                                                0.0s
 =&gt; =&gt; exporting attestation manifest sha256:f33bf8633f608ee8d0a807cf0adbcfde2335d0a38026fc9d95fc390af4b4ace6                                  0.0s
 =&gt; =&gt; exporting manifest sha256:84ac4119bdbdfad3828ee69ce192331177a392a68ba3438582852edff1424cbb                                              0.0s
 =&gt; =&gt; exporting config sha256:48b111bd6dffb0730a19cb2c0f8aab4d1b5bdff7577392d6f90c09eaea2a4fb0                                                0.0s
 =&gt; =&gt; exporting attestation manifest sha256:e133468d18aad6fb9d11448bf18cd5d70c93b128a125df0e2e3f830e374a4756                                  0.0s
 =&gt; =&gt; exporting manifest list sha256:ea149847fd05e1b469ce86835cf7f4722a3cba6590e302ebf3d3e7869e42da90                                         0.0s
 =&gt; =&gt; naming to docker.io/sangam14/sidecarcontainer:latest                                                                                    0.0s
 =&gt; =&gt; unpacking to docker.io/sangam14/sidecarcontainer:latest                                                                                 0.0s
 =&gt; =&gt; pushing layers                                                                                                                          8.0s
 =&gt; =&gt; pushing manifest for docker.io/sangam14/sidecarcontainer:latest@sha256:ea149847fd05e1b469ce86835cf7f4722a3cba6590e302ebf3d3e7869e42da9  3.5s
 =&gt; [auth] sangam14/sidecarcontainer:pull,push token for registry-1.docker.io                                                                  0.0s
 =&gt; [auth] sangam14/servingcontainer:pull sangam14/sidecarcontainer:pull,push token for registry-1.docker.io                                   0.0s
 =&gt; pushing sangam14/sidecarcontainer with docker                                                                                              4.7s
 =&gt; =&gt; pushing layer c3d694a809a6                                                                                                              4.6s
 =&gt; =&gt; pushing layer cf04c63912e1                                                                                                              4.6s
 =&gt; =&gt; pushing layer e8a452786f60                                                                                                              4.6s
 =&gt; =&gt; pushing layer 62ffe345c65c                                                                                                              4.6s
 =&gt; =&gt; pushing layer 4d650751acc4                                                                                                              4.6s
 =&gt; =&gt; pushing layer ec4bf944c859                                                                                                              4.6s
 =&gt; =&gt; pushing layer 1b45ea6e206a                                                                                                              4.6s
 =&gt; =&gt; pushing layer 43c4264eed91                                                                                                              4.6s
</code></pre>
<p>here is knative service</p>
<pre><code class="lang-plaintext">apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: multi-container
  namespace: default
spec:
  template:
    spec:
      containers:
      - image: docker.io/sangam14/servingcontainer:latest
        ports:
          - containerPort: 8881
      - image: docker.io/sangam14/sidecarcontainer:latest
</code></pre>
<p>After the build has completed and the container is pushed to Docker Hub, youcan deploy the app into your cluster. Ensure that the container image value in <code>service.yaml</code> matches the container you built in the previous step. Applythe configuration using <code>kubectl</code></p>
<pre><code class="lang-plaintext">kubectl apply --filename service.yaml
service.serving.knative.dev/multi-container created
</code></pre>
<p>check kn service to get url</p>
<pre><code class="lang-plaintext">kn service list 
NAME              URL                                               LATEST                  AGE    CONDITIONS   READY   REASON
multi-container   http://multi-container.default.127.0.0.1.nip.io   multi-container-00001   51s    3 OK / 3     True
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725901673762/a779111d-68e5-408f-8536-25d8ef7e71e0.png" alt class="image--center mx-auto" /></p>
<p>With Knative, you can easily run serverless applications on Kubernetes, combining the power of Kubernetes and the flexibility of serverless. The multi-container approach showcased here opens up even more possibilities for deploying complex applications</p>
]]></content:encoded></item><item><title><![CDATA[Infrastructure from code is new trend ?]]></title><description><![CDATA[Infrastructure from Code a New Trend?  
Wait! I know Infrastructure as Code (IaC), that's Terraform. Terraform has been a cornerstone of IaC, providing developers with the ability to manage and automate infrastructure efficiently. However, recent eve...]]></description><link>https://blog.cloudnativefolks.org/infrastructure-from-code-is-new-trend</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/infrastructure-from-code-is-new-trend</guid><category><![CDATA[Infrastructure as code]]></category><category><![CDATA[infrastructure from code]]></category><category><![CDATA[Terraform]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Tue, 10 Sep 2024 11:16:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724946622273/dbe43c3d-2593-45f0-9b21-2eb117dbfd8b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Infrastructure from Code a New Trend?  </p>
<p>Wait! I know Infrastructure as Code (IaC), that's Terraform. Terraform has been a cornerstone of IaC, providing developers with the ability to manage and automate infrastructure efficiently. However, recent events have made me concerned about its future, especially following HashiCorp's decision to switch Terraform's licensing to the Business Source License (BSL) and IBM’s intention to acquire HashiCorp. </p>
<p><img src="https://miro.medium.com/v2/resize:fit:612/0*_Utm8gNxLlp6FPkR.jpg" alt class="image--center mx-auto" /></p>
<p>However, as the complexity of cloud environments and microservices architectures grows, there's an increasing need for even more dynamic, context-aware infrastructure that can adapt to changes in real-time. This is where "Infrastructure from Code" comes in - it takes the principles of IaC a step further by directly linking infrastructure creation and management to the application code itself.</p>
<h3 id="heading-what-is-infrastructure-from-code">What is Infrastructure from Code ?</h3>
<p>Infrastructure as Code (IaC) like Terraform allows you to define your infrastructure using code, but Infrastructure from Code (IfC) takes it a step further by generating infrastructure directly from the application code itself.</p>
<p>In simpler terms, IfC automates the creation of infrastructure resources based on the requirements defined within your application code without requiring a separate infrastructure definition file. This concept bridges the gap between application development and infrastructure management by analyzing the application code, understanding its dependencies, and then automatically generating the necessary infrastructure.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://blog.stackgen.com/what-is-infrastructure-from-code">https://blog.stackgen.com/what-is-infrastructure-from-code</a></div>
<p> </p>
<h3 id="heading-why-is-it-a-new-trend">Why is it a New Trend?</h3>
<p>Yes, Infrastructure from Code (IfC) is an emerging trend, particularly in the context of modern DevOps practices and cloud-native development. As organizations increasingly adopt microservices, serverless architectures, and continuous delivery pipelines, the need for more streamlined and automated infrastructure management has grown. IfC addresses this need by making infrastructure provisioning a more integrated part of the development process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724841974978/04064d92-f7ea-4060-b9c7-7c0b535abc93.jpeg" alt="Garner Report :- https://www.gartner.com/en/documents/5519995" class="image--center mx-auto" /></p>
<p>refer - <a target="_blank" href="https://www.gartner.com/en/documents/5519995">https://www.gartner.com/en/documents/5519995</a></p>
<ol>
<li><p><strong>Automation and Efficiency</strong>: Developers and operations teams are always looking for ways to reduce manual effort and increase efficiency. IfC automates the infrastructure provisioning process directly from the application code, reducing the need for separate infrastructure scripts.</p>
</li>
<li><p><strong>Tight Integration</strong>: As applications become more complex, there's a growing need for infrastructure that is tightly integrated with the application itself. IfC ensures that the infrastructure is directly aligned with the codebase, reducing issues related to infrastructure drift and misconfiguration.</p>
</li>
<li><p><strong>Context Aware</strong>: Based on the code requirements and available cloud resources, infrastructure is provisioned with security and application requirements covered. </p>
</li>
<li><p><strong>Serverless and Microservices</strong>: These architectures naturally lend themselves to Infrastructure from Code. In serverless, for instance, the boundaries between application code and infrastructure are often blurred. IfC fits well in these environments by allowing infrastructure to be defined and provisioned in a way that is tightly coupled with the application logic.</p>
</li>
<li><p><strong>Tooling and Ecosystem</strong>: The trend is supported by new tools and frameworks that enable Infrastructure from Code. These tools are becoming more sophisticated, allowing for more complex infrastructure to be automatically generated from code. Examples include <a target="_blank" href="http://StackGen.com"><code>StackGen</code></a>, AWS CDK (Cloud Development Kit) and Pulumi, which enable developers to define cloud infrastructure using familiar programming languages.</p>
</li>
<li><p><strong>DevOps and GitOps</strong>: As DevOps practices evolve, there is a push towards making all aspects of development and operations code-centric. GitOps, for instance, emphasizes the use of Git as the single source of truth for both application code and infrastructure. IfC aligns with this philosophy by embedding infrastructure definitions within the application code itself.</p>
</li>
</ol>
<p>Infrastructure from Code is indeed a new trend, driven by the need for more efficient, integrated, and automated infrastructure management in modern cloud-native development environments. It represents a natural evolution of DevOps practices, pushing towards even tighter integration between code and infrastructure with security best practices included by default.</p>
]]></content:encoded></item><item><title><![CDATA[Dockerizing Golang CLI Tool - A Step-by-Step Guide]]></title><description><![CDATA[Introduction
In the ever-evolving landscape of software development, where rapid deployment and seamless scalability are key, Docker has emerged as a game-changer. Whether you're a seasoned developer or just starting your journey into the world of co...]]></description><link>https://blog.cloudnativefolks.org/dockerizing-golang-cli-tool-a-step-by-step-guide</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/dockerizing-golang-cli-tool-a-step-by-step-guide</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Docker]]></category><category><![CDATA[cli]]></category><category><![CDATA[cobra-cli]]></category><dc:creator><![CDATA[Siddhesh Khandagale]]></dc:creator><pubDate>Fri, 22 Sep 2023 18:30:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695394279379/c065214f-b42d-4ea0-b0c5-fd020fc4faee.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In the ever-evolving landscape of software development, where rapid deployment and seamless scalability are key, Docker has emerged as a game-changer. Whether you're a seasoned developer or just starting your journey into the world of containers, understanding Docker's core concepts and practical applications can significantly boost your development workflow.</p>
<p>This blog post aims to demystify Docker and guide you through the process of Dockerizing your Golang Command Line Interface (CLI) tool. We'll start from the ground up, covering Docker's fundamental principles, and then seamlessly transition into hands-on implementation. By the end of this guide, you'll not only grasp the essentials of Docker but also have a Dockerized Golang CLI tool ready to conquer your development tasks.</p>
<p>So, whether you're looking to improve the reproducibility of your projects, simplify deployment, or just harness the power of containerization for your Golang applications, you're in the right place. Let's embark on this journey to explore Docker and elevate your development process.</p>
<h2 id="heading-understanding-docker">Understanding Docker</h2>
<p>In today's fast-paced world of software development, agility and reproducibility are paramount. This is where Docker comes into play. Docker is a powerful platform that simplifies the way you create, deploy, and run applications. In this section, we'll lay the foundation by exploring the fundamentals of Docker.</p>
<ol>
<li><h3 id="heading-what-is-docker">What is Docker?</h3>
<p> Docker is an open-source platform designed to automate the deployment of applications inside lightweight, portable containers. These containers are self-sufficient units that encapsulate everything an application needs to run, including code, runtime, libraries, and system tools. Think of Docker containers as standardized, consistent environments that can run seamlessly on any system that supports Docker.</p>
<h4 id="heading-key-advantages-of-docker">Key Advantages of Docker:</h4>
<ul>
<li><p><strong>Isolation:</strong> Containers provide process and file system isolation, allowing applications to run independently without interfering with each other.</p>
</li>
<li><p><strong>Portability:</strong> Docker containers are highly portable, making it easy to move applications across different environments, from development to production.</p>
</li>
<li><p><strong>Resource Efficiency:</strong> Containers share the host operating system's kernel, which results in minimal overhead and faster startup times compared to traditional virtual machines.</p>
</li>
<li><p><strong>Version Control:</strong> Docker allows you to version your containers and images, ensuring that your application behaves consistently across different stages of development and deployment.</p>
</li>
</ul>
</li>
</ol>
<ol>
<li><h3 id="heading-docker-components">Docker Components</h3>
<p> To better understand Docker, it's essential to be familiar with some of its components:</p>
<h4 id="heading-image">Image :</h4>
<ul>
<li><p><strong>Definition:</strong> An image is a lightweight, standalone, and executable package that includes everything needed to run a piece of software, including the code, runtime, libraries, and dependencies.</p>
</li>
<li><p><strong>Usage:</strong> Images serve as the blueprint for containers. When you run a container from an image, you're essentially starting an instance of that image.</p>
</li>
</ul>
</li>
</ol>
<h4 id="heading-container">Container :</h4>
<ul>
<li><p><strong>Definition:</strong> A container is a runnable instance of an image. It encapsulates the application and all its dependencies while providing isolation from the host system and other containers.</p>
</li>
<li><p><strong>Usage:</strong> Containers are where your applications execute. They are ephemeral, which means they can be created, started, stopped, and destroyed without affecting other containers or the host system.</p>
</li>
</ul>
<h4 id="heading-registry">Registry :</h4>
<ul>
<li><p><strong>Definition:</strong> A registry is a centralized repository for storing Docker images. The most well-known registry is <a target="_blank" href="https://hub.docker.com/search?q=">Docker Hub</a>, which hosts a vast collection of publicly available images.</p>
</li>
<li><p><strong>Usage:</strong> You can pull (download) and push (upload) Docker images to and from registries. This sharing of images enables collaboration and distribution of applications.</p>
</li>
</ul>
<ol>
<li><h3 id="heading-docker-vs-virtual-machines">Docker v/s Virtual Machines</h3>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695397463187/2a475e5d-cddf-49d5-a7da-860acc95da26.png" alt class="image--center mx-auto" /></p>
<p> Docker containers are often compared to virtual machines (VMs) because they both provide isolation. However, there are significant differences between the two:</p>
<h4 id="heading-docker-containers">Docker Containers :</h4>
<ul>
<li><p><strong>Lightweight:</strong> Containers share the host OS kernel, making them smaller in size and more resource-efficient.</p>
</li>
<li><p><strong>Faster Startup:</strong> Containers start quickly, often in seconds.</p>
</li>
<li><p><strong>Resource Sharing:</strong> Containers are efficient at sharing resources with the host and other containers.</p>
</li>
</ul>
</li>
</ol>
<h4 id="heading-virtual-machines">Virtual Machines :</h4>
<ul>
<li><p><strong>Heavier:</strong> VMs include a full OS, making them larger in size and resource-intensive.</p>
</li>
<li><p><strong>Slower Startup:</strong> VMs take longer to start, typically in minutes.</p>
</li>
<li><p><strong>Resource Overhead:</strong> VMs have more significant resource overhead due to running a full OS.</p>
</li>
</ul>
<p>    In summary, Docker containers offer a lightweight, efficient, and consistent way to package and run applications, making them an ideal choice for modern software development and deployment.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<ol>
<li><h3 id="heading-installing-docker-desktop">Installing Docker Desktop</h3>
<p> Now, you need to install the latest version of Docker Desktop. <em>(You can download it</em> <a target="_blank" href="https://docs.docker.com/desktop/install/windows-install/"><em>here</em></a><em>, do follow the steps given in it to start the Docker Desktop)</em>.</p>
</li>
<li><h3 id="heading-building-the-cli-tool">Building the CLI tool</h3>
<p> After installing the Docker Desktop, you need to have <a target="_blank" href="https://golang.org/">Golang</a> and <a target="_blank" href="https://cobra.dev/">Cobra cli</a> installed before building the CLI.</p>
<p> For installing Cobra-CLI you can go to <a target="_blank" href="https://cobra.dev/"><strong>Cobra</strong></a> or run <code>go install</code> <a target="_blank" href="http://github.com/spf13/cobra-cli@latest"><code>github.com/spf13/cobra-cli@latest</code></a> in the terminal.</p>
<p> After completing the Installation part to get started make a folder for eg. <code>go-docker-cli</code> , run the given command</p>
</li>
</ol>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> mod init github.com/Siddheshk02/<span class="hljs-keyword">go</span>-docker-cli
</code></pre>
<p>(<em>In place of</em> <code>Siddheshk02</code> <em>use the name in which your project directories are. Now the structure will look like this)</em></p>
<pre><code class="lang-go">Cobra-cli init
</code></pre>
<p>This command initializes the CLI and creates a <code>main.go</code> file along with <code>cmd</code> folder containing <code>root.go</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695119178615/663e496e-9875-4e98-8ec2-8af2429fcc44.png" alt class="image--center mx-auto" /></p>
<p>Now, we are going to build a simple Calculator CLI.</p>
<p>Let's add the commands for Addition, Subtraction, Multiplication and Division.</p>
<p>To add a new command run the following code,</p>
<pre><code class="lang-go">Cobra-cli add add <span class="hljs-comment">//adds an "add" command for addition</span>
Cobra-cli add subtract <span class="hljs-comment">//for subtraction</span>
Cobra-cli add multiply <span class="hljs-comment">//for multiplication</span>
Cobra-cli add divide <span class="hljs-comment">//for division</span>
</code></pre>
<p>Now, let's define flags for the two integer values we need to take for the arithmetic operations.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> cmd

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>

    <span class="hljs-string">"github.com/spf13/cobra"</span>
)

<span class="hljs-keyword">var</span> (
    num1, num2 <span class="hljs-keyword">int</span>
)

<span class="hljs-comment">// addCmd represents the add command</span>
<span class="hljs-keyword">var</span> addCmd = &amp;cobra.Command{
    Use:   <span class="hljs-string">"add"</span>,
    Short: <span class="hljs-string">"Addition of two integers"</span>,
    Run: <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(cmd *cobra.Command, args []<span class="hljs-keyword">string</span>)</span></span> {
        result := num1 + num2
        fmt.Printf(<span class="hljs-string">"Result of %d + %d = %d\n"</span>, num1, num2, result)
    },
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">init</span><span class="hljs-params">()</span></span> {
    rootCmd.AddCommand(addCmd)

    addCmd.Flags().IntVar(&amp;num1, <span class="hljs-string">"num1"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"First integer"</span>)
    addCmd.Flags().IntVar(&amp;num2, <span class="hljs-string">"num2"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"Second integer"</span>)
}
</code></pre>
<p>This is how the <code>add.go</code> file will look after updating. Similarly, update the <code>subtract.go</code> , <code>multiply.go</code> and <code>divide.go</code> .</p>
<p><code>subtract.go</code> :</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> subtractCmd = &amp;cobra.Command{
    Use:   <span class="hljs-string">"subtract"</span>,
    Short: <span class="hljs-string">"Subtraction of two integers"</span>,
    Run: <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(cmd *cobra.Command, args []<span class="hljs-keyword">string</span>)</span></span> {
        result := num1 - num2
        fmt.Printf(<span class="hljs-string">"Result of %d - %d = %d\n"</span>, num1, num2, result)
    },
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">init</span><span class="hljs-params">()</span></span> {
    rootCmd.AddCommand(subtractCmd)

    subtractCmd.Flags().IntVar(&amp;num1, <span class="hljs-string">"num1"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"First integer"</span>)
    subtractCmd.Flags().IntVar(&amp;num2, <span class="hljs-string">"num2"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"Second integer"</span>)
}
</code></pre>
<p><code>multiply.go</code> :</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> multiplyCmd = &amp;cobra.Command{
    Use:   <span class="hljs-string">"multiply"</span>,
    Short: <span class="hljs-string">"Multiplication of two integers"</span>,
    Run: <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(cmd *cobra.Command, args []<span class="hljs-keyword">string</span>)</span></span> {
        result := num1 * num2
        fmt.Printf(<span class="hljs-string">"Result of %d * %d = %d\n"</span>, num1, num2, result)
    },
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">init</span><span class="hljs-params">()</span></span> {
    rootCmd.AddCommand(multiplyCmd)

    multiplyCmd.Flags().IntVar(&amp;num1, <span class="hljs-string">"num1"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"First integer"</span>)
    multiplyCmd.Flags().IntVar(&amp;num2, <span class="hljs-string">"num2"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"Second integer"</span>)
}
</code></pre>
<p><code>divide.go</code> :</p>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> divideCmd = &amp;cobra.Command{
    Use:   <span class="hljs-string">"divide"</span>,
    Short: <span class="hljs-string">"Division of two integers"</span>,
    Run: <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(cmd *cobra.Command, args []<span class="hljs-keyword">string</span>)</span></span> {
        result := num1 / num2
        fmt.Printf(<span class="hljs-string">"Result of %d / %d = %d\n"</span>, num1, num2, result)
    },
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">init</span><span class="hljs-params">()</span></span> {
    rootCmd.AddCommand(divideCmd)

    divideCmd.Flags().IntVar(&amp;num1, <span class="hljs-string">"num1"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"First integer"</span>)
    divideCmd.Flags().IntVar(&amp;num2, <span class="hljs-string">"num2"</span>, <span class="hljs-number">0</span>, <span class="hljs-string">"Second integer"</span>)
}
</code></pre>
<p>Let's update the description for our CLI in the <code>root.go</code> , (update the rootCmd variable)</p>
<pre><code class="lang-dockerfile">var rootCmd = &amp;cobra.Command{
    Use:   <span class="hljs-string">"go-docker-cli"</span>,
    Short: <span class="hljs-string">"A Calculator CLI tool"</span>,
}
</code></pre>
<p>Now, Build and Run the CLI. Run the command <code>go build .</code> . This command compiles Go source code files in the current directory into an executable binary with the same name as the directory, allowing you to run the resulting program.</p>
<p>Run the CLI using the command <code>./go-docker-cli</code> , This will give the output as shown below.</p>
<pre><code class="lang-go">A Calculator CLI tool.

Usage:
  <span class="hljs-keyword">go</span>-docker-cli [command]

Available Commands:
  add         Addition of two integers
  completion  Generate the autocompletion script <span class="hljs-keyword">for</span> the specified shell
  divide      Division of two integers
  help        Help about any command
  multiply    Multiplication of two integers
  subtract    Subtraction of two integers

Flags:
  -h, --help     help <span class="hljs-keyword">for</span> <span class="hljs-keyword">go</span>-docker-cli
  -t, --toggle   Help message <span class="hljs-keyword">for</span> toggle

Use <span class="hljs-string">"go-docker-cli [command] --help"</span> <span class="hljs-keyword">for</span> more information about a command.
</code></pre>
<p>Try running the other commands, <code>./go-docker-cli add --num1 3 --num2 4</code> this will give the output as <code>Result of 3 + 4 = 7</code> . You can try other commands.</p>
<p>So, it's running and giving the results as expected :)</p>
<p>Now, let's delve into the steps for dockerizing our CLI app.</p>
<h2 id="heading-dockerizing-the-cli-tool">Dockerizing the CLI tool</h2>
<p>Dockerization involves packaging your application and its dependencies into a Docker container, ensuring consistent and reproducible execution across different environments.</p>
<ol>
<li><h3 id="heading-creating-the-dockerfile">Creating the Dockerfile</h3>
<p> The first step in Dockerizing your Golang CLI tool is to create a Dockerfile. This file contains instructions for building a Docker image that encapsulates your application. Let's create a basic Dockerfile for our CLI calculator:</p>
<pre><code class="lang-dockerfile"> <span class="hljs-comment"># Use an official Golang runtime as a parent image</span>
 <span class="hljs-keyword">FROM</span> golang:alpine

 <span class="hljs-comment"># Set the working directory inside the container</span>
 <span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

 <span class="hljs-comment"># Copy the local package files to the container's workspace</span>
 <span class="hljs-keyword">COPY</span><span class="bash"> . /app</span>

 <span class="hljs-comment"># Build the Go application inside the container</span>
 <span class="hljs-keyword">RUN</span><span class="bash"> go build -o go-docker-cli</span>

 <span class="hljs-comment"># Define the command to run your application</span>
 <span class="hljs-keyword">ENTRYPOINT</span><span class="bash"> [<span class="hljs-string">"./go-docker-cli"</span>]</span>
</code></pre>
<p> Explanation:</p>
<p> <code>FROM golang:alpine</code>: This states that Docker should start building your Docker image using the official Golang image that is based on Alpine Linux, a lightweight Linux distribution. This Golang image provides the base environment for building and running Go applications.</p>
<p> <code>WORKDIR /app</code> : Here, we set the working directory inside the container to <code>/app</code>. This means that any subsequent commands in the Dockerfile will be executed in the context of the <code>/app</code> directory within the container. It's like changing to a specific folder when you're working on a computer.</p>
<p> <code>COPY . /app</code> : This line copies the contents of your local directory (the directory where you have your Dockerfile and Golang code) into the <code>/app</code> directory inside the Docker container. It effectively transfers all your application files and code into the container's workspace.</p>
<p> <code>RUN go build -o go-docker-cli</code> : Here, we instruct Docker to run a command inside the container. Specifically, it tells Docker to execute the <code>go build</code> command, which compiles your Golang code into an executable binary. The <code>-o go-docker-cli</code> part specifies that the output binary should be named "go-docker-cli."</p>
<p> <code>ENTRYPOINT ["./go-docker-cli"]</code> : This line defines the entry point for your Docker container. When you run a container from this image, it will execute the specified command. In this case, it tells the container to run the "go-docker-cli" binary, which is the Golang application you compiled earlier.</p>
</li>
<li><h3 id="heading-building-the-docker-image">Building the Docker Image</h3>
<p> Now, let's build the Docker Image. Run the following command,</p>
<pre><code class="lang-dockerfile"> docker build -t siddheshk02/go-docker-cli:latest .
</code></pre>
<p> Here, <code>siddheshk02</code> is the username (use your username from the Docker Hub)</p>
<p> This command builds a Docker image from your Golang CLI tool's source code and Dockerfile. The <code>-t</code> flag tags your image with a name and version (in this case, "siddheshk02/go-docker-cli:latest"). The <code>.</code> at the end specifies that the Dockerfile is in the current directory. This step creates a container image ready for distribution.</p>
<p> Now, we'll push this Image to the Docker Hub. <em>(Docker Hub is a central registry for Docker containers, enabling users to store, share, and distribute container images, making it an essential resource for containerization and application deployment.)</em> Run the following command :</p>
<pre><code class="lang-dockerfile"> docker push siddheshk02/go-docker-cli:latest
</code></pre>
<p> After successfully building your Docker image, you can use this command to upload it to Docker Hub, a public registry for Docker images. By doing so, you make your Dockerized Golang CLI tool publicly accessible for anyone to download and use.</p>
<p> For pulling the Image from the Docker Hub the command is :</p>
<pre><code class="lang-dockerfile"> docker pull siddheshk02/go-docker-cli:latest
</code></pre>
</li>
<li><h3 id="heading-running-the-docker-container">Running the Docker Container</h3>
<p> Now to run the Image you've built, use the following command :</p>
<pre><code class="lang-dockerfile"> docker <span class="hljs-keyword">run</span><span class="bash"> go-docker-cli add --num1 2 --num2 4</span>
</code></pre>
<p> The specified subcommand "add" and accompanying flags "--num1" and "--num2" are passed to your Golang CLI tool inside the container. This step demonstrates how to execute your CLI tool within a containerized environment.</p>
<p> Similarly to Subtract, Multiply and Divide you just need to use <code>subtract</code>, <code>multiply</code> and <code>divide</code> is instead of <code>add</code> along with the "--num1" and "--num2".</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695397709460/f454d680-26e0-4705-b5ff-2ad627d7a668.avif" alt class="image--center mx-auto" /></p>
<p>In conclusion, this blog has walked you through the fundamentals of Docker and how to Dockerize your Golang CLI tool, facilitating consistent deployment across diverse environments. By following the steps outlined here, you've learned to build, share, and run your containerized application, empowering you to harness the power of Docker for seamless software distribution and execution.</p>
<p>The complete code for this tutorial is updated on <a target="_blank" href="https://github.com/Siddheshk02/go-docker-cli">GitHub</a>.</p>
<p>To get more information about Golang concepts and to stay updated on the Tutorials follow <a target="_blank" href="https://twitter.com/siddhesh1102"><strong>Siddhesh on Twitter</strong></a> and <a target="_blank" href="https://github.com/Siddheshk02"><strong>GitHub</strong></a>.</p>
<p>Until then <strong>Keep Learning, Keep Building 🚀🚀</strong></p>
]]></content:encoded></item><item><title><![CDATA[eBPF for Cybersecurity - Part 4]]></title><description><![CDATA[What is LSM?
The Linux Security Module is a framework that allows the kernel to support multiple security models simultaneously. It provides a way for security policies, such as access control or integrity checking, to be added to the kernel without ...]]></description><link>https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-4</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-4</guid><category><![CDATA[eBPF]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[Linux]]></category><category><![CDATA[linux kernel]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Fri, 19 May 2023 22:10:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683291337893/10c872a5-a21f-4bbf-af68-92e9aaebcf5b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-what-is-lsm">What is LSM?</h4>
<p>The Linux Security Module is a framework that allows the kernel to support multiple security models simultaneously. It provides a way for security policies, such as access control or integrity checking, to be added to the kernel without requiring modifications to the kernel itself.</p>
<p>LSM enables the kernel to enforce security policies based on the security attributes of various objects, such as files, processes, or network connections. Some examples of security modules that use the LSM framework include SELinux (Security-Enhanced Linux), AppArmor, and Smack.</p>
<p>The use of LSM makes it easier to develop and integrate security policies in the Linux kernel and provides a more flexible and extensible approach to enforcing security.</p>
<h4 id="heading-lsm-for-ebpf">LSM for eBPF</h4>
<p>The eBPF LSM provides a security model that is based on the eBPF bytecode, which is a flexible and extensible mechanism for processing and filtering network packets and system calls. The LSM for eBPF allows users to attach eBPF programs to specific security hooks in the kernel, enabling fine-grained control over the behaviour of the system.</p>
<p>The eBPF LSM can be used to enforce security policies related to networking, system calls, file access, and other system resources. For example, it can be used to filter network traffic based on specific criteria or to monitor and restrict the behaviour of user processes.</p>
<p>The LSM for eBPF is a powerful tool for enhancing the security of Linux systems, and it is gaining popularity among developers and security experts due to its flexibility and versatility.</p>
<h4 id="heading-lsm-hooks-and-documentation">LSM Hooks and Documentation</h4>
<p>all lsm hooks are documented here by categories</p>
<p><a target="_blank" href="https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hooks.h">https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hooks.h</a></p>
<p>Contain full parameter passes to hook</p>
<p><a target="_blank" href="https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hook_defs.h">https://elixir.bootlin.com/linux/latest/source/include/linux/lsm_hook_defs.h</a></p>
<p>hooks named different from caller</p>
<p><a target="_blank" href="https://elixir.bootlin.com/linux/latest/source/include/linux/security.h">https://elixir.bootlin.com/linux/latest/source/include/linux/security.h</a></p>
<h4 id="heading-lsm-bpf">LSM + BPF</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683546210121/5e3ed2e4-99b5-43c1-b60d-c1689f11296e.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-lsm-hooks">LSM hooks</h4>
<p>Linux Security Modules (LSM) are a set of kernel features that allow for the customization of the security policy of the Linux kernel. LSM hooks are points in the kernel where LSM modules can be inserted to intercept and modify system calls. EBPF is a technology that allows programs to be written in the form of bytecode that can be executed directly in the Linux kernel.</p>
<p>Monitoring and enforcement via LSM hooks EBPF is a technique that uses LSM hooks and EBPF to monitor and enforce security policies on a Linux system. This technique can be used to monitor and enforce a wide variety of security policies, including:</p>
<ul>
<li><p>File access</p>
</li>
<li><p>Network access</p>
</li>
<li><p>Process execution</p>
</li>
<li><p>System calls</p>
</li>
</ul>
<p>Monitoring and enforcement via LSM hooks eBPF is a powerful technique that can be used to improve the security of a Linux system. This technique is relatively new, but it is gaining popularity due to its flexibility and performance.</p>
<p>Here are some of the benefits of using monitoring and enforcement via LSM hooks EBPF:</p>
<ul>
<li><p>Flexibility: LSM hooks eBPF can be used to monitor and enforce a wide variety of security policies.</p>
</li>
<li><p>Performance: LSM hooks eBPF is a very efficient technique, and it does not have a significant impact on the performance of the system.</p>
</li>
<li><p>Scalability: LSM hooks eBPF can be used to monitor and enforce security policies on large systems.</p>
</li>
</ul>
<p>Here are some of the challenges of using monitoring and enforcement via LSM hooks EBPF:</p>
<ul>
<li><p>Complexity: LSM hooks eBPF is a complex technique, and it requires some knowledge of the Linux kernel.</p>
</li>
<li><p>Tooling: There are a limited number of tools available for developing and debugging LSM hooks EBPF programs.</p>
</li>
<li><p>Support: LSM hooks eBPF is a relatively new technique, and it is not yet widely supported by operating systems and security products.</p>
</li>
</ul>
<p>Overall, monitoring and enforcement via LSM hooks EBPF is a powerful technique that can be used to improve the security of a Linux system. This technique is relatively new, but it is gaining popularity due to its flexibility and performance.</p>
<h4 id="heading-what-can-an-lsm-program-do">What can an LSM program do?</h4>
<p>An LSM program can do a lot of things, but some of the most common things include:</p>
<ul>
<li><p>Auditing system calls: An LSM program can be used to audit system calls, which means that it can track what system calls are being made and by whom. This can be useful for troubleshooting security problems or for gathering information about how a system is being used.</p>
</li>
<li><p>Controlling access to files and directories: An LSM program can be used to control access to files and directories. This can be useful for preventing unauthorized users from accessing sensitive data.</p>
</li>
<li><p>Monitoring system activity: An LSM program can be used to monitor system activity, such as which processes are running, which files are being accessed, and which network connections are being made. This can be useful for detecting security problems or for gathering information about how a system is being used.</p>
</li>
<li><p>Enforcing security policies: An LSM program can be used to enforce security policies. This can be useful for preventing unauthorized users from accessing sensitive data or for preventing malicious software from running on a system.</p>
</li>
</ul>
<p>LSM programs are a powerful tool that can be used to improve the security of a Linux system. They are flexible and can be used to implement a wide variety of security policies.</p>
<h3 id="heading-introducing-ebpfguard"><strong>Introducing eBPFGuard</strong></h3>
<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/deepfence/ebpfguard">https://github.com/deepfence/ebpfguard</a></div>
<p> </p>
<h4 id="heading-clone-the-ebpfguard-repository">Clone the ebpfguard repository</h4>
<pre><code class="lang-bash">ubuntu@ip-172-31-56-217:~$ git <span class="hljs-built_in">clone</span> https://github.com/deepfence/ebpfguard
Cloning into <span class="hljs-string">'ebpfguard'</span>...
remote: Enumerating objects: 820, <span class="hljs-keyword">done</span>.
remote: Counting objects: 100% (147/147), <span class="hljs-keyword">done</span>.
remote: Compressing objects: 100% (100/100), <span class="hljs-keyword">done</span>.
remote: Total 820 (delta 61), reused 56 (delta 46), pack-reused 673
Receiving objects: 100% (820/820), 4.52 MiB | 25.14 MiB/s, <span class="hljs-keyword">done</span>.
Resolving deltas: 100% (398/398), <span class="hljs-keyword">done</span>.
</code></pre>
<h4 id="heading-update-llvm">update LLVM</h4>
<pre><code class="lang-bash">sudo apt-get install libllvm-15-ocaml-dev libllvm15 llvm-15 llvm-15-dev llvm-15-doc llvm-15-examples llvm-15-runtime
</code></pre>
<h4 id="heading-check-if-your-kernel-has-bpf-lsm-support">check if your kernel has BPF LSM support:</h4>
<pre><code class="lang-bash">$ cat /sys/kernel/security/lsm
lockdown,capability,landlock,yama,apparmor
</code></pre>
<p>in my case, it's not installed follow prerequisites</p>
<p><a target="_blank" href="https://github.com/deepfence/ebpfguard/blob/main/docs/gh/prerequisites.md">https://github.com/deepfence/ebpfguard/blob/main/docs/gh/prerequisites.md</a></p>
<p>updated bpf lsm</p>
<h4 id="heading-install-required-packages-and-tools">Install required packages and tools</h4>
<pre><code class="lang-bash">$ sudo apt-get update &amp;&amp; apt-get install -y --no-install-recommends \
    build-essential \
    clang \
    libclang-dev \
    linux-tools-$(uname -r)

$ curl --proto <span class="hljs-string">'=https'</span> --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ rustup target add x86_64-unknown-linux-musl
$ cargo install bindgen-cli
$ cargo install bpf-linker --git https://github.com/noboruma/bpf-linker
</code></pre>
<h4 id="heading-mount">mount</h4>
<p>The <a target="_blank" href="https://github.com/deepfence/ebpfguard/tree/main/examples/file_open">mount</a> example shows how to define a policy for <code>sb_mount</code>, <code>sb_remount</code> and <code>sb_umount</code> LSM hooks as Rust code. It denies the mount operations for all processes except for the optionally given one.</p>
<p>in following folder <code>examples/mount/examples/mount.rs</code></p>
<pre><code class="lang-bash">use std::{
    fs::{create_dir_all, remove_dir_all},
    path::PathBuf,
};

use clap::Parser;
use ebpfguard::{
    policy::{PolicySubject, SbMount, SbRemount, SbUmount},
    PolicyManager,
};
use <span class="hljs-built_in">log</span>::info;

<span class="hljs-comment">#[derive(Debug, Parser)]</span>
struct Opt {
    <span class="hljs-comment">#[clap(long, default_value = "/sys/fs/bpf")]</span>
    bpffs_path: PathBuf,
    <span class="hljs-comment">#[clap(long, default_value = "example_sb_mount")]</span>
    bpffs_dir: PathBuf,
    /// Binary <span class="hljs-built_in">which</span> should be allowed to mount filesystems.
    <span class="hljs-comment">#[clap(long)]</span>
    allow: Option&lt;PathBuf&gt;,
}

<span class="hljs-comment">#[tokio::main]</span>
async fn main() -&gt; anyhow::Result&lt;()&gt; {
    <span class="hljs-built_in">let</span> opt = Opt::parse();

    env_logger::init();

    // Create a directory <span class="hljs-built_in">where</span> ebpfguard policy manager can store its BPF
    // objects (maps).
    <span class="hljs-built_in">let</span> bpf_path = opt.bpffs_path.join(opt.bpffs_dir);
    create_dir_all(&amp;bpf_path)?;

    // Create a policy manager.
    <span class="hljs-built_in">let</span> mut policy_manager = PolicyManager::new(&amp;bpf_path)?;

    // Attach the policy manager to the mount LSM hooks.
    <span class="hljs-built_in">let</span> mut sb_mount = policy_manager.attach_sb_mount()?;
    <span class="hljs-built_in">let</span> mut sb_remount = policy_manager.attach_sb_remount()?;
    <span class="hljs-built_in">let</span> mut sb_umount = policy_manager.attach_sb_umount()?;

    // Get the receiver end of the alerts channel (<span class="hljs-keyword">for</span> the `file_open` LSM
    // hook).
    <span class="hljs-built_in">let</span> mut sb_mount_rx = sb_mount.alerts().await?;
    <span class="hljs-built_in">let</span> mut sb_remount_rx = sb_remount.alerts().await?;
    <span class="hljs-built_in">let</span> mut sb_umount_rx = sb_umount.alerts().await?;

    // Define policies <span class="hljs-built_in">which</span> deny mount operations <span class="hljs-keyword">for</span> all processes (except
    // <span class="hljs-keyword">for</span> the specified subject, <span class="hljs-keyword">if</span> defined).
    sb_mount
        .add_policy(SbMount {
            subject: PolicySubject::All,
            allow: <span class="hljs-literal">false</span>,
        })
        .await?;
    sb_remount
        .add_policy(SbRemount {
            subject: PolicySubject::All,
            allow: <span class="hljs-literal">false</span>,
        })
        .await?;
    sb_umount
        .add_policy(SbUmount {
            subject: PolicySubject::All,
            allow: <span class="hljs-literal">false</span>,
        })
        .await?;
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">let</span> Some(subject) = opt.allow {
        sb_mount
            .add_policy(SbMount {
                subject: PolicySubject::Binary(subject.clone()),
                allow: <span class="hljs-literal">true</span>,
            })
            .await?;
        sb_remount
            .add_policy(SbRemount {
                subject: PolicySubject::Binary(subject.clone()),
                allow: <span class="hljs-literal">true</span>,
            })
            .await?;
        sb_umount
            .add_policy(SbUmount {
                subject: PolicySubject::Binary(subject),
                allow: <span class="hljs-literal">true</span>,
            })
            .await?;
    }

    info!(<span class="hljs-string">"Waiting for Ctrl-C..."</span>);

    // Wait <span class="hljs-keyword">for</span> policy violation alerts (or <span class="hljs-keyword">for</span> CTRL+C).
    loop {
        tokio::select! {
            Some(alert) = sb_mount_rx.recv() =&gt; {
                info!(
                    <span class="hljs-string">"sb_mount: pid={} subject={}"</span>,
                    alert.pid,
                    alert.subject,
                );
            }
            Some(alert) = sb_remount_rx.recv() =&gt; {
                info!(
                    <span class="hljs-string">"sb_remount: pid={} subject={}"</span>,
                    alert.pid,
                    alert.subject,
                );
            }
            Some(alert) = sb_umount_rx.recv() =&gt; {
                info!(
                    <span class="hljs-string">"sb_umount: pid={} subject={}"</span>,
                    alert.pid,
                    alert.subject,
                );
            }
            _ = tokio::signal::ctrl_c() =&gt; {
                <span class="hljs-built_in">break</span>;
            }
        }
    }

    info!(<span class="hljs-string">"Exiting..."</span>);
    remove_dir_all(&amp;bpf_path)?;

    Ok(())
}
</code></pre>
<h4 id="heading-create-two-directory-inside-ebpfguard-repo">create two directory inside ebpfguard repo</h4>
<pre><code class="lang-bash">$ mkdir /tmp/test1
$ mkdir /tmp/test2
</code></pre>
<h4 id="heading-run-policy-program-without-binary">run policy program without binary</h4>
<pre><code class="lang-bash">~/ebpfguard$ RUST_LOG=info cargo xtask run --example mount
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.09s
     Running `target/x86_64-unknown-linux-musl/debug/xtask run --example mount`
       Fresh unicode-ident v1.0.8
       Fresh proc-macro2 v1.0.58
       Fresh libc v0.2.144
       Fresh quote v1.0.27
       Fresh syn v2.0.16
       Fresh bitflags v1.3.2
       Fresh io-lifetimes v1.0.10
       Fresh linux-raw-sys v0.3.7
       Fresh cfg-if v1.0.0
       Fresh rustix v0.37.19
       Fresh glob v0.3.1
       Fresh utf8parse v0.2.1
       Fresh anstyle-parse v0.2.0
       Fresh memchr v2.5.0
       Fresh is-terminal v0.4.7
       Fresh colorchoice v1.0.0
       Fresh anstyle v1.0.0
       Fresh minimal-lexical v0.2.1
       Fresh core v0.0.0 (/home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core)
       Fresh anstyle-query v1.0.0
       Fresh rustc-std-workspace-core v1.99.0 (/home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/rustc-std-workspace-core)
       Fresh anstream v0.3.2
       Fresh nom v7.1.3
       Fresh libloading v0.7.4
       Fresh either v1.8.1
       Fresh regex-syntax v0.7.1
       Fresh clap_lex v0.4.1
       Fresh heck v0.4.1
       Fresh strsim v0.10.0
       Fresh clap_derive v4.2.0
       Fresh clap_builder v4.2.7
       Fresh regex v1.8.1
       Fresh <span class="hljs-built_in">which</span> v4.4.0
       Fresh clang-sys v1.6.1
       Fresh cexpr v0.6.0
       Fresh <span class="hljs-built_in">log</span> v0.4.17
       Fresh compiler_builtins v0.1.91
       Fresh prettyplease v0.2.5
       Fresh thiserror-impl v1.0.40
       Fresh shlex v1.1.0
       Fresh once_cell v1.17.1
       Fresh peeking_take_while v0.1.2
       Fresh lazy_static v1.4.0
       Fresh lazycell v1.3.0
       Fresh fastrand v1.9.0
       Fresh rustc-hash v1.1.0
       Fresh tempfile v3.5.0
       Fresh bindgen v0.65.1
       Fresh clap v4.2.7
       Fresh thiserror v1.0.40
       Fresh anyhow v1.0.71
       Fresh rustversion v1.0.12
       Fresh aya-tool v0.1.0 (https://github.com/deepfence/aya-rs?branch=btf-fixes<span class="hljs-comment">#611950e7)</span>
       Fresh aya-bpf-cty v0.2.1 (https://github.com/deepfence/aya-rs?branch=btf-fixes<span class="hljs-comment">#611950e7)</span>
       Fresh aya-bpf-bindings v0.1.0 (https://github.com/deepfence/aya-rs?branch=btf-fixes<span class="hljs-comment">#611950e7)</span>
       Fresh aya-bpf-macros v0.1.0 (https://github.com/deepfence/aya-rs?branch=btf-fixes<span class="hljs-comment">#611950e7)</span>
       Fresh aya-bpf v0.1.0 (https://github.com/deepfence/aya-rs?branch=btf-fixes<span class="hljs-comment">#611950e7)</span>
       Fresh ebpfguard-common v0.1.0 (/home/ubuntu/ebpfguard/ebpfguard-common)
       Fresh ebpfguard-ebpf v0.1.0 (/home/ubuntu/ebpfguard/ebpfguard-ebpf)
    Finished dev [optimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.16s
   Compiling ebpfguard v0.1.0 (/home/ubuntu/ebpfguard/ebpfguard)
   Compiling mount v0.1.0 (/home/ubuntu/ebpfguard/examples/mount)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 6.68s
[2023-05-19T21:35:30Z INFO  mount] Waiting <span class="hljs-keyword">for</span> Ctrl-C...
</code></pre>
<h4 id="heading-open-new-terminal-bind-mount-the-directory-it-will-fail">open new terminal bind mount the directory it will fail</h4>
<pre><code class="lang-bash">$ sudo mount --<span class="hljs-built_in">bind</span> /tmp/test1 /tmp/test2
mount: /tmp/test2: permission denied.
</code></pre>
<p>check it out more example <a target="_blank" href="https://github.com/deepfence/ebpfguard/tree/main/examples">https://github.com/deepfence/ebpfguard/tree/main/examples</a></p>
<p>Reach out to me on Twitter <a target="_blank" href="https://twitter.com/sangamtwts">@sangamtwts</a></p>
<p>Thanks for reading! give a star to <a target="_blank" href="https://github.com/deepfence/ebpfguard/tree/main/examples">https://github.com/deepfence/ebpfguard</a> project !</p>
]]></content:encoded></item><item><title><![CDATA[Simplifying open-source contributions & Git-GitHub: A Practical Guide]]></title><description><![CDATA[In this blog, I'll be explaining Git-GitHub to the extent that is enough to do open-source contributions like a professional. I'll also demonstrate a straightforward approach to contributing, you can use this approach without a second thought for mos...]]></description><link>https://blog.cloudnativefolks.org/simplifying-open-source-contributions-git-github-a-practical-guide</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/simplifying-open-source-contributions-git-github-a-practical-guide</guid><category><![CDATA[Git]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[contribution to open source]]></category><category><![CDATA[version control]]></category><dc:creator><![CDATA[Ayush Tripathi]]></dc:creator><pubDate>Tue, 09 May 2023 15:22:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683645714391/01e9516a-cc2a-4b5c-abc5-747098b053e8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog, I'll be explaining Git-GitHub to the extent that is enough to do open-source contributions like a professional. I'll also demonstrate a straightforward approach to contributing, you can use this approach without a second thought for most of your contributions.</p>
<p>Open source refers to software whose source code is freely available to the public and can be modified, studied, and distributed by anyone. Open-source software is often created collaboratively by a community of developers who share their work and contribute to the improvement of the software.</p>
<h3 id="heading-why-contribute-to-open-source">Why contribute to Open Source?</h3>
<ol>
<li><p>Open source is the future, day by day we see more and more freely available open-source software (Hashnode being one of them) coming to the tech world.</p>
</li>
<li><p>You get to connect with a lot of folks, work and learn under their guidance.</p>
</li>
<li><p>It opens the doorway to remote jobs where you can work at your leisure.</p>
</li>
</ol>
<p>Let us start with the basics (If you are familiar with the basics, feel free to jump to the last section)</p>
<h3 id="heading-what-is-git"><strong>What is Git?</strong></h3>
<ol>
<li><p>Git is a VCS (Version Control System) used to track changes in a repository (repo) or folder.</p>
</li>
<li><p>Both code and non-code (documentation) changes are tracked using Git.</p>
</li>
<li><p>Git is used to collaborate on code (multiple developers working on the same code).<br /> When you make a change in your project, you won't have to send the files to all the team members, just send a PR. (Pull Request)</p>
</li>
</ol>
<h3 id="heading-what-is-github"><strong>What is GitHub?</strong></h3>
<ol>
<li><p>GitHub is a web-based platform for hosting and managing Git repositories. It provides developers with a centralized location to store and manage their code, collaborate with others, and track changes over time.</p>
</li>
<li><p>It is like Google Drive for all your code with collaboration features :)</p>
</li>
</ol>
<h3 id="heading-installation">Installation</h3>
<ol>
<li><p>Go to this link: <a target="_blank" href="https://git-scm.com/downloads">Git download</a></p>
</li>
<li><p>Download the version as per your system and install it.</p>
</li>
<li><p>Make sure to go with the recommended options.</p>
</li>
<li><p>Lastly, make sure the path in the system is enabled for all terminals (even 3rd party) and not just Git Bash.</p>
</li>
</ol>
<p><img src="https://cdn.nerdschalk.com/wp-content/uploads/2021/09/win-11-install-git-11.png?width=800" alt="How to Install and Use Git on Windows 11" class="image--center mx-auto" /></p>
<p><strong>Verifying installation</strong></p>
<pre><code class="lang-bash">git --version
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683477666217/0c7d7762-0162-4ad5-a911-4ec521e93569.png" alt class="image--center mx-auto" /></p>
<p>This command shows the version of Git installed on your system. Next, you can go around exploring Git using by writing just "git" or ''git --help'</p>
<pre><code class="lang-bash">git 
git --<span class="hljs-built_in">help</span>
</code></pre>
<h3 id="heading-configuring-git-for-the-first-time">Configuring Git for the first time</h3>
<pre><code class="lang-bash">git config --global user.name “&lt;Enter your username here&gt;”
git config --global user.email “&lt;Enter your email here&gt;”
</code></pre>
<h3 id="heading-fork-andamp-pull-request">Fork &amp; Pull Request</h3>
<p>The forked repo is the clone of the main repo that you want to contribute into. It is the copy of the main repo, it is made to ensure that the main code is not directly affected.<br />Any change made in the forked repo does not affect the main repo. When you make a change in your forked repo by pushing the changes (sending the changes) you get the option of creating a Pull Request.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683301241336/61d19f25-bcfa-4a11-a32d-7c8f04faa9ad.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683301460522/bccd497e-4253-45b0-b0b8-c4b4336c0149.png" alt class="image--center mx-auto" /></p>
<p>Pull Request is the request you send to the maintainer or owner of the main repo to merge your code in their codebase. The name “pull request” comes from the idea that you're requesting the project to “pull” changes from your fork.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683305647818/c2730bbc-4b6d-4d37-a84b-903e488077c5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-basic-git-commands-and-features">Basic Git commands and features</h3>
<p><strong>git init:</strong> To initialize an empty git repository on your local system.<br />This means that every change in the folder in which this command is executed will be tracked by git.</p>
<pre><code class="lang-bash">git init
</code></pre>
<p><strong>git remote:</strong> To check and manipulate the URLs associated with the repository.<br />URLs mean the GitHub repo link that you need to collaborate on.<br />git remote specifies the names of the URLs associated with the git local repo.<br />git remote -v is the verbose version of this, that is, it shows the names of the URLs along with the URLs. (output attached in last section)</p>
<pre><code class="lang-bash">git remote
git remote -v
</code></pre>
<p><strong>git remote add &lt;url-name&gt;:</strong> To add a remote URL. The URL name can be anything, but the standard convention is to name the forked repo URL "origin" and the main repo URL "upstream".<br /><strong>git remote rm &lt;url-name&gt;:</strong> To remove a URL from the list of remote URLs for a repo.</p>
<p>A local git repo can have any number of remote URLs, just make sure that names are unique.<br />Remote URLs are nothing but GitHub repo links.</p>
<pre><code class="lang-bash">git remote add &lt;url-name&gt; &lt;url&gt;
git remote rm &lt;url-name&gt;
</code></pre>
<p><strong>git branch:</strong> To check which branch is currently active. All the changes done in one branch are associated with that branch only and do not have any effect on any other branch.</p>
<pre><code class="lang-bash">git branch
</code></pre>
<p><strong>git branch &lt;branch-name&gt;:</strong> To create a new branch.</p>
<pre><code class="lang-bash">git branch &lt;branch-name&gt;
</code></pre>
<p><strong>git checkout &lt;branch-name&gt;:</strong> To change the current working directory. (to move to a different branch)</p>
<pre><code class="lang-bash">git checkout &lt;branch-name&gt;
</code></pre>
<p><strong>git checkout -b &lt;branch-name&gt;:</strong> This is a shortcut to create and move to the branch in just one command.</p>
<pre><code class="lang-bash">git checkout -b &lt;branch-name&gt;
</code></pre>
<p><strong>git status:</strong> To check the status and changes in the working directory. (any and every change in the repo is tracked, but this command shows the changes associated only with the current branch)</p>
<pre><code class="lang-bash">git status
</code></pre>
<p><strong>git add:</strong> Adding the changes / staging the changes.</p>
<p>In Git, there is a concept of a staging area and working directory.</p>
<p><strong>Working directory</strong> - the directory/folder of the current branch constitutes the working directory, the WD is different for different branches. It means that every branch has different files because every branch is used to develop a different feature without any over-ridding of any other branch.</p>
<p><strong>Staging area</strong> - Here we don't make any changes, it is automatically handled by Git, a file is said to be in the staging area when it is added to it using the git add command.</p>
<pre><code class="lang-bash">git add &lt;file-name&gt;
git add .
</code></pre>
<p><strong>git commit:</strong> Committing the changes with a custom message. This creates a commit for all the files added previously using git add.</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"commit-message"</span>
</code></pre>
<p><strong>git push:</strong> Pushing the changes to the repo.<br />Remember, only one PR (Pull Request) is associated with one branch. So, if you push another change through the same branch before merging of PR, it will just get added to the same PR.</p>
<pre><code class="lang-bash">git push &lt;remote-url&gt; &lt;branch&gt;
</code></pre>
<p>If you are the maintainer then no Pull Request is required but in the case of collaborators a <strong>PR or Pull Request</strong> needs to be sent to the main repo from your forked repo.</p>
<p><strong>git merge:</strong> To merge any branch with any other branch. This is generally used to merge any other branch with the main branch.</p>
<pre><code class="lang-bash">git merge &lt;branch-name&gt;
</code></pre>
<p><strong>git log:</strong> To check the commit history of the working directory of the current branch.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">log</span>
</code></pre>
<p>Rolling back to previous versions is one of the most important features of a VCS. In the case of Git, this can be done in many ways: git reset, git revert, etc. But to keep the process simple and easy to understand I'll stick to git reset.</p>
<p><strong>git reset:</strong> To move to any previous commit from the history.<br />There are two types of reset - hard and soft, but for simplicity purposes, just use the command as written. You will eventually have to learn the advanced commands as per your needs.</p>
<p>There is also a command known as <strong>git revert</strong>, now this command is the same as git reset with the only difference being that it created a new commit to go back to any commit. For a straightforward approach, let's stick with <strong>git reset</strong>.</p>
<pre><code class="lang-bash">git reset &lt;commit-id&gt;
</code></pre>
<p><strong>git clone:</strong> To create a copy of the fork that you have created of any GitHub repository on your local system.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> &lt;repo-url&gt;
</code></pre>
<p><strong>git pull &lt;remote-url&gt; &lt;branch-name&gt;:</strong> To pull the changes in the upstream GitHub repository onto your local system.</p>
<p>If multiple developers are working on a project, it generally happens that before you submit your PR some other developer's PR is already merged and the entire codebase is updated on GitHub. So, it is advisable to pull changes onto your local system and forked repo from time to time. It is especially important before submitting a new PR.</p>
<pre><code class="lang-bash">git pull &lt;remote-url&gt; &lt;branch-name&gt;
</code></pre>
<p><strong>git stash:</strong> To stash all changes which were being tracked by Git. This rolls back the entire branch to the way it was before any change was done (Note: doesn't rollback a commit)</p>
<p><strong>git stash pop:</strong> To bring back the changes saved in the stash.</p>
<p><strong>git stash drop:</strong> To delete the stash files and changes.</p>
<p>For example, you were working on a feature but due to time constraints have to work on some other feature, so you just stash the changes and after completing the required work you pop the stash back and continue your work.</p>
<pre><code class="lang-bash">git stash 
git stash pop
git stash drop
</code></pre>
<h3 id="heading-possible-roles-in-open-source">Possible Roles in Open-Source</h3>
<p>There are three roles possible - <strong>Owner, Maintainer and Collaborator</strong>.<br /><strong>Owner</strong> - In this role, you are the one who has created the repo and is responsible for maintaining it.</p>
<p><strong>Maintainer</strong> - This role is found in projects which are considerably large and cannot be maintained by a single developer. Maintainers have certain admin rights given to them by the owner and they make sure that the codebase doesn't break.</p>
<p><strong>Collaborator</strong> - In this role, you have forked (explained ahead) the repo for collaboration purposes and are responsible for pushing changes to the code.<br />(For open-source contributions, you are the collaborator or contributor)</p>
<h3 id="heading-approach-for-open-source-contributions">Approach for open-source contributions</h3>
<p>1. <strong>Fork</strong> the repo you want to contribute in</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683301241336/61d19f25-bcfa-4a11-a32d-7c8f04faa9ad.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683301460522/bccd497e-4253-45b0-b0b8-c4b4336c0149.png" alt class="image--center mx-auto" /></p>
<p>This is the forked repository, the top-left corner shows the "forked from" repo.<br />2. <strong>git clone</strong> (init is included)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683302091081/005d0eba-837c-42cd-a06c-f8301485af8d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683302146277/0ea73319-eb11-4192-b190-e2c83d288cfc.png" alt class="image--center mx-auto" /></p>
<p>3. <strong>git branch</strong> (never make changes on the main branch)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683302455213/33ff7ede-696a-44d7-bc9d-0f77250706a0.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683302902347/0a89e03d-83eb-4257-90ac-41add1f9ad6f.png" alt class="image--center mx-auto" /></p>
<p>Creating a new branch and then moving to that branch.</p>
<p>4. Add the required <strong>remote URLs</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683304185954/4bbf6f5d-7210-4361-b2e7-e739f72f7dcd.png" alt class="image--center mx-auto" /></p>
<p>5. <strong>git pull</strong> (always make sure your local repo is up to date with the main repo)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683304444820/3d9a664f-5d5d-458a-ae93-f3873028bfe5.png" alt class="image--center mx-auto" /></p>
<p>6. <strong>git ACP - add, commit, push</strong> (make changes / create new feature)</p>
<p>First, make some changes / Add a feature.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683304540203/26aee2b9-cfc2-4ed6-b59f-dde9282f3408.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683304623247/3b1d8193-f44d-447f-ba5d-1775029e5682.png" alt class="image--center mx-auto" /></p>
<p>You can make changes in a branch and merge (git merge) it with the main branch then push the main branch instead as well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683304859180/04799d3e-9641-4e6a-b2a3-f3ede63b1fb4.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683306052568/92c9020f-980f-4c19-9a92-516a7048bccb.png" alt class="image--center mx-auto" /></p>
<p>7. <strong>Opening a PR</strong></p>
<p>Go to the GitHub page of your forked repository.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683304971011/d7d85329-035a-40b5-abd9-255d7cb40209.png" alt class="image--center mx-auto" /></p>
<p>Click on "Compare and pull request" -&gt; "Create pull request"</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683305053564/e0d62448-95f2-4859-a49d-d040309632e5.png" alt class="image--center mx-auto" /></p>
<p>Now you can find your PR in the upstream repository. Then, wait for a comment from the maintainer or merge successful mail.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683305647818/c2730bbc-4b6d-4d37-a84b-903e488077c5.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683305765652/e3bc576e-7102-496e-8839-4601e705e861.png" alt class="image--center mx-auto" /></p>
<p>I have tried to simplify the entire Git-GitHub into a streamlined approach because a lot of developers get confused with multiple commands. As a beginner in open-source, you can follow this exact procedure without any second thoughts. Hope it helped you!</p>
<p>Connect with me on my socials: <a target="_blank" href="https://linktr.ee/ayusht02">https://linktr.ee/ayusht02</a></p>
]]></content:encoded></item><item><title><![CDATA[Caching in Golang]]></title><description><![CDATA[Introduction
Caching is an important technique used in web development to improve the performance of applications. It involves storing frequently accessed data in a temporary storage area, such as in-memory, to reduce the amount of time required to f...]]></description><link>https://blog.cloudnativefolks.org/caching-in-golang</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/caching-in-golang</guid><category><![CDATA[Go Language]]></category><category><![CDATA[go-fiber]]></category><category><![CDATA[Postman]]></category><category><![CDATA[caching]]></category><dc:creator><![CDATA[Siddhesh Khandagale]]></dc:creator><pubDate>Fri, 05 May 2023 11:18:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683285458002/18333471-0642-40ba-b70f-19bf6986bbf3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Caching is an important technique used in web development to improve the performance of applications. It involves storing frequently accessed data in a temporary storage area, such as in-memory, to reduce the amount of time required to fetch the data from its source.</p>
<p>There are different types of caching, including in-memory caching, database caching, and file-based caching. Each type has its advantages and disadvantages, and choosing the right one depends on the specific use case and the requirements of the application.</p>
<p>In-memory caching is one of the simplest and fastest caching methods available, making it a popular choice for many applications. It involves storing data in the memory of the server, making it quickly accessible to the application without the need for any external dependencies.</p>
<p>In this blog post, we will focus on in-memory caching in Golang and demonstrate its implementation using a simple API as an example. By the end of this blog, you'll have a solid understanding of in-memory caching works.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>To continue with the tutorial, firstly you need to have Golang and Fiber installed.</p>
<h3 id="heading-installations"><strong>Installations :</strong></h3>
<ul>
<li><p><a target="_blank" href="https://go.dev/doc/install"><strong>Golang</strong></a></p>
</li>
<li><p><a target="_blank" href="https://docs.gofiber.io/"><strong>Fiber</strong></a>: We'll see this ahead in the tutorial.</p>
</li>
</ul>
<h2 id="heading-getting-started"><strong>Getting Started 🚀</strong></h2>
<p>Let's get started by creating the main project directory <code>Go-Cache-API</code> by using the following command.</p>
<p>(🟥Be careful, sometimes I've done the explanation by commenting in the code)</p>
<pre><code class="lang-go">mkdir Go-Cache-API <span class="hljs-comment">//Creates a 'Go-Cache-API' directory</span>
cd Go-Cache-API <span class="hljs-comment">//Change directory to 'Go-Cache-API'</span>
</code></pre>
<p>Now initialize a mod file. <em>(If you publish a module, this must be a path from which your module can be downloaded by Go tools. That would be your code's repository.)</em></p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> mod init github.com/&lt;username&gt;/Go-Cache-API <span class="hljs-comment">//&lt;username&gt; is your github username</span>
</code></pre>
<p>To install the Fiber Framework run the following command :</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get -u github.com/gofiber/fiber/v2
</code></pre>
<p>For implementing the In-Memory Caching we are going to use <code>go-cache</code> , to install it run the following command :</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get github.com/patrickmn/<span class="hljs-keyword">go</span>-cache
</code></pre>
<p><code>go-cache</code> is an in-memory key: value store/cache similar to memcached that is suitable for applications running on a single machine.</p>
<p>Now, let's make the <code>main.go</code> in which we are going to define the routes.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"time"</span>
    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
    <span class="hljs-string">"github.com/Siddheshk02/Go-Cache-API/middleware"</span>
    <span class="hljs-string">"github.com/Siddheshk02/Go-Cache-API/routes"</span>
    <span class="hljs-string">"github.com/patrickmn/go-cache"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    app := fiber.New() <span class="hljs-comment">// Creating a new instance of Fiber.</span>

    <span class="hljs-comment">//cache := cache.New(10*time.Minute, 20*time.Minute) // setting default expiration time and clearance time.</span>

    app.Get(<span class="hljs-string">"/"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-keyword">return</span> c.SendString(<span class="hljs-string">"Hello, World 👋!"</span>)
    })
    <span class="hljs-comment">//app.Get("/posts/:id", middleware.CacheMiddleware(cache),   routes.GetPosts) //commenting this route just to test the "/" endpoint.</span>
    app.Listen(<span class="hljs-string">":8080"</span>)
}
</code></pre>
<p>In the <code>main.go</code> file, the first step is to initialize a new Fiber app using the <a target="_blank" href="http://fiber.New"><code>fiber.New</code></a><code>()</code> method. This creates a new instance of the Fiber framework that will handle the HTTP requests and responses.</p>
<p>We are going to use <a target="_blank" href="https://jsonplaceholder.typicode.com/">https://jsonplaceholder.typicode.com/</a> for fetching example data. We are going to fetch data from <code>/posts</code> endpoint. <a target="_blank" href="https://jsonplaceholder.typicode.com/">Jsonplaceholder</a> provides fake data for many other api endpoints you can try for any.</p>
<p>The <code>cache.New()</code> function takes two arguments:</p>
<ol>
<li><p>The first argument is the amount of time that a cache entry should live before it's automatically evicted. In this case, it's set to 10 minutes.</p>
</li>
<li><p>The second argument is the amount of time that a cache entry can remain idle (without being accessed) before it's automatically evicted. In this case, it's set to 20 minutes.</p>
</li>
</ol>
<p>After running the <code>go run main.go</code> command the terminal will look like this,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675596510246/7e6eedea-a46e-4477-baa0-77e48a6b89a7.png?auto=compress,format&amp;format=webp" alt class="image--center mx-auto" /></p>
<p>You can now uncomment all the code lines.</p>
<p>As you can see a middleware function is added to the <code>/posts</code> route. When a request is made to this endpoint, the server will first execute the <code>CacheMiddleware</code> function with a <code>cache</code> parameter. This middleware function is responsible for checking if the requested data is already cached and returning it from the cache instead of making a new API call. If the data is not present in the cache, the middleware function will pass the request to the next function in the middleware chain, which is <code>routes.GetPosts</code>.</p>
<p><code>routes.GetPosts</code> is a function that will be executed when the request reaches this point. This function will handle the request by making a GET request to the external API at <a target="_blank" href="https://jsonplaceholder.typicode.com/posts/:id"><code>https://jsonplaceholder.typicode.com/posts/:id</code></a> to fetch the post data. The <code>:id</code> part of the URL is a placeholder that will be replaced with the actual ID of the post being requested.</p>
<p>Let's define the <code>CacheMiddleware()</code> function for this, make a folder <code>middleware</code> in the main directory. In this make a file <code>cache.go</code>.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> middleware

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
    <span class="hljs-string">"github.com/patrickmn/go-cache"</span>
)

<span class="hljs-keyword">type</span> Post <span class="hljs-keyword">struct</span> {
    UserID <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"userId"`</span>
    ID     <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"id"`</span>
    Title  <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"title"`</span>
    Body   <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"body"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">CacheMiddleware</span><span class="hljs-params">(cache *cache.Cache)</span> <span class="hljs-title">fiber</span>.<span class="hljs-title">Handler</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-keyword">if</span> c.Method() != <span class="hljs-string">"GET"</span> {
            <span class="hljs-comment">// Only cache GET requests</span>
            <span class="hljs-keyword">return</span> c.Next()
        }

        cacheKey := c.Path() + <span class="hljs-string">"?"</span> + c.Params(<span class="hljs-string">"id"</span>) <span class="hljs-comment">// Generate a cache key from the request path and query parameters</span>

        <span class="hljs-comment">// Check if the response is already in the cache</span>
        <span class="hljs-keyword">if</span> cached, found := cache.Get(cacheKey); found {
            <span class="hljs-keyword">return</span> c.JSON(cached)
        }
        err := c.Next()
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> err
        }

        <span class="hljs-keyword">var</span> data Post
        cacheKey := c.Path() + <span class="hljs-string">"?"</span> + c.Params(<span class="hljs-string">"id"</span>)

        body := c.Response().Body()
        err = json.Unmarshal(body, &amp;data)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> c.JSON(fiber.Map{<span class="hljs-string">"error"</span>: err.Error()})
        }

        <span class="hljs-comment">// Cache the response for 10 minutes</span>
        cache.Set(cacheKey, data, <span class="hljs-number">10</span>*time.Minute)

        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }
}
</code></pre>
<p>The middleware function <code>CacheMiddleware</code> that takes a pointer to a <code>cache.Cache</code> object as an argument and return a <code>fiber.Handler</code> function.</p>
<p>The middleware function first checks if the HTTP method of the request is <code>GET</code>. If it is not a <code>GET</code> request, it simply passes the request to the next middleware function.</p>
<p>If it is a <code>GET</code> request, it generates a cache key by concatenating the request path and query parameters. It then checks if the response for that cache key is already present in the cache by using the <code>Get</code> method of the <code>cache.Cache</code> object. If the response is present in the cache, it returns the cached response using the <code>JSON</code> method of the <code>fiber.Ctx</code> object.</p>
<p>If the response is not present in the cache, it calls the next middleware function by using the <code>Next</code> method of the <code>fiber.Ctx</code> object. It then creates a new cache key by concatenating the request path and query parameters, and reads the response body using the <code>Response().Body()</code> method of the <code>fiber.Ctx</code> object. It then unmarshals the response body into a <code>Post</code> struct using the <code>json.Unmarshal</code> method.</p>
<p>If there is an error in unmarshaling the response body, it returns an error response using the <code>JSON</code> method of the <code>fiber.Ctx</code> object.</p>
<p>If there is no error, it caches the response for 10 minutes using the <code>Set</code> method of the <code>cache.Cache</code> object and returns <code>nil</code> to indicate that the middleware function has completed processing the request.</p>
<p>Now, let's define the <code>GetPosts()</code> function for this, make a folder <code>routes</code> in the main directory. In this make a file <code>routes.go</code>.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> routes

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"io/ioutil"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"net/http"</span>

    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
)

<span class="hljs-keyword">type</span> Post <span class="hljs-keyword">struct</span> {
    UserID <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"userId"`</span>
    ID     <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"id"`</span>
    Title  <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"title"`</span>
    Body   <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"body"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GetPosts</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    id := c.Params(<span class="hljs-string">"id"</span>) <span class="hljs-comment">// Get the post ID from the request URL parameters</span>
    <span class="hljs-keyword">if</span> id == <span class="hljs-string">""</span> {
        log.Fatal(<span class="hljs-string">"Invalid ID"</span>)
    }

    <span class="hljs-comment">// Fetch the post data from the API</span>
    resp, err := http.Get(<span class="hljs-string">"https://jsonplaceholder.typicode.com/posts/"</span> + id)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.JSON(fiber.Map{<span class="hljs-string">"error"</span>: err.Error()})
    }
    <span class="hljs-keyword">defer</span> resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.JSON(fiber.Map{<span class="hljs-string">"error"</span>: err.Error()})
    }

    <span class="hljs-keyword">var</span> data Post
    err = json.Unmarshal(body, &amp;data)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.JSON(fiber.Map{<span class="hljs-string">"error"</span>: err.Error()})
    }

    <span class="hljs-keyword">return</span> c.JSON(data)

}
</code></pre>
<p>This function first extracts the ID parameter from the URL using <code>c.Params("id")</code>. If the ID is not provided or is invalid, it logs a fatal error.</p>
<p>It then makes an HTTP <code>GET</code> request to the <a target="_blank" href="https://jsonplaceholder.typicode.com/posts/"><code>https://jsonplaceholder.typicode.com/posts/</code></a> API with the provided ID as the endpoint. It checks for any errors during the request and returns an error response if an error occurs.</p>
<p>The response body is then read using the <code>ioutil.ReadAll()</code> function and unmarshaled into a <code>Post</code> struct using <code>json.Unmarshal()</code>. If an error occurs during the unmarshaling, an error response is returned.</p>
<p>Finally, the function returns a JSON response with the <code>Post</code> data. this data is then stored in the cache by the <code>CacheMiddleware()</code> function.</p>
<p>Now, if we want to determine if the response is coming from the cache or the API server, we'll add a header to the response indicating whether the response was served from the cache or not. We'll add a custom header named <code>Cache-Status</code> and set its value to <code>HIT</code> or <code>MISS</code> depending on whether the response was served from the cache or not. So, the <code>CacheMiddleware()</code> function will look like :</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> middleware

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"time"</span>

    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
    <span class="hljs-string">"github.com/patrickmn/go-cache"</span>
)

<span class="hljs-keyword">type</span> Post <span class="hljs-keyword">struct</span> {
    UserID <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"userId"`</span>
    ID     <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"id"`</span>
    Title  <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"title"`</span>
    Body   <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"body"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">CacheMiddleware</span><span class="hljs-params">(cache *cache.Cache)</span> <span class="hljs-title">fiber</span>.<span class="hljs-title">Handler</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-keyword">if</span> c.Method() != <span class="hljs-string">"GET"</span> {
            <span class="hljs-comment">// Only cache GET requests</span>
            <span class="hljs-keyword">return</span> c.Next()
        }

        cacheKey := c.Path() + <span class="hljs-string">"?"</span> + c.Params(<span class="hljs-string">"id"</span>) <span class="hljs-comment">// Generate a cache key from the request path and query parameters</span>

        <span class="hljs-comment">// Check if the response is already in the cache</span>
        <span class="hljs-keyword">if</span> cached, found := cache.Get(cacheKey); found {
            c.Response().Header.Set(<span class="hljs-string">"Cache-Status"</span>, <span class="hljs-string">"HIT"</span>)
            <span class="hljs-keyword">return</span> c.JSON(cached)
        }

        c.Set(<span class="hljs-string">"Cache-Status"</span>, <span class="hljs-string">"MISS"</span>)
        err := c.Next()
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> err
        }

        <span class="hljs-keyword">var</span> data Post
        cacheKey := c.Path() + <span class="hljs-string">"?"</span> + c.Params(<span class="hljs-string">"id"</span>)

        body := c.Response().Body()
        err = json.Unmarshal(body, &amp;data)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> c.JSON(fiber.Map{<span class="hljs-string">"error"</span>: err.Error()})
        }

        <span class="hljs-comment">// Cache the response for 10 minutes</span>
        cache.Set(cacheKey, data, <span class="hljs-number">10</span>*time.Minute)

        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }
}
</code></pre>
<p>Let's test the API, run <code>go run main.go</code> in the terminal, after getting the same output as earlier, open any API testing tool for example <a target="_blank" href="https://www.postman.com/">Postman</a>.</p>
<p>Enter the URL : <code>http://127.0.0.1:8080/posts/1</code> then press enter.</p>
<p>Output :</p>
<pre><code class="lang-go">{
    <span class="hljs-string">"userId"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-string">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-string">"title"</span>: <span class="hljs-string">"sunt aut facere repellat provident occaecati excepturi optio reprehenderit"</span>,
    <span class="hljs-string">"body"</span>: <span class="hljs-string">"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"</span>
}
</code></pre>
<p>Now click on the Headers option, you can see <code>Cache-Status</code> : <code>MISS</code>. Press Enter again for the same ID and see the <code>Cache-Status</code>. Now it is changed to <code>HIT</code>. This shows that the second time when the same parameters were passed the response was sent through the cache.</p>
<p>This is the Basic implementation of In-Memory Caching in Golang.</p>
<h2 id="heading-conclusion"><strong>Conclusion ✨💯</strong></h2>
<p><img src="https://images.unsplash.com/photo-1603302576837-37561b2e2302?ixlib=rb-4.0.3&amp;ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTR8fGxhcHRvcHxlbnwwfHwwfHw%3D&amp;w=1000&amp;q=80" alt /></p>
<p>You can find the complete code repository for this tutorial here 👉<a target="_blank" href="https://github.com/Siddheshk02/Go-Cache-API"><strong>Github</strong></a>.</p>
<p>In Golang, you can implement caching using in-memory cache systems like the one we discussed in this blog post. By using a middleware function, you can easily integrate caching into your Golang web applications and reduce the response time for your users.</p>
<p>However, caching can also lead to stale data if not managed properly. It is important to consider the cache expiration time and update the cache whenever the underlying data changes.</p>
<p>Overall, caching can be a great addition to your web development toolkit, and I hope this blog post has provided a useful introduction to in-memory caching in Golang.</p>
<p>To get more information about Golang concepts, projects, etc. and to stay updated on the Tutorials do follow <a target="_blank" href="https://twitter.com/siddhesh1102"><strong>Siddhesh on Twitter</strong></a> and <a target="_blank" href="https://github.com/Siddheshk02"><strong>GitHub</strong></a>.</p>
<p>Until then <strong>Keep Learning, Keep Building 🚀🚀</strong></p>
]]></content:encoded></item><item><title><![CDATA[Build your first Docker Extension]]></title><description><![CDATA[TABLE OF CONTENTS :

Introduction to Docker Extensions.

Prerequisites.

Getting Started.

Building the Extension.

Installing the Extension in the Docker Desktop.

Updating and Rebuilding the Extension.

Open Chrome Dev Tools.

Validate your Extensi...]]></description><link>https://blog.cloudnativefolks.org/build-your-first-docker-extension</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/build-your-first-docker-extension</guid><category><![CDATA[cloud native]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Docker]]></category><category><![CDATA[DockerExtension]]></category><dc:creator><![CDATA[Shravani Kadam]]></dc:creator><pubDate>Mon, 10 Apr 2023 09:14:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681117945779/553eec42-a1cf-4e9b-bd40-1086f5fb5e0e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>TABLE OF CONTENTS :</strong></p>
<ul>
<li><p>Introduction to Docker Extensions.</p>
</li>
<li><p>Prerequisites.</p>
</li>
<li><p>Getting Started.</p>
</li>
<li><p>Building the Extension.</p>
</li>
<li><p>Installing the Extension in the Docker Desktop.</p>
</li>
<li><p>Updating and Rebuilding the Extension.</p>
</li>
<li><p>Open Chrome Dev Tools.</p>
</li>
<li><p>Validate your Extension.</p>
</li>
<li><p>Build the extensions for multiple architectures.</p>
</li>
</ul>
<h2 id="heading-introduction">Introduction:</h2>
<p>What are Docker Extensions?</p>
<ul>
<li><p>Docker Extensions are a way to add new functionality to the Docker Desktop Application.</p>
</li>
<li><p>Developers can easily integrate their preferred development tools into their application development and deployment workflows via extensions.</p>
</li>
<li><p>Communities, Partners, and Individuals can contribute to Docker Desktop by building and publishing their extensions.</p>
</li>
<li><p>It is a way to discover new tools to solve existing problems.</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites:</h2>
<p>To follow along with this tutorial, you'll need</p>
<ul>
<li>The <a target="_blank" href="https://www.docker.com/products/docker-desktop/">latest version</a> of Docker Desktop.</li>
</ul>
<p>Install the latest version of Docker Desktop.</p>
<h2 id="heading-getting-started">Getting Started!!</h2>
<p><strong>Create the extension file</strong></p>
<p>Type the following command in your CLI to create an extension file.</p>
<pre><code class="lang-plaintext">docker extension init my_extension
</code></pre>
<p>A few questions to set up your "my_extension" directory will be asked as you start with this command in your CLI.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681060932693/e557cf80-b9c9-42ad-b36c-d00e9ecc5d74.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-plaintext">cd my_extension
</code></pre>
<p><strong>You should be able to see these files in your directory ( I have opened the directory in my VS Code ) recommend you do the same.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681061427335/44621680-f91e-4e0c-81df-e76ff149a236.png" alt class="image--center mx-auto" /></p>
<p>Here, the <code>ui</code> folder contains a react application and the <code>backend</code> folder contains a Go backend service for the application.</p>
<p><code>Makefile</code> helps you run things locally, ensuring that the environment is exactly what it will be when you run it on your servers. On top of that, it removes the need to install every tool locally and instead allows you to simply run a docker command to have your application running.</p>
<p><code>Dockerfile</code> is a text file of instructions that are used <strong>to automate the</strong> installation and configuration of a Docker image.</p>
<p><code>Docker Compose.yaml</code> is used for <strong>running multiple containers as a single service</strong>. Each of the containers here runs in isolation but can interact with each other when required. With Compose, you use a <strong>YAML file</strong> to configure your application's services.</p>
<p><code>metadata.json</code> contains information about the extension.</p>
<h2 id="heading-building-the-extension">Building the Extension</h2>
<p>A docker extension is the Docker image, so first let's try to build the extension image.</p>
<pre><code class="lang-plaintext">docker build -t my/docker-extension:latest .
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681064722096/22ed1388-8d34-41a8-9c71-dcb1c56114ad.png" alt class="image--center mx-auto" /></p>
<p>Three steps of a multi-stage Dockerfile are offered while building our extension :</p>
<p>The first builds the <code>backend service</code>, the second the <code>React app</code>, and the third copies the <code>backend binaries</code> and the <code>React components</code>. The backend service is then launched with the CMD command, which uses a socket to watch for requests from the React app.</p>
<p><strong>To build the extension, use either</strong> <code>docker build</code> <strong>or the preset</strong> <code>make build-extension</code> <strong>command.</strong></p>
<h2 id="heading-installing-the-extension-in-the-docker-desktop">Installing the Extension in the Docker Desktop</h2>
<pre><code class="lang-plaintext">docker extension install my/docker-extension:latest
</code></pre>
<pre><code class="lang-plaintext">y
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681065256389/1ec8bc47-fe84-46cd-8daf-fd1e4cb7e96c.png" alt class="image--center mx-auto" /></p>
<p>Open your Docker Desktop application, you'll be able to see your Extension named <strong>My Extension</strong> as well as the container for the Extension.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681065476146/c1402ffe-860c-4e0c-9394-f03b88be1bfa.png" alt class="image--center mx-auto" /></p>
<p>Click on <strong>My Extension</strong></p>
<p>Your very first Extension is ready. Hurraayy!!!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681065545180/9f1af8a3-f397-4715-8a2d-9a19800d0f70.png" alt class="image--center mx-auto" /></p>
<p>Now click on the <strong>Call backend</strong> button and you'll be able to see the response from the Backend saying ''hello''.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681065702017/99b37fcf-b566-4775-93b4-108905fa2665.png" alt class="image--center mx-auto" /></p>
<p>We can check that the extension has been installed using the following CLI command</p>
<pre><code class="lang-plaintext">docker extension ls
</code></pre>
<p>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681068159937/3204def8-9ca7-482a-804b-29a50cdf6c6f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-updating-and-rebuilding-the-extension">Updating and Rebuilding the Extension</h2>
<p>Let's make minor changes to our Code</p>
<p>In the <strong>main.go</strong> file, we have made the changes in our message from <strong>"hello"</strong> to <strong>"hello, this is our First Extension!!!"</strong></p>
<p>Save the file.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681066159333/88074aa5-20d1-4461-b5ed-70638bce31f9.png" alt class="image--center mx-auto" /></p>
<p>In the <strong>App.tsx</strong> file,</p>
<p>We have added an Extension UI API (The extension UI API provides a way for the frontend to perform different actions and communicate with the Docker Desktop dashboard or the underlying system.)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681066544554/207e511d-b47b-47e3-bc85-95740f074636.png" alt class="image--center mx-auto" /></p>
<p>Toasts provide a brief notification to the user. They appear temporarily and shouldn’t interrupt the user experience. They also don’t require user input to disappear.</p>
<p>The <strong>Success!!!</strong> message will be displayed on the Docker Desktop Dashboard.</p>
<p>Visit <a target="_blank" href="https://docs.docker.com/desktop/extensions-sdk/dev/api/dashboard/">https://docs.docker.com/desktop/extensions-sdk/dev/api/dashboard/</a> for more such toast messages.</p>
<p>Let's build our application again in order to affect the changes that we made in our code.</p>
<pre><code class="lang-plaintext">docker build -t my/docker-extension:latest .
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681067032779/6b78ad87-e210-4967-8330-dea55aed44b8.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-note-after-building-your-application-you-cannot-try-to-install-it-again-with-the-same-command-you-used-to-install-your-application-for-the-first-time-as-it-will-throw-an-error-saying-the-application-is-already-installed">NOTE: After building your application you cannot try to install it again with the same command you used to install your application for the first time as it will throw an error saying the application is already installed.</h3>
<p>We need to update our extension :</p>
<pre><code class="lang-plaintext">docker extension update my/docker-extension:latest
</code></pre>
<pre><code class="lang-plaintext">y
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681067419961/1d660a9e-6e65-46f8-8c0a-bc9d95c51939.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681067602062/78cea00c-6f29-4f80-ba83-309266781cf8.png" alt class="image--center mx-auto" /></p>
<p>Congrats!! We have successfully updated our Extension...</p>
<h2 id="heading-open-chrome-dev-tools"><strong>Open Chrome Dev Tools</strong></h2>
<p>In order to open the Chrome Dev Tools for your extension when clicking on the extension tab, run:</p>
<p><code>docker extension dev debug my/docker-extension:latest</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681068476053/5c874c0c-b7ce-467e-8407-f809741b3e8d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681068491983/30262a9b-6899-4ec5-a2b6-243af68054be.png" alt class="image--center mx-auto" /></p>
<p>In order to stop the debug mode, use the following command:</p>
<pre><code class="lang-plaintext">docker extension dev reset my/docker-extension:latest
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681068638078/591f6db2-145b-4daf-a5de-f96debe58cf0.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-validate-your-extension">Validate your Extension</h2>
<p>Validate your extension before you share or publish it. Validating the extension ensures:</p>
<ul>
<li><p>That the extension is built with the image labels it requires to display correctly in the marketplace</p>
</li>
<li><p>That the extension installs and runs without problems</p>
</li>
<li><p>The validation checks if the extension’s <code>Dockerfile</code> specifies all the required labels and if the metadata file is valid against the JSON schema file.</p>
</li>
</ul>
<p>To validate your extension, run:</p>
<pre><code class="lang-plaintext">docker extension validate &lt;name-of-your-extension&gt;
</code></pre>
<p>If your extension is valid, you will receive the message as:</p>
<pre><code class="lang-plaintext">The extension image "name-of-your-extension" is valid
</code></pre>
<h2 id="heading-build-the-extensions-for-multiple-architectures"><strong>Build the extensions for multiple architectures</strong></h2>
<p><strong>Docker Desktop retrieves the extension image according to the user’s system architecture.</strong></p>
<p><strong>If the extension does not provide an image that matches the user’s system architecture, Docker Desktop is not able to install the extension. As a result, users can’t run the extension in Docker Desktop</strong>.</p>
<p>To build the extension for multiple architectures, use the following command</p>
<p>Here the username should be your <strong>docker hub</strong> username.</p>
<pre><code class="lang-plaintext">docker buildx build --push --platform linux/amd64,linux/arm64 --tag username/my-extension:0.0.1 .
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681114717882/e61c3066-2069-41da-a415-95a87115197a.png" alt class="image--center mx-auto" /></p>
<p><strong>TAKE A LOOK AT THE ERROR MESSAGE...</strong></p>
<p>The issue is that the default driver for docker(which is named docker) does not support multi-architecture builds.</p>
<p>Multi-architecture images are images that can be used on <strong>multiple platforms</strong>. For example, images that can run on <strong>Intel Macs(amd64)</strong> and <strong>M1 Macs (arm64)</strong>. You will find this useful, as most users of your images would use them on various platforms.</p>
<p>To solve this create a new builder, using a different driver like <code>docker-container</code> which supports multi-architecture builds.</p>
<h3 id="heading-steps-for-creating-your-custom-builder">STEPS FOR CREATING YOUR CUSTOM BUILDER</h3>
<ul>
<li><p>Create your custom builder by running</p>
<pre><code class="lang-plaintext">  docker buildx create --name mycustombuilder --driver docker-container --bootstrap
</code></pre>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681115290661/6b1fd530-c5c3-4592-a5ab-171956eca910.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Ask docker to use this new builder for future builds by running</p>
<pre><code class="lang-plaintext">  docker buildx use mycustombuilder
</code></pre>
</li>
<li><p>Inspect buildx to see if docker has indeed switched builders to the new one you asked it to use by running</p>
<pre><code class="lang-plaintext">  docker buildx inspect
</code></pre>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681115960153/66dfb591-2efc-4230-823d-109ba25fc551.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p>Good! Now you can build extension for multiple architectures by running the following command</p>
<p>DO NOT FORGET TO SPECIFY YOUR DOCKER HUB <strong>USERNAME</strong></p>
<pre><code class="lang-plaintext">docker buildx build --push --platform linux/amd64,linux/arm64 --tag username/my-extension:0.0.1 .
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681116591170/402b0b8f-6075-486c-ad34-79739d79ff96.png" alt class="image--center mx-auto" /></p>
<p>Once the build is complete, go to your docker hub account and check the newly pushed image in your repository</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681116724538/ff512e25-a931-45c5-a86a-68ab0bf43194.png" alt class="image--center mx-auto" /></p>
<p>Click on the Image which you pushed recently</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681116776103/becbb5eb-32e1-4cca-ac3b-597598185880.png" alt class="image--center mx-auto" /></p>
<p>We can now see that the image supports multi-architecture..</p>
<p><strong>THANK YOU FOR READING...</strong></p>
]]></content:encoded></item><item><title><![CDATA[Exploring the Features and Functionality of Traefik Yaegi]]></title><description><![CDATA[Why?
Well, I want to understand the project, so that I can get involved with it because it seems complex, at least at this point, Yes it does
I spent a reasonable amount of time learning Go, but I didn't harness it by building projects and contributi...]]></description><link>https://blog.cloudnativefolks.org/exploring-the-features-and-functionality-of-traefik-yaegi</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/exploring-the-features-and-functionality-of-traefik-yaegi</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[Traefik]]></category><category><![CDATA[interpreter]]></category><category><![CDATA[yaegi]]></category><dc:creator><![CDATA[Kiran Satya Raj]]></dc:creator><pubDate>Sun, 26 Feb 2023 13:07:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675229782771/03f7962b-b0e5-46bc-a5b6-8e5325aa1cc4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-why">Why?</h3>
<p>Well, I want to understand the project, so that I can get involved with it because it seems complex, at least at this point, Yes it does</p>
<p>I spent a reasonable amount of time learning Go, but I didn't harness it by building projects and contributing to open source projects, I believe this can help me understand Golang even better.</p>
<p>I'm unfamiliar with the terminology of the project, I don't understand the idea and why we have it.</p>
<h3 id="heading-how-to-use-yaegi-cli">How To Use Yaegi CLI</h3>
<h4 id="heading-installation-steps">Installation steps</h4>
<pre><code class="lang-bash"><span class="hljs-comment"># you may get permission denied error so it's better to execute it as sudo</span>
<span class="hljs-comment"># Output:</span>
$ sudo curl -sfL https://raw.githubusercontent.com/traefik/yaegi/master/install.sh | sudo bash -s -- -b <span class="hljs-variable">$GOPATH</span>/bin v0.9.0
traefik/yaegi info checking GitHub <span class="hljs-keyword">for</span> tag <span class="hljs-string">'v0.9.0'</span>
traefik/yaegi info found version: 0.9.0 <span class="hljs-keyword">for</span> v0.9.0/linux/amd64
traefik/yaegi info installed /bin/yaegi
</code></pre>
<blockquote>
<p>Despite being static and strongly typed, Go feels like a dynamic language. The standard library even provides the Go parser used by the compiler and the reflection system to interact dynamically with the runtime. So why not just take the last logical step and finally build a complete Go interpreter? - <a target="_blank" href="https://traefik.io/blog/announcing-yaegi-263a1e2d070a/">Announcing Yaegi</a></p>
</blockquote>
<ul>
<li><p>Here's an example of it, it's a simple program that prints the average of a slice of numbers, and I've added a new function that gives the median of that slice of ints, the code is pretty self-explanatory</p>
<p>  Sample code: <a target="_blank" href="https://go.dev/play/p/IkgziY-ZNvK">RUN</a></p>
<pre><code class="lang-bash">  <span class="hljs-comment"># Creating a go file</span>
  $ <span class="hljs-built_in">cd</span> 
  $ mkdir yaegi-test &amp;&amp; <span class="hljs-built_in">cd</span> yaegi-test
  $ code main.go 
  <span class="hljs-comment"># pasting the sample code given above and saving it(ctrl + s)</span>
  package main

  import <span class="hljs-string">"fmt"</span>

  var nums = []int{1, 2, 3, 4, 5}

  func <span class="hljs-function"><span class="hljs-title">main</span></span>() {
      sum := 0
      <span class="hljs-keyword">for</span> _, num := range nums {
          sum += num
      }
      average := float64(sum) / float64(len(nums))
      fmt.Println(<span class="hljs-string">"The average is"</span>, average)
  }
</code></pre>
<p>  output:</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># opening the terminal in vscode(ctrl + `)</span>
  $ go run main.go

  The average is 3
</code></pre>
<p>  <code>yaegi run main.go</code> interprets the program, and compiles at runtime, one way to check is to declare a variable and don't use it, and print a simple message</p>
<pre><code class="lang-go">  <span class="hljs-keyword">package</span> main

  <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-keyword">var</span> k <span class="hljs-keyword">int</span>
      <span class="hljs-built_in">println</span>(<span class="hljs-string">"Hello, 世界"</span>)
  }
</code></pre>
<pre><code class="lang-bash">  $ go run main.go
  <span class="hljs-comment"># command-line-arguments</span>
  ./main.go:4:6: k declared and not used
  $ yaegi run main.go
  Hello, 世界
</code></pre>
<p>  Note that, you need to have the file saved first before you run the interactive yaegi REPL on the program</p>
<p>  Now in the program's home directory, I'm executing this</p>
<p>  <code>yaegi run -i main.go</code></p>
<p>  <code>i</code> - the program runs and this flag starts a new interactive REPL within the program's context, any program we run within the reply belong to this interpreter context</p>
<p>  sample program: <a target="_blank" href="https://go.dev/play/p/IkgziY-ZNvK">RUN</a></p>
<pre><code class="lang-bash">  $ <span class="hljs-built_in">cd</span> yaegi-test
  $ yaegi run -i main.go
  The average is 3
  <span class="hljs-comment"># a new function within the context of main.go</span>
  &gt; func median(nums []int) float64 {
      sorted := make([]int, len(nums))
      copy(sorted, nums)
      sort.Ints(sorted)
      length := len(sorted)
      <span class="hljs-keyword">if</span> length%2 == 0 {
          <span class="hljs-built_in">return</span> float64(sorted[length/2]+sorted[(length/2)-1]) / 2.0
      }
      <span class="hljs-built_in">return</span> float64(sorted[length/2])
  }
  The average is 3
  <span class="hljs-comment"># this is the reflect value of function median</span>
  : 0xc0001bf5f0
  &gt; fmt.Println(<span class="hljs-string">"The median is"</span>, median(nums))
  The median is 3
  The average is 3
  : 16
</code></pre>
<p>  In interactive mode, the stdlib packages("sort" in this case) are pre-imported so that I can use them directly</p>
<p>  the code in REPL is evaluated and it returns a <a target="_blank" href="https://pkg.go.dev/reflect#Value"><code>reflect.value</code></a> , value interface reflects the type and value of the Go object, we'll see how we are comparing values using the <code>Interface()</code> method when we are using yaegi interpreter and evaluating code with <code>Eval()</code>method in its dynamic extension framework</p>
</li>
<li><p>so far I see yaegi CLI is for executing a standalone script within the program's context, when I specifically know the task I'm automating, I can experiment with the existing program and also be able to test the new functionality in the interactive shell</p>
</li>
<li><p>In the above context, I'm making changes in real-time(while it's executing) and performing operations on the existing data of the program</p>
</li>
</ul>
<h3 id="heading-yaegi-specs">Yaegi specs</h3>
<ul>
<li><p>The interpreter provides an interactive and dynamic way to run the code, I don't have to recompile the program each time I make a change, I can see the results immediately, and I am also able to test and debug individuals lines of code</p>
</li>
<li><p>Here I'm running the program or it can be a code snippet in an interactive shell on a command-line-interface(a REPL=Read-Eval-Print Loop) like the way we do with python(it's just an example)</p>
</li>
</ul>
<pre><code class="lang-python-repl">&gt; python
Python 3.10.7 (main, Dec 30 2022, 10:22:51) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
<span class="hljs-meta">&gt;&gt;&gt;</span> <span class="python">print(<span class="hljs-string">"Hello, world"</span>)</span>
Hello, world
<span class="hljs-meta">&gt;&gt;&gt;</span> <span class="python">name = <span class="hljs-string">"spike"</span></span>
<span class="hljs-meta">&gt;&gt;&gt;</span> <span class="python">print(name)</span>
spike
</code></pre>
<blockquote>
<p>Motivation</p>
<ul>
<li><p>Make Go programs extensible</p>
</li>
<li><p>Existing <a target="_blank" href="https://github.com/golang/go/wiki/Projects#virtual-machines-and-languages">script engines</a> less fit than Go itself</p>
</li>
<li><p>Unify scripting and implementation languages - <a target="_blank" href="https://www.youtube.com/watch?v=8kwRbjzPVBE"><strong>GoLab 2019 - Marc Vertes - YAEGI, Yet Another Elegant Go Interpreter</strong></a></p>
</li>
</ul>
</blockquote>
<ul>
<li>The dynamic nature of Go and its efficiency makes it a suitable language for scripting, an interpreter like yaegi puts up a solid point to consider it as a scripting engine and use Go for scripting</li>
</ul>
<h3 id="heading-yaegi-as-an-embedded-interpreter">Yaegi as an embedded interpreter</h3>
<pre><code class="lang-bash"><span class="hljs-comment"># command-line executable</span>
<span class="hljs-comment"># for adding the dependency package or upgrading it to latest version</span>
$ <span class="hljs-built_in">cd</span> yaegi-test
$ go mod init github.com/KiranSatyaRaj/yaegi-test
go: creating new go.mod: module github.com/KiranSatyaRaj/yaegi-test
$ go get -u github.com/traefik/yaegi/cmd/yaegi
go: added github.com/traefik/yaegi v0.15.0
$ go get -u github.com/traefik/yaegi/interp
</code></pre>
<pre><code class="lang-go"><span class="hljs-comment">// import path</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">"github.com/traefik/yaegi/interp"</span>
</code></pre>
<ul>
<li><p>Yaegi only relies on the go standard library and no external dependencies, the only API is New(), Use(), and Eval()</p>
</li>
<li><p>For creating customs scripts on the fly, yaegi as embedded interpreter cuts in, the program itself is less tightly integrated into the source code making it easier to modify and update it</p>
</li>
<li><p>Even though I'm executing the <code>go run</code> command each time I run it, the program isn't recompiled every time, it's being interpreted at runtime, we'll see that in action in this article itself</p>
</li>
</ul>
<h4 id="heading-new-method-to-create-a-new-interpreter-context">New() method to create a new interpreter context</h4>
<ul>
<li><p>New() is a part of the <a target="_blank" href="https://pkg.go.dev/github.com/traefik/yaegi/interp">yaegi interp library</a> which provides a complete Go interpreter, <code>interp.New()</code> method creates a new interpreter context and returns it</p>
</li>
<li><p>It takes <code>interp.Options{}</code> as input, <a target="_blank" href="https://pkg.go.dev/github.com/traefik/yaegi/interp#Options"><code>Options{}</code></a> is a custom type of interp package it's a struct type, and the values it holds are:</p>
<p>  <a target="_blank" href="https://go.dev/play/p/xq2NG81MCWe">Run</a></p>
<p>  Output:</p>
<pre><code class="lang-bash">  <span class="hljs-comment"># pasting code in given from RUN link and executing it</span>
  $ go run main.go 
  {GoPath: BuildTags:[] Stdin:&lt;nil&gt; Stdout:&lt;nil&gt; Stderr:&lt;nil&gt; Args:[] Env:[] SourcecodeFilesystem:&lt;nil&gt; Unrestricted:<span class="hljs-literal">false</span>}
</code></pre>
</li>
</ul>
<h4 id="heading-use-method-to-import-standard-library-packages-into-the-interpreter-context"><code>Use()</code> method to import standard library packages into the interpreter context</h4>
<p>It takes <code>stlib.Symbols</code> as input, here <code>Symbols</code> can be functions, variables, and data structures, the <code>Use()</code> method takes the binary representation of these symbols and makes them available for the code in the interpreter context, to simply put the standard library packages are imported natively as given in the import path</p>
<p>It throws an error if this isn't configured, we'll see this in action soon</p>
<h4 id="heading-eval-method-to-evaluate-the-code-in-the-interpreter-context"><code>Eval()</code> method to evaluate the code in the interpreter context</h4>
<p>It evaluates the source code</p>
<p>The Go code is represented as a string and taken as input, returns the result computed by the interpreter or else we get a non-nil error</p>
<p>Let's <a target="_blank" href="https://go.dev/play/p/n2RA-KeqYNd">RUN</a> this</p>
<p>output:</p>
<pre><code class="lang-bash">$ go run main.go
panic: 4:9: import <span class="hljs-string">"fmt"</span> error: unable to find <span class="hljs-built_in">source</span> related to: <span class="hljs-string">"fmt"</span>. Either the GOPATH environment variable, or the Interpreter.Options.GoPath needs to be <span class="hljs-built_in">set</span>

goroutine 1 [running]:
main.main()
    /tmp/sandbox4073505706/prog.go:22 +0x9a

Program exited.
</code></pre>
<p><a target="_blank" href="https://go.dev/play/p/BMVV8RhKYR-">RUN</a> with Use() method</p>
<pre><code class="lang-bash">$ go get -u github.com/traefik/yaegi/stdlib
</code></pre>
<pre><code class="lang-bash">import <span class="hljs-string">"github.com/traefik/yaegi/stdlib"</span>
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">$ go run main.go 
Hello Yaegi
</code></pre>
<p>This is a simple implementation of the embedded interpreter</p>
<h3 id="heading-yaegi-dynamic-extension-framework">Yaegi dynamic extension framework</h3>
<p>A dynamic function run from static code, what does that mean?</p>
<p>The code is being compiled at runtime, I'm not altering the behavior of the static code which is compiled ahead of runtime, and the code that's defined is only available within the interpreter context</p>
<p>i.Eval() returns a <a target="_blank" href="https://pkg.go.dev/reflect#Value"><code>reflect.value</code></a></p>
<p><a target="_blank" href="https://go.dev/play/p/g82aUAUJqZr">RUN</a></p>
<p>output:</p>
<pre><code class="lang-bash">$ go run main.go 
The median is 3
The average is 3
</code></pre>
<p>In the above code, the <code>v</code> stores the <code>reflect.value</code> which is the interface value to access the specific method providing a similar function signature as in <code>v.Interface().(func([]int) int)</code>, where we are comparing the value types with <code>Interface()</code> method, which was the <code>average</code> function</p>
<h2 id="heading-end-thoughts">End thoughts</h2>
<blockquote>
<p>The goal is to provide a Go dynamic interpreter embeddable, simple, secure and fast enough to be used as plugin engine</p>
<p>this is not a toy, it's for use in production - <a target="_blank" href="https://github.com/traefik/yaegi-talk/blob/master/GoLab-2019/30min-talk.slide#L59">GoLab-talk-slides</a></p>
</blockquote>
<ul>
<li>It aims to unify Go as the scripting language and these are simple implementations of yaegi, it's specifically for production use cases and faster development so I'm looking forward to using yaegi on projects with large codebases(more likely to use it on an open source project)</li>
</ul>
<p>So far I've tried my hands on the yaegi-CLI, yaegi as an embedded interpreter, and its dynamic-extension framework, and yet to be explored are its production use cases, architecture, security, and performance too, I need to understand them in detail</p>
<p>Do check this <a target="_blank" href="https://github.com/traefik/yaegi/discussions/1505">GitHub discussion</a>, the issues I faced and how it was resolved</p>
<p>A series on Traefik-Yaegi would be a good way of continuing it Thanks for staying till the end, I hope this helped you and I'll see you in the next one. HAPPY LEARNING</p>
]]></content:encoded></item><item><title><![CDATA[eBPF for Cybersecurity - Part 3]]></title><description><![CDATA[previously we learned the basics of Ebpf and How to use the BPF library for the Rust programming language here will see eBPF program attached to sys_enter_exeve tracepoint in the Linux kernel and is executed for each sys_execve syscall.
Unsafe Rust
f...]]></description><link>https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-3</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-3</guid><category><![CDATA[#cybersecurity]]></category><category><![CDATA[Rust]]></category><category><![CDATA[observability]]></category><category><![CDATA[Linux]]></category><category><![CDATA[epbf]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Wed, 22 Feb 2023 13:09:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676412064596/b518f3f1-2551-438f-80d1-7ca510f0283a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>previously we learned the basics of Ebpf and How to use the BPF library for the Rust programming language here will see eBPF program attached to <code>sys_enter_exeve</code> tracepoint in the Linux kernel and is executed for each <code>sys_execve</code> syscall.</p>
<h4 id="heading-unsafe-rust">Unsafe Rust</h4>
<p>for eBPF programs written using rust, it is often required to access Linux kernel data structure or call Linux kernel helper functions. Unsafe Rust is the glue that helps achieve this functionality</p>
<p>following are the two essential functionalities enabled by unsafe Rust concerning eBPF programs</p>
<ul>
<li><p>ability to dereference a raw memory pointer that points to Linux kernel data structure</p>
</li>
<li><p>ability to call a Linux kernel helper function implemented in C</p>
</li>
</ul>
<p>Unsafe code in Rust is enclosed in a code block or a function block marked with an unsafe keyword the best way to understand how unsafe rust enables an eBPF program to interface with the Linux kernel is via the following two simple programs</p>
<h4 id="heading-kernel-data-structure-access">Kernel Data Structure Access</h4>
<p>every eBPF program gets calked with context passes as an input parameter. The context is the kernel data structure pointer, its type depends on the eBPF program type. the memory referenced by the context can access only with unsafe Rust code</p>
<pre><code class="lang-bash">unsafe fn ptr_at&lt;T&gt;(ctx: &amp;Xdpcontext,offset: unsize)

-&gt; Result&lt;*const T ,()&gt; {

    <span class="hljs-built_in">let</span> start = ctx.data();
    <span class="hljs-built_in">let</span> end = ctx.data_end();
    <span class="hljs-built_in">let</span> len = mem::size_of::&lt;T&gt;();

  <span class="hljs-keyword">if</span> start + offset + len &gt; end {
    <span class="hljs-built_in">return</span> Err(());
  }  

  Ok((start + offser) as *const T)

}
</code></pre>
<p>In the code snippet above, the <code>ptr_at</code> the function used by an eBPF program of the type <code>BPF_PROG_TYPE_XDP</code> the function takes <code>ctx</code> as an input parameter, a reference to an object type <code>XdpContext</code> this reference represents a <code>C</code> struct variable of type <code>struct xdp_md</code> in the Linux kernel. The <code>xdp_md</code> data structure points to a region in memory where a network packet resides. the <code>start</code> and <code>end</code> variables store the starting and ending memory address for the packet, while <code>offset</code> represent an offset within the packet. <code>ptr_at</code> the function returns a pointer to a valid offset within the packet's memory representation</p>
<pre><code class="lang-bash">fn try_xdp_firewall(ctx: XdpContext) -&gt;
   Result&lt;u32, () &gt; {


    <span class="hljs-built_in">let</span> eth_type = u16::from_be(unsafe {
    *ptr_at(&amp;ctx, offset_of!(ethhdr,h_proto))?

    });

    <span class="hljs-keyword">if</span> eth_type != ETH_P_IP {

        <span class="hljs-built_in">return</span> Ok(XdpContext::XDP_PASS);
    }

    <span class="hljs-built_in">let</span> <span class="hljs-built_in">source</span> = u32::from_be(unsafe {
        *ptr_at(&amp;ctx, ETH_HDR_LEN + offset_of!(iphdr,saddr))?
    });
   <span class="hljs-keyword">if</span> blocked_ip(<span class="hljs-built_in">source</span>){

    <span class="hljs-built_in">return</span> Ok(xdp_action::XDP_DROP)
   }

   Ok(xdp_action::XDP_PASS)
   }
</code></pre>
<p>the <code>try_xdp_firewall</code> uses the <code>ptr_at</code> function to get the <code>EtherType</code> from the raw packet. if the packet encapsulated in the ethernet frame is an IP packet, the source IP is extracted using <code>ptr-at</code> function. if the source IP address is blocked the packet is dropped by return <code>XDP_DROP</code> action.</p>
<h4 id="heading-kernel-function-call">kernel Function call</h4>
<p>unsafe rust code also enables the calling of certain Linux kernel helper function from the eBPF programs. The kernel helper functions that the eBPF program is permitted to call are contingent on the type of the program</p>
<pre><code class="lang-bash">use aya_bpf::{

    programs::ProbeContext,

    helpers::bpf_ktime_get_ns, 
};

fn try_nfs_file_read(ctx:ProbeContext)

  - &gt; Result&lt;u32,u32&gt; {

    <span class="hljs-built_in">let</span> start_mount_ns = 

    unsafe { bpf_ktime_get_ns()};
    ok(0)
  }
</code></pre>
<p>In the code snippet above, <code>bpf_ktime_get_ns</code> is a Linux kernel helper function that returns the number of nanoseconds since boot time and is used to compute the time delta between events or as a timestamp in this example the <code>bpf_ktime_get_ns</code> the function is called to record the start time of the NFS file read encapsulating the helper function call in an unsafe block.</p>
<p>let's install lima with ubuntu</p>
<pre><code class="lang-bash">limactl start ubuntu-lts       
INFO[0000] Creating an instance <span class="hljs-string">"ubuntu-lts"</span> from template://default (Not from template://ubuntu-lts) 
WARN[0000] This form is deprecated. Use `limactl start --name=ubuntu-lts template://default` instead 
? Creating an instance <span class="hljs-string">"ubuntu-lts"</span> Proceed with the current configuration
INFO[0017] Attempting to download the image from <span class="hljs-string">"https://cloud-images.ubuntu.com/releases/22.10/release-20221201/ubuntu-22.10-server-cloudimg-arm64.img"</span>  digest=<span class="hljs-string">"sha256:9575dfe9f925ec251a933b88a38c5582a18e9d19495025ac01cb2e217e5f14ca"</span>
47.94 MiB / 664.62 MiB [--&gt;___________________________________] 7.21% 3.52 MiB/s
limactl shell ubuntu-lts
</code></pre>
<p>connect Lima to your Vscode</p>
<pre><code class="lang-bash">limactl show-ssh --format=config ubuntu-lts
Host lima-ubuntu-lts
  IdentityFile <span class="hljs-string">"/Users/sangambiradar/.lima/_config/user"</span>
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  NoHostAuthenticationForLocalhost yes
  GSSAPIAuthentication no
  PreferredAuthentications publickey
  Compression no
  BatchMode yes
  IdentitiesOnly yes
  Ciphers <span class="hljs-string">"^aes128-gcm@openssh.com,aes256-gcm@openssh.com"</span>
  User sangambiradar
  ControlMaster auto
  ControlPath <span class="hljs-string">"/Users/sangambiradar/.lima/ubuntu-lts/ssh.sock"</span>
  ControlPersist 5m
  Hostname 127.0.0.1
  Port 55305
</code></pre>
<p>we will see Trace Programs</p>
<ul>
<li><p>Kernel Proble(kprobe)</p>
</li>
<li><p>kernel Tracepoint</p>
</li>
<li><p>User Space Probe ( UProbe)</p>
</li>
<li><p>User Space Tracepoint</p>
</li>
</ul>
<h4 id="heading-kernel-probe-kprobe">Kernel Probe ( Kprobe)</h4>
<p>Linux kernel probes enable you to attach eBPF programs to kernel functions to gather information or modify the function’s behaviour. This section will provide examples of both.</p>
<pre><code class="lang-bash">$ cat /proc/kallsyms
</code></pre>
<p>There are some 300+ different system calls in the Linux kernel. Applications/workloads running in the user space interact with the kernel using syscalls. e.g. if an application wants to do something like access a file, communicate using a network or even find the time of day, it will have to ask the kernel to do it on the application's behalf via a syscall; hence by attaching these probes to syscalls we're able to judiciously monitor what applications are doing in the user space. A list of all kernel syscall identifiers for a kernel can be found in this file: <code>/proc/kallsyms</code>. Here is an excerpt:</p>
<pre><code class="lang-bash">0000000000000000 T vs_create
0000000000000000 T vfs_mkdir
0000000000000000 T vfs_mknod
0000000000000000 T vs link
0000000000000000 T vs unlink
0000000000000000 t path_openat
0000000000000000 T vs_rename
0000000000000000 T getname kernel
0000000000000000 T putname
0000000000000000 t getname_flags.part. O
0000000000000000 T getname flags
0000000000000000 T getname
</code></pre>
<p><a target="_blank" href="http://System.map"><strong>System.map</strong></a> <strong>file and /proc/kallsyms</strong></p>
<p><a target="_blank" href="http://System.map">System.map</a> file format: address type notation</p>
<p>The type is lowercase for local symbols, and uppercase for global (external).<br />Focus on several types:<br />T, The symbol is in the text(code) section<br />D The symbol is in the initialized data section<br />R The symbol is in a read-only data section<br />t static<br />d static<br />R const<br />r static const</p>
<p>For example, suppose you have a Rust object file named <code>hello.o</code> that contains a function named <code>hello</code>. You can use <code>nm</code> to list the symbols in this object file by running the following command:</p>
<pre><code class="lang-bash">$ nm hello.o
</code></pre>
<p>This will print a list of symbols in the <code>hello.o</code> object file, which might look something like this:</p>
<pre><code class="lang-bash">0000000000000000 T hello
                 U __libc_start_main
</code></pre>
<h4 id="heading-block-mount">Block Mount</h4>
<p>start of the <code>open_ctree</code> function call. The eBPF helper function <code>bpf_override_return</code> short circuits the open_ctree function execution by returning ENOMEM. This prevents the btrfs volume from being mounted.</p>
<pre><code class="lang-bash"><span class="hljs-comment">#![no_std]</span>
<span class="hljs-comment">#![no_main]</span>

use aya_bpf::{
    helpers::bpf_override_return, macros::kprobe,
    programs::ProbeContext,
};
use aya_log_ebpf::info;

const ENOMEM: i32 = -12;
<span class="hljs-comment">#[kprobe(name = "block_mount")]</span>
pub fn block_mount(ctx: ProbeContext) -&gt; u32 {
    match try_block_mount(ctx) {
        Ok(ret) =&gt; ret,
        Err(ret) =&gt; ret,
    }
}

fn try_block_mount(
    ctx: ProbeContext,
) -&gt; Result&lt;u32, u32&gt; {
    info!(&amp;ctx, <span class="hljs-string">"function open_ctree called"</span>);
    unsafe {
        bpf_override_return(ctx.regs, ENOMEM as u64)
    };
    Ok(0)
}

<span class="hljs-comment">#[panic_handler]</span>
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
    unsafe { core::hint::unreachable_unchecked() }
}
</code></pre>
<h3 id="heading-kernel-tracepoint">kernel Tracepoint</h3>
<pre><code class="lang-bash">cargo generate https://github.com/aya-rs/aya-template
🤷   Project Name: tracepoint-sangam
🔧   Destination: /home/ubuntu/tracepoint-sangam ...
🔧   project-name: tracepoint-sangam ...
🔧   Generating template ...
✔ 🤷   Which <span class="hljs-built_in">type</span> of eBPF program? · tracepoint
🤷   Which tracepoint category? (e.g <span class="hljs-built_in">sched</span>, net etc...): sys_enter_execve
🤷   Which tracepoint name? (e.g sched_switch, net_dev_queue): systemcalls
[ 1/35]   Done: .cargo/config.toml                                                                                    [ 2/35]   Done: .cargo                                                                                                [ 3/35]   Done: .gitignore                                                                                            [ 4/35]   Done: .vim/coc-settings.json                                                                                [ 5/35]   Done: .vim                                                                                                  [ 6/35]   Done: .vscode/settings.json                                                                                 [ 7/35]   Done: .vscode                                                                                               [ 8/35]   Done: Cargo.toml                                                                                            [ 9/35]   Done: README.md                                                                                             [10/35]   Ignored: pre-script.rhai                                                                                    [11/35]   Done: xtask/Cargo.toml                                                                                      [12/35]   Done: xtask/src/build_ebpf.rs                                                                               [13/35]   Done: xtask/src/main.rs                                                                                     [14/35]   Done: xtask/src/run.rs                                                                                      [15/35]   Done: xtask/src                                                                                             [16/35]   Done: xtask                                                                                                 [17/35]   Done: tracepoint-sangam/Cargo.toml                                                                          [18/35]   Done: tracepoint-sangam/src/main.rs                                                                         [19/35]   Done: tracepoint-sangam/src                                                                                 [20/35]   Done: tracepoint-sangam                                                                                     [21/35]   Done: tracepoint-sangam-common/Cargo.toml                                                                   [22/35]   Done: tracepoint-sangam-common/src/lib.rs                                                                   [23/35]   Done: tracepoint-sangam-common/src                                                                          [24/35]   Done: tracepoint-sangam-common                                                                              [25/35]   Done: tracepoint-sangam-ebpf/.cargo/config.toml                                                             [26/35]   Done: tracepoint-sangam-ebpf/.cargo                                                                         [27/35]   Done: tracepoint-sangam-ebpf/.vim/coc-settings.json                                                         [28/35]   Done: tracepoint-sangam-ebpf/.vim                                                                           [29/35]   Done: tracepoint-sangam-ebpf/.vscode/settings.json                                                          [30/35]   Done: tracepoint-sangam-ebpf/.vscode                                                                        [31/35]   Done: tracepoint-sangam-ebpf/Cargo.toml                                                                     [32/35]   Done: tracepoint-sangam-ebpf/rust-toolchain.toml                                                            [33/35]   Done: tracepoint-sangam-ebpf/src/main.rs                                                                    [34/35]   Done: tracepoint-sangam-ebpf/src                                                                            [35/35]   Done: tracepoint-sangam-ebpf                                                                                🔧   Moving generated files into: `/home/ubuntu/tracepoint-sangam`...
💡   Initializing a fresh Git repository
✨   Done! New project created /home/ubuntu/tracepoint-sangam
ubuntu@ip-172-31-56-217:~$
</code></pre>
<p>its generate template</p>
<pre><code class="lang-bash">.
├── Cargo.toml
├── README.md
├── tracepoint-sangam
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── tracepoint-sangam-common
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── tracepoint-sangam-ebpf
│   ├── Cargo.toml
│   ├── rust-toolchain.toml
│   └── src
│       └── main.rs
└── xtask
    ├── Cargo.toml
    └── src
        ├── build_ebpf.rs
        ├── main.rs
        └── run.rs
</code></pre>
<ul>
<li><p>tracepoint-sangam - contains the user space program</p>
</li>
<li><p>tracepoint-sangam-ebpf - contains the epbf program</p>
</li>
<li><p>trace-sangam-common contains the code for data structure and data types common to both user space and eBPF programs</p>
</li>
</ul>
<p>The user space program can be buit using</p>
<pre><code class="lang-bash">~/tracepoint-sangam$ cargo build
</code></pre>
<p>the eBPF program can be built using</p>
<pre><code class="lang-bash">~/tracepoint-sangam$ cargo xtask build-ebpf
</code></pre>
<p>the release version of the eBPF program can be build using</p>
<pre><code class="lang-bash">~/tracepoint-sangam$ cargo xtask build-ebpf --release
</code></pre>
<p>The userspace program which loads the eBPF program into kernel can be run using</p>
<pre><code class="lang-bash">/tracepoint-sangam$ cargo xtask run
</code></pre>
<p>above simple ebpf program attached to <code>sys_enter_exeve</code> tracepoint in the Linux kenel and is executed for each <code>sys_execve</code> syscall.</p>
<p>The eBPF program on execution logs a perf event and this event is returned to the user space for printing via the perf event array map. exporting the logs from the kernel to the user space is abstracted from the developer and handled by the aya-logging library</p>
<p>That's it for this part we will learn more about aya and ebpf .</p>
<p>the eBPF developer experience by allowing Rust programs to easily run within the kernel.</p>
<p>Aya is the first Rust-native eBPF library that is similar in nature to libbpf but entirely written in the Rust programming language, popular for its memory safety and concurrency features, among other reasons this programming language is becoming very popular for systems programming.</p>
]]></content:encoded></item><item><title><![CDATA[eBPF for Cybersecurity - Part 2]]></title><description><![CDATA[How are ebpf programs written?

You write an eBPF program. Mostly in restricted C.

Compile the program into bytecode using tools like clang

Use bpftool or another high-level program to load bytecode into the kernel

the verification evaluates the e...]]></description><link>https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-2</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-2</guid><category><![CDATA[eBPF]]></category><category><![CDATA[observability]]></category><category><![CDATA[Security]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Mon, 06 Feb 2023 20:49:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675642202280/785f2b81-c0cf-47c9-b3db-fc2276b4a4db.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-how-are-ebpf-programs-written">How are ebpf programs written?</h4>
<ol>
<li><p>You write an eBPF program. Mostly in restricted C.</p>
</li>
<li><p>Compile the program into bytecode using tools like clang</p>
</li>
<li><p>Use bpftool or another high-level program to load bytecode into the kernel</p>
</li>
<li><p>the verification evaluates the eBPF program and ensures its safe to run</p>
</li>
<li><p>the JIT compiler converts the bytecode to native assembly for faster execution</p>
</li>
<li><p>the program is then attached/linked to is hookpoints</p>
</li>
<li><p>Anytime the hookpoint is traversed, our attached middleware gets executed.</p>
</li>
</ol>
<p>the ebpf program you write and run can inspect data in the memory of the processed they attach to. to achieve this you can use header file <code>#include "vmlinux.h"</code> .</p>
<p>basically <code>vmlinux.h</code> is generated code. Linux kernel that contains definitions and declarations for the virtual memory management subsystem. This file is used by the kernel to define the data structures and functions used to manage virtual memory, such as page tables, memory zones, and page flags. It also includes definitions for macros and constants used in the virtual memory management code, such as page sizes, page flags, and memory zones. Overall, <code>vmlinux.h</code> is an important part of the Linux kernel that helps the operating system manage the memory resources of the system.</p>
<p>one of the output artefacts is a file called <code>vmlinux</code> It's also typically packaged with major distribution distributions. this ELF binary contains the compiled bootable kernel inside it.</p>
<p>here is a little walkthrough on ELF101</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/e/e4/ELF_Executable_and_Linkable_Format_diagram_by_Ange_Albertini.png" alt class="image--center mx-auto" /></p>
<p><code>bpftool</code> that maintained within the Linux repository its has features to read the <code>vmlinux</code> object generate a <code>vmlinux.h</code></p>
<p><a target="_blank" href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/bpf/bpftool?h=v5.14">https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/bpf/bpftool?h=v5.14</a></p>
<pre><code class="lang-bash">ubuntu $ ls
bin   dev  home  lib32  libx32      media  opt   root  sbin  srv       sys  usr
boot  etc  lib   lib64  lost+found  mnt    proc  run   snap  swapfile  tmp  var
</code></pre>
<p>check <code>sys/kerne</code>l folder</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> sys/kernel
ubuntu $ ls
boot_params  config  iommu_groups        kexec_crash_size  mm         rcu_expedited  slab            uevent_helper
btf          debug   irq                 kexec_loaded      notes      rcu_normal     software_nodes  uevent_seqnum
cgroup       fscaps  kexec_crash_loaded  livepatch         profiling  security       tracing         vmcoreinfo
ubuntu $
</code></pre>
<p>in the btf you find <code>vimliux</code> object</p>
<pre><code class="lang-bash">sudo apt install  linux-tools-5.15.0-57-generic
</code></pre>
<p>note: Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-57-generic aarch64)</p>
<pre><code class="lang-bash">ubuntu@primary:~$ sudo bpftool prog show
62: cgroup_device  tag ee0e253c78993a24  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 416B  jited 400B  memlock 4096B
63: cgroup_device  tag 384856681694f215  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 744B  jited 644B  memlock 4096B
64: cgroup_skb  tag 6deef7357e7b4530  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 64B  jited 96B  memlock 4096B
65: cgroup_skb  tag 6deef7357e7b4530  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 64B  jited 96B  memlock 4096B
69: cgroup_device  tag 134b8a301991f6b7  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 504B  jited 464B  memlock 4096B
70: cgroup_skb  tag 6deef7357e7b4530  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 64B  jited 96B  memlock 4096B
71: cgroup_skb  tag 6deef7357e7b4530  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 64B  jited 96B  memlock 4096B
72: cgroup_device  tag 4b9ba398cc75f876  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 496B  jited 460B  memlock 4096B
73: cgroup_skb  tag 6deef7357e7b4530  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 64B  jited 96B  memlock 4096B
74: cgroup_skb  tag 6deef7357e7b4530  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 64B  jited 96B  memlock 4096B
75: cgroup_device  tag 654d7024997e7811  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 464B  jited 436B  memlock 4096B
76: cgroup_device  tag 134b8a301991f6b7  gpl
    loaded_at 2023-01-21T11:00:09+0530  uid 0
    xlated 504B  jited 464B  memlock 4096B
</code></pre>
<p>"bpftool prog show" is used to list all BPF programs currently loaded on the system (loaded ⇏ attached).</p>
<pre><code class="lang-bash">cat  my_bpf_program.c 
int <span class="hljs-function"><span class="hljs-title">func</span></span>()
{
        <span class="hljs-built_in">return</span> 0;
}
</code></pre>
<p>run using clang</p>
<pre><code class="lang-bash">clang -target bpf -Wall -O2 -c my_bpf_program.c -o my_bpf_objfile.o
</code></pre>
<pre><code class="lang-bash">clang -O2 -emit-llvm -c my_bpf_program.c -o - |       llc -march=bpf -mcpu=probe -filetype=obj -o my_bpf_objfile.o
</code></pre>
<p>might need to pass the <code>-mcpu</code> option to <code>llc</code>and would use something closer to the following command instead</p>
<pre><code class="lang-bash">ubuntu@primary:~$ readelf -x .text my_bpf_objfile.o

Hex dump of section <span class="hljs-string">'.text'</span>:
  0x00000000 b7000000 00000000 95000000 00000000 ................
</code></pre>
<p>It worked! We have two eBPF instructions here:</p>
<pre><code class="lang-bash">b7 0 0 0000 00000000    <span class="hljs-comment"># r0 = 0</span>
95 0 0 0000 00000000    <span class="hljs-comment"># exit and return r0</span>
</code></pre>
<p>ebpf assembly instruction:- https://github.com/iovisor/bpf-docs/blob/master/eBPF.md</p>
<ul>
<li><p>Compiling from C to eBPF bytecode as an object file is really useful. The ELF file produced can directly attach the programs to the various hooks , TC, XDP,Kprobes etc</p>
</li>
<li><p>writing advanced programs as bytecode would be very time-consuming</p>
</li>
<li><p>Compile from C to an eBPF assembly language. Edit the assembly, then assemble it as bytecode in an object file.</p>
</li>
</ul>
<p>Clang and LLVM now allow to do just that! Generating a human-readable version of the program on one side, then assembling it on the other side. Bonus: <code>llvm-objdump</code> can even be used to dump the program contained in an object-file.</p>
<h4 id="heading-compiling-from-c-to-ebpf-assembly">Compiling from C to eBPF Assembly</h4>
<pre><code class="lang-bash">$ cat bpf.c
int <span class="hljs-function"><span class="hljs-title">func</span></span>()
{
    <span class="hljs-built_in">return</span> 0;
}

$ clang -target bpf -S -o bpf.s bpf.c
$ cat bpf.s
    .text
    .globl    func                    <span class="hljs-comment"># -- Begin function func</span>
    .p2align    3
func:                                   <span class="hljs-comment"># @func</span>
<span class="hljs-comment"># %bb.0:</span>
    r1 = 0
    *(u32 *)(r10 - 4) = r1
    r0 = r1
    <span class="hljs-built_in">exit</span>
                                        <span class="hljs-comment"># -- End function</span>
</code></pre>
<p>Great, now let’s modify it and add our instructions at the bottom!</p>
<pre><code class="lang-bash">$ sed -i <span class="hljs-string">'$a \\tr0 = 3'</span> bpf.s
$ cat bpf.s
    .text
    .globl    func                    <span class="hljs-comment"># -- Begin function func</span>
    .p2align    3
func:                                   <span class="hljs-comment"># @func</span>
<span class="hljs-comment"># %bb.0:</span>
    r1 = 0
    *(u32 *)(r10 - 4) = r1
    r0 = r1
    <span class="hljs-built_in">exit</span>
                                        <span class="hljs-comment"># -- End function</span>

    r0 = 3
</code></pre>
<h4 id="heading-assembling-to-an-elf-object-file">Assembling to an ELF object file</h4>
<p>we can assemble this file into an ELF object file containing bytcode</p>
<pre><code class="lang-bash">$ llvm-mc -triple bpf -filetype=obj -o bpf.o bpf.s
</code></pre>
<p>lets dump bytecode</p>
<pre><code class="lang-bash">$ readelf -x .text bpf.o

Hex dump of section <span class="hljs-string">'.text'</span>:
  0x00000000 b7010000 00000000 631afcff 00000000 ........c.......
  0x00000010 bf100000 00000000 95000000 00000000 ................
  0x00000020 b7000000 03000000 b7000000 03000000 ................
</code></pre>
<p>object file in human-readable format</p>
<pre><code class="lang-bash">$ llvm-objdump -d bpf.o

bpf.o:    file format ELF64-BPF

Disassembly of section .text:
func:
       0:    b7 01 00 00 00 00 00 00     r1 = 0
       1:    63 1a <span class="hljs-built_in">fc</span> ff 00 00 00 00     *(u32 *)(r10 - 4) = r1
       2:    bf 10 00 00 00 00 00 00     r0 = r1
       3:    95 00 00 00 00 00 00 00     <span class="hljs-built_in">exit</span>
       4:    b7 00 00 00 03 00 00 00     r0 = 3
</code></pre>
<p>you can see we edited <code>r0 = 3</code></p>
<p>LLVM can embed debug symbols so they can be dumped inspection. we can give the c instruction at the same time as the bytecode . embedding instructions is done by compiling from C with the <code>-g</code> flag passed to clang</p>
<pre><code class="lang-bash">$ clang -target bpf -g -S -o bpf.s bpf.c
$ llvm-mc -triple bpf -filetype=obj -o bpf.o bpf.s
$ llvm-objdump -S bpf.o

bpf.o:    file format ELF64-BPF

Disassembly of section .text:
func:
; int <span class="hljs-function"><span class="hljs-title">func</span></span>() {
       0:    b7 01 00 00 00 00 00 00     r1 = 0
       1:    63 1a <span class="hljs-built_in">fc</span> ff 00 00 00 00     *(u32 *)(r10 - 4) = r1
; <span class="hljs-built_in">return</span> 0;
       2:    bf 10 00 00 00 00 00 00     r0 = r1
       3:    95 00 00 00 00 00 00 00     <span class="hljs-built_in">exit</span>
</code></pre>
<p>another way is an inline assembly (<a target="_blank" href="https://docs.cilium.io/en/latest/bpf/#llvm">https://docs.cilium.io/en/latest/bpf/#llvm</a>)</p>
<p>In short, instead of compiling an eBPF program from C to an ELF object file, you can alternatively compile it to an assembly language, edit it according to your needs, and then assemble this version as the final object file. For this, you need clang and LLVM in version 6.0 and higher, and the commands are:</p>
<pre><code class="lang-bash">$ clang -target bpf -S -o bpf.s bpf.c
$ llvm-mc -triple bpf -filetype=obj -o bpf.o bpf.s
</code></pre>
<p>dump in human-readable format</p>
<pre><code class="lang-bash">$ llvm-objdump -d bpf.o
$ llvm-objdump -S bpf.o         <span class="hljs-comment"># add C code, if -g was passed to clang</span>
</code></pre>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/qeole/status/1101450782841466880?s=20&amp;t=dDnaTDUbT6yrTgtj2yb_XQ">https://twitter.com/qeole/status/1101450782841466880?s=20&amp;t=dDnaTDUbT6yrTgtj2yb_XQ</a></div>
<p> </p>
<p>In the whole series of ebpf we are going to use <a target="_blank" href="https://github.com/aya-rs/aya">https://github.com/aya-rs/aya</a> - Aya is an eBPF library for the Rust programming language, built with a focus on developer experience and operability.</p>
<h4 id="heading-so-why-rust-c-is-fine">So why Rust? C is fine</h4>
<p>As you saw in the last article, BPF programs are typically programmed in C. But why couldn't we use Rust? It can be just as low level as C.</p>
<p>The biggest win in my mind is the ergonomics that could be achieved (which I will hopefully be able to improve across these next few posts) along with the crates ecosystem which has enormous potential when compared to the C BPF ecosystem. It could be argued that because of the verifier, the borrow checker is moot, but I don't see it in quite the same light. Sure the verifier will enforce specific checks and be arguably far more strict than the borrow checker but that<br />doesn't mean we can't get any use out of leaning on Rust's borrowing system.</p>
<p>Of course, there is the subjective benefit that I'm more productive in Rust, and far more proficient with Rust than with C. Plus if I'm writing the supporting applications/libraries in Rust it'd be nice to stay in a single language when possible.</p>
<h4 id="heading-install-rust-on-linux">Install rust on linux</h4>
<pre><code class="lang-bash">sudo apt-get update
curl https://sh.rustup.rs -sSf | sh -s -- -y
<span class="hljs-built_in">source</span> <span class="hljs-variable">$HOME</span>/.cargo/env
rustup --version
rustup install stable
rustup toolchain install nightly --component rust-src
sudo apt install build-essential
sudo apt-get update
sudo apt install build-essential
</code></pre>
<p>Before working with aya, you need to install bpf-linker crate. If you are running on a Linux x86_64 system, use the following command:</p>
<pre><code class="lang-bash">cargo install bpf-linker
</code></pre>
<p>If you are running Linux on any other architecture (e.g. arm64), you need to install LLVM 15 first (using <a target="_blank" href="https://apt.llvm.org/">https://apt.llvm.org/</a> or packages for your distribution) and then use the following command:</p>
<pre><code class="lang-bash">cargo install --no-default-features --features system-llvm bpf-linker
</code></pre>
<p><code>cargo-generate</code> is a developer tool to help you get up and running quickly with a new Rust project by leveraging a pre-existing git repository as a template.</p>
<pre><code class="lang-bash">cargo install cargo-generate --locked cargo
</code></pre>
<p>use aya template to generate different type of ebpf program</p>
<pre><code class="lang-bash">cargo generate https://github.com/aya-rs/aya-template
⚠️   Favorite `https://github.com/aya-rs/aya-template` not found <span class="hljs-keyword">in</span> config, using it as a git repository: https://github.com/aya-rs/aya-template
🤷   Project Name: aya-rust-sangam
🔧   Destination: /home/ubuntu/aya-rust-sangam ...
🔧   project-name: aya-rust-sangam ...
🔧   Generating template ...
✔ 🤷   Which <span class="hljs-built_in">type</span> of eBPF program? · cgroup_sysctl
[ 1/35]   Done: .cargo/config.toml                                                                                                                          [ 2/35]   Done: .cargo                                                                                                                                      [ 3/35]   Done: .gitignore                                                                                                                                  [ 4/35]   Done: .vim/coc-settings.json                                                                                                                      [ 5/35]   Done: .vim                                                                                                                                        [ 6/35]   Done: .vscode/settings.json                                                                                                                       [ 7/35]   Done: .vscode                                                                                                                                     [ 8/35]   Done: Cargo.toml                                                                                                                                  [ 9/35]   Done: README.md                                                                                                                                   [10/35]   Ignored: pre-script.rhai                                                                                                                          [11/35]   Done: xtask/Cargo.toml                                                                                                                            [12/35]   Done: xtask/src/build_ebpf.rs                                                                                                                     [13/35]   Done: xtask/src/main.rs                                                                                                                           [14/35]   Done: xtask/src/run.rs                                                                                                                            [15/35]   Done: xtask/src                                                                                                                                   [16/35]   Done: xtask                                                                                                                                       [17/35]   Done: aya-rust-sangam/Cargo.toml                                                                                                                  [18/35]   Done: aya-rust-sangam/src/main.rs                                                                                                                 [19/35]   Done: aya-rust-sangam/src                                                                                                                         [20/35]   Done: aya-rust-sangam                                                                                                                             [21/35]   Done: aya-rust-sangam-common/Cargo.toml                                                                                                           [22/35]   Done: aya-rust-sangam-common/src/lib.rs                                                                                                           [23/35]   Done: aya-rust-sangam-common/src                                                                                                                  [24/35]   Done: aya-rust-sangam-common                                                                                                                      [25/35]   Done: aya-rust-sangam-ebpf/.cargo/config.toml                                                                                                     [26/35]   Done: aya-rust-sangam-ebpf/.cargo                                                                                                                 [27/35]   Done: aya-rust-sangam-ebpf/.vim/coc-settings.json                                                                                                 [28/35]   Done: aya-rust-sangam-ebpf/.vim                                                                                                                   [29/35]   Done: aya-rust-sangam-ebpf/.vscode/settings.json                                                                                                  [30/35]   Done: aya-rust-sangam-ebpf/.vscode                                                                                                                [31/35]   Done: aya-rust-sangam-ebpf/Cargo.toml                                                                                                             [32/35]   Done: aya-rust-sangam-ebpf/rust-toolchain.toml                                                                                                    [33/35]   Done: aya-rust-sangam-ebpf/src/main.rs                                                                                                            [34/35]   Done: aya-rust-sangam-ebpf/src                                                                                                                    [35/35]   Done: aya-rust-sangam-ebpf                                                                                                                        🔧   Moving generated files into: `/home/ubuntu/aya-rust-sangam`...
💡   Initializing a fresh Git repository
✨   Done! New project created /home/ubuntu/aya-rust-sangam
ubuntu@ip-172-31-56-217:~$
</code></pre>
<p>here the structure of the program</p>
<pre><code class="lang-bash">└── aya-rust-sangam
    ├── Cargo.toml
    ├── README.md
    ├── aya-rust-sangam
    │   ├── Cargo.toml
    │   └── src
    │       └── main.rs
    ├── aya-rust-sangam-common
    │   ├── Cargo.toml
    │   └── src
    │       └── lib.rs
    ├── aya-rust-sangam-ebpf
    │   ├── Cargo.toml
    │   ├── rust-toolchain.toml
    │   └── src
    │       └── main.rs
    └── xtask
        ├── Cargo.toml
        └── src
            ├── build_ebpf.rs
            ├── main.rs
            └── run.rs
</code></pre>
<p><a target="_blank" href="https://docs.rs/aya/0.11.0/aya/programs/cgroup_sysctl/struct.CgroupSysctl.html"><code>CgroupSysctl</code></a> programs can be attached to a cgroup and will be called every time a process inside that cgroup tries to read from or write to a sysctl knob in proc.</p>
<pre><code class="lang-bash">/aya-rust-sangam/aya-rust-sangam/src$ cat main.rs 
use aya::programs::CgroupSysctl;
use aya::{include_bytes_aligned, Bpf};
use aya_log::BpfLogger;
use clap::Parser;
use <span class="hljs-built_in">log</span>::{info, warn};
use tokio::signal;

<span class="hljs-comment">#[derive(Debug, Parser)]</span>
struct Opt {
    <span class="hljs-comment">#[clap(short, long, default_value = "/sys/fs/cgroup/unified")]</span>
    cgroup_path: String,
}

<span class="hljs-comment">#[tokio::main]</span>
async fn main() -&gt; Result&lt;(), anyhow::Error&gt; {
    <span class="hljs-built_in">let</span> opt = Opt::parse();

    env_logger::init();

    // This will include your eBPF object file as raw bytes at compile-time and load it at
    // runtime. This approach is recommended <span class="hljs-keyword">for</span> most real-world use cases. If you would
    // like to specify the eBPF program at runtime rather than at compile-time, you can
    // reach <span class="hljs-keyword">for</span> `Bpf::load_file` instead.
    <span class="hljs-comment">#[cfg(debug_assertions)]</span>
    <span class="hljs-built_in">let</span> mut bpf = Bpf::load(include_bytes_aligned!(
        <span class="hljs-string">"../../target/bpfel-unknown-none/debug/aya-rust-sangam"</span>
    ))?;
    <span class="hljs-comment">#[cfg(not(debug_assertions))]</span>
    <span class="hljs-built_in">let</span> mut bpf = Bpf::load(include_bytes_aligned!(
        <span class="hljs-string">"../../target/bpfel-unknown-none/release/aya-rust-sangam"</span>
    ))?;
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">let</span> Err(e) = BpfLogger::init(&amp;mut bpf) {
        // This can happen <span class="hljs-keyword">if</span> you remove all <span class="hljs-built_in">log</span> statements from your eBPF program.
        warn!(<span class="hljs-string">"failed to initialize eBPF logger: {}"</span>, e);
    }
    <span class="hljs-built_in">let</span> program: &amp;mut CgroupSysctl = bpf.program_mut(<span class="hljs-string">"aya_rust_sangam"</span>).unwrap().try_into()?;
    <span class="hljs-built_in">let</span> cgroup = std::fs::File::open(opt.cgroup_path)?;
    program.load()?;
    program.attach(cgroup)?;

    info!(<span class="hljs-string">"Waiting for Ctrl-C..."</span>);
    signal::ctrl_c().await?;
    info!(<span class="hljs-string">"Exiting..."</span>);

    Ok(())
}
</code></pre>
<p>The main entry point into the library, used to work with eBPF programs and maps.</p>
<pre><code class="lang-bash"><span class="hljs-comment">#![no_std]</span>
<span class="hljs-comment">#![no_main]</span>

use aya_bpf::{
    macros::cgroup_sysctl,
    programs::SysctlContext,
};
use aya_log_ebpf::info;

<span class="hljs-comment">#[cgroup_sysctl(name = "aya_rust_sangam")]</span>
pub fn aya_rust_sangam(ctx: SysctlContext) -&gt; i32 {
    match try_aya_rust_sangam(ctx) {
        Ok(ret) =&gt; ret,
        Err(ret) =&gt; ret,
    }
}

fn try_aya_rust_sangam(ctx: SysctlContext) -&gt; Result&lt;i32, i32&gt; {
    info!(&amp;ctx, <span class="hljs-string">"sysctl operation called"</span>);
    Ok(0)
}

<span class="hljs-comment">#[panic_handler]</span>
fn panic(_info: &amp;core::panic::PanicInfo) -&gt; ! {
    unsafe { core::hint::unreachable_unchecked() }
}
</code></pre>
<p>cargo configurations</p>
<pre><code class="lang-bash">~/aya-rust-sangam/aya-rust-sangam-ebpf$ cat Cargo.toml 
[package]
name = <span class="hljs-string">"aya-rust-sangam-ebpf"</span>
version = <span class="hljs-string">"0.1.0"</span>
edition = <span class="hljs-string">"2021"</span>

[dependencies]
aya-bpf = { git = <span class="hljs-string">"https://github.com/aya-rs/aya"</span>, branch = <span class="hljs-string">"main"</span> }
aya-log-ebpf = { git = <span class="hljs-string">"https://github.com/aya-rs/aya"</span>, branch = <span class="hljs-string">"main"</span> }
aya-rust-sangam-common = { path = <span class="hljs-string">"../aya-rust-sangam-common"</span> }

[[bin]]
name = <span class="hljs-string">"aya-rust-sangam"</span>
path = <span class="hljs-string">"src/main.rs"</span>

[profile.dev]
opt-level = 3
debug = <span class="hljs-literal">false</span>
debug-assertions = <span class="hljs-literal">false</span>
overflow-checks = <span class="hljs-literal">false</span>
lto = <span class="hljs-literal">true</span>
panic = <span class="hljs-string">"abort"</span>
incremental = <span class="hljs-literal">false</span>
codegen-units = 1
rpath = <span class="hljs-literal">false</span>

[profile.release]
lto = <span class="hljs-literal">true</span>
panic = <span class="hljs-string">"abort"</span>
codegen-units = 1

[workspace]
members = []
</code></pre>
<pre><code class="lang-bash">ubuntu@ip-172-31-56-217:~/aya-rust-sangam$ cargo xtask build-ebpf
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.28s
     Running `target/debug/xtask build-ebpf`
       Fresh unicode-ident v1.0.6
       Fresh proc-macro2 v1.0.51
       Fresh quote v1.0.23
       Fresh syn v1.0.107
       Fresh core v0.0.0 (/home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core)
       Fresh rustc-std-workspace-core v1.99.0 (/home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/rustc-std-workspace-core)
       Fresh num_enum_derive v0.5.9
       Fresh compiler_builtins v0.1.85
       Fresh rustversion v1.0.11
       Fresh aya-bpf-cty v0.2.1 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh aya-bpf-bindings v0.1.0 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh aya-log-parser v0.1.11-dev.0 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh num_enum v0.5.9
       Fresh aya-bpf-macros v0.1.0 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh aya-log-ebpf-macros v0.1.0 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh aya-bpf v0.1.0 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh aya-log-common v0.1.13 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh aya-log-ebpf v0.1.0 (https://github.com/aya-rs/aya?branch=main<span class="hljs-comment">#7868fffd)</span>
       Fresh aya-rust-sangam-common v0.1.0 (/home/ubuntu/aya-rust-sangam/aya-rust-sangam-common)
       Fresh aya-rust-sangam-ebpf v0.1.0 (/home/ubuntu/aya-rust-sangam/aya-rust-sangam-ebpf)
    Finished dev [optimized] target(s) <span class="hljs-keyword">in</span> 0.30s
</code></pre>
<pre><code class="lang-bash"> llvm-objdump -S target/bpfel-unknown-none/debug/aya-rust-sangam

target/bpfel-unknown-none/debug/aya-rust-sangam:    file format ELF64-BPF


Disassembly of section .text:

0000000000000000 memset:
llvm-objdump: warning: <span class="hljs-string">'target/bpfel-unknown-none/debug/aya-rust-sangam'</span>: failed to parse debug information <span class="hljs-keyword">for</span> target/bpfel-unknown-none/debug/aya-rust-sangam
       0:    15 03 06 00 00 00 00 00    <span class="hljs-keyword">if</span> r3 == 0 goto +6 &lt;LBB1_3&gt;
       1:    b7 04 00 00 00 00 00 00    r4 = 0

0000000000000010 LBB1_2:
       2:    bf 15 00 00 00 00 00 00    r5 = r1
       3:    0f 45 00 00 00 00 00 00    r5 += r4
       4:    73 25 00 00 00 00 00 00    *(u8 *)(r5 + 0) = r2
       5:    07 04 00 00 01 00 00 00    r4 += 1
       6:    2d 43 fb ff 00 00 00 00    <span class="hljs-keyword">if</span> r3 &gt; r4 goto -5 &lt;LBB1_2&gt;

0000000000000038 LBB1_3:
       7:    95 00 00 00 00 00 00 00    <span class="hljs-built_in">exit</span>

0000000000000040 memcpy:
       8:    15 03 09 00 00 00 00 00    <span class="hljs-keyword">if</span> r3 == 0 goto +9 &lt;LBB2_3&gt;
       9:    b7 04 00 00 00 00 00 00    r4 = 0

0000000000000050 LBB2_2:
      10:    bf 15 00 00 00 00 00 00    r5 = r1
      11:    0f 45 00 00 00 00 00 00    r5 += r4
      12:    bf 20 00 00 00 00 00 00    r0 = r2
      13:    0f 40 00 00 00 00 00 00    r0 += r4
      14:    71 00 00 00 00 00 00 00    r0 = *(u8 *)(r0 + 0)
      15:    73 05 00 00 00 00 00 00    *(u8 *)(r5 + 0) = r0
      16:    07 04 00 00 01 00 00 00    r4 += 1
      17:    2d 43 f8 ff 00 00 00 00    <span class="hljs-keyword">if</span> r3 &gt; r4 goto -8 &lt;LBB2_2&gt;

0000000000000090 LBB2_3:
      18:    95 00 00 00 00 00 00 00    <span class="hljs-built_in">exit</span>

Disassembly of section cgroup/sysctl/aya_rust_sangam:

0000000000000000 aya_rust_sangam:
       0:    bf 16 00 00 00 00 00 00    r6 = r1
       1:    b7 07 00 00 00 00 00 00    r7 = 0
       2:    63 7a <span class="hljs-built_in">fc</span> ff 00 00 00 00    *(u32 *)(r10 - 4) = r7
       3:    bf a2 00 00 00 00 00 00    r2 = r10
       4:    07 02 00 00 <span class="hljs-built_in">fc</span> ff ff ff    r2 += -4
       5:    18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00    r1 = 0 ll
       7:    85 00 00 00 01 00 00 00    call 1
       8:    15 00 26 01 00 00 00 00    <span class="hljs-keyword">if</span> r0 == 0 goto +294 &lt;LBB0_2&gt;
       9:    73 70 0f 00 00 00 00 00    *(u8 *)(r0 + 15) = r7
      10:    73 70 0e 00 00 00 00 00    *(u8 *)(r0 + 14) = r7
      11:    73 70 0d 00 00 00 00 00    *(u8 *)(r0 + 13) = r7
      12:    73 70 0c 00 00 00 00 00    *(u8 *)(r0 + 12) = r7
      13:    73 70 0b 00 00 00 00 00    *(u8 *)(r0 + 11) = r7
      14:    73 70 0a 00 00 00 00 00    *(u8 *)(r0 + 10) = r7
      15:    73 70 09 00 00 00 00 00    *(u8 *)(r0 + 9) = r7
      16:    b7 03 00 00 0f 00 00 00    r3 = 15
      17:    73 30 08 00 00 00 00 00    *(u8 *)(r0 + 8) = r3
      18:    73 70 07 00 00 00 00 00    *(u8 *)(r0 + 7) = r7
      19:    73 70 06 00 00 00 00 00    *(u8 *)(r0 + 6) = r7
      20:    73 70 05 00 00 00 00 00    *(u8 *)(r0 + 5) = r7
      21:    73 70 04 00 00 00 00 00    *(u8 *)(r0 + 4) = r7
      22:    73 70 03 00 00 00 00 00    *(u8 *)(r0 + 3) = r7
      23:    73 70 02 00 00 00 00 00    *(u8 *)(r0 + 2) = r7
      24:    73 70 01 00 00 00 00 00    *(u8 *)(r0 + 1) = r7
      25:    b7 01 00 00 01 00 00 00    r1 = 1
      26:    73 10 00 00 00 00 00 00    *(u8 *)(r0 + 0) = r1
      27:    bf 04 00 00 00 00 00 00    r4 = r0
      28:    07 04 00 00 10 00 00 00    r4 += 16
      29:    18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00    r2 = 0 ll
      31:    71 25 00 00 00 00 00 00    r5 = *(u8 *)(r2 + 0)
      32:    73 54 00 00 00 00 00 00    *(u8 *)(r4 + 0) = r5
      33:    71 25 01 00 00 00 00 00    r5 = *(u8 *)(r2 + 1)
      34:    73 54 01 00 00 00 00 00    *(u8 *)(r4 + 1) = r5
      35:    71 25 02 00 00 00 00 00    r5 = *(u8 *)(r2 + 2)
      36:    73 54 02 00 00 00 00 00    *(u8 *)(r4 + 2) = r5
      37:    71 25 03 00 00 00 00 00    r5 = *(u8 *)(r2 + 3)
      38:    73 54 03 00 00 00 00 00    *(u8 *)(r4 + 3) = r5
      39:    71 25 04 00 00 00 00 00    r5 = *(u8 *)(r2 + 4)
      40:    73 54 04 00 00 00 00 00    *(u8 *)(r4 + 4) = r5
      41:    71 25 05 00 00 00 00 00    r5 = *(u8 *)(r2 + 5)
      42:    73 54 05 00 00 00 00 00    *(u8 *)(r4 + 5) = r5
      43:    71 25 06 00 00 00 00 00    r5 = *(u8 *)(r2 + 6)
      44:    73 54 06 00 00 00 00 00    *(u8 *)(r4 + 6) = r5
      45:    71 25 07 00 00 00 00 00    r5 = *(u8 *)(r2 + 7)
      46:    73 54 07 00 00 00 00 00    *(u8 *)(r4 + 7) = r5
      47:    71 25 08 00 00 00 00 00    r5 = *(u8 *)(r2 + 8)
      48:    73 54 08 00 00 00 00 00    *(u8 *)(r4 + 8) = r5
      49:    71 25 09 00 00 00 00 00    r5 = *(u8 *)(r2 + 9)
      50:    73 54 09 00 00 00 00 00    *(u8 *)(r4 + 9) = r5
      51:    71 25 0a 00 00 00 00 00    r5 = *(u8 *)(r2 + 10)
      52:    73 54 0a 00 00 00 00 00    *(u8 *)(r4 + 10) = r5
      53:    71 25 0b 00 00 00 00 00    r5 = *(u8 *)(r2 + 11)
      54:    73 54 0b 00 00 00 00 00    *(u8 *)(r4 + 11) = r5
      55:    71 25 0c 00 00 00 00 00    r5 = *(u8 *)(r2 + 12)
      56:    73 54 0c 00 00 00 00 00    *(u8 *)(r4 + 12) = r5
      57:    71 25 0d 00 00 00 00 00    r5 = *(u8 *)(r2 + 13)
      58:    73 54 0d 00 00 00 00 00    *(u8 *)(r4 + 13) = r5
      59:    71 25 0e 00 00 00 00 00    r5 = *(u8 *)(r2 + 14)
      60:    73 54 0e 00 00 00 00 00    *(u8 *)(r4 + 14) = r5
      61:    73 30 3f 00 00 00 00 00    *(u8 *)(r0 + 63) = r3
      62:    b7 03 00 00 03 00 00 00    r3 = 3
      63:    73 30 37 00 00 00 00 00    *(u8 *)(r0 + 55) = r3
      64:    73 30 2f 00 00 00 00 00    *(u8 *)(r0 + 47) = r3
      65:    b7 03 00 00 02 00 00 00    r3 = 2
      66:    73 30 1f 00 00 00 00 00    *(u8 *)(r0 + 31) = r3
      67:    73 70 46 00 00 00 00 00    *(u8 *)(r0 + 70) = r7
      68:    73 70 45 00 00 00 00 00    *(u8 *)(r0 + 69) = r7
      69:    73 70 44 00 00 00 00 00    *(u8 *)(r0 + 68) = r7
      70:    73 70 43 00 00 00 00 00    *(u8 *)(r0 + 67) = r7
      71:    73 70 42 00 00 00 00 00    *(u8 *)(r0 + 66) = r7
      72:    73 70 41 00 00 00 00 00    *(u8 *)(r0 + 65) = r7
      73:    73 70 40 00 00 00 00 00    *(u8 *)(r0 + 64) = r7
      74:    73 70 3e 00 00 00 00 00    *(u8 *)(r0 + 62) = r7
      75:    73 70 3d 00 00 00 00 00    *(u8 *)(r0 + 61) = r7
      76:    73 70 3c 00 00 00 00 00    *(u8 *)(r0 + 60) = r7
      77:    73 70 3b 00 00 00 00 00    *(u8 *)(r0 + 59) = r7
      78:    73 70 3a 00 00 00 00 00    *(u8 *)(r0 + 58) = r7
      79:    73 70 39 00 00 00 00 00    *(u8 *)(r0 + 57) = r7
      80:    73 70 38 00 00 00 00 00    *(u8 *)(r0 + 56) = r7
      81:    73 70 36 00 00 00 00 00    *(u8 *)(r0 + 54) = r7
      82:    73 70 35 00 00 00 00 00    *(u8 *)(r0 + 53) = r7
      83:    73 70 34 00 00 00 00 00    *(u8 *)(r0 + 52) = r7
      84:    73 70 33 00 00 00 00 00    *(u8 *)(r0 + 51) = r7
      85:    73 70 32 00 00 00 00 00    *(u8 *)(r0 + 50) = r7
      86:    73 70 31 00 00 00 00 00    *(u8 *)(r0 + 49) = r7
      87:    73 70 30 00 00 00 00 00    *(u8 *)(r0 + 48) = r7
      88:    73 70 2e 00 00 00 00 00    *(u8 *)(r0 + 46) = r7
      89:    73 70 2d 00 00 00 00 00    *(u8 *)(r0 + 45) = r7
      90:    73 70 2c 00 00 00 00 00    *(u8 *)(r0 + 44) = r7
      91:    73 70 2b 00 00 00 00 00    *(u8 *)(r0 + 43) = r7
      92:    73 70 2a 00 00 00 00 00    *(u8 *)(r0 + 42) = r7
      93:    73 70 29 00 00 00 00 00    *(u8 *)(r0 + 41) = r7
      94:    73 70 28 00 00 00 00 00    *(u8 *)(r0 + 40) = r7
      95:    b7 03 00 00 08 00 00 00    r3 = 8
      96:    73 30 27 00 00 00 00 00    *(u8 *)(r0 + 39) = r3
      97:    73 70 26 00 00 00 00 00    *(u8 *)(r0 + 38) = r7
      98:    73 70 25 00 00 00 00 00    *(u8 *)(r0 + 37) = r7
      99:    73 70 24 00 00 00 00 00    *(u8 *)(r0 + 36) = r7
     100:    73 70 23 00 00 00 00 00    *(u8 *)(r0 + 35) = r7
     101:    73 70 22 00 00 00 00 00    *(u8 *)(r0 + 34) = r7
     102:    73 70 21 00 00 00 00 00    *(u8 *)(r0 + 33) = r7
     103:    73 70 20 00 00 00 00 00    *(u8 *)(r0 + 32) = r7
     104:    bf 04 00 00 00 00 00 00    r4 = r0
     105:    07 04 00 00 47 00 00 00    r4 += 71
     106:    71 25 00 00 00 00 00 00    r5 = *(u8 *)(r2 + 0)
     107:    73 54 00 00 00 00 00 00    *(u8 *)(r4 + 0) = r5
     108:    71 25 01 00 00 00 00 00    r5 = *(u8 *)(r2 + 1)
     109:    73 54 01 00 00 00 00 00    *(u8 *)(r4 + 1) = r5
     110:    71 25 02 00 00 00 00 00    r5 = *(u8 *)(r2 + 2)
     111:    73 54 02 00 00 00 00 00    *(u8 *)(r4 + 2) = r5
     112:    71 25 03 00 00 00 00 00    r5 = *(u8 *)(r2 + 3)
     113:    73 54 03 00 00 00 00 00    *(u8 *)(r4 + 3) = r5
     114:    71 25 04 00 00 00 00 00    r5 = *(u8 *)(r2 + 4)
     115:    73 54 04 00 00 00 00 00    *(u8 *)(r4 + 4) = r5
     116:    71 25 05 00 00 00 00 00    r5 = *(u8 *)(r2 + 5)
     117:    73 54 05 00 00 00 00 00    *(u8 *)(r4 + 5) = r5
     118:    71 25 06 00 00 00 00 00    r5 = *(u8 *)(r2 + 6)
     119:    73 54 06 00 00 00 00 00    *(u8 *)(r4 + 6) = r5
     120:    71 25 07 00 00 00 00 00    r5 = *(u8 *)(r2 + 7)
     121:    73 54 07 00 00 00 00 00    *(u8 *)(r4 + 7) = r5
     122:    71 25 08 00 00 00 00 00    r5 = *(u8 *)(r2 + 8)
     123:    73 54 08 00 00 00 00 00    *(u8 *)(r4 + 8) = r5
     124:    71 25 09 00 00 00 00 00    r5 = *(u8 *)(r2 + 9)
     125:    73 54 09 00 00 00 00 00    *(u8 *)(r4 + 9) = r5
     126:    71 25 0a 00 00 00 00 00    r5 = *(u8 *)(r2 + 10)
     127:    73 54 0a 00 00 00 00 00    *(u8 *)(r4 + 10) = r5
     128:    71 25 0b 00 00 00 00 00    r5 = *(u8 *)(r2 + 11)
     129:    73 54 0b 00 00 00 00 00    *(u8 *)(r4 + 11) = r5
     130:    71 25 0c 00 00 00 00 00    r5 = *(u8 *)(r2 + 12)
     131:    73 54 0c 00 00 00 00 00    *(u8 *)(r4 + 12) = r5
     132:    71 25 0d 00 00 00 00 00    r5 = *(u8 *)(r2 + 13)
     133:    73 54 0d 00 00 00 00 00    *(u8 *)(r4 + 13) = r5
     134:    71 25 0e 00 00 00 00 00    r5 = *(u8 *)(r2 + 14)
     135:    73 54 0e 00 00 00 00 00    *(u8 *)(r4 + 14) = r5
     136:    b7 02 00 00 0b 00 00 00    r2 = 11
     137:    73 20 5e 00 00 00 00 00    *(u8 *)(r0 + 94) = r2
     138:    73 70 65 00 00 00 00 00    *(u8 *)(r0 + 101) = r7
     139:    73 70 64 00 00 00 00 00    *(u8 *)(r0 + 100) = r7
     140:    73 70 63 00 00 00 00 00    *(u8 *)(r0 + 99) = r7
     141:    73 70 62 00 00 00 00 00    *(u8 *)(r0 + 98) = r7
     142:    73 70 61 00 00 00 00 00    *(u8 *)(r0 + 97) = r7
     143:    73 70 60 00 00 00 00 00    *(u8 *)(r0 + 96) = r7
     144:    73 70 5f 00 00 00 00 00    *(u8 *)(r0 + 95) = r7
     145:    73 70 5d 00 00 00 00 00    *(u8 *)(r0 + 93) = r7
     146:    73 70 5c 00 00 00 00 00    *(u8 *)(r0 + 92) = r7
     147:    73 70 5b 00 00 00 00 00    *(u8 *)(r0 + 91) = r7
     148:    73 70 5a 00 00 00 00 00    *(u8 *)(r0 + 90) = r7
     149:    73 70 59 00 00 00 00 00    *(u8 *)(r0 + 89) = r7
     150:    73 70 58 00 00 00 00 00    *(u8 *)(r0 + 88) = r7
     151:    73 70 57 00 00 00 00 00    *(u8 *)(r0 + 87) = r7
     152:    b7 02 00 00 04 00 00 00    r2 = 4
     153:    73 20 56 00 00 00 00 00    *(u8 *)(r0 + 86) = r2
     154:    bf 04 00 00 00 00 00 00    r4 = r0
     155:    07 04 00 00 66 00 00 00    r4 += 102
     156:    18 05 00 00 0f 00 00 00 00 00 00 00 00 00 00 00    r5 = 15 ll
     158:    71 58 00 00 00 00 00 00    r8 = *(u8 *)(r5 + 0)
     159:    73 84 00 00 00 00 00 00    *(u8 *)(r4 + 0) = r8
     160:    71 58 01 00 00 00 00 00    r8 = *(u8 *)(r5 + 1)
     161:    73 84 01 00 00 00 00 00    *(u8 *)(r4 + 1) = r8
     162:    71 58 02 00 00 00 00 00    r8 = *(u8 *)(r5 + 2)
     163:    73 84 02 00 00 00 00 00    *(u8 *)(r4 + 2) = r8
     164:    71 58 03 00 00 00 00 00    r8 = *(u8 *)(r5 + 3)
     165:    73 84 03 00 00 00 00 00    *(u8 *)(r4 + 3) = r8
     166:    71 58 04 00 00 00 00 00    r8 = *(u8 *)(r5 + 4)
     167:    73 84 04 00 00 00 00 00    *(u8 *)(r4 + 4) = r8
     168:    71 58 05 00 00 00 00 00    r8 = *(u8 *)(r5 + 5)
     169:    73 84 05 00 00 00 00 00    *(u8 *)(r4 + 5) = r8
     170:    71 58 06 00 00 00 00 00    r8 = *(u8 *)(r5 + 6)
     171:    73 84 06 00 00 00 00 00    *(u8 *)(r4 + 6) = r8
     172:    71 58 07 00 00 00 00 00    r8 = *(u8 *)(r5 + 7)
     173:    73 84 07 00 00 00 00 00    *(u8 *)(r4 + 7) = r8
     174:    71 58 08 00 00 00 00 00    r8 = *(u8 *)(r5 + 8)
     175:    73 84 08 00 00 00 00 00    *(u8 *)(r4 + 8) = r8
     176:    71 58 09 00 00 00 00 00    r8 = *(u8 *)(r5 + 9)
     177:    73 84 09 00 00 00 00 00    *(u8 *)(r4 + 9) = r8
     178:    71 58 0a 00 00 00 00 00    r8 = *(u8 *)(r5 + 10)
     179:    73 84 0a 00 00 00 00 00    *(u8 *)(r4 + 10) = r8
     180:    b7 04 00 00 17 00 00 00    r4 = 23
     181:    73 40 a5 00 00 00 00 00    *(u8 *)(r0 + 165) = r4
     182:    b7 04 00 00 10 00 00 00    r4 = 16
     183:    73 40 9d 00 00 00 00 00    *(u8 *)(r0 + 157) = r4
     184:    73 10 95 00 00 00 00 00    *(u8 *)(r0 + 149) = r1
     185:    73 30 8d 00 00 00 00 00    *(u8 *)(r0 + 141) = r3
     186:    b7 01 00 00 06 00 00 00    r1 = 6
     187:    73 10 85 00 00 00 00 00    *(u8 *)(r0 + 133) = r1
     188:    b7 01 00 00 13 00 00 00    r1 = 19
     189:    73 10 81 00 00 00 00 00    *(u8 *)(r0 + 129) = r1
     190:    73 20 79 00 00 00 00 00    *(u8 *)(r0 + 121) = r2
     191:    73 70 ac 00 00 00 00 00    *(u8 *)(r0 + 172) = r7
     192:    73 70 ab 00 00 00 00 00    *(u8 *)(r0 + 171) = r7
     193:    73 70 aa 00 00 00 00 00    *(u8 *)(r0 + 170) = r7
     194:    73 70 a9 00 00 00 00 00    *(u8 *)(r0 + 169) = r7
     195:    73 70 a8 00 00 00 00 00    *(u8 *)(r0 + 168) = r7
     196:    73 70 a7 00 00 00 00 00    *(u8 *)(r0 + 167) = r7
     197:    73 70 a6 00 00 00 00 00    *(u8 *)(r0 + 166) = r7
     198:    73 70 a4 00 00 00 00 00    *(u8 *)(r0 + 164) = r7
     199:    73 70 a3 00 00 00 00 00    *(u8 *)(r0 + 163) = r7
     200:    73 70 a2 00 00 00 00 00    *(u8 *)(r0 + 162) = r7
     201:    73 70 a1 00 00 00 00 00    *(u8 *)(r0 + 161) = r7
     202:    73 70 a0 00 00 00 00 00    *(u8 *)(r0 + 160) = r7
     203:    73 70 9f 00 00 00 00 00    *(u8 *)(r0 + 159) = r7
     204:    73 70 9e 00 00 00 00 00    *(u8 *)(r0 + 158) = r7
     205:    73 70 9c 00 00 00 00 00    *(u8 *)(r0 + 156) = r7
     206:    73 70 9b 00 00 00 00 00    *(u8 *)(r0 + 155) = r7
     207:    73 70 9a 00 00 00 00 00    *(u8 *)(r0 + 154) = r7
     208:    73 70 99 00 00 00 00 00    *(u8 *)(r0 + 153) = r7
     209:    73 70 98 00 00 00 00 00    *(u8 *)(r0 + 152) = r7
     210:    73 70 97 00 00 00 00 00    *(u8 *)(r0 + 151) = r7
     211:    73 70 96 00 00 00 00 00    *(u8 *)(r0 + 150) = r7
     212:    73 70 94 00 00 00 00 00    *(u8 *)(r0 + 148) = r7
     213:    73 70 93 00 00 00 00 00    *(u8 *)(r0 + 147) = r7
     214:    73 70 92 00 00 00 00 00    *(u8 *)(r0 + 146) = r7
     215:    73 70 91 00 00 00 00 00    *(u8 *)(r0 + 145) = r7
     216:    73 70 90 00 00 00 00 00    *(u8 *)(r0 + 144) = r7
     217:    73 70 8f 00 00 00 00 00    *(u8 *)(r0 + 143) = r7
     218:    73 70 8e 00 00 00 00 00    *(u8 *)(r0 + 142) = r7
     219:    73 70 8c 00 00 00 00 00    *(u8 *)(r0 + 140) = r7
     220:    73 70 8b 00 00 00 00 00    *(u8 *)(r0 + 139) = r7
     221:    73 70 8a 00 00 00 00 00    *(u8 *)(r0 + 138) = r7
     222:    73 70 89 00 00 00 00 00    *(u8 *)(r0 + 137) = r7
     223:    73 70 88 00 00 00 00 00    *(u8 *)(r0 + 136) = r7
     224:    73 70 87 00 00 00 00 00    *(u8 *)(r0 + 135) = r7
     225:    73 70 86 00 00 00 00 00    *(u8 *)(r0 + 134) = r7
     226:    73 70 84 00 00 00 00 00    *(u8 *)(r0 + 132) = r7
     227:    73 70 83 00 00 00 00 00    *(u8 *)(r0 + 131) = r7
     228:    73 70 82 00 00 00 00 00    *(u8 *)(r0 + 130) = r7
     229:    73 70 80 00 00 00 00 00    *(u8 *)(r0 + 128) = r7
     230:    73 70 7f 00 00 00 00 00    *(u8 *)(r0 + 127) = r7
     231:    73 70 7e 00 00 00 00 00    *(u8 *)(r0 + 126) = r7
     232:    73 70 7d 00 00 00 00 00    *(u8 *)(r0 + 125) = r7
     233:    73 70 7c 00 00 00 00 00    *(u8 *)(r0 + 124) = r7
     234:    73 70 7b 00 00 00 00 00    *(u8 *)(r0 + 123) = r7
     235:    73 70 7a 00 00 00 00 00    *(u8 *)(r0 + 122) = r7
     236:    73 70 78 00 00 00 00 00    *(u8 *)(r0 + 120) = r7
     237:    73 70 77 00 00 00 00 00    *(u8 *)(r0 + 119) = r7
     238:    73 70 76 00 00 00 00 00    *(u8 *)(r0 + 118) = r7
     239:    73 70 75 00 00 00 00 00    *(u8 *)(r0 + 117) = r7
     240:    73 70 74 00 00 00 00 00    *(u8 *)(r0 + 116) = r7
     241:    73 70 73 00 00 00 00 00    *(u8 *)(r0 + 115) = r7
     242:    73 70 72 00 00 00 00 00    *(u8 *)(r0 + 114) = r7
     243:    b7 01 00 00 05 00 00 00    r1 = 5
     244:    73 10 71 00 00 00 00 00    *(u8 *)(r0 + 113) = r1
     245:    bf 01 00 00 00 00 00 00    r1 = r0
     246:    07 01 00 00 ad 00 00 00    r1 += 173
     247:    18 02 00 00 1a 00 00 00 00 00 00 00 00 00 00 00    r2 = 26 ll
     249:    71 23 00 00 00 00 00 00    r3 = *(u8 *)(r2 + 0)
     250:    73 31 00 00 00 00 00 00    *(u8 *)(r1 + 0) = r3
     251:    71 23 01 00 00 00 00 00    r3 = *(u8 *)(r2 + 1)
     252:    73 31 01 00 00 00 00 00    *(u8 *)(r1 + 1) = r3
     253:    71 23 02 00 00 00 00 00    r3 = *(u8 *)(r2 + 2)
     254:    73 31 02 00 00 00 00 00    *(u8 *)(r1 + 2) = r3
     255:    71 23 03 00 00 00 00 00    r3 = *(u8 *)(r2 + 3)
     256:    73 31 03 00 00 00 00 00    *(u8 *)(r1 + 3) = r3
     257:    71 23 04 00 00 00 00 00    r3 = *(u8 *)(r2 + 4)
     258:    73 31 04 00 00 00 00 00    *(u8 *)(r1 + 4) = r3
     259:    71 23 05 00 00 00 00 00    r3 = *(u8 *)(r2 + 5)
     260:    73 31 05 00 00 00 00 00    *(u8 *)(r1 + 5) = r3
     261:    71 23 06 00 00 00 00 00    r3 = *(u8 *)(r2 + 6)
     262:    73 31 06 00 00 00 00 00    *(u8 *)(r1 + 6) = r3
     263:    71 23 07 00 00 00 00 00    r3 = *(u8 *)(r2 + 7)
     264:    73 31 07 00 00 00 00 00    *(u8 *)(r1 + 7) = r3
     265:    71 23 08 00 00 00 00 00    r3 = *(u8 *)(r2 + 8)
     266:    73 31 08 00 00 00 00 00    *(u8 *)(r1 + 8) = r3
     267:    71 23 09 00 00 00 00 00    r3 = *(u8 *)(r2 + 9)
     268:    73 31 09 00 00 00 00 00    *(u8 *)(r1 + 9) = r3
     269:    71 23 0a 00 00 00 00 00    r3 = *(u8 *)(r2 + 10)
     270:    73 31 0a 00 00 00 00 00    *(u8 *)(r1 + 10) = r3
     271:    71 23 0b 00 00 00 00 00    r3 = *(u8 *)(r2 + 11)
     272:    73 31 0b 00 00 00 00 00    *(u8 *)(r1 + 11) = r3
     273:    71 23 0c 00 00 00 00 00    r3 = *(u8 *)(r2 + 12)
     274:    73 31 0c 00 00 00 00 00    *(u8 *)(r1 + 12) = r3
     275:    71 23 0d 00 00 00 00 00    r3 = *(u8 *)(r2 + 13)
     276:    73 31 0d 00 00 00 00 00    *(u8 *)(r1 + 13) = r3
     277:    71 23 0e 00 00 00 00 00    r3 = *(u8 *)(r2 + 14)
     278:    73 31 0e 00 00 00 00 00    *(u8 *)(r1 + 14) = r3
     279:    71 23 0f 00 00 00 00 00    r3 = *(u8 *)(r2 + 15)
     280:    73 31 0f 00 00 00 00 00    *(u8 *)(r1 + 15) = r3
     281:    71 23 10 00 00 00 00 00    r3 = *(u8 *)(r2 + 16)
     282:    73 31 10 00 00 00 00 00    *(u8 *)(r1 + 16) = r3
     283:    71 23 11 00 00 00 00 00    r3 = *(u8 *)(r2 + 17)
     284:    73 31 11 00 00 00 00 00    *(u8 *)(r1 + 17) = r3
     285:    71 23 12 00 00 00 00 00    r3 = *(u8 *)(r2 + 18)
     286:    73 31 12 00 00 00 00 00    *(u8 *)(r1 + 18) = r3
     287:    71 23 13 00 00 00 00 00    r3 = *(u8 *)(r2 + 19)
     288:    73 31 13 00 00 00 00 00    *(u8 *)(r1 + 19) = r3
     289:    71 23 14 00 00 00 00 00    r3 = *(u8 *)(r2 + 20)
     290:    73 31 14 00 00 00 00 00    *(u8 *)(r1 + 20) = r3
     291:    71 23 15 00 00 00 00 00    r3 = *(u8 *)(r2 + 21)
     292:    73 31 15 00 00 00 00 00    *(u8 *)(r1 + 21) = r3
     293:    71 23 16 00 00 00 00 00    r3 = *(u8 *)(r2 + 22)
     294:    73 31 16 00 00 00 00 00    *(u8 *)(r1 + 22) = r3
     295:    bf 61 00 00 00 00 00 00    r1 = r6
     296:    18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00    r2 = 0 ll
     298:    18 03 00 00 ff ff ff ff 00 00 00 00 00 00 00 00    r3 = 4294967295 ll
     300:    bf 04 00 00 00 00 00 00    r4 = r0
     301:    b7 05 00 00 c4 00 00 00    r5 = 196
     302:    85 00 00 00 19 00 00 00    call 25

0000000000000978 LBB0_2:
     303:    b7 00 00 00 00 00 00 00    r0 = 0
     304:    95 00 00 00 00 00 00 00    <span class="hljs-built_in">exit</span>
</code></pre>
<pre><code class="lang-bash">Usage: aya-rust-sangam [OPTIONS]

Options:
  -c, --cgroup-path &lt;CGROUP_PATH&gt;  [default: /sys/fs/cgroup/unified]
  -h, --<span class="hljs-built_in">help</span>                       Print <span class="hljs-built_in">help</span>
</code></pre>
<p>That's it for this part we will learn more around aya and ebpf .</p>
<p>the eBPF developer experience by allowing Rust programs to easily run within the kernel.</p>
<p>Aya is the first Rust-native eBPF library that is similar in nature to libbpf but entirely written in the Rust programming language, popular for its memory safety and concurrency features, among other reasons this programming language is becoming very popular for systems programming.</p>
]]></content:encoded></item><item><title><![CDATA[Web Scraping in Golang]]></title><description><![CDATA[Introduction
Every developer uses web scraping as a necessary tool at some time in their career. Therefore, developers must understand web scrapers and how to create them.
In this blog, we will be covering the basics of web scraping in Go using the F...]]></description><link>https://blog.cloudnativefolks.org/web-scraping-in-golang</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/web-scraping-in-golang</guid><category><![CDATA[Go Language]]></category><category><![CDATA[Scraping]]></category><category><![CDATA[go-fiber]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Colly ]]></category><dc:creator><![CDATA[Siddhesh Khandagale]]></dc:creator><pubDate>Sun, 05 Feb 2023 19:28:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675625272529/9bf462aa-041c-4ed9-8072-b82b4254d5fe.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Every developer uses web scraping as a necessary tool at some time in their career. Therefore, developers must understand web scrapers and how to create them.</p>
<p>In this blog, we will be covering the basics of web scraping in Go using the <a target="_blank" href="https://docs.gofiber.io/">Fiber</a> and <a target="_blank" href="http://go-colly.org/">Colly</a> frameworks. Colly is an open-source web scraping framework written in Go. It provides a simple and flexible API for performing web scraping tasks, making it a popular choice among Go developers. Colly uses Go's concurrency features to efficiently handle multiple requests and extract data from websites. It offers a wide range of customization options, including the ability to set request headers, handle cookies, follow redirects, and more</p>
<p>We'll start with a simple example of extracting data from a website and then move on to more advanced topics like customizing the scraping process and setting request headers. By the end of this blog, you'll have a solid understanding of how to build a web scraper using Go and be able to extract data from any website.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>To continue with the tutorial, firstly you need to have Golang and Fiber installed.</p>
<h3 id="heading-installations"><strong>Installations :</strong></h3>
<ul>
<li><p><a target="_blank" href="https://go.dev/doc/install"><strong>Golang</strong></a></p>
</li>
<li><p><a target="_blank" href="https://docs.gofiber.io/"><strong>Fiber</strong></a>: We'll see this ahead in the tutorial.</p>
</li>
<li><p><a target="_blank" href="http://go-colly.org/">Colly</a>: We'll see this ahead in the tutorial.</p>
</li>
</ul>
<h2 id="heading-getting-started"><strong>Getting Started</strong></h2>
<p>Let's get started by creating the main project directory <code>Go-Scraper</code> by using the following command.</p>
<p>(🟥Be careful, sometimes I've done the explanation by commenting in the code)</p>
<pre><code class="lang-go">mkdir Go-Scraper <span class="hljs-comment">//Creates a 'Go-Scraper' directory</span>
cd Go-Scraper <span class="hljs-comment">//Change directory to 'Go-Scraper'</span>
</code></pre>
<p>Now initialize a mod file. <em>(If you publish a module, this must be a path from which your module can be downloaded by Go tools. That would be your code's repository.)</em></p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> mod init github.com/&lt;username&gt;/Go-Scraper
</code></pre>
<p>To install the Fiber Framework run the following command :</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get -u github.com/gofiber/fiber/v2
</code></pre>
<p>To install the Colly Framework run the following command :</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get -u github.com/gocolly/colly/...
</code></pre>
<p>Now, let's make the <code>main.go</code> in which we are going to implement the scraping process.</p>
<p>In the <code>main.go</code> file, the first step is to initialize a new Fiber app using the <code>fiber.New()</code> method. This creates a new instance of the Fiber framework that will handle the HTTP requests and responses.</p>
<p>Next, we define a new endpoint for the web scraper by calling the <code>app.Get("/scrape", ...)</code> method. This creates a new GET endpoint at the <code>/scrape</code> route, which will be used to trigger the web scraping process.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    app := fiber.New() <span class="hljs-comment">// Creating a new instance of Fiber.</span>
    app.Get(<span class="hljs-string">"/scrape"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-keyword">return</span> c.SendString(<span class="hljs-string">"Go Web Scraper"</span>)
    })
    app.Listen(<span class="hljs-string">":8080"</span>)
}
</code></pre>
<p>After running the <code>go run main.go</code> command the terminal will look like this,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675596510246/7e6eedea-a46e-4477-baa0-77e48a6b89a7.png" alt class="image--center mx-auto" /></p>
<p>Let's create a new instance of the Colly collector using the <code>colly.NewCollector()</code> method. The collector is responsible for visiting the website, extracting data, and storing the results.</p>
<pre><code class="lang-go">collector := colly.NewCollector(
    colly.AllowedDomains(<span class="hljs-string">"j2store.net"</span>),
)
collector.OnRequest(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(r *colly.Request)</span></span> {
    fmt.Println(<span class="hljs-string">"Visiting"</span>, r.URL)
})
</code></pre>
<p>The <code>colly.AllowedDomains</code> property in the Colly framework is used to restrict the domains that the web scraper is allowed to visit. This property is used to prevent the scraper from visiting unwanted websites. For this blog, we are going to use <a target="_blank" href="http://j2store.net/demo/index.php/shop">this</a> site which contains sample data and the domain is <code>j2store.net</code> .</p>
<p>The Colly collector can be configured in a variety of ways to customize the web scraping process. In this case, we define a request handler using the <code>collector.OnRequest(...)</code> method. This handler is called each time a request is made to the website, and it simply logs the URL being visited.</p>
<p>Now, to extract data from the website, we are going to use the <code>collector.OnHTML(...)</code> method to define a handler for a specific HTML element.</p>
<p>This is how the sample data on the site looks,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675597913267/15b170db-4bb5-42dc-8bab-d8c1c16a5ace.png" alt class="image--center mx-auto" /></p>
<p>Here are some product images, their names and their price. We are just going the extract their names, image URL and prices.</p>
<p>So, let's create a struct <code>item</code> containing these three fields i.e. Name, Price, Image URL. The data type is defined as a string. JSON field is added as we are going to return all the data in JSON.</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> item <span class="hljs-keyword">struct</span> {
    Name   <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"name"`</span>
    Price  <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"price"`</span>
    ImgUrl <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"imgurl"`</span>
}
</code></pre>
<p>Now, Let's work on the <code>OnHTML()</code> callback.</p>
<pre><code class="lang-go">collector.OnHTML(<span class="hljs-string">"div.col-sm-9 div[itemprop=itemListElement] "</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(h *colly.HTMLElement)</span></span> {
    item := item{
        Name:   h.ChildText(<span class="hljs-string">"h2.product-title"</span>),
        Price:  h.ChildText(<span class="hljs-string">"div.sale-price"</span>),
        ImgUrl: h.ChildAttr(<span class="hljs-string">"img"</span>, <span class="hljs-string">"src"</span>),
    }
    items = <span class="hljs-built_in">append</span>(items, item)
})
</code></pre>
<p>Here, inside the OnHTML() function firstly, we added something inside quotes that is the parent element it's a CSS selector, inside this div tags all the products are added. You can see it on the page by Inspect Element and hovering over the product just like the way I did in the image below. This means that whenever this parent element comes then this OnHTML callback must be called.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675599074190/82efc179-793e-4f77-a1b9-018585c7819f.png" alt class="image--center mx-auto" /></p>
<p>We've used the child element to get only the required data i.e the Name, Price and the ImgUrl. You can see these Child elements just the way we did for the parent element.</p>
<p>Finally, add the product details one by one into <code>items</code> .</p>
<p>Now, the main.go will look like,</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"fmt"</span>

    <span class="hljs-string">"github.com/gocolly/colly"</span>
    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
)

<span class="hljs-keyword">type</span> item <span class="hljs-keyword">struct</span> {
    Name   <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"name"`</span>
    Price  <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"price"`</span>
    ImgUrl <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"imgurl"`</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    app := fiber.New()
    app.Get(<span class="hljs-string">"/scrape"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
        <span class="hljs-keyword">var</span> items []item
        collector := colly.NewCollector(
            colly.AllowedDomains(<span class="hljs-string">"j2store.net"</span>),
        )
        collector.OnRequest(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(r *colly.Request)</span></span> {
            fmt.Println(<span class="hljs-string">"Visiting"</span>, r.URL)
        })

        collector.OnHTML(<span class="hljs-string">"div.col-sm-9 div[itemprop=itemListElement] "</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(h *colly.HTMLElement)</span></span> {
            item := item{
                Name:   h.ChildText(<span class="hljs-string">"h2.product-title"</span>),
                Price:  h.ChildText(<span class="hljs-string">"div.sale-price"</span>),
                ImgUrl: h.ChildAttr(<span class="hljs-string">"img"</span>, <span class="hljs-string">"src"</span>),
            }
            items = <span class="hljs-built_in">append</span>(items, item)
        })

        collector.Visit(<span class="hljs-string">"http://j2store.net/demo/index.php/shop"</span>) <span class="hljs-comment">// initiate a request to the specified URL.</span>
        <span class="hljs-keyword">return</span> c.JSON(items) <span class="hljs-comment">//we return the extracted data to the client by calling the c.JSON(...) method.</span>
    })

    app.Listen(<span class="hljs-string">":8080"</span>)
}
</code></pre>
<p>Now, run the command <code>go run main.go</code> and head to <code>http://127.0.0.1:8080/scrape</code> on your browser.</p>
<p>You'll see the data like the following,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675601448330/f3c49403-db57-4e02-ae6b-760ee9f6f270.png" alt class="image--center mx-auto" /></p>
<p>Now, this data is from the first page but there are multiple pages on the site so we've to deal with all the pages. Colly Framework works very well with this. We need to add one more OnHTML callback for moving to the next page.</p>
<pre><code class="lang-go">collector.OnHTML(<span class="hljs-string">"[title=Next]"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(e *colly.HTMLElement)</span></span> {
    next_page := e.Request.AbsoluteURL(e.Attr(<span class="hljs-string">"href"</span>))
    collector.Visit(next_page)
})
</code></pre>
<p>[title=Next] is the CSS selector for the <code>Next</code> button. You can see this by following the same way as did earlier. Now the URL added in the href tag is not an absolute URL, so we've used the AbsoluteUrl() function to convert the relative URL to an absolute URL.</p>
<p>Now, run the command <code>go run main.go</code> and head to <code>http://127.0.0.1:8080/scrape</code> on your browser.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1675602591281/3a4152a2-a88c-4d0d-989c-d7d65772c8b1.png" alt class="image--center mx-auto" /></p>
<p>You'll see all product details from all the pages.</p>
<p>This is the basic implementation of a web scraper using the Fiber and Colly frameworks in Go</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You can find the complete code repository for this tutorial here 👉<a target="_blank" href="https://github.com/Siddheshk02/Go-Scraper">Github</a>.</p>
<p>Now, I hope you must have a solid foundation to build more complex and sophisticated web scraping projects. Now, you can try Scraping dynamic websites along with Data storage(SQL or NoSQL), Image and file download, Distributed scraping and so on.</p>
<p>Until then <strong>Keep Learning, Keep Building 🚀🚀</strong></p>
]]></content:encoded></item><item><title><![CDATA[Writing Rust CLIs - Clap]]></title><description><![CDATA[How echo works
purpose of this is to show you how to use arguments from the command line to change the behaviour of the program at runtime.
$ echo Hello
Hello

to start echo will prints its arguments to STDOUT
➜  rustlabs echo "welcome to  rustlabs "...]]></description><link>https://blog.cloudnativefolks.org/writing-rust-clis-clap</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/writing-rust-clis-clap</guid><category><![CDATA[Rust]]></category><category><![CDATA[command line]]></category><category><![CDATA[clap]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Thu, 19 Jan 2023 10:49:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674125290070/f6a4c28b-8161-4b3a-8bfe-92d850f42f91.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-how-echo-works">How echo works</h4>
<p>purpose of this is to show you how to use arguments from the command line to change the behaviour of the program at runtime.</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">echo</span> Hello
Hello
</code></pre>
<p>to start echo will prints its arguments to STDOUT</p>
<pre><code class="lang-bash">➜  rustlabs <span class="hljs-built_in">echo</span> <span class="hljs-string">"welcome to  rustlabs "</span>
welcome to  rustlabs 
➜  rustlabs <span class="hljs-built_in">echo</span> welcome to  rustlabs  
welcome to rustlabs
</code></pre>
<p>if you want the spaces to be prevented I must enclose them in quotes.</p>
<p><code>man echo</code> you will see more options around it .</p>
<pre><code class="lang-bash">ECHO(1)                                                          General Commands Manual                                                         ECHO(1)

NAME
     <span class="hljs-built_in">echo</span> – write arguments to the standard output

SYNOPSIS
     <span class="hljs-built_in">echo</span> [-n] [string ...]

DESCRIPTION
     The <span class="hljs-built_in">echo</span> utility writes any specified operands, separated by single blank (‘ ’) characters and followed by a newline (‘\n’) character, to the
     standard output.

     The following option is available:

     -n    Do not <span class="hljs-built_in">print</span> the trailing newline character.  This may also be achieved by appending ‘\c’ to the end of the string, as is <span class="hljs-keyword">done</span> by iBCS2
           compatible systems.  Note that this option as well as the effect of ‘\c’ are implementation-defined <span class="hljs-keyword">in</span> IEEE Std 1003.1-2001 (“POSIX.1”) as
           amended by Cor. 1-2002.  Applications aiming <span class="hljs-keyword">for</span> maximum portability are strongly encouraged to use <span class="hljs-built_in">printf</span>(1) to suppress the newline
           character.

     Some shells may provide a <span class="hljs-built_in">builtin</span> <span class="hljs-built_in">echo</span> <span class="hljs-built_in">command</span> <span class="hljs-built_in">which</span> is similar or identical to this utility.  Most notably, the <span class="hljs-built_in">builtin</span> <span class="hljs-built_in">echo</span> <span class="hljs-keyword">in</span> sh(1) does not
     accept the -n option.  Consult the <span class="hljs-built_in">builtin</span>(1) manual page.

EXIT STATUS
     The <span class="hljs-built_in">echo</span> utility exits 0 on success, and &gt;0 <span class="hljs-keyword">if</span> an error occurs.

SEE ALSO
     <span class="hljs-built_in">builtin</span>(1), csh(1), <span class="hljs-built_in">printf</span>(1), sh(1)

STANDARDS
     The <span class="hljs-built_in">echo</span> utility conforms to IEEE Std 1003.1-2001 (“POSIX.1”) as amended by Cor. 1-2002.

macOS 13.1                                                           April 12, 2003                                                           macOS 13.1
</code></pre>
<p>by default the text that <code>echo</code> prints on the command line are terminated by a new line character. if you see the above manual the program has a single <code>-n</code> option to omit the final newline.</p>
<pre><code class="lang-bash">➜  rustlabs <span class="hljs-built_in">echo</span> -n Hello &gt; hello-n
➜  rustlabs <span class="hljs-built_in">echo</span> Hello &gt; hello-a
</code></pre>
<p>the diff tool will display the difference between the two files .</p>
<pre><code class="lang-bash">rustlabs <span class="hljs-built_in">echo</span> Hello &gt; hello-a 
➜  rustlabs diff hello-n hello-a    
1c1
&lt; Hello
\ No newline at end of file
---
&gt; Hello
</code></pre>
<hr />
<h4 id="heading-getting-started">getting started</h4>
<p>lets a new directory with the name <code>echor</code> using cargo :</p>
<pre><code class="lang-bash">$ cargo new echor
     Created binary (application) `echor` package
</code></pre>
<p>change the new directory to see the structure</p>
<pre><code class="lang-bash">➜  rustlabs <span class="hljs-built_in">cd</span> echor 
➜  echor git:(master) ✗ tree
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
</code></pre>
<p>use cargo to run the program</p>
<pre><code class="lang-bash">➜  echor git:(master) ✗ cargo run
   Compiling echor v0.1.0 (/Users/sangambiradar/Documents/rustlabs/echor)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.84s
     Running `target/debug/echor`
Hello, world!
</code></pre>
<p>rust will start the program executing the <code>main</code> function in <code>src/main.rs</code> all function in <code>src/main</code> all functions return a value and the return type may be indicated with an arrow and the type such as <code>-&gt; u32</code> to say the function returns an unsigned <code>32-bit</code> integer . the lack of any return type for the main implies that the function returns what calls the <code>unit</code> type /</p>
<p><code>println!</code> the macro will automatically append a new line to the output, which is a feature you'll need to control when the user requests no terminating newline.</p>
<blockquote>
<p>the unit type is like an empty value and is signified with a set of empty parentheses <code>()</code> the documentation says this "is used when there is no other meaningful value that could be returned " its not quite like a null pointer or undefined value in other languages</p>
</blockquote>
<hr />
<h4 id="heading-accessing-the-command-line-arguments">Accessing the command-line arguments</h4>
<p>getting the command-line arguments to print. you can use <code>std::env::args</code> here <code>std::env</code> to interact with the environment which is where the program will find the arguments if you look at the documentation for a function, you will see it returns something of the type <code>args</code></p>
<pre><code class="lang-bash">pub fn args() -&gt; args
</code></pre>
<p>edit <code>src/main.rs</code> to print the arguments. you can call the function by using the full path followed by an empty set of parentheses</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-built_in">println!</span>(std::env::args());
}
</code></pre>
<p>execute the program using <code>cargo run</code></p>
<pre><code class="lang-rust">echor git:(master) ✗ cargo run
   Compiling echor v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/echor)
error: format argument must be a string literal
 --&gt; src/main.rs:<span class="hljs-number">2</span>:<span class="hljs-number">14</span>
  |
<span class="hljs-number">2</span> |     <span class="hljs-built_in">println!</span>(std::env::args());
  |              ^^^^^^^^^^^^^^^^
  |
help: you might be missing a string literal to format with
  |
<span class="hljs-number">2</span> |     <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, std::env::args());
  |              +++++

error: could not compile `echor` due to previous error
</code></pre>
<p>here you can't directly print the value that is returned from the function but it also suggests how to fix the problem. it wants you to first provide a literal string that has a set of curly braces <code>{}</code> that will serve as a placeholder for printed value so change the code</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>,std::env::args());
}
</code></pre>
<p>execute cargo run</p>
<pre><code class="lang-rust">➜  echor git:(master) ✗ cargo run
   Compiling echor v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/echor)
error[E0277]: `Args` doesn<span class="hljs-symbol">'t</span> implement `std::fmt::Display`
 --&gt; src/main.rs:<span class="hljs-number">2</span>:<span class="hljs-number">19</span>
  |
<span class="hljs-number">2</span> |     <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>,std::env::args());
  |                   ^^^^^^^^^^^^^^^^ `Args` cannot be formatted with the default formatter
  |
  = help: the <span class="hljs-class"><span class="hljs-keyword">trait</span> `<span class="hljs-title">std</span></span>::fmt::Display` is not implemented <span class="hljs-keyword">for</span> `Args`
  = note: <span class="hljs-keyword">in</span> format strings you may be able to <span class="hljs-keyword">use</span> `{:?}` (or {:#?} <span class="hljs-keyword">for</span> pretty-print) instead
  = note: this error originates <span class="hljs-keyword">in</span> the <span class="hljs-keyword">macro</span> `$crate::format_args_nl` which comes from the expansion of the <span class="hljs-keyword">macro</span> `println` (<span class="hljs-keyword">in</span> Nightly builds, run with -Z <span class="hljs-keyword">macro</span>-backtrace <span class="hljs-keyword">for</span> more info)

For more information about this error, <span class="hljs-keyword">try</span> `rustc --explain E0277`.
error: could not compile `echor` due to previous error
</code></pre>
<p>there is a lot of information in that compiler message. the trait <code>std::fmt::Display</code> not being implemented for <code>Args</code> . A <code>trait</code> in rust is a way to define the behaviour of an object abstractly. if an object implements the <code>Display</code> trait, then it can be formatted for user-facing out.</p>
<p>The compiler suggests you should use <code>{:?}</code> instead of {} for placeholder . this is an instruction to print a <code>Debug</code> a version of the structure, which will format the output in debugging context</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{:?}"</span>,std::env::args());
}
</code></pre>
<p>execute cargo run</p>
<pre><code class="lang-rust">
➜  echor git:(master) ✗ cargo run
   Compiling echor v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/echor)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.44</span>s
     Running `target/debug/echor`
Args { inner: [<span class="hljs-string">"target/debug/echor"</span>] }
</code></pre>
<p>if you are unfamiliar with command line arguments, it's common for the first value to be the path of the program itself.</p>
<pre><code class="lang-rust">➜  echor git:(master) ✗ cargo run hello world
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.00</span>s
     Running `target/debug/echor hello world`
Args { inner: [<span class="hljs-string">"target/debug/echor"</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-string">"world"</span>] }
</code></pre>
<p>let's see with <code>-n</code> flag</p>
<pre><code class="lang-rust">  echor git:(master) ✗ cargo run hello world -n
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.03</span>s
     Running `target/debug/echor hello world -n`
Args { inner: [<span class="hljs-string">"target/debug/echor"</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-string">"world"</span>, <span class="hljs-string">"-n"</span>] }
</code></pre>
<p>cargo think the <code>-n</code> argument itself</p>
<hr />
<h4 id="heading-adding-clap-as-a-dependency">Adding Clap as a Dependency</h4>
<p>there are various methods and crates for parsing command-line arguments. we will use <code>clap</code> (<a target="_blank" href="https://crates.io/crates/clap">https://crates.io/crates/clap</a>)</p>
<p>let's add <code>clap</code> dependency to <code>Cargo.toml</code></p>
<pre><code class="lang-rust">[package]
name = <span class="hljs-string">"echor"</span>
version = <span class="hljs-string">"0.1.0"</span>
edition = <span class="hljs-string">"2021"</span>

# See more keys and their definitions at https:<span class="hljs-comment">//doc.rust-lang.org/cargo/reference/manifest.html</span>

[dependencies]
clap = <span class="hljs-string">"4.1.1"</span>
</code></pre>
<p>here we are using <code>4.1.1</code> a version of clap as a dependency</p>
<p>run <code>cargo build</code> to just build the new binary and not run it :</p>
<pre><code class="lang-rust">➜  echor git:(master) ✗ cargo build             
    Updating crates.io index
  Downloaded clap_lex v0.<span class="hljs-number">3.1</span>
  Downloaded io-lifetimes v1.<span class="hljs-number">0.4</span>
  Downloaded is-terminal v0.<span class="hljs-number">4.2</span>
  Downloaded termcolor v1.<span class="hljs-number">2.0</span>
  Downloaded errno v0.<span class="hljs-number">2.8</span>
  Downloaded rustix v0.<span class="hljs-number">36.6</span>
  Downloaded os_str_bytes v6.<span class="hljs-number">4.1</span>
  Downloaded clap v4.<span class="hljs-number">1.1</span>
  Downloaded <span class="hljs-number">8</span> crates (<span class="hljs-number">599.0</span> KB) <span class="hljs-keyword">in</span> <span class="hljs-number">0.55</span>s
   Compiling libc v0.<span class="hljs-number">2.139</span>
   Compiling io-lifetimes v1.<span class="hljs-number">0.4</span>
   Compiling rustix v0.<span class="hljs-number">36.6</span>
   Compiling bitflags v1.<span class="hljs-number">3.2</span>
   Compiling os_str_bytes v6.<span class="hljs-number">4.1</span>
   Compiling termcolor v1.<span class="hljs-number">2.0</span>
   Compiling strsim v0.<span class="hljs-number">10.0</span>
   Compiling clap_lex v0.<span class="hljs-number">3.1</span>
   Compiling errno v0.<span class="hljs-number">2.8</span>
   Compiling is-terminal v0.<span class="hljs-number">4.2</span>
   Compiling clap v4.<span class="hljs-number">1.1</span>
   Compiling echor v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/echor)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">13.25</span>s
</code></pre>
<blockquote>
<p>a consequence of rust placing the dependencies into a target is that this directory is now quite large. you can use the disk usage command <code>du -shc</code></p>
</blockquote>
<hr />
<h4 id="heading-parsing-command-line-arguments-using-clap">parsing Command Line Arguments using Clap</h4>
<p>update <code>src/main.rs</code> that creates a <code>new clap::Command</code> struct to parsing the command line arguments</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> clap::Command;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> _matches = Command::new(<span class="hljs-string">"echor-app"</span>)
    .version(<span class="hljs-string">"0.1.0"</span>)
    .author(<span class="hljs-string">"Sangam Biradar &lt;sangam14@gmail.com"</span>)
    .about(<span class="hljs-string">"Rust echo"</span>)
    .get_matches();
}
</code></pre>
<ul>
<li><p>Import the <code>clap::Command</code> struct</p>
</li>
<li><p>Create a new App with the name <code>echor</code> app</p>
</li>
<li><p>User Semantic version information</p>
</li>
<li><p>Include your name and email address so people know where to send the help</p>
</li>
</ul>
<p>execute cargo run</p>
<pre><code class="lang-rust">echor git:(master) ✗ cargo run -- -h
   Compiling echor v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/echor)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.76</span>s
     Running `target/debug/echor -h`
Rust echo

Usage: echor

Options:
  -h, --help     Print help
  -V, --version  Print version 
➜  echor git:(master) ✗ cargo run -- -V
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.02</span>s
     Running `target/debug/echor -V`
echor-app <span class="hljs-number">0.1</span>.<span class="hljs-number">0</span>
</code></pre>
<p>Inable <code>derive flag</code> you can create application declaratievly with <code>struct</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::path::PathBuf;

<span class="hljs-keyword">use</span> clap::{Parser, Subcommand};

<span class="hljs-meta">#[derive(Parser)]</span>
<span class="hljs-meta">#[command(author, version, about, long_about = None)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Cli</span></span> {
    <span class="hljs-comment">/// Optional name to operate on</span>
    name: <span class="hljs-built_in">Option</span>&lt;<span class="hljs-built_in">String</span>&gt;,

    <span class="hljs-comment">/// Sets a custom config file</span>
    <span class="hljs-meta">#[arg(short, long, value_name = <span class="hljs-meta-string">"FILE"</span>)]</span>
    config: <span class="hljs-built_in">Option</span>&lt;PathBuf&gt;,

    <span class="hljs-comment">/// Turn debugging information on</span>
    <span class="hljs-meta">#[arg(short, long, action = clap::ArgAction::Count)]</span>
    debug: <span class="hljs-built_in">u8</span>,

    <span class="hljs-meta">#[command(subcommand)]</span>
    command: <span class="hljs-built_in">Option</span>&lt;Commands&gt;,
}

<span class="hljs-meta">#[derive(Subcommand)]</span>
<span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Commands</span></span> {
    <span class="hljs-comment">/// does testing things</span>
    Test {
        <span class="hljs-comment">/// lists test values</span>
        <span class="hljs-meta">#[arg(short, long)]</span>
        list: <span class="hljs-built_in">bool</span>,
    },
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> cli = Cli::parse();

    <span class="hljs-comment">// You can check the value provided by positional arguments, or option arguments</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(name) = cli.name.as_deref() {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value for name: {}"</span>, name);
    }

    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(config_path) = cli.config.as_deref() {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Value for config: {}"</span>, config_path.display());
    }

    <span class="hljs-comment">// You can see how many times a particular flag or argument occurred</span>
    <span class="hljs-comment">// Note, only flags can have multiple occurrences</span>
    <span class="hljs-keyword">match</span> cli.debug {
        <span class="hljs-number">0</span> =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Debug mode is off"</span>),
        <span class="hljs-number">1</span> =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Debug mode is kind of on"</span>),
        <span class="hljs-number">2</span> =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Debug mode is on"</span>),
        _ =&gt; <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Don't be crazy"</span>),
    }

    <span class="hljs-comment">// You can check for the existence of subcommands, and if found use their</span>
    <span class="hljs-comment">// matches just as you would the top level cmd</span>
    <span class="hljs-keyword">match</span> &amp;cli.command {
        <span class="hljs-literal">Some</span>(Commands::Test { list }) =&gt; {
            <span class="hljs-keyword">if</span> *list {
                <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Printing testing lists..."</span>);
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Not printing testing lists..."</span>);
            }
        }
        <span class="hljs-literal">None</span> =&gt; {}
    }

    <span class="hljs-comment">// Continued program logic goes here...</span>
}
</code></pre>
<p>cargo run</p>
<pre><code class="lang-rust">cargo run -- -h     
   Compiling echor v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/echor)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.46</span>s
     Running `target/debug/echor -h`
Usage: echor [OPTIONS] [NAME] [COMMAND]

Commands:
  test  does testing things
  help  Print this message or the help of the given subcommand(s)

Arguments:
  [NAME]  Optional name to operate on

Options:
  -c, --config &lt;FILE&gt;  Sets a custom config file
  -d, --debug...       Turn debugging information on
  -h, --help           Print help
  -V, --version        Print version
➜  echor git:(master) ✗
</code></pre>
<p>add Clap with<code>derive</code> feature for CLI and anyhow for error propagation</p>
<pre><code class="lang-rust">cargo add clap -F derive
cargo add anyhow
</code></pre>
<p>organize directory with the following file structure</p>
<pre><code class="lang-rust"> src
├── commands
│   ├── cli.rs
│   └── <span class="hljs-keyword">mod</span>.rs
└── main.rs
Cargo.lock
Cargo.toml
</code></pre>
<p>add the following code to <code>src/commands/mod.rs</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> cli;
</code></pre>
<p>add the following code to <code>src/commands/cli.rs</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> anyhow::<span class="hljs-built_in">Result</span>;
<span class="hljs-keyword">use</span> clap::Parser;

<span class="hljs-comment">/// Rusty example app</span>
<span class="hljs-meta">#[derive(Parser, Debug)]</span>
<span class="hljs-meta">#[command(version, bin_name = <span class="hljs-meta-string">"rusty"</span>, disable_help_subcommand = true)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Cli</span></span> {}

<span class="hljs-keyword">impl</span> Cli {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Hello, World!"</span>);

        <span class="hljs-literal">Ok</span>(())
    }
}
</code></pre>
<p>update entry point</p>
<pre><code class="lang-rust"><span class="hljs-keyword">mod</span> commands;

<span class="hljs-keyword">use</span> anyhow::<span class="hljs-built_in">Result</span>;
<span class="hljs-keyword">use</span> clap::Parser;


<span class="hljs-keyword">use</span> crate::commands::cli::Cli;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> cli = Cli::parse();

    cli.exec()
}
</code></pre>
<p>execute cargo run</p>
<pre><code class="lang-rust"> cargo run -q -- --help
Rusty example app

Usage: rusty

Options:
  -h, --help     Print help
  -V, --version  Print version
</code></pre>
<hr />
<h4 id="heading-argument-passing">Argument Passing</h4>
<pre><code class="lang-rust">src
├── commands
│   ├── cli.rs
│   ├── exec.rs
│   └── <span class="hljs-keyword">mod</span>.rs
└── main.rs
Cargo.lock
Cargo.toml
</code></pre>
<p>create the following file with content <code>src/commands/exec.rs</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> anyhow::<span class="hljs-built_in">Result</span>;
<span class="hljs-keyword">use</span> clap::Args;
<span class="hljs-keyword">use</span> std::process::{exit, Command};

<span class="hljs-comment">/// Execute an arbitrary command</span>
<span class="hljs-comment">///</span>
<span class="hljs-comment">/// All arguments are passed through unless --help is first</span>
<span class="hljs-meta">#[derive(Args, Debug)]</span>
<span class="hljs-meta">#[command()]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Cli</span></span> {
    <span class="hljs-meta">#[arg(required = true, trailing_var_arg = true, allow_hyphen_values = true)]</span>
    args: <span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">String</span>&gt;,
}

<span class="hljs-keyword">impl</span> Cli {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> command = Command::new(&amp;<span class="hljs-keyword">self</span>.args[<span class="hljs-number">0</span>]);
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">self</span>.args.len() &gt; <span class="hljs-number">1</span> {
            command.args(&amp;<span class="hljs-keyword">self</span>.args[<span class="hljs-number">1</span>..]);
        }

        <span class="hljs-keyword">let</span> status = command.status()?;
        exit(status.code().unwrap_or(<span class="hljs-number">1</span>));
    }
}
</code></pre>
<p>add new module</p>
<pre><code class="lang-rust"><span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> cli;
<span class="hljs-keyword">pub</span> <span class="hljs-keyword">mod</span> exec;
</code></pre>
<p>modify root command</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> anyhow::<span class="hljs-built_in">Result</span>;
<span class="hljs-keyword">use</span> clap::{Parser, Subcommand};

<span class="hljs-comment">/// Rusty example app</span>
<span class="hljs-meta">#[derive(Parser, Debug)]</span>
<span class="hljs-meta">#[command(version, bin_name = <span class="hljs-meta-string">"rusty"</span>, disable_help_subcommand = true)]</span>
<span class="hljs-keyword">pub</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Cli</span></span> {
    <span class="hljs-meta">#[command(subcommand)]</span>
    command: Commands,
}

<span class="hljs-meta">#[derive(Subcommand, Debug)]</span>
<span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Commands</span></span> {
    Exec(super::exec::Cli),
}

<span class="hljs-keyword">impl</span> Cli {
    <span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">exec</span></span>(&amp;<span class="hljs-keyword">self</span>) -&gt; <span class="hljs-built_in">Result</span>&lt;()&gt; {
        <span class="hljs-keyword">match</span> &amp;<span class="hljs-keyword">self</span>.command {
            Commands::Exec(cli) =&gt; cli.exec(),
        }
    }
}
</code></pre>
<p>execute cargo run</p>
<pre><code class="lang-rust">❯ cargo run -q -- --help
Rusty example app

Usage: rusty &lt;COMMAND&gt;

Commands:
  exec  Execute an arbitrary command

Options:
  -h, --help     Print help information
  -V, --version  Print version information
❯ cargo run -q -- exec --help
Execute an arbitrary command

All arguments are passed through unless --help is first

Usage: rusty exec &lt;ARGS&gt;...

Arguments:
  &lt;ARGS&gt;...


Options:
  -h, --help
          Print help information (<span class="hljs-keyword">use</span> `-h` <span class="hljs-keyword">for</span> a summary)
❯ cargo run -q -- exec ls -a
.
..
.git
.gitignore
Cargo.lock
Cargo.toml
src
target
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Writing Rust CLIs - Hello World !]]></title><description><![CDATA[organizing Rust Project Directory
create a directory structure with the following commands
$ mkdir -p hello/src

mkdir the command will make a directory the -p options create a parent directory before creating a child directory
create hello.rs with t...]]></description><link>https://blog.cloudnativefolks.org/writing-rust-clis-hello-world</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/writing-rust-clis-hello-world</guid><category><![CDATA[Rust]]></category><category><![CDATA[cli]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Sun, 15 Jan 2023 12:43:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673786468514/bcfe93cc-081f-4916-835b-3436075fc0fb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-organizing-rust-project-directory">organizing Rust Project Directory</h4>
<p>create a directory structure with the following commands</p>
<pre><code class="lang-bash">$ mkdir -p hello/src
</code></pre>
<p><code>mkdir</code> the command will make a directory the <code>-p</code> options create a parent directory before creating a child directory</p>
<p>create <code>hello.rs</code> with the following content :</p>
<pre><code class="lang-rust">
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>(){
     <span class="hljs-built_in">println!</span>(<span class="hljs-string">"hello,world!"</span>);
}
</code></pre>
<p>move <code>hello.rs</code> source file into <code>hello/src</code> using the <code>mv</code> command :</p>
<pre><code class="lang-bash">$  mv hello.rs hello/src
</code></pre>
<p>use the <code>cd</code> command to change into that directory and compile your program again :</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> hello 
$ rustc src/hello.rs
</code></pre>
<p>you should now have a <code>hello</code> executable in the directory.</p>
<pre><code class="lang-bash">$ tree
➜  hello tree 
.
├── hello
└── src
    └── hello.rs
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673496476200/058088b8-69ae-4c0a-959d-e8e437c628fd.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-creating-and-running-a-project-with-cargo">Creating and Running a project with Cargo</h4>
<p>start a new rust project is to use the Cargo tool.</p>
<pre><code class="lang-bash">➜  hello <span class="hljs-built_in">cd</span> ..
➜  rustlabs rm -rf hello
</code></pre>
<p>delete the existing project. the <code>-r</code> the recursive option will remove the contents of a directory and <code>-f</code> force option will skip any errors</p>
<p>Then start your project in a new using Cargo like so :</p>
<pre><code class="lang-bash">$ cargo new hello
     Created binary (application) `hello` package
</code></pre>
<p>this should create a new <code>hello</code> the directory that you can change into</p>
<pre><code class="lang-bash">  Created binary (application) `hello` package
➜  rustlabs tree
.
└── hello
    ├── Cargo.toml
    └── src
        └── main.rs

2 directories, 2 files
➜  rustlabs <span class="hljs-built_in">cd</span> hello
➜  hello git:(master) ✗ tree    
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
</code></pre>
<p><code>Cargo.toml</code> is a configuration file for the project. the extension <code>.toml</code> stands for Tom's Obvious, Minimal Language</p>
<p>the <code>src</code> the directory is for rust source code files</p>
<p><code>main.rs</code> is the default starting point for the rust program</p>
<pre><code class="lang-rust">hello git:(master) ✗ cat src/main.rs 
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Hello, world!"</span>);
}
</code></pre>
<p>we use to compile projects using <code>rustc</code> to combine the program. to run in one command using <code>cargo run</code></p>
<pre><code class="lang-rust"> hello git:(master) ✗ cargo run 
   Compiling hello v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/hello)
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.84</span>s
     Running `target/debug/hello`
Hello, world!
</code></pre>
<p>if you would like for Cargo to not print status messages about compiling and running the code use the <code>-q</code> or <code>--quiet</code> options</p>
<pre><code class="lang-rust">cargo run --quiet
Hello, world!
</code></pre>
<p>use <code>ls</code> command to list the content of the current working directory</p>
<pre><code class="lang-rust">hello git:(master) ✗ ls
Cargo.lock Cargo.toml src        target
</code></pre>
<p>you will see the directory <code>target/debug</code> that contains the build artifacts</p>
<pre><code class="lang-bash">➜  hello git:(master) ✗ ./target/debug/hello
Hello, world!
</code></pre>
<p>why was the binary file called <code>hello</code> , though, and not main? to answer that at <code>Cargo.toml</code></p>
<pre><code class="lang-bash">➜  hello git:(master) ✗ ls
Cargo.lock Cargo.toml src        target
➜  hello git:(master) ✗ cat Cargo.toml 
[package]
name = <span class="hljs-string">"hello"</span>
version = <span class="hljs-string">"0.1.0"</span>
edition = <span class="hljs-string">"2021"</span>

<span class="hljs-comment"># See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html</span>

[dependencies]
</code></pre>
<ul>
<li><p><code>name = "hello"</code> of the project created with <code>Cargo</code> so it will also be the name of executable</p>
</li>
<li><p><code>version = "0.1.0"</code> is the version of the program</p>
</li>
<li><p><code>edition = "2021"</code> ate how the rust community introduce changes that are not backward compatible</p>
</li>
<li><p><code>#</code> comment line</p>
</li>
<li><p><code>[dependencies]</code> where you will list any external crates your project uses this project has none at this point so it's blank</p>
</li>
</ul>
<blockquote>
<p>Rust libraries are called <code>crates</code> and they use semantic version numbers in form major.minor.patch so that 1.2.4. a change in a major version indicates breaking changes in the create's public programming interface learn more - <a target="_blank" href="https://crates.io">https://crates.io</a></p>
</blockquote>
<hr />
<h4 id="heading-writing-and-running-integration-tests">Writing and Running Integration tests</h4>
<p>let's create a test directory, goal is to test the hello program by running it on the command line as the user will do . create the file <code>tests/cli.rs</code></p>
<pre><code class="lang-rust"><span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">works</span></span>(<span class="hljs-number">0</span>
  <span class="hljs-built_in">assert!</span>(<span class="hljs-literal">true</span>);
}
</code></pre>
<ul>
<li><p><code>#[test]</code> attribute tells rust to run this function when testing</p>
</li>
<li><p><code>assert!</code> macro assert that a boolean expression is true</p>
</li>
</ul>
<p>now our project look lake this</p>
<pre><code class="lang-bash">➜  hello git:(master) ✗ mkdir tests 
➜  hello git:(master) ✗ cargo run 
    Finished dev [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.02s
     Running `target/debug/hello`
Hello, world!
➜  hello git:(master) ✗ tree -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
├── target
│   ├── CACHEDIR.TAG
│   └── debug
└── tests
    └── cli.rs

4 directories, 5 files
➜  hello git:(master) ✗
</code></pre>
<ul>
<li><p><code>Cargo.lock</code> file records the exact versions of the dependencies used to build your pogram .[ Note:- you should not edit this file ]</p>
</li>
<li><p>the <code>src</code> the directory is for the Rust Source code files to build the program.</p>
</li>
<li><p>the <code>target</code> the directory holds the building artifacts</p>
</li>
<li><p>the <code>tests</code> the directory holds the Rust Source code for testing the program</p>
</li>
</ul>
<p>run test</p>
<pre><code class="lang-bash">$ cargo run
</code></pre>
<pre><code class="lang-bash">➜  hello git:(master) ✗ cargo <span class="hljs-built_in">test</span> 
   Compiling hello v0.1.0 (/Users/sangambiradar/Documents/rustlabs/hello)
    Finished <span class="hljs-built_in">test</span> [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.62s
     Running unittests src/main.rs (target/debug/deps/hello-2d4f25cc5b31a396)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running tests/cli.rs (target/debug/deps/cli-4a0f9bf0df349d1e)

running 1 <span class="hljs-built_in">test</span>
<span class="hljs-built_in">test</span> works ... ok

<span class="hljs-built_in">test</span> result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s
</code></pre>
<p>the micro <code>assert!</code> will verify that expectation is true or <code>assert_eq!</code> to verify that something is an expected value since this test is evaluating the literal value <code>test</code> , it will always succeed .</p>
<pre><code class="lang-bash"><span class="hljs-comment">#[test]</span>
fn <span class="hljs-function"><span class="hljs-title">works</span></span>() {
    assert!(<span class="hljs-literal">false</span>);
}
</code></pre>
<p>run cargo test again</p>
<pre><code class="lang-bash"> hello git:(master) ✗ cargo <span class="hljs-built_in">test</span> 
   Compiling hello v0.1.0 (/Users/sangambiradar/Documents/rustlabs/hello)
    Finished <span class="hljs-built_in">test</span> [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.58s
     Running unittests src/main.rs (target/debug/deps/hello-2d4f25cc5b31a396)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running tests/cli.rs (target/debug/deps/cli-4a0f9bf0df349d1e)

running 1 <span class="hljs-built_in">test</span>
<span class="hljs-built_in">test</span> works ... FAILED

failures:

---- works stdout ----
thread <span class="hljs-string">'works'</span> panicked at <span class="hljs-string">'assertion failed: false'</span>, tests/cli.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    works

<span class="hljs-built_in">test</span> result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

error: <span class="hljs-built_in">test</span> failed, to rerun pass `--<span class="hljs-built_in">test</span> cli`
</code></pre>
<p>Replace the contents of <code>tests/cli.rs</code> with the following code :</p>
<pre><code class="lang-bash">use std::process::Command;
<span class="hljs-comment">#[test]</span>
fn <span class="hljs-function"><span class="hljs-title">runs</span></span>() {
    <span class="hljs-built_in">let</span> mut cmd = Command::new(<span class="hljs-string">"ls"</span>);
    <span class="hljs-built_in">let</span> res = cmd.output();
    assert!(res.is_ok());

}
</code></pre>
<ul>
<li><p>Import <code>std::process::Commnd</code>. The <code>std</code> tells us this is a standard library and is Rust code that is so universally useful it is included with the language</p>
</li>
<li><p>create a new <code>Command</code> to run <code>ls</code> The <code>let</code> the keyword will bind a value to a variable and <code>mut</code> will make variably mutable so that it can change</p>
</li>
</ul>
<p>run test and varify your passong test</p>
<pre><code class="lang-bash"> cargo <span class="hljs-built_in">test</span>
   Compiling hello v0.1.0 (/Users/sangambiradar/Documents/rustlabs/hello)
    Finished <span class="hljs-built_in">test</span> [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.53s
     Running unittests src/main.rs (target/debug/deps/hello-2d4f25cc5b31a396)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running tests/cli.rs (target/debug/deps/cli-4a0f9bf0df349d1e)

running 1 <span class="hljs-built_in">test</span>
<span class="hljs-built_in">test</span> runs ... ok

<span class="hljs-built_in">test</span> result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.01s
</code></pre>
<p>lets update <code>tests/cli.rs</code> with the following code so that the runs function executes <code>hello</code> instead of <code>ls</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> std::process::Command;
<span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">runs</span></span>() {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> cmd = Command::new(<span class="hljs-string">"hello"</span>);
    <span class="hljs-keyword">let</span> res = cmd.output();
    <span class="hljs-built_in">assert!</span>(res.is_ok());

}
</code></pre>
<p>when you run a test case its get fail because <code>hello</code> the program can't be found :</p>
<pre><code class="lang-rust"> hello git:(master) ✗ cargo test
   Compiling hello v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/hello)
    Finished test [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.57</span>s
     Running unittests src/main.rs (target/debug/deps/hello-<span class="hljs-number">2</span>d4f25cc5b31a396)

running <span class="hljs-number">0</span> tests

test result: ok. <span class="hljs-number">0</span> passed; <span class="hljs-number">0</span> failed; <span class="hljs-number">0</span> ignored; <span class="hljs-number">0</span> measured; <span class="hljs-number">0</span> filtered out; finished <span class="hljs-keyword">in</span> <span class="hljs-number">0.00</span>s

     Running tests/cli.rs (target/debug/deps/cli-<span class="hljs-number">4</span>a0f9bf0df349d1e)

running <span class="hljs-number">1</span> test
test runs ... FAILED

failures:

---- runs stdout ----
thread <span class="hljs-symbol">'runs</span>' panicked at <span class="hljs-symbol">'assertion</span> failed: res.is_ok()', tests/cli.rs:<span class="hljs-number">6</span>:<span class="hljs-number">5</span>
note: run with `RUST_BACKTRACE=<span class="hljs-number">1</span>` environment variable to display a backtrace


failures:
    runs

test result: FAILED. <span class="hljs-number">0</span> passed; <span class="hljs-number">1</span> failed; <span class="hljs-number">0</span> ignored; <span class="hljs-number">0</span> measured; <span class="hljs-number">0</span> filtered out; finished <span class="hljs-keyword">in</span> <span class="hljs-number">0.00</span>s

error: test failed, to rerun pass `--test cli`
➜  hello git:(master) ✗
</code></pre>
<p>recall the binary</p>
<pre><code class="lang-rust">➜  hello git:(master) ✗ hello
zsh: command not found: hello
</code></pre>
<p>when you execute any command your operating system look in predefined set of directories for something by neme</p>
<pre><code class="lang-bash">
 hello git:(master) ✗ <span class="hljs-built_in">echo</span> <span class="hljs-variable">$PATH</span> | tr : <span class="hljs-string">'\n'</span>
/Users/sangambiradar/.docker/bin
/Users/sangambiradar/Downloads/google-cloud-sdk/bin
/Library/Frameworks/Python.framework/Versions/3.11/bin
/opt/homebrew/bin
/opt/homebrew/sbin
/usr/<span class="hljs-built_in">local</span>/bin
/System/Cryptexes/App/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
/Users/sangambiradar/.docker/bin
/Users/sangambiradar/Downloads/google-cloud-sdk/bin
/Library/Frameworks/Python.framework/Versions/3.11/bin
/opt/homebrew/bin
/opt/homebrew/sbin
/Users/sangambiradar/.cargo/bin
➜  hello git:(master) ✗
</code></pre>
<p>if we change the directory also it will not work if you refer current directory with binary, not the command</p>
<pre><code class="lang-rust">➜  hello git:(master) ✗ cd target/debug 
➜  debug git:(master) ✗ hello
zsh: command not found: hello
</code></pre>
<p>run executable binary</p>
<pre><code class="lang-rust">➜  debug git:(master) ✗ ./hello
Hello, world!
</code></pre>
<hr />
<h4 id="heading-adding-a-project-dependency">Adding a Project Dependency</h4>
<p>we have seen so far only in the target/debug directory. if we can copy it to $PATH directory ) so it will execute and test run successfully . but don't want to copy my program and test it.</p>
<p>I can use <code>crate assert_cmd</code> to find the program in my crate directory.</p>
<pre><code class="lang-rust">[package]
name = <span class="hljs-string">"hello"</span>
version = <span class="hljs-string">"0.1.0"</span>
edition = <span class="hljs-string">"2021"</span>


[dependencies]

[dev-dependencies]
assert_cmd = <span class="hljs-string">"1"</span>
</code></pre>
<p>using this crate to create a command that looks in Cargo binary directories. that the following test does not verify that the program produces the correct output. update <code>tests/cli.rs</code> the run function will use <code>assert_cmd::Command</code> instead of <code>std::process::Command</code></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> assert_cmd::Command;
<span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">runs</span></span>() {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> cmd = Command::cargo_bin(<span class="hljs-string">"hello"</span>).unwrap();
    cmd.assert().success();

}
</code></pre>
<ul>
<li><p>import <code>assert_cmd::Command</code></p>
</li>
<li><p>Create <code>Command</code> to run <code>hello</code> in the current crate this returns a Results and code call <code>Result::unwrap</code> because the binary should be found if not found test will fail</p>
</li>
<li><p>use <code>assert::success</code> to ensure command successful</p>
</li>
</ul>
<p>Run <code>cargo run</code> to verify test cases</p>
<pre><code class="lang-rust">
hello git:(master) ✗ cargo test
   Compiling hello v0.<span class="hljs-number">1.0</span> (/Users/sangambiradar/Documents/rustlabs/hello)
    Finished test [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> <span class="hljs-number">0.32</span>s
     Running unittests src/main.rs (target/debug/deps/hello-<span class="hljs-number">73</span>f1e61ebe7b71e0)

running <span class="hljs-number">0</span> tests

test result: ok. <span class="hljs-number">0</span> passed; <span class="hljs-number">0</span> failed; <span class="hljs-number">0</span> ignored; <span class="hljs-number">0</span> measured; <span class="hljs-number">0</span> filtered out; finished <span class="hljs-keyword">in</span> <span class="hljs-number">0.00</span>s

     Running tests/cli.rs (target/debug/deps/cli-<span class="hljs-number">734782</span>d1ff788617)

running <span class="hljs-number">1</span> test
test runs ... ok

test result: ok. <span class="hljs-number">1</span> passed; <span class="hljs-number">0</span> failed; <span class="hljs-number">0</span> ignored; <span class="hljs-number">0</span> measured; <span class="hljs-number">0</span> filtered out; finished <span class="hljs-keyword">in</span> <span class="hljs-number">0.27</span>s
</code></pre>
<hr />
<h4 id="heading-understanding-program-exit-values">Understanding Program exit values</h4>
<p>what does it mean for a program to run successfully? command-line programs should report the final status to the operating system to indicate success or failure. ( POSIX) standards indicate that the standard exit code is 0 to. indicate success</p>
<pre><code class="lang-bash">TRUE(1)                                                                                   General Commands Manual                                                                                   TRUE(1)

NAME
     <span class="hljs-literal">true</span> – <span class="hljs-built_in">return</span> <span class="hljs-literal">true</span> value

SYNOPSIS
     <span class="hljs-literal">true</span>

DESCRIPTION
     The <span class="hljs-literal">true</span> utility always returns with an <span class="hljs-built_in">exit</span> code of zero.

     Some shells may provide a <span class="hljs-built_in">builtin</span> <span class="hljs-literal">true</span> <span class="hljs-built_in">command</span> <span class="hljs-built_in">which</span> is identical to this utility.  Consult the <span class="hljs-built_in">builtin</span>(1) manual page.

SEE ALSO
     <span class="hljs-built_in">builtin</span>(1), csh(1), <span class="hljs-literal">false</span>(1), sh(1)

STANDARDS
     The <span class="hljs-literal">true</span> utility is expected to be IEEE Std 1003.2 (“POSIX.2”) compatible.

macOS 13.1                                                                                      June 9, 1993                                                                                     macOS 13.1
</code></pre>
<p>if you see the above command notes do nothing except return the exit code zero but I can inspect the bash variable <code>$?</code> to see the exit status of the recent command</p>
<pre><code class="lang-bash">$ <span class="hljs-literal">true</span> 
$ <span class="hljs-built_in">echo</span> $?
0
</code></pre>
<p>the false command is will give 1</p>
<pre><code class="lang-bash">$ <span class="hljs-literal">false</span> 
$ <span class="hljs-built_in">echo</span> $?
1
</code></pre>
<p>let's create <code>src/bin</code> using <code>mkdir src/bin</code> then create <code>src/bin/true.rs</code> with content:</p>
<pre><code class="lang-bash">fn <span class="hljs-function"><span class="hljs-title">main</span></span>() {
    std::process::<span class="hljs-built_in">exit</span>(0) 
}
</code></pre>
<p>run the program and manually check the exit value</p>
<pre><code class="lang-bash">➜  hello git:(master) ✗ cargo run --quiet --bin <span class="hljs-literal">true</span> 
➜  hello git:(master) ✗ <span class="hljs-built_in">echo</span> $?
0
</code></pre>
<p>the <code>--bin</code> the option is the name of the binary target to run</p>
<p>add the following test to <code>test/cli.rs</code> to ensure it works correctly</p>
<p>cargo test</p>
<pre><code class="lang-bash">  hello git:(master) ✗ cargo <span class="hljs-built_in">test</span>                   
   Compiling hello v0.1.0 (/Users/sangambiradar/Documents/rustlabs/hello)
    Finished <span class="hljs-built_in">test</span> [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.48s
     Running unittests src/main.rs (target/debug/deps/hello-73f1e61ebe7b71e0)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running unittests src/bin/true.rs (target/debug/deps/true-68835b704201d7bf)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running tests/cli.rs (target/debug/deps/cli-e061012399bb0d29)

running 1 <span class="hljs-built_in">test</span>
<span class="hljs-built_in">test</span> true_ok ... ok

<span class="hljs-built_in">test</span> result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.06s

➜  hello git:(master) ✗
</code></pre>
<p>rust programmes will exit with the value zero by default . recall that <code>src/main.rs</code> doesn't explicitly call <code>std::process::exit</code> . this means that the true program can do nothing to change <code>src/bin/true.rs</code> to following</p>
<pre><code class="lang-bash">fun <span class="hljs-function"><span class="hljs-title">main</span></span>() {}
</code></pre>
<p>run the test and verify its still passes</p>
<pre><code class="lang-bash">➜  hello git:(master) ✗ cargo run -q --bin <span class="hljs-literal">true</span> 
➜  hello git:(master) ✗ <span class="hljs-built_in">echo</span> $?                 
0
</code></pre>
<p>let's write a false program at the following path <code>src/bin/false.rs</code></p>
<pre><code class="lang-bash">fn <span class="hljs-function"><span class="hljs-title">main</span></span>() {
    std::process::<span class="hljs-built_in">exit</span>(1);
 }
</code></pre>
<p>exit with any value between 1 and 255 to indicate an error</p>
<pre><code class="lang-bash">✗ cargo run -q --bin <span class="hljs-literal">false</span>
error[E0601]: `main` <span class="hljs-keyword">function</span> not found <span class="hljs-keyword">in</span> crate `r<span class="hljs-comment">#false`</span>
  |
  = note: consider adding a `main` <span class="hljs-keyword">function</span> to `src/bin/false.rs`

For more information about this error, try `rustc --explain E0601`.
error: could not compile `hello` due to previous error
➜  hello git:(master) ✗ <span class="hljs-built_in">echo</span> $?                 
101
</code></pre>
<p>then add this test to <code>tests/cli.ts</code> to verify that the program reports a failure when run</p>
<pre><code class="lang-bash">$ cargo <span class="hljs-built_in">test</span>
</code></pre>
<p>another way to write false program use <code>std::process::abort</code> change <code>src/bin/false</code></p>
<pre><code class="lang-bash">fn <span class="hljs-function"><span class="hljs-title">main</span></span>() {
    std::process::abort();
 }
</code></pre>
<hr />
<h4 id="heading-testing-the-program-output">Testing the program output</h4>
<p>The hello world program exits correctly, I'd like to ensure it prints the correct output to <code>STDOUT</code> which is the standard place for output to appear and it is usually the console. update your runs function in <code>tests/cli.rs</code> to following :</p>
<pre><code class="lang-bash"><span class="hljs-comment">#[test]</span>
fn <span class="hljs-function"><span class="hljs-title">runs</span></span>() {
   <span class="hljs-built_in">let</span> mut cmd = Command::cargo_bin(<span class="hljs-string">"hello"</span>).unwrap();
   cmd.assert().success().stdout(<span class="hljs-string">"Hello,World!\n"</span>);
}
</code></pre>
<p>run the tests and verify the hello does indeed work correctly. change <code>src/main.rs</code></p>
<pre><code class="lang-bash">fn <span class="hljs-function"><span class="hljs-title">main</span></span>() {
    println!(<span class="hljs-string">"Hello, world!!!"</span>);
}
</code></pre>
<p>run the tests again to observe a failing test</p>
<pre><code class="lang-bash"> hello git:(master) ✗ cargo <span class="hljs-built_in">test</span>
    Finished <span class="hljs-built_in">test</span> [unoptimized + debuginfo] target(s) <span class="hljs-keyword">in</span> 0.04s
     Running unittests src/bin/false.rs (target/debug/deps/false-8eec864b008dbf20)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running unittests src/main.rs (target/debug/deps/hello-73f1e61ebe7b71e0)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running unittests src/bin/true.rs (target/debug/deps/true-68835b704201d7bf)

running 0 tests

<span class="hljs-built_in">test</span> result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished <span class="hljs-keyword">in</span> 0.00s

     Running tests/cli.rs (target/debug/deps/cli-90bd290aca80271c)

running 1 <span class="hljs-built_in">test</span>
<span class="hljs-built_in">test</span> runs ... FAILED

failures:

---- runs stdout ----
thread <span class="hljs-string">'runs'</span> panicked at <span class="hljs-string">'Unexpected stdout, failed diff original var
├── original: Hello,World!
├── diff: 
│   ---         orig
│   +++         var
│   @@ -1 +1 @@
│   -Hello,World!
│   +Hello, world!!!
└── var as str: Hello, world!!!

command=`"/Users/sangambiradar/Documents/rustlabs/hello/target/debug/hello"`
code=0
stdout=```"Hello, world!!!\n"</span>
</code></pre>
<p>stderr=<code>""</code>
', /Users/sangambiradar/.cargo/registry/src/github.com-1ecc6299db9ec823/assert_cmd-1.0.8/src/assert.rs:124:9
note: run with <code>RUST_BACKTRACE=1</code> environment variable to display a backtrace</p>
<p>failures:
    runs</p>
<p>test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s</p>
<p>error: test failed, to rerun pass <code>--test cli</code>
➜  hello git:(master) ✗ cargo test</p>
<pre><code>
<span class="hljs-string">`-Hello,World!`</span> is the expected output <span class="hljs-keyword">from</span> the program

<span class="hljs-string">`+Hello, world!!!`</span> is the output the program actually created

\<span class="hljs-string">`command=\`"/Users/sangambiradar/Documents/rustlabs/hello/target/debug/hello"\`\` is shortened version of the command

`</span>code=<span class="hljs-number">0</span><span class="hljs-string">` exit code from the program was 0

stdout=\`\`\`"Hello, world!!!\\n"\`\` is the test that was received on `</span>STDOUT<span class="hljs-string">`

---

#### exit values make programs composable

the exit value is important because a failed process used in conjunction with another process should cause the combination to failed . for instance, i can use the logical operator &amp;&amp; in bash to chain two commands true and ls. Ony if the first process reports success will the second process run

`</span><span class="hljs-string">``</span>bash
hello git:(master) ✗ <span class="hljs-literal">true</span> &amp;&amp; ls
Cargo.lock Cargo.toml src        target     tests
</code></pre>]]></content:encoded></item><item><title><![CDATA[eBPF for Cybersecurity - Part 1]]></title><description><![CDATA[What is eBPF ?

born out of a need for a better Linux tracing tool. first released in a limited capacity in 2014 with Linux 3.18, making full use of eBPF at least Linux 4.4 or above

eBPF can run sandboxed programs in the Linux kernel without changin...]]></description><link>https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-1</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/ebpf-for-cybersecurity-part-1</guid><category><![CDATA[eBPF]]></category><category><![CDATA[Linux]]></category><category><![CDATA[linux kernel]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Thu, 12 Jan 2023 02:32:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673490641324/71b7138e-ba99-4309-a475-34d399b53ad6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4 id="heading-what-is-ebpf">What is eBPF ?</h4>
<ul>
<li><p>born out of a need for a better Linux tracing tool. first released in a limited capacity in 2014 with Linux 3.18, making full use of eBPF at least Linux 4.4 or above</p>
</li>
<li><p>eBPF can run sandboxed programs in the Linux kernel without changing kernel source code or loading kernel modules</p>
</li>
<li><p>eBPf is a mechanism for Linux applications to execute code in Linux Kernal space eBPF has been used to create programs for networking, debugging , tracing, firewalls and more</p>
</li>
</ul>
<p>to understand in more detail starting with Linux and it divides its memory into areas.</p>
<ol>
<li><p>kernel space - in simple words to understand it, kernel space is where the core of the operating system resides and has all unrestricted access to all hardware - memory, storage, CPU, etc . due to the privileged nature of the kernel itself.</p>
<p> kernel space is protected and allowed to run only trusted code which is kernel code and device drivers.</p>
</li>
<li><p>User space - user space is where anything is not a kernel process run e.g regular applications, user space code has limited access to hardware and replies on code running in kernel space for privileged operations such as disk or network or any I/O . this happens via kernel API referred to as "system calls"</p>
</li>
</ol>
<p>while the system calls interface us sufficiently in most cases and developers need to add support to new hardware, implement new filesystems or even custom calls to make this possible for programmers to extend the base kernel without adding directly to kernel source code. Linux Kernel Modules (LKMs) serve this function.</p>
<ol>
<li><p>LKM ( Linux Kernel Modules) are loaded directly kernel. it can load at runtime, removing the need to recompile the entire kernel and reboot the machine each time a new kernel module is required.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673395349077/5944f204-cd05-4562-9dac-33ce8ed5ca46.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>LKM is helpful but introduced risk to the system. Indeed also separations between Kernel and user space add several import security measures to the OS kernel. Kernel Services Connet user space to physical hardware.</p>
</li>
<li><p>LKMs can make the kernel Crash and kernel version upgradation can add more radius of security vulnerabilities. it's hard for maintainers too!</p>
</li>
</ol>
<h4 id="heading-what-does-ebpf-do">What does eBPF do?</h4>
<blockquote>
<p>" eBPF does to Linux what javaScript does to HTML " - Brenbdan Gregg , Sr Performace Engineer , Netflix</p>
</blockquote>
<ul>
<li><p>eBPF (Extended Berkeley Packet Filter) is a technology that makes it possible to run special programs deep inside the Linux operating system in an isolated way.</p>
</li>
<li><p>as it filers data packets from the network and embedded into the kernel, the BPF provides</p>
<p>  a network interface with a security layer that ensures the packet data is reliable and accessible using this approach teams can more easily collect the most important observability data from Linux applications and network resources.</p>
</li>
<li><p>Developed out of a need for improved Linux tracing tools, eBPF was influenced by dtrace tools available mainly for BSD and Solaris systems. unlike dtrace , Linux was not able to achieve a global overview of running systems rather it was restricted to specific frameworks for library calls functions and system calls.</p>
</li>
<li><p>Before being loaded into the kernel the eBPF program needs to pass a particular series of requirements. Verification includes executing the eBPF program in the virtual machine.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673403734743/c746f5bf-0975-4a56-a4ef-0a692c40011c.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>with 10,000+ lines of code, to carry out a set of checks the verified will go over the potential paths the eBPF program might take when executed in the kernel to ensure the program runs to completion without any looping which would result in a kernel lockup.</p>
</li>
<li><p>if all checks are cleared, the eBPF program is loaded and compiled into the kernel at a location in a code path and waits for the appropriate signal when the signal is received from an event the eBPF program loaded in the code path. once initiated the bytecode collects and executes information.</p>
</li>
<li><p>this way eBPF allows programmers to execute byte code safely within the Linux kernel without adding or changing kernel source code. It can't replace LKM altogether eBPF program introduces custom code that is related to protected hardware resources with a limited threat to the kernel.</p>
</li>
<li><p>eBPF programs are event-driven and are run when the kernel or an application passes a certain hook point. Pre-defined hooks include system calls, function entry/exit, kernel tracepoints, network events, and several others.</p>
</li>
</ul>
<h4 id="heading-ebpf-includes-the-following-elements">eBPF includes the following elements :</h4>
<ol>
<li><p>Predefined as eBPF is event-driven and its pass-through hook. Hooks are predefined and can include events like network events, system calls, function entry and exit kernel tracepoints. if there is no pre-defined hook for a certain requirement, you can create a user or kernel probe ( uprobe and kprobe)</p>
</li>
<li><p>Program verification - The eBPF system call can be used to load the eBPF program into the Linux kernel by using some eBPF library. when the program load into the kernel it has to verify to ensure it is safe to run</p>
<ul>
<li><p>the program can only be loaded by a privileged eBPF process</p>
</li>
<li><p>the program won't crash or damage the system</p>
</li>
<li><p>It will not run in a loop. the program always runs to completion</p>
</li>
</ul>
</li>
<li><p>eBPF maps - eBPF must be able to store its state and share collected data. user can access the eBPF map via system calls from both application and programs</p>
</li>
<li><p>Helper Calls - eBPF program needs to maintain its compatibility and avoid being bound to a specific Linux kernel. helper function are API provided by the kernel. helper calls allow programs to generate random numbers and receive time and date, access eBPF data, manipulate forwarding logic and network packets and more</p>
</li>
<li><p>Function and tail call - enabling function call to function to define called in the program. tails enable the execution of other eBPF programs</p>
</li>
</ol>
<blockquote>
<h4 id="heading-ebpf-programs-can-be-utilized-for-efficient-networking-tracing-and-data-profiling-observability-and-security-tooling-eg-for-threat-defense-and-intrusion-detection">eBPF programs can be utilized for efficient <em>networking, tracing and data profiling, observability, and security tooling</em>, e.g., for threat defense and intrusion detection</h4>
</blockquote>
<h4 id="heading-why-is-this-technology-useful-for-security">why is this technology useful for security?</h4>
<p>It extends visibility and control to all system calls as well as provides packet level visibility of all networking traffic in a singular system that doesn't have the performance implications of traditional security agents.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673409273130/673e500d-e777-466b-bb4e-cd8ccf2343e4.png" alt class="image--center mx-auto" /></p>
<p>This allows for the following security use cases to be achieved easier than in the past:</p>
<p>1. Reduce alert fatigue - w/ additional insight from eBPF, teams can reduce alert fatigue by 97% with proper context, i.e. security observability</p>
<p>2. Security protection at point of attack</p>
<p>Why would a vendor implement eBPF?</p>
<p>1. Decouple security innovation from OS, while still allowing same deep insight as in-kernel tech</p>
<p>2. More system throughput</p>
<p>3. Consolidate sys call, network filtering &amp; process context into single system</p>
<p>4. Limit overhead for observability</p>
<h4 id="heading-conclusion">Conclusion</h4>
<p>eBPF stands for the kernel and JavaScript stands for the Web browser. Although some challenges exist: eBPF development is not easy, eBPF is fast-paced and hard to keep up with, implementation details may vary by kernel version and there is no easy packaging/deployment solution. But this fundamental enabling technology is leading to a major wave of innovation in the kernel space, bringing immediate benefits in a cloud-native environment, especially due to its dynamic programmability, reliability and ability to get great workload visibility with minimal disruption.</p>
<p>The fact that we can inspect packets gives us extremely performant <strong>observability</strong> tools that can be mapped to other aspects such as Kubernetes metadata and get in-depth security forensics from the extracted information. We can use the ability to drop or modify packets for network policies and do encryption with eBPF for security. Also, since we can send packets and change the destination for a packet, eBPF allows us to create powerful network functionalities, such as load balancing, routing and service mesh.</p>
]]></content:encoded></item><item><title><![CDATA[OAuth 2.0 Implementation in Golang]]></title><description><![CDATA[Introduction :
Security is without doubt a very important feature for any public and even private facing service or API and it’s something that you need to pay a lot of attention to get right.
In this tutorial, we are going to see an in-depth explana...]]></description><link>https://blog.cloudnativefolks.org/oauth-20-implementation-in-golang</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/oauth-20-implementation-in-golang</guid><category><![CDATA[Go Language]]></category><category><![CDATA[oauth]]></category><category><![CDATA[authentication]]></category><category><![CDATA[Google]]></category><category><![CDATA[OAuth2]]></category><dc:creator><![CDATA[Siddhesh Khandagale]]></dc:creator><pubDate>Mon, 09 Jan 2023 19:45:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673293310188/27edc14a-7e51-49b3-9bb1-3cfd3de02941.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction"><strong>Introduction :</strong></h2>
<p>Security is without doubt a very important feature for any public and even private facing service or API and it’s something that you need to pay a lot of attention to get right.</p>
<p>In this tutorial, we are going to see an in-depth explanation of OAuth2 and its implementation using Golang.</p>
<h3 id="heading-oauth-20"><strong>OAuth 2.0 :</strong></h3>
<p><strong>OAuth 2.0</strong>, which stands for “Open Authorization”, is a standard designed to allow a website or application to access resources hosted by other web apps on behalf of a user.</p>
<p>OAuth 2.0 is an authorization protocol and NOT an authentication protocol. As such, it is designed primarily as a means of granting access to a set of resources, for example, remote APIs or user data.</p>
<p>OAuth 2.0 uses Access Tokens. An <strong>Access Token</strong> is a piece of data that represents the authorization to access resources on behalf of the end user. OAuth 2.0 doesn’t define a specific format for Access Tokens. However, in some contexts, the JSON Web Token (JWT) format is often used. This enables token issuers to include data in the token itself. Also, for security reasons, Access Tokens may have an expiration date.</p>
<h3 id="heading-what-are-we-building">What are we building :</h3>
<p>In this tutorial, we are going to build a simple API using Google API for authentication and authorization of the user.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673118017656/b38956d4-c27a-44ca-9295-9966b18087a6.png?auto=compress,format&amp;format=webp" alt /></p>
<h2 id="heading-prerequisites"><strong>Prerequisites💯 :</strong></h2>
<p>To continue with the tutorial, firstly you need to have Golang and Fiber installed.</p>
<h3 id="heading-installations"><strong>Installations :</strong></h3>
<ul>
<li><p><a target="_blank" href="https://go.dev/doc/install"><strong>Golang</strong></a></p>
</li>
<li><p><a target="_blank" href="https://docs.gofiber.io/"><strong>Go-Fiber</strong></a>: We'll see this ahead in the tutorial.</p>
</li>
</ul>
<h2 id="heading-getting-started"><strong>Getting Started 🚀:</strong></h2>
<p>Let's get started by creating the main project directory <code>go-oauth2</code> by using the following command.</p>
<p>(🟥Be careful, sometimes I've done the explanation by commenting in the code)</p>
<pre><code class="lang-go">mkdir jwt-auth-api <span class="hljs-comment">//Creates a 'jwt-auth-api' directory</span>
cd jwt-auth-api <span class="hljs-comment">//Change directory to 'jwt-auth-api'</span>
</code></pre>
<p>Now initialize a mod file. <em>(If you publish a module, this must be a path from which your module can be downloaded by Go tools. That would be your code's repository.)</em></p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> mod init github.com/&lt;username&gt;/<span class="hljs-keyword">go</span>-oauth2
</code></pre>
<p>To install the Fiber Framework run the following command :</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get -u github.com/gofiber/fiber/v2
</code></pre>
<h3 id="heading-client-id-and-client-secret"><strong>Client ID and Client Secret :</strong></h3>
<p>Before moving ahead let's get the Client ID and Client Secret for Google API which we are going to store in <code>.env</code> file in our main directory <code>go-oauth2</code> .</p>
<p>Follow the steps below for getting the Client Credentials for Google API :</p>
<ol>
<li><p>Open <a target="_blank" href="https://console.developers.google.com/apis"><strong>Google APIs console</strong></a>, Click on the Credentials page.</p>
</li>
<li><p>Click Create Credentials &gt; OAuth client ID. Select the Application type as Web Application and add the name of the Application. For this tutorial, I've entered the Application as <code>Go-Auth2</code> .</p>
</li>
<li><p>Click ADD URI under Authorized JavaScript origins and add <code>http://localhost</code> . Again click ADD URI and add <code>http://localhost:8080</code> as URI 2.</p>
</li>
<li><p>Click ADD URI under Authorized redirect URIs and add <code>http://localhost:8080/google_callback</code> .</p>
</li>
<li><p>Copy the Client Credentials Displayed.</p>
</li>
</ol>
<p>After getting the Credentials, store them in the <code>.env</code> file as shown below.</p>
<pre><code class="lang-go">GOOGLE_CLIENT_ID : &lt;CLIENT_ID&gt; <span class="hljs-comment">//Replace &lt;CLIENT_ID&gt; with your ID.</span>
GOOGLE_CLIENT_SECRET : &lt;CLIENT_SECRET&gt; <span class="hljs-comment">//Replace &lt;CLIENT_SECRET&gt; with your SECRET.</span>
</code></pre>
<h2 id="heading-initializing"><strong>Initializing 💻:</strong></h2>
<p>Let's set up our server by creating a new instance of Fiber. For this create a file <code>main.go</code> and add the following code to it :</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"github.com/Siddheshk02/go-oauth2/controllers"</span> <span class="hljs-comment">//imoprting the controllers package</span>
    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    app := fiber.New()

    app.Post(<span class="hljs-string">"/google_login"</span>, controllers.GoogleLogin)
    app.Post(<span class="hljs-string">"/google_callback"</span>, controllers.GoogleCallback)

    app.Listen(<span class="hljs-string">":8080"</span>)

}
</code></pre>
<p>Firstly, we are going to work on Google Login. So, comment on the Google Callback route for now.</p>
<p>Now, make a package/folder <code>controllers</code> , in this folder create <code>google.go</code> file.</p>
<p>We are going to create the <code>GoogleLogin</code>, <code>GoogleCallback</code> functions in the <code>google.go</code> file</p>
<p>We are going to use the <a target="_blank" href="http://golang.org/x/oauth2"><strong>golang.org/x/oauth2</strong></a> package, to install it run the command,</p>
<pre><code class="lang-go"><span class="hljs-keyword">go</span> get golang.org/x/oauth2
</code></pre>
<p>Before working on these functions, we need to define the oauth2 configurations for the Google API.</p>
<p>Let's define <code>oauth2.Config</code> variable object <code>GoogleLoginConfig</code> in the <code>GoogleConfig()</code> function in <code>config.go</code> file. For this create a package/folder config and a file <code>config.go</code> inside the folder.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> config

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"os"</span>

    <span class="hljs-string">"github.com/joho/godotenv"</span>
    <span class="hljs-string">"golang.org/x/oauth2"</span>
    <span class="hljs-string">"golang.org/x/oauth2/google"</span>
)

<span class="hljs-keyword">type</span> Config <span class="hljs-keyword">struct</span> {
    GoogleLoginConfig oauth2.Config
}

<span class="hljs-keyword">var</span> AppConfig Config

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GoogleConfig</span><span class="hljs-params">()</span> <span class="hljs-title">oauth2</span>.<span class="hljs-title">Config</span></span> {
    err := godotenv.Load(<span class="hljs-string">".env"</span>)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatalf(<span class="hljs-string">"Some error occured. Err: %s"</span>, err)
    }

    AppConfig.GoogleLoginConfig = oauth2.Config{
        RedirectURL:  <span class="hljs-string">"http://localhost:8080/google_callback"</span>,
        ClientID:     os.Getenv(<span class="hljs-string">"GOOGLE_CLIENT_ID"</span>),
        ClientSecret: os.Getenv(<span class="hljs-string">"GOOGLE_CLIENT_SECRET"</span>),
        Scopes: []<span class="hljs-keyword">string</span>{<span class="hljs-string">"https://www.googleapis.com/auth/userinfo.email"</span>,
            <span class="hljs-string">"https://www.googleapis.com/auth/userinfo.profile"</span>},
        Endpoint: google.Endpoint,
    }

    <span class="hljs-keyword">return</span> AppConfig.GoogleLoginConfig
}
</code></pre>
<ul>
<li><p><strong>RedirectURL</strong>: Redirect URLs are a critical part of the OAuth flow. After a user successfully authorizes an application, the authorization server will redirect the user back to the application.</p>
</li>
<li><p><strong>ClientID</strong>: This we earlier stored in the <code>.env</code> file. The <code>Client_ID</code> is a public identifier for apps. It is not guessable by third parties, so many implementations use something like a 32-character hex string. If the client ID is guessable, it makes it slightly easier to craft phishing attacks against arbitrary applications. It must also be unique across all clients that the authorization server handles.</p>
</li>
<li><p><strong>ClientSecret</strong>: This we earlier stored in the <code>.env</code> file. The <code>Client_Secret</code> is known only to the application and the authorization server. It is the application’s password. It must be sufficiently random to not be guessable, which means you should avoid using common UUID libraries which often take into account the timestamp or MAC address of the server generating it.</p>
</li>
<li><p><strong>Scopes</strong>: It is a mechanism in OAuth 2.0 to limit an application's access to a user's account.</p>
</li>
</ul>
<p>Update the main.go with the following code,</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"github.com/Siddheshk02/go-oauth2/config"</span>
    <span class="hljs-string">"github.com/Siddheshk02/go-oauth2/controllers"</span>
    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    app := fiber.New()

    config.GoogleConfig()

    app.Get(<span class="hljs-string">"/google_login"</span>, controllers.GoogleLogin)
    <span class="hljs-comment">//app.Post("/google_callback", controllers.GoogleCallback)</span>

    app.Listen(<span class="hljs-string">":8080"</span>)

}
</code></pre>
<p>Now, let's work on the function <code>GoogleLogin()</code> in the <code>google.go</code> file.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> controllers

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"github.com/Siddheshk02/go-oauth2/config"</span>
    <span class="hljs-string">"github.com/gofiber/fiber/v2"</span>
)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GoogleLogin</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {

    url := config.AppConfig.GoogleLoginConfig.AuthCodeURL(<span class="hljs-string">"randomstate"</span>)

    c.Status(fiber.StatusSeeOther)
    c.Redirect(url)
    <span class="hljs-keyword">return</span> c.JSON(url)
}
</code></pre>
<p><code>randomstate</code> is called the State. It is a token to protect the user from CSRF attacks. You must always provide a non-empty string and validate that it matches the state query parameter on your redirect callback.</p>
<p>Now, let's test the login functions. Run the command <code>go run main.go</code> . Then go to the address <a target="_blank" href="http://127.0.0.1:8080/google_login"><code>http://127.0.0.1:8080/google_login</code></a> in your browser. It must look like this,</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673273290596/9f45e541-644c-46e4-a988-e1cb1f7b1fe9.avif" alt class="image--center mx-auto" /></p>
<p>If you are already signed in then it will show that particular mail id and Use another account option.</p>
<p>Now, the login function is done. Let's create the <code>GoogleCallback</code> function.</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">GoogleCallback</span><span class="hljs-params">(c *fiber.Ctx)</span> <span class="hljs-title">error</span></span> {
    state := c.Query(<span class="hljs-string">"state"</span>)
    <span class="hljs-keyword">if</span> state != <span class="hljs-string">"randomstate"</span> {
        <span class="hljs-keyword">return</span> c.SendString(<span class="hljs-string">"States don't Match!!"</span>)
    }

    code := c.Query(<span class="hljs-string">"code"</span>)

    googlecon := config.GoogleConfig()

    token, err := googlecon.Exchange(context.Background(), code)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.SendString(<span class="hljs-string">"Code-Token Exchange Failed"</span>)
    }

    resp, err := http.Get(<span class="hljs-string">"https://www.googleapis.com/oauth2/v2/userinfo?access_token="</span> + token.AccessToken)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.SendString(<span class="hljs-string">"User Data Fetch Failed"</span>)
    }

    userData, err := ioutil.ReadAll(resp.Body)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> c.SendString(<span class="hljs-string">"JSON Parsing Failed"</span>)
    }

    <span class="hljs-keyword">return</span> c.SendString(<span class="hljs-keyword">string</span>(userData))

}
</code></pre>
<p>Here, we are going to pass the state variable from the URL parameter and we are going to check the <code>randomstate</code> that we've set in the GoogleLogin function, matches the <code>randomstate</code> that we are getting. If it matches, then that's the correct data that we want.</p>
<p>Next, we are passing the code variable for getting the token from the google server using the function <code>Exchange()</code> .</p>
<p>After getting the access token, we are getting the user data in the variable <code>resp</code> . We are getting a JSON response and storing it in <code>userData</code> variable.</p>
<p>Let's test for the <code>/google_callback</code> route. Run the command <code>go run main.go</code> . Then go to the address <a target="_blank" href="http://127.0.0.1:8080/google_login"><code>http://127.0.0.1:8080/google_login</code></a> in your browser. Sign in using your account. On Successful Sign-in, your data will be displayed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673090736696/08ea7828-a769-4a86-9020-efd47938f3db.png?auto=compress,format&amp;format=webp" alt /></p>
<p>So, the API is ready. Further, you can add other features by connecting it to a Database and adding new users in your App, more routes, etc.</p>
<p>The complete code is saved in this <a target="_blank" href="https://github.com/Siddheshk02/go-oauth2"><strong>GitHub</strong></a> repository.</p>
]]></content:encoded></item><item><title><![CDATA[Build a Fullstack Application with Next.js,Tailwind  and Database ( MongoDB(or)HarperDB) with Auth(firebase)]]></title><description><![CDATA[Introduction to Next.js
Next.js is a JavaScript framework for building server-rendered or statically-exported React applications. It was developed by the team at Vercel (formerly known as Zeit) and has gained popularity for its simplicity and ease of...]]></description><link>https://blog.cloudnativefolks.org/build-a-fullstack-application-with-nextjstailwind-and-harperdb-with-firebase</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/build-a-fullstack-application-with-nextjstailwind-and-harperdb-with-firebase</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Full Stack Development]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[Firebase]]></category><dc:creator><![CDATA[MAHESHWARAN M]]></dc:creator><pubDate>Mon, 02 Jan 2023 06:21:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672576343661/d87f2940-b239-4e45-843a-42c2c57c8f2b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction-to-nextjs">Introduction to Next.js</h3>
<p>Next.js is a JavaScript framework for building server-rendered or statically-exported React applications. It was developed by the team at Vercel (formerly known as Zeit) and has gained popularity for its simplicity and ease of use.</p>
<p>One of the key benefits of using Next.js is that it allows you to build universal JavaScript applications, which means that the same code can be used on both the client and the server. This can lead to improved performance and a better user experience, as the server can pre-render pages and send them to the client, reducing the amount of work the client has to do.</p>
<p>Overall, Next.js is a powerful and flexible tool for building modern web applications and is well worth considering if you are looking to build a performant, scalable, and deployable app.</p>
<p>Here I am Writing a Few Combinations to Build a Fullstack Application using Next.js With Different databases Try your application architecture And choose Database and follow the section of the database with next.js.</p>
<h3 id="heading-setting-up-a-nextjs-project-with-visual-studio-code">Setting up a Next.js project with Visual Studio Code</h3>
<p>To set up a Next.js project with Visual Studio Code (VS Code), you will need to have Node.js and npm (the Node Package Manager) installed on your machine. If you don't already have these tools, you can download them from the Node.js website (<a target="_blank" href="https://nodejs.org/"><strong>https://nodejs.org/</strong></a>) and follow the instructions to install them.</p>
<ol>
<li><p>Open VS Code and click <code>"File &gt; Open Folder"</code> to create a new folder for your project.</p>
</li>
<li><p>In the terminal, run the following command to create a new Next.js project using the Next.js <code>CLI (Command Line Interface):</code></p>
</li>
</ol>
<pre><code class="lang-plaintext"> npx create-next-app my-project
</code></pre>
<ol>
<li><p>This will create a new directory called <code>"my-project"</code> with the necessary files and dependencies for a Next.js app.</p>
</li>
<li><p>Navigate into the new project directory by running the following command:</p>
<pre><code class="lang-plaintext"> cd my-project
</code></pre>
</li>
<li><p>To start the development server, run the following command:</p>
<pre><code class="lang-plaintext"> npm run dev
</code></pre>
</li>
<li><p>This will start the development server and open a new browser window with your Next.js app running at <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a>. Any changes you make to the</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672509885940/329cd7d7-4fed-4fcb-9937-1a96a7a13984.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-setting-up-a-nextjs-project-with-github-codespaces-optional">Setting up a Next.js project with GitHub Codespaces: (optional)</h3>
<ol>
<li><p>Go to <a target="_blank" href="https://github.com/"><strong>https://github.com/</strong></a> and log in to your account.</p>
</li>
<li><p>Navigate to the repository where you want to create your Next.js project.</p>
</li>
<li><p>Click the <code>"Code"</code> button and then select <code>"Open in Codespaces"</code> from the dropdown menu.</p>
</li>
<li><p>This will open a new Codespaces window with a terminal and code editor.</p>
</li>
<li><p>In the terminal, run the following command to create a new Next.js project using the Next.js CLI (Command Line Interface):</p>
<pre><code class="lang-plaintext"> npx create-next-app my-project
</code></pre>
</li>
<li><p>This will create a new directory called "my-project" with the necessary files and dependencies for a Next.js app.</p>
</li>
<li><p>To open the project in VS Code, click the "Open in Visual Studio Code" button in the top menu.</p>
</li>
<li><p>To start the development server from within VS Code, click the "Run" button in the top menu and select "Start Debugging" (or press "F5").</p>
</li>
<li><p>This will start the development server and open a new browser window with your Next.js app running at <a target="_blank" href="http://localhost:3000"><strong>http://localhost:3000</strong></a>. Any changes you make to the code will be automatically reloaded in the browser.</p>
</li>
</ol>
<h3 id="heading-setting-up-a-nextjs-project-with-docker">Setting up a Next.js project with Docker:</h3>
<ol>
<li><p>Install Docker on your machine by following the instructions at <a target="_blank" href="https://docs.docker.com/get-docker/"><strong>https://docs.docker.com/get-docker/</strong></a>.</p>
</li>
<li><p>Open VS Code and click "File &gt; Open Folder" to create a new folder for your project.</p>
</li>
<li><p>Create a new file called "Dockerfile" in the project directory and add the following lines to it:</p>
<pre><code class="lang-plaintext"> FROM node:14-alpine

 WORKDIR /app

 COPY package.json /app/package.json
 COPY package-lock.json /app/package-lock.json

 RUN npm install

 COPY . /app

 EXPOSE 3000

 CMD ["npm", "run", "dev"]
</code></pre>
</li>
<li><p>Create a new file called "docker-compose.yml" in the project directory and add the following lines to it:</p>
<pre><code class="lang-plaintext"> version: '3'
 services:
   app:
     build: .
     ports:
       - "3000:3000"
</code></pre>
</li>
<li><p>Run the following command to build the Docker image and start the development server:</p>
<pre><code class="lang-plaintext"> docker-compose up
</code></pre>
</li>
<li><p>This will start the development server and open a new browser window with your Next.js app running at <a target="_blank" href="http://localhost:3000"><strong>http://localhost:3000</strong></a>. Any changes you make to the code will be automatically reloaded in the browser.</p>
</li>
</ol>
<h3 id="heading-nextjs-pages">Next.js Pages</h3>
<p>In Next.js, a page is a React component that is exported from a .js, .jsx, .ts, or .tsx file in the "pages" directory. Each page is associated with a route based on its file name. This means that if you have a file called "about.js" in the "pages" directory, it will be accessible at the route "/about".</p>
<p>To create a page in Next.js, you can create a new file in the "pages" directory with a relevant name and export a React component from it. For example, to create an "About" page, you could create a file called "about.js" in the "pages" directory and add the following code to it:</p>
<pre><code class="lang-plaintext">import React from 'react';

const About = () =&gt; {
  return (
    &lt;div&gt;
      &lt;h1&gt;About&lt;/h1&gt;
      &lt;p&gt;This is an about page.&lt;/p&gt;
    &lt;/div&gt;
  );
};

export default About;
</code></pre>
<p>This will create a page at the route "/about" that displays an "About" heading and some text. You can add more content or functionality to the page as needed.</p>
<p>To navigate between pages in your Next.js app, you can use the <code>Link</code> component provided by Next.js. For example, you could add a link to the "About" page in the header of your app like this:</p>
<pre><code class="lang-plaintext">import Link from 'next/link';

const Header = () =&gt; {
  return (
    &lt;header&gt;
      &lt;Link href="/about"&gt;
        &lt;a&gt;About&lt;/a&gt;
      &lt;/Link&gt;
    &lt;/header&gt;
  );
};

export default Header;
</code></pre>
<p>This will create a link that navigates to the "/about" route when clicked. You can add more links to your app as needed by creating more pages and adding them to the "pages" directory.</p>
<h2 id="heading-routing-in-nextjs">Routing in Next.js</h2>
<p>Routing in Next.js is the process of mapping URLs to specific pages or functionality in your app. Next.js offers a few different ways to handle routing, each with its benefits and trade-offs.</p>
<ol>
<li><p>Automatic routing: The most basic way to handle routing in Next.js is to use automatic routing. This means that Next.js will automatically create a route for each page in your <code>"pages"</code> a directory based on the file name. For example, if you have a file called <code>"about.js"</code> in the "pages" directory, it will be accessible at the route <code>"/about"</code> .</p>
</li>
<li><p>Custom routes: If you need more control over your routes, you can use custom routes. This allows you to specify custom routes and map them to specific pages or functionality in your app.</p>
<p> To use custom routes, you can create a <code>"routes.js"</code> file in the root of your project and define your routes using the <code>Routes</code> and <code>Route</code> components provided by Next.js.</p>
<pre><code class="lang-plaintext"> import { Routes, Route } from 'next-routes';

 const routes = new Routes();

 routes
   .add('home', '/')
   .add('about', '/about')
   .add('blog', '/blog/:slug', 'blog')
   .add('product', '/product/:id', 'product');

 export default routes;
</code></pre>
<p> This will create four routes: "/", "/about", "/blog/:slug", and "/product/:id". You can then use the <code>Link</code> component provided by Next.js to navigate between these routes in your app.</p>
<pre><code class="lang-plaintext"> import Link from 'next/link';
 import routes from '../routes';

 const Header = () =&gt; {
   return (
     &lt;header&gt;
       &lt;Link href={routes.home()}&gt;
         &lt;a&gt;Home&lt;/a&gt;
       &lt;/Link&gt;
       &lt;Link href={routes.about()}&gt;
         &lt;a&gt;About&lt;/a&gt;
       &lt;/Link&gt;
       &lt;Link href={routes.blog({ slug: 'my-first-post' })}&gt;
         &lt;a&gt;Blog&lt;/a&gt;
       &lt;/Link&gt;
       &lt;Link href={routes.product({ id: 123 })}&gt;
         &lt;a&gt;Product&lt;/a&gt;
       &lt;/Link&gt;
     &lt;/header&gt;
   );
 };

 export default Header;
</code></pre>
</li>
<li><p>To use dynamic routing, you can create a file in the "pages" directory with a name that includes a placeholder, such as "blog/[slug].js". This will create a route that matches any URL that starts with "/blog/", with the remainder of the URL being passed as a parameter.</p>
<pre><code class="lang-plaintext"> import { useRouter } from 'next/router';

 const BlogPost = () =&gt; {
   const router = useRouter();
   const { slug } = router.query;

   return (
     &lt;div&gt;
       &lt;h1&gt;Blog post: {slug}&lt;/h1&gt;
       &lt;p&gt;This is a blog post with a dynamic URL.&lt;/p&gt;
     &lt;/div&gt;
   );
 };

 export default BlogPost;
</code></pre>
<p> This will create a page that can handle any URL that starts with <code>"/blog/"</code>, with the remainder of the URL being passed as the "slug" parameter. You can then use this parameter to retrieve the appropriate blog post from your database or API and display it on the page.</p>
</li>
</ol>
<h3 id="heading-built-in-css-support-in-nextjs">Built-In CSS Support in Next.js</h3>
<ol>
<li><p>Global styles: To apply styles globally to your entire app, you can create a file called "styles.css" in the "public" directory and import it in the "_app.js" file in the "pages" directory. This will make the styles available to all pages in your app.</p>
<pre><code class="lang-plaintext"> import '../public/styles.css';

 const MyApp = ({ Component, pageProps }) =&gt; {
   return &lt;Component {...pageProps} /&gt;;
 };

 export default MyApp;
</code></pre>
</li>
<li><p>Component-level styles: To apply styles to a specific component, you can use the <code>style</code> prop. This allows you to specify inline styles for a component, which can be useful for small, self-contained components.</p>
<pre><code class="lang-plaintext"> const MyComponent = () =&gt; {
   return (
     &lt;div style={{ color: 'red' }}&gt;
       This text is red
     &lt;/div&gt;
   );
 };
</code></pre>
<p> CSS Modules: To apply styles to a specific component and avoid conflicts with other styles in your app, you can use CSS Modules. This allows you to import a CSS file and use it to style a specific component, with the class names being automatically scoped to that component.</p>
<ol>
<li><p>To use CSS Modules, you will need to install the <code>@zeit/next-css</code> and <code>css-loader</code> packages and add them to your Next.js configuration file. Then, you can create a CSS file for a specific component and import it in the component file.</p>
<pre><code class="lang-plaintext"> // next.config.js

 const withCSS = require('@zeit/next-css');

 module.exports = withCSS({
   cssLoaderOptions: {
     modules: {
       localIdentName: '[local]___[hash:base64:5]',
     },
   },
 });

 // MyComponent.module.css

 .red {
   color: red;
 }

 // MyComponent.js

 import styles from './MyComponent.module.css';

 const MyComponent = () =&gt; {
   return (
     &lt;div className={styles.red}&gt;
       This text is red
     &lt;/div&gt;
   );
 };
</code></pre>
</li>
</ol>
</li>
</ol>
<h3 id="heading-tailwind-css-with-nextjs">Tailwind CSS with Next.js</h3>
<ol>
<li><p>Tailwind CSS is a popular utility-first CSS framework that allows you to create custom styles by composing classes based on a set of predefined styles. You can use Tailwind CSS with Next.js to style your app</p>
</li>
<li><p>Install the Tailwind CSS package by running the following command in your project's root directory:</p>
<pre><code class="lang-plaintext"> npm install tailwindcss
</code></pre>
</li>
<li><p>Create a configuration file for Tailwind CSS by running the following command:</p>
<pre><code class="lang-plaintext"> npx tailwindcss init
</code></pre>
</li>
<li><p>Create a CSS file in your project and import the Tailwind CSS styles. You can do this by adding the following code to the file:</p>
<pre><code class="lang-plaintext"> @import 'tailwindcss/base';
 @import 'tailwindcss/components';
 @import 'tailwindcss/utilities';
</code></pre>
</li>
<li><p>Next, you need to configure Next.js to use the CSS file you just created. To do this, you will need to install the <code>@zeit/next-css</code> and <code>css-loader</code> packages and add them to your Next.js configuration file.</p>
<pre><code class="lang-plaintext"> // next.config.js

 const withCSS = require('@zeit/next-css');

 module.exports = withCSS({});
</code></pre>
<ol>
<li><p>Finally, you can import the CSS file in your app and start using Tailwind CSS classes to style your components. For example, you could create a button component like this:</p>
<pre><code class="lang-plaintext"> import styles from './Button.css';

 const Button = ({ children }) =&gt; {
   return (
     &lt;button className={styles.button}&gt;
       {children}
     &lt;/button&gt;
   );
 };

 export default Button;
</code></pre>
<p> You can then use the <code>Button</code> the component in your app and apply Tailwind CSS styles to it using the <code>className</code></p>
<pre><code class="lang-plaintext"> import Button from './Button';

 const App = () =&gt; {
   return (
     &lt;div&gt;
       &lt;Button className="bg-blue-500 text-white font-bold py-2 px-4 rounded-full"&gt;
         Click me
       &lt;/Button&gt;
     &lt;/div&gt;
   );
 };

 export default App;
</code></pre>
</li>
</ol>
</li>
</ol>
<pre><code>you can use Tailwind CSS <span class="hljs-keyword">with</span> Next.js by installing the Tailwind CSS package, creating a configuration file, creating a CSS file, configuring Next.js to use the CSS file, and then importing the CSS file <span class="hljs-keyword">in</span> your app and using Tailwind CSS classes to style your components. This allows you to easily apply custom styles to your app using the utility-first approach provided by Tailwind CSS.
</code></pre><h3 id="heading-mongo-db-with-nextjs">Mongo DB with Next.js</h3>
<p>MongoDB is a popular NoSQL database that you can use with Next.js to store and retrieve data for your app. To use MongoDB with Next.js</p>
<ol>
<li><p>Install the MongoDB driver for Node.js by running the following command in your project's root directory:</p>
<pre><code class="lang-plaintext"> npm install mongodb
</code></pre>
</li>
<li><p>Next, you will need to connect to a MongoDB server. You can do this by creating a file called "db.js" in your project and adding the following code to it:</p>
</li>
</ol>
<pre><code class="lang-plaintext">import MongoClient from 'mongodb';

const uri = 'mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.mongodb.net/test?retryWrites=true&amp;w=majority';

const client = new MongoClient(uri, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

export default client;
</code></pre>
<p>Replace <code>&lt;username&gt;</code> and <code>&lt;password&gt;</code> with your MongoDB username and password.</p>
<ol>
<li><p>Next, you can create a function to connect to the MongoDB server and perform operations on the database. You can do this by adding the following code to the "db.js" file:</p>
<pre><code class="lang-plaintext"> import MongoClient from 'mongodb';

 const uri = 'mongodb+srv://&lt;username&gt;:&lt;password&gt;@cluster0.mongodb.net/test?retryWrites=true&amp;w=majority';

 const client = new MongoClient(uri, {
   useNewUrlParser: true,
   useUnifiedTopology: true,
 });

 const connect = async () =&gt; {
   try {
     await client.connect();
     console.log('Connected to MongoDB');
   } catch (error) {
     console.log(error);
   }
 };

 export { client, connect };
</code></pre>
<ol>
<li><p>You can now use the <code>connect</code> function to connect to the MongoDB server and perform operations on the database. For example, you could create a function to insert a new document into a collection like this:</p>
<pre><code class="lang-plaintext"> import { client, connect } from './db';

 const insertDocument = async (collection, document) =&gt; {
   try {
     await connect();
     const result = await client.db('test').collection(collection).insertOne(document);
     console.log(`Inserted ${result.insertedCount} document(s) into the ${collection} collection`);
   } catch (error) {
     console.log(error);
   }
 };

 export { insertDocument };
</code></pre>
<p> You can then use the <code>insertDocument</code> function to insert a</p>
<pre><code class="lang-plaintext"> import { insertDocument } from './db';

 const document = {
   name: 'John',
   age: 30,
 };

 insertDocument('users', document);
</code></pre>
<p> his will insert a new document into the "users" collection with the name and age fields.</p>
</li>
</ol>
</li>
</ol>
<p>You can also create functions to retrieve documents from the database or perform other operations, such as updating or deleting documents. For example, you could create a function to find all documents in a collection like this:</p>
<pre><code class="lang-plaintext">import { client, connect } from './db';

const findDocuments = async (collection) =&gt; {
  try {
    await connect();
    const result = await client.db('test').collection(collection).find({}).toArray();
    console.log(result);
  } catch (error) {
    console.log(error);
  }
};

export { findDocuments };
</code></pre>
<p>You can then use the <code>findDocuments</code> function to retrieve all documents from the "users" collection:</p>
<pre><code class="lang-plaintext">import { findDocuments } from './db';

findDocuments('users');
</code></pre>
<p>you can use MongoDB with Next.js by installing the MongoDB driver for Node.js, connecting to a MongoDB server, and performing operations on the database using functions.</p>
<h3 id="heading-harperdb-with-nextjs">HarperDB with Next.js</h3>
<p>HarperDB is a scalable, high-performance database that you can use with Next.js to store and retrieve data for your app. To use HarperDB with Next.js</p>
<ol>
<li><p>Install the HarperDB Node.js client by running the following command in your project's root directory:</p>
<pre><code class="lang-plaintext"> npm install harperdb
</code></pre>
</li>
<li><p>Next, you will need to create a file called "db.js" in your project and add the following code to it:</p>
<pre><code class="lang-plaintext"> import HarperDB from 'harperdb';

 const client = new HarperDB({
   host: 'localhost',
   port: 9925,
   username: '&lt;username&gt;',
   password: '&lt;password&gt;',
 });

 export default client;
</code></pre>
<p> Replace <code>&lt;username&gt;</code> and <code>&lt;password&gt;</code> with your HarperDB username and password.</p>
</li>
<li><p>You can now use the <code>client</code> object to perform operations on the HarperDB database. For example, you could create a function to insert a new row into a table like this:</p>
<pre><code class="lang-plaintext"> import client from './db';

 const insertRow = async (table, row) =&gt; {
   try {
     const result = await client.insert({
       schema: '&lt;schema&gt;',
       table: table,
       rows: [row],
     });
     console.log(`Inserted ${result.affected_rows} row(s) into the ${table} table`);
   } catch (error) {
     console.log(error);
   }
 };

 export { insertRow };
</code></pre>
<p> This will insert a new row into the "users" table with the name and age fields.</p>
<p> You can also create functions to retrieve rows from the database or perform other operations, such as updating or deleting rows. For example, you could create a function to find all rows in a table like this:</p>
</li>
</ol>
<pre><code class="lang-plaintext">import client from './db';

const findRows = async (table) =&gt; {
  try {
    const result = await client.query({
      schema: '&lt;schema&gt;',
      table: table,
      action: 'select',
    });
    console.log(result.rows);
  } catch (error) {
    console.log(error);
  }
};

export { findRows };
</code></pre>
<p>You can then use the <code>findRows</code> function to retrieve all rows from the "users" table:</p>
<pre><code class="lang-plaintext">import { findRows } from './db';

findRows('users');
</code></pre>
<p>you can use HarperDB with Next.js by installing the HarperDB Node.js client, connecting to a HarperDB server, and performing operations on the database using functions. This allows you to store and retrieve data for your Next.js app using HarperDB.</p>
<h3 id="heading-firebase-with-nextjs">Firebase with Next.js</h3>
<ol>
<li><p>Go to the <a target="_blank" href="https://firebase.google.com/"><strong>Firebase website</strong></a> and create a new project.</p>
</li>
<li><p>Install the Firebase npm package by running the following command in your project's root directory:</p>
</li>
</ol>
<pre><code class="lang-plaintext">npm install firebase
</code></pre>
<ol>
<li><p>Next, you will need to create a file called "firebase.js" in your project and add the following code to it:</p>
<pre><code class="lang-plaintext"> import firebase from 'firebase';

 const config = {
   apiKey: '&lt;API_KEY&gt;',
   authDomain: '&lt;PROJECT_ID&gt;.firebaseapp.com',
   databaseURL: 'https://&lt;DATABASE_NAME&gt;.firebaseio.com',
   projectId: '&lt;PROJECT_ID&gt;',
   storageBucket: '&lt;BUCKET&gt;.appspot.com',
   messagingSenderId: '&lt;SENDER_ID&gt;',
 };

 firebase.initializeApp(config);

 export default firebase;
</code></pre>
<p> Replace <code>&lt;API_KEY&gt;</code>, <code>&lt;PROJECT_ID&gt;</code>, <code>&lt;DATABASE_NAME&gt;</code>, <code>&lt;BUCKET&gt;</code>, and <code>&lt;SENDER_ID&gt;</code> with the values from your Firebase project.</p>
</li>
<li><p>You can now use the <code>firebase</code> object to perform operations with Firebase. For example, you could create a function to add a new document to a collection like this:</p>
</li>
</ol>
<pre><code class="lang-plaintext">import firebase from './firebase';

const addDocument = async (collection, document) =&gt; {
  try {
    const result = await firebase.firestore().collection(collection).add(document);
    console.log(`Added document with ID: ${result.id}`);
  } catch (error) {
    console.log(error);
  }
};

export { addDocument };
</code></pre>
<p>You can then use the <code>addDocument</code> function to add a new document to the "users" collection:</p>
<pre><code class="lang-plaintext">import { addDocument } from './firebase';

const document = {
  name: 'John',
  age: 30,
};

addDocument('users', document);
</code></pre>
<p>This will add a new document to the "users" collection with the name and age fields.</p>
<p>You can also create functions to retrieve documents from the database or perform other operations, such as updating or deleting documents. For example, you could create a function to find all documents in a collection like this:</p>
<pre><code class="lang-plaintext">import firebase from './firebase';

const findDocuments = async (collection) =&gt; {
  try {
    const snapshot = await firebase.

firestore().collection(collection).get();
console.log(snapshot.docs);
} catch (error) {
console.log(error);
}
};

export { findDocuments };
</code></pre>
<p>You can then use the <code>findDocuments</code> function to retrieve all documents from the "users" collection.</p>
<h3 id="heading-conclusion"><strong>Conclusion:</strong></h3>
<p>In conclusion, Next.js is a powerful JavaScript framework that allows you to build full-stack applications with ease. With its built-in support for server-side rendering, automatic code splitting, and optimized performance, Next.js makes it easy to build high-performance and scalable applications. Additionally, the ability to use Next.js with a variety of databases and authentication methods, such as MongoDB, HarperDB, and Firebase, makes it a versatile choice for building full-stack applications.</p>
<p>If you want to build a full-stack application with Next.js, there are a few key things to keep in mind:</p>
<ul>
<li><p>Set up your development environment with Next.js and your preferred code editor or development environment, such as Visual Studio Code or GitHub Codespaces.</p>
</li>
<li><p>Use the <code>pages</code> directory to define your application's routes and create React components for each page.</p>
</li>
<li><p>Take advantage of Next.js's built-in CSS support to style your application, or use a CSS framework like Tailwind CSS.</p>
</li>
<li><p>Use a database and authentication method to store and retrieve data and handle user authentication. <strong>Options include MongoDB, HarperDB, and Firebase.</strong></p>
</li>
</ul>
<p>By following these steps, you can build a full-stack application with Next.js that is fast, scalable, and easy to maintain.</p>
]]></content:encoded></item><item><title><![CDATA[Dev Retro 2022 :- Wrap up the year 2022 .... ! looking forward to 2023]]></title><description><![CDATA[Jan 2022
started DevSecOpsConf non-profitable event and spend a lot of time organizing a standalone to empower the community as well as one of the speakers!
◉ DevSecOps Conf 2022 | Powered by CloudNativeFolks Community - Virtual Event - 8 Jan 2022
I ...]]></description><link>https://blog.cloudnativefolks.org/dev-retro-2022-wrap-up-the-year-2022-looking-forward-to-2023</link><guid isPermaLink="true">https://blog.cloudnativefolks.org/dev-retro-2022-wrap-up-the-year-2022-looking-forward-to-2023</guid><category><![CDATA[community]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[#DevRetro2022]]></category><dc:creator><![CDATA[Sangam Biradar]]></dc:creator><pubDate>Sat, 31 Dec 2022 08:13:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672474333392/30bc9f62-7ea7-43e8-ba2b-eefa46dab1af.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-jan-2022">Jan 2022</h2>
<p>started DevSecOpsConf non-profitable event and spend a lot of time organizing a standalone to empower the community as well as one of the speakers!</p>
<h5 id="heading-devsecops-conf-2022-or-powered-by-cloudnativefolks-community-virtual-event-8-jan-2022">◉ DevSecOps Conf 2022 | Powered by CloudNativeFolks Community - Virtual Event - 8 Jan 2022</h5>
<p>I want to thank all speakers and attendees for supporting free events!</p>
<p><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main"><br />🔻Kubernetes Security Tools , Saiyam Pathak ,Civo Cloud , CNCF ambassador</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Secure Infrastructure as code with GitHub action by Sangam Biradar , Technical Advocate , Tenable</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Open Policy Agent as a Control Engine by David Melamed , CTO and Co-Founder of Jit</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻DevSecOps; more than just pipelines by Tanya Janca | SheHacksPurple ( best-selling author of ‘Alice and Bob Learn Application Security’)</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Don't just detect threats. Take pro-active Action! by Chandu P</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Pragmatic Security Automation and DevSecOps in the Cloud by Joshua Arvin Lat , CTO of NuWorks Interactive Labs,</a> <a target="_blank" href="http://Inc.AWS">Inc.AWS</a> <a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">Machine Learning Hero</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Diversity and Inclusion : Remote/WFH edition by Ixchel Ruiz , DA/DX at jfrog</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Securing Cloud Native Workloads with Istio by Software Enginee at IBM Cloud</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Infrastructure as Code by Kannan Anandakrishnan</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Why is security important in Infrastructure as code ? by Avinash Dalvi , eagleview , AWS Community builder</a></p>
<p>find my slides here - <a target="_blank" href="https://slides.com/sangambiradar/iac-terrascan-github-action">Secure IAC/k8s/Helm/Docker with Github Action</a></p>
<p><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Secure Infrastructure as code with GitHub action by Sangam Biradar , Technical Advocate , Tenable</a></p>
<p>Blogs</p>
<ul>
<li>The Ultimate Docker Cheatsheet for everyone | <a target="_blank" href="https://slides.com/sangambiradar/the-ultimate-docker-cheatsheet-for-everyone-2022/fullscreen">slides</a> | <a target="_blank" href="https://blog.cloudnativefolks.org/the-ultimate-docker-cheatsheet-for-everyone">Blog</a> |</li>
</ul>
<p>Chaos Carnival 2022</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672378589989/d517567d-e357-4d72-9e21-4987cabb283c.jpeg" alt class="image--center mx-auto" /></p>
<p>Presented around on GitOps Meets Chaos Engineering</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672379155196/3c2bc000-ee84-4953-9121-fd727a7d67d7.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-feb-2022">Feb 2022</h2>
<p>Bugtron Conference provides crucial for coders to become a software developers</p>
<p>and invited me to present on DevSecOps | K8s | Docker I tried to make it a short overview with some practical hands-on.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/myuaUkQnRLQ">https://youtu.be/myuaUkQnRLQ</a></div>
<p> </p>
<p>excited to announce I've been selected for AWS Community Builder Program in the Container Category! Thanks for the opportunity Jason Dunn, and Shafraz Rahim!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672380522970/97d8f54a-8b67-4049-b9a8-7705ecce57fc.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-mar-2022">Mar 2022</h2>
<p>the just pandemic we all worked hard and spend time with the community its time to get back to the in-person event and meet amazing community members who always enjoyed those conversions.</p>
<h5 id="heading-demystifying-kubernetes-security-jfrog-office-blore-march-26">◉ Demystifying Kubernetes Security - Jfrog office b'lore - March 26</h5>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672381330937/657230ed-c00f-433d-a743-b3b6c8da5d36.jpeg" alt class="image--center mx-auto" /></p>
<p>slides - <a target="_blank" href="https://slides.com/sangambiradar/demistifying-kubernetes-security">Demystifying Kubernetes Security</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672382026557/d1074e05-2d3f-4f5f-91c9-de2320e1d979.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672382122433/b6daefb7-31e5-4d89-afe1-29b971cc4039.jpeg" alt class="image--center mx-auto" /></p>
<p>we celebrated docker's 9th birthday with all the amazing speakers and attendees</p>
<p>we order an amazing cake!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672381784400/94962a5c-0706-409c-92e3-25107f1ba061.jpeg" alt class="image--center mx-auto" /></p>
<p>In March, I got promoted to Principal Security Advocate / Sr Product Marketing Manager role</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672380935238/cc48ce89-68cc-44b1-b1ba-4569ce685a64.png" alt class="image--center mx-auto" /></p>
<p>Tenable is one of the best company in the cybersecurity space advocating for OSS strategy and being the first DevRel person for Tenable make me feel so proud. I miss all my co-worker's amazing team.</p>
<p>hosted yet another event DevOps India Conference 2022</p>
<p>◉ DevOps India Conference 2022 | Powered by CloudNativeFolks Community - 6 Mar 2022</p>
<p>once again I want to thank all speakers for presenting at this FREE event!</p>
<p><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻 Keep your code safe during the development path using open source tools by Fillipi Pires</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Stop Committing your secrets -git hooks to the rescue by Dwayne McDaniel</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Managed secretes across cloud using kubernetes by Jhonnatan Gil Chaves</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Explore Elastic Observability &amp; Parse different log format with elastic stack by Ashish Tiwari</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Distribute Deployment of a microservices applications multiple k8s clusters by Karan Singh</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Software BoM at the time of DevOps by Manuel Schuller</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Monitoring kubernetes Vs Serverless based applications by Erez Berkner</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Unit testing without writing test cases or mocks using keploy by Shubham Jain</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Demystifying Kubernetes health check by Gundeep Singh</a><br /><a target="_blank" href="https://github.com/cloudnativefolks/speaker-bureau/blob/main">🔻Evolving your REST APIs , a pragmatic approach by Nicolas Frankel</a></p>
<h2 id="heading-may-2022">May 2022</h2>
<p>DockerCon 2022 - Docker in Hindi room</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672382635067/2e7e911e-f282-460c-9f31-ea6a3ecfcc7f.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672382586436/6cc2a083-5a83-498a-9a81-fd3720d68e97.jpeg" alt class="image--center mx-auto" /></p>
<p>Slides - <a target="_blank" href="https://slides.com/sangambiradar/dockercon2022">Developing end to end Rust app using docker deskstop</a></p>
<h3 id="heading-june-2022">June 2022</h3>
<h5 id="heading-docker-developer-community-meetup-at-microsoft-reactor-june-11"><strong>Docker Developer Community Meetup at Microsoft Reactor - June 11</strong></h5>
<h5 id="heading-sangam-biradar-principal-security-advocate-tenable">Sangam Biradar, Principal Security Advocate, Tenable</h5>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672383220815/90ab4173-2b76-4973-9c82-4d8206177f2e.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672383254255/cc4e28e1-8a97-45df-8e8f-80f4e4b9f88c.jpeg" alt class="image--center mx-auto" /></p>
<p>I want to thank Microsoft Reactor and team for sponsoring the venue for this event</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672383266247/a5ddd69f-40d7-4e2e-89d6-801601688c13.jpeg" alt class="image--center mx-auto" /></p>
<p><strong>slides -</strong> <a target="_blank" href="https://slides.com/sangambiradar/pod-security"><strong>An Ultimate Guide to Pod Security that every k8s Developers Must Know</strong></a></p>
<h2 id="heading-july-2022">July 2022</h2>
<p>we did a unique meetup at Nandi Hills 😂</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672384265517/205bb7fc-e5ea-499e-bca9-29fec2fb51e8.jpeg" alt class="image--center mx-auto" /></p>
<p>Presented around Gitops Security with Terrascan at Harness office - July 30</p>
<p>slides - <a target="_blank" href="https://slides.com/sangambiradar/extend-gitops-security-with-terrascan">Gitops Security with Terrascan</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672384331533/a978ae5a-1f38-45b0-9716-012fb8b6d965.jpeg" alt class="image--center mx-auto" /></p>
<p>started sketchbook around CNCF and other open-source projects</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672385130777/94b01915-8735-4e9f-8fb1-934c3d928bf2.jpeg" alt class="image--center mx-auto" /></p>
<p>Terrascan - <a target="_blank" href="https://github.com/tenable/terrascan">https://github.com/tenable/terrascan</a> - Detect compliance and security violations across Infrastructure as Code to mitigate risk before provisioning cloud native infrastructure.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.linkedin.com/posts/sangambiradar_cncf-opensource-terraform-activity-6947627372518989825-T0WN?utm_source=share&amp;utm_medium=member_desktop">https://www.linkedin.com/posts/sangambiradar_cncf-opensource-terraform-activity-6947627372518989825-T0WN?utm_source=share&amp;utm_medium=member_desktop</a></div>
<p> </p>
<h2 id="heading-aug-2022">AUG 2022</h2>
<p>Open Source Marketplace For Kubernetes - <a target="_blank" href="https://github.com/alexellis/arkade">https://github.com/alexellis/arkade</a></p>
<p>add magic to your CLI</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672387549815/67c0d1e6-4fb9-4e9c-90d1-776498a98b42.jpeg" alt class="image--center mx-auto" /></p>
<p><a target="_blank" href="https://www.okteto.com">Okteto</a> - Instantly spin up production-like dev environments in the cloud for every developer.</p>
<p>reduce inner loop and focus on application and code ! Don't think much about Kubernetes Cluster</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672387572644/f719d9a5-2438-4800-8003-fdeb1523eb36.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672387808815/ec44e951-2971-4a8f-ac14-bc5206b3ac01.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-sep-2022">Sep 2022</h2>
<p>yet another great journey started! Deepfence - <strong>Cloud-Native Application Protection Platform</strong></p>
<p>Actionable detection, response and compliance for the cloud, without the alert fatigue.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672387922112/d5492151-6422-4859-80a5-70172d7d1b99.png" alt class="image--center mx-auto" /></p>
<p>PSP is dead and now its time to adopt Pod Security standard presented at DeveloperWeek Cloud 2022</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672387458253/fa2e73aa-3a82-457a-b6d9-dfaed31ffa41.png" alt class="image--center mx-auto" /></p>
<p>here is a blog -</p>
<p><a target="_blank" href="https://blog.cloudnativefolks.org/introduction-to-kubernetes-part-4-pod-security-standards">https://blog.cloudnativefolks.org/introduction-to-kubernetes-part-4-pod-security-standards</a></p>
<p>written blogpost around YaraHunter - <a target="_blank" href="https://github.com/deepfence/YaraHunter">https://github.com/deepfence/YaraHunter</a></p>
<h4 id="heading-yarahunter-malware-scanner-for-cloud-native-as-part-of-cicd-and-at-runtimehttpsblogcloudnativefolksorgyarahunter-malware-scanner-for-cloud-native-as-part-of-cicd-and-at-runtime"><a target="_blank" href="https://blog.cloudnativefolks.org/yarahunter-malware-scanner-for-cloud-native-as-part-of-cicd-and-at-runtime">YaraHunter : Malware scanner for cloud-native, as part of CI/CD and at Runtime</a></h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672388714679/535ca7d2-fc73-40ec-a309-15942daaed71.jpeg" alt class="image--center mx-auto" /></p>
<p>Thanks to docker !</p>
<p>Cloud Native Community Day , Nagpur 2022</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672388783197/fd3383bd-6733-45e9-8c44-7dc78def50ca.jpeg" alt class="image--center mx-auto" /></p>
<p>amazing crowd at Nagpur!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672389205776/4075611b-56bd-4f0f-bf1e-a03999dd6257.jpeg" alt class="image--center mx-auto" /></p>
<p>its houseful! cheers 🥂 to all organizers and attendees!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672389104143/223832ad-e83d-46ed-abc1-32a64bdb3565.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672389155220/84a1da36-1ede-4245-879c-8304c6925e5f.jpeg" alt class="image--center mx-auto" /></p>
<p>Thanks to all organisers and speakers as well as the audience really bringing value via community-driven events and knowledge-sharing sessions</p>
<p>Here I have started with Securing the Software Development life cycle moving from monolithic to Microservice and entering into container and Kubernetes and breaking down security using Open Source Cloud Native Security tool Threatmapper hunts for threats in your production platforms, and ranks these threats based on their risk-of-exploit and new threat graph feature is amazing 🤩</p>
<p>And showing different integration and use cases around Google cloud and GKE</p>
<p>Indeed SBOM became so important as well as a lot of secrets 🤐 getting exposed via container images and file systems also we are not thinking enough of malware scanning for cloud-native runtime</p>
<p>And ebpf is a game changer when it’s come to security observability and networking</p>
<p>we planned another event in CNCF Nagpur</p>
<ul>
<li><p>Avinash Upadhaya - CNCF Landscape Overview</p>
</li>
<li><p>Golang Workshop - 5hr training</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672389002438/90449a3c-f099-46dc-b45a-1dffe6feedba.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672388879104/ca6fd2d8-0678-47de-a1a5-9a9c419bf08a.jpeg" alt class="image--center mx-auto" /></p>
<p>decided to do a workshop track since adoption of Golang growing massively! conducted 5hr free workshop with hands-on training</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672389480332/d8dc12b0-1b68-4169-9075-7530871df4e2.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-oct-2022">Oct 2022</h2>
<p>I meet a 16-year-old student/developer <a class="user-mention" href="https://hashnode.com/@Maheshdevspcae">MAHESHWARAN M</a> one of the events and he travelled from Hosur to Bangalore to attend meetups and events! I also came from a diploma background so I can understand enthusiasm to learn early can give me a lot of opportunities.</p>
<p>I decided to travel to his diploma colleague and conducted an in-person workshop track on Golang. seems they already know another programming language so it's easy and so interactive learning! enjoyed</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672389677531/83cff87f-e342-40f2-97ec-8cec39efa7ef.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672389659314/52347a6e-281d-4b1f-9266-92875c85021c.jpeg" alt class="image--center mx-auto" /></p>
<p>Google Cloud Next Innovator Hive</p>
<p>Thanks to Google Cloud Team for inviting me to the Influencer table! it's great to be part of the most active techie bringing change in India!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672391018373/3074ee6b-e058-4a9a-a912-016928c898c0.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672391006754/6c73a059-ac4a-4f80-9711-b0a10c61f2bc.jpeg" alt class="image--center mx-auto" /></p>
<p>it was great meeting with Urs Holze, SVP of Engineering and Priyanka Vargadia, Google Developer Advocate and Google India Team!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672391001568/d444a19b-02f1-4bfd-834e-7fdf3b588369.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672470039272/4427d7cd-09dc-45aa-952a-257e293ab2a0.jpeg" alt class="image--center mx-auto" /></p>
<h4 id="heading-hacktoberfest-2022-docker-extensions-show-n-tell"><strong>Hacktoberfest 2022: Docker Extensions "Show-n-Tell"</strong></h4>
<p>Deepfence's Team build 2 Docker extensions</p>
<ul>
<li><p><a target="_blank" href="https://github.com/deepfence/secretscanner-docker-extension">SecretScanner</a> - Find secrets and passwords in container images and file systems via Docker extension</p>
</li>
<li><p><a target="_blank" href="https://github.com/deepfence/yarahunter-docker-extension">YaraHunter</a> - Malware scanner for cloud-native, as part of CI/CD and at Runtime via Docker extension</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672470179841/73b01caf-7531-410c-b297-588fd49629a7.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672470187838/613fd55c-0a02-4882-8099-7a5e2900d195.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-nov-2022">Nov 2022</h2>
<p>AWS Community Day - 5th Nov</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672470792623/c8745878-2439-4e8b-bbf5-c91bae6baabb.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672470895221/bce35691-08da-4253-8abb-a6f349b322d9.jpeg" alt class="image--center mx-auto" /></p>
<p>Thanks to AWS Jaipur User Group for the Wonderful Opportunity!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672470909274/d46f74bf-c48d-49a8-95d0-eefabcfc44d1.jpeg" alt class="image--center mx-auto" /></p>
<p>10th Nov - 7th annual All Day DevOps returns on November 10, 2022<br />"Demystifying Kubernetes Pod Security "<br />let's learn about Pod Security Standards &amp; more</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672471515676/fbcb8a1e-cd93-412e-b5fe-a4d6384eaf84.jpeg" alt class="image--center mx-auto" /></p>
<p>Thanks to AllDayDevOps for the amazing goodies and swag!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672471648998/46bf7b8f-682a-414c-b830-fc42aea42e99.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672471598738/94282141-84ad-4e5f-b966-4c6c10229653.jpeg" alt class="image--center mx-auto" /></p>
<p>16th Nov visited diploma college where I started my tech journey! its refreshed my all memories!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672471022698/fc930081-3ff0-4d37-8201-52aecbb61898.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-dec-2022">Dec 2022</h2>
<p>upgraded setup!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672471225488/e8de3b68-bf5e-46df-bab3-c1622917f27a.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672471725200/ae0bd812-6b08-4e94-83df-1da3f7660e74.jpeg" alt class="image--center mx-auto" /></p>
<p>wrapped up the 2022 event! with all active community organizers and community leaders</p>
<p>2023 will be a great year for <a target="_blank" href="https://blog.cloudnativefolks.org">https://blog.cloudnativefolks.org</a> ! officially Launched logo</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1672471970490/008d9559-0e21-4e3e-a258-e6ff8eddbf20.png" alt class="image--center mx-auto" /></p>
<p>Join CloudNativeFolks Community on Discord - <a target="_blank" href="https://discord.com/invite/9ERSnT7">https://discord.com/invite/9ERSnT7</a></p>
<p>Thank you for all the amazing moments, and conversions with community members we shared this year! you made 365 days feel like a few days !</p>
]]></content:encoded></item></channel></rss>