mirror of
https://github.com/avinal/avinal.github.io.git
synced 2026-07-04 07:40:09 +05:30
feat: use new theme for the website
Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com> rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
---
|
||||
category: development
|
||||
date: 2021-05-24T23:56:00
|
||||
description: CMake stands for Cross-platform Make. Normally, a build tool like Make
|
||||
will parse a configuration file (Makefile) that contains all the commands required
|
||||
to build an artifact based on the source files and other resources inside the project.
|
||||
image: /images/cmake-office.webp
|
||||
slug: cmake-basics
|
||||
tags:
|
||||
- cmake
|
||||
- gsoc
|
||||
- fossology
|
||||
- gsoc21
|
||||
title: Hello CMake
|
||||
---
|
||||
|
||||
CMake stands for Cross-platform Make. Normally, a build tool like Make
|
||||
will parse a configuration file (Makefile) that contains all the
|
||||
commands required to build an artifact based on the source files and
|
||||
other resources inside the project.
|
||||
|
||||
I proposed a new architecture for FOSSology that uses CMake instead of
|
||||
bare-metal Make as a Google Summer of Code 2021 project. Although these
|
||||
tutorials will be useful for anyone interested in learning CMake they
|
||||
are specifically tailored to the FOSSology project. This is the first
|
||||
blog on CMake in this series. In this blog, I will discuss CMake syntax
|
||||
and various features.
|
||||
|
||||
## What is CMake?
|
||||
|
||||

|
||||
|
||||
CMake stands for Cross-platform Make. Normally, a build tool like Make
|
||||
will parse a configuration file (Makefile) that contains all the
|
||||
commands required to build an artifact based on the source files and
|
||||
other resources inside the project. On the other hand, CMake will also
|
||||
parse a configuration file (CMakeLists.txt), but instead of directly
|
||||
build the artifact, it’ll generate another configuration file that will
|
||||
build the artifact.
|
||||
|
||||
This approach is very common in Computer Science and is called *adding
|
||||
another level of indirection*. In short, you may say that:
|
||||
|
||||
With just one configuration file you’ll be able to generate different configuration files to build your project for different platforms (Make, Visual Studio, etc).
|
||||
|
||||
Another nice CMake feature is the so-called out-of-source build. Any
|
||||
file required for the final build, executables included, will be stored
|
||||
in a separated build directory (usually called build/). This prevents
|
||||
cluttering up the source directory and makes it easy to start over
|
||||
again: just remove the build directory and you are done.
|
||||
|
||||
## CMake Syntax
|
||||
|
||||

|
||||
|
||||
CMake unlike Make is a configuration language itself. CMake supplies a
|
||||
rich library of inherent functions as well as common programming
|
||||
language features like conditions, looping, macros, and functions. In
|
||||
addition to that CMake is highly modular and you can always write a
|
||||
CMake module yourself independent of any project. Specifically for C/C++
|
||||
programming, it supplies commands to find and link libraries
|
||||
automatically and lot many features.
|
||||
|
||||
### Language Rules
|
||||
|
||||
As mentioned above CMake is a language itself hence there are some
|
||||
language rules related to syntax, comments, variables, etc.
|
||||
|
||||
- There are two types of comment in CMake, both start with `#`
|
||||
character. The first one is line comments, as clear by name it is
|
||||
delimited by a newline. The other one is bracket comment and can
|
||||
span until the matching brackets are found.
|
||||
|
||||
```cmake
|
||||
# This is a line comment and it ends with the line.
|
||||
|
||||
#[[This is a bracket comment and it can span up to multiple lines.
|
||||
But it is only supported in CMake 3.0 or later.]]
|
||||
```
|
||||
|
||||
- Variables in CMake are like any other programming language. They are
|
||||
case-sensitive and have any alphanumeric characters. In general, it
|
||||
is recommended using upper case names as variables. They can be
|
||||
assigned and unassigned using `set` and `unset` commands. A variable
|
||||
can be referenced using `${VARIABLE_NAME}`.
|
||||
|
||||
> CMake reserves some types of identifers:
|
||||
>
|
||||
> - begin with **CMAKE_**(upper-, lower-, or mixed-case)
|
||||
> - begin with ***CMAKE***(upper-, lower-, or mixed-case)
|
||||
> - begin with **_** followed by the name of any CMake Command
|
||||
|
||||
- The CMake commands are case insensitive in the latest version (3.0)
|
||||
of CMake. That means `message()`, `Message()` or `MESSAGE()` are all
|
||||
same.
|
||||
|
||||
### Basic CMake Commands
|
||||
|
||||
- The `project()` command is used to set the name of the CMake project
|
||||
and optionally a language that is used by the project. Every
|
||||
top-level CMake configuration must have this option set. The syntax
|
||||
is as below:
|
||||
|
||||
```cmake
|
||||
project (projectname [CXX] [C] [Java] [NONE])
|
||||
```
|
||||
|
||||
If no language is specified then CMake defaults to supporting C/C++.
|
||||
If `NONE` is specified then no language support is enabled.
|
||||
|
||||
- The `set()` command is used to set a variable to a value or lists of
|
||||
values. It is one of the most used CMake commands. The accompanying
|
||||
command is `unset()`. The `unset()` command is used to unset a
|
||||
variable or remove a variable from the current scope. The syntax for
|
||||
the three commands are:
|
||||
|
||||
```cmake
|
||||
set (BLOG_TITLE "CMake Introduction") # assign single value
|
||||
set (BLOG_TAGS "gsoc" "cmake" "fossology" "gsoc21") # assign a list of values
|
||||
|
||||
unset (BLOG_TITLE) # unset BLOG_TITLE
|
||||
```
|
||||
|
||||
- The `message()` command can be used to display formatted messages
|
||||
with different alert modes. There are many
|
||||
[modes](https://cmake.org/cmake/help/v3.20/command/message.html#general-messages)
|
||||
of displaying messages. The syntax is :
|
||||
|
||||
```cmake
|
||||
message ([<mode>] "message text" ...)
|
||||
|
||||
message(NOTICE "Hey this is ${BLOG_TITLE}") # Example message with variable
|
||||
```
|
||||
|
||||
- The `cmake_minimum_required()` is used to set the minimum CMake
|
||||
version to use to generate the build files. If any older version is
|
||||
used than specified then the user gets an error message. It must be
|
||||
specified at the top of the *CMakeLists.txt* file.
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required (VERSION 3.0)
|
||||
```
|
||||
|
||||
- The commands `add_executable()` and `add_library()` specifies what
|
||||
executables and libraries to build and what source files must be
|
||||
used to build them. One of the two commands must be used for any
|
||||
binary generation.
|
||||
|
||||
```cmake
|
||||
add_executable(<name> [WIN32] [MACOSX_BUNDLE]
|
||||
[EXCLUDE_FROM_ALL]
|
||||
[source1] [source2 ...])
|
||||
|
||||
add_library(<name> [STATIC | SHARED | MODULE]
|
||||
[EXCLUDE_FROM_ALL]
|
||||
[<source>...])
|
||||
```
|
||||
|
||||
### Flow Control
|
||||
|
||||
CMake provides three flow control structures. They are conditional
|
||||
statements (`if`), looping constructs (`foreach` and `while`) and
|
||||
procedure definitions (`function` and `macro`). I will explain each of
|
||||
them one by one.
|
||||
|
||||
- **Conditional Statements** The `if` command in CMake is just like
|
||||
the `if` command in any other language. It evaluates its expression
|
||||
and based on that either executes the code in its body or optionally
|
||||
the code in the `else` clause.
|
||||
|
||||
```cmake
|
||||
if (FOO)
|
||||
# do something here
|
||||
elseif (BAR)
|
||||
if (NESTED_BAR)
|
||||
# do something nested here
|
||||
endif(NESTED_BAR)
|
||||
# do something else
|
||||
else ()
|
||||
# do something here
|
||||
endif (FOO)
|
||||
```
|
||||
|
||||
You can use many operators to form complex conditions. Available
|
||||
options are **NOT**, **AND**, **OR**, **COMMAND**, **DEFINED**,
|
||||
**EXISTS**, **IS_DIRECTORY**, **IS_ABSOLUTE**, **MATCHES**,
|
||||
**IS_NEWER_THAN**, and operators for numerical comparisons
|
||||
**EQUAL**, **LESS**, **GREATER**, **STRLESS**, **STREQUAL**,
|
||||
**STRGREATER**.
|
||||
|
||||
- **Looping Constructs** The `foreach` command enables you to execute
|
||||
a group of CMake commands repeatedly on the members of a list.The
|
||||
first argument of the foreach command is the name of the variable
|
||||
that will take on a different value with each iteration of the loop.
|
||||
The remaining arguments are the list of values over which to loop.
|
||||
|
||||
```cmake
|
||||
foreach(<loop_var> <items>)
|
||||
<commands>
|
||||
endforeach()
|
||||
```
|
||||
|
||||
The `while` command provides for looping based on a test condition.
|
||||
The format for the test expression in the `while` command is the
|
||||
same as that for the `if` command described earlier.
|
||||
|
||||
```cmake
|
||||
while(<condition>)
|
||||
<commands>
|
||||
endwhile()
|
||||
```
|
||||
|
||||
It is worth mentioning that foreach loops can be nested and that the
|
||||
loop variable is replaced prior to any other variable expansion.
|
||||
This means that in the body of a foreach loop you can construct
|
||||
variable names using the loop variable.
|
||||
|
||||
- **Procedure Definitions** A function in CMake is very much like a
|
||||
function in C or C++. You can pass arguments into it, and the
|
||||
arguments passed in become variables within the function. The first
|
||||
argument is the name of the function to define. All additional
|
||||
arguments are formal parameters to the function.
|
||||
|
||||
```cmake
|
||||
function(<name> [<arg1> ...])
|
||||
# write the function body here
|
||||
<commands>
|
||||
endfunction()
|
||||
```
|
||||
|
||||
Macros are defined and called in the same manner as functions. The
|
||||
main differences are that a macro does not push and pop a new
|
||||
variable scope, and the arguments to a macro are not treated as
|
||||
variables but are string replaced prior to execution. This is very
|
||||
much like the differences between a macro and a function in C or
|
||||
C++. The first argument is the name of the macro to create. All
|
||||
additional arguments are formal parameters to the macro.
|
||||
|
||||
```cmake
|
||||
macro(<name> [<arg1> ...])
|
||||
# write macro definition here
|
||||
<commands>
|
||||
endmacro()
|
||||
```
|
||||
|
||||
## A Hello CMake example
|
||||
|
||||
This example compiles a simple *hello_cmake* program. This example and
|
||||
the terminal commands are used in Linux context, however there is very
|
||||
little difference in different platforms. Make sure to [install
|
||||
CMake](https://cmake.org/install/) for your platform.
|
||||
|
||||
- Create a folder and create a file named `hello_cmake.cpp` in that.
|
||||
You may add your own code. Here is my example code.
|
||||
|
||||
```cpp
|
||||
#include<iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello CMake\n";
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- Create another file named `CMakeLists.txt` and add the following
|
||||
script in that file.
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
# set project name
|
||||
project(hello_cmake)
|
||||
|
||||
# print compiler info
|
||||
message("The compiler is ${CMAKE_CXX_COMPILER}")
|
||||
|
||||
# add executable
|
||||
add_executable(Hello_cmake hello_cmake.cpp)
|
||||
```
|
||||
|
||||
- Create another directory `build` and run the following commands.
|
||||
|
||||
```bash
|
||||
# create folder and change directory
|
||||
mkdir build && cd build
|
||||
|
||||
# run cmake config
|
||||
cmake ..
|
||||
|
||||
# build project
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
You will be able to see a `Hello_cmake` binary in the *build* folder.
|
||||
Hooray you have successfully built a project using CMake. For more [read
|
||||
here](https://cmake.org/cmake/help/v3.20/guide/tutorial/index.html). In
|
||||
the next blog I will explain how to create CMake configuration for a
|
||||
more complex project.
|
||||
|
||||
Thanks!
|
||||
|
||||
## References and Credits
|
||||
|
||||
- [CMake Website](https://cmake.org)
|
||||
- [CMake
|
||||
Documentation](https://cmake.org/cmake/help/latest/index.html)
|
||||
- [Mastering CMake Book](https://www.kitware.com/what-we-offer/#books)
|
||||
- [CMake
|
||||
Tutorial](https://cmake.org/cmake/help/v3.20/guide/tutorial/index.html)
|
||||
- [You (C)Make Me
|
||||
Happy](https://prateekvjoshi.com/2014/02/01/cmake-vs-make/)
|
||||
- [Compiling xkcd.com](https://xkcd.com/303/)
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
category: development
|
||||
date: 2022-02-25T20:47:00
|
||||
description: I made it to the Red Hat as a DevTools intern. This post is about onboarding
|
||||
and how I prepared myself for working on the actual project.
|
||||
image: /images/fedora-wall.webp
|
||||
tags:
|
||||
- kubernetes
|
||||
- redhat
|
||||
- docker
|
||||
- golang
|
||||
- tekton
|
||||
- openshift
|
||||
- intern
|
||||
title: My internship at Red Hat
|
||||
---
|
||||
|
||||
I have been contributing to open source for the last 3 years and Red Hat
|
||||
was one of the companies that I was very fond of. I must say all my
|
||||
contributions and consistency paid off, and I made it to the Red Hat as
|
||||
a DevTools intern. This post is about onboarding and how I prepared
|
||||
myself for working on the actual project.
|
||||
|
||||
On the first day of my internship, I met two amazing teammates
|
||||
[Saytam](https://github.com/) and [Utkarsh](https://github.com/). We
|
||||
were also introduced to a Senior Software Engineer [Piyush
|
||||
Garg](https://github.com) who later mentored us. The initial few
|
||||
meetings were more on the introduction and what to learn topics. Before
|
||||
I jump into more details let me explain first what does a **DevTools
|
||||
Developer/Engineer** do?
|
||||
|
||||
## What does a DevTools Developer/Engineer do?
|
||||
|
||||
From [MDN Web
|
||||
Docs](https://developer.mozilla.org/en-US/docs/Glossary/Developer_Tools)
|
||||
**Developer tools (or "development tools" or short "DevTools") are
|
||||
programs that allow a developer to create, test, and debug software.**
|
||||
At RedHat, a lot of open source developer tools of industry standards
|
||||
are developed. There are many, OpenShift, Tekton, CodeReady containers,
|
||||
and many more.
|
||||
|
||||
## Learning on the Go
|
||||
|
||||
There was a lot of learning and still a lot to learn. In a meeting with
|
||||
my manager [^1] Pradeepto Bhattacharya, I was told that I will be working on
|
||||
TektonCD or OpenShift Pipelines, and both of them require a sound
|
||||
knowledge of Golang, CI/CD, Containers, Docker, and Kubernetes. I was
|
||||
familiar with CI/CD, containers, and Docker but never used Golang and
|
||||
Kubernetes. We were provided plenty of good resources and my teammates
|
||||
also helped with many awesome resources. I am listing all the resources
|
||||
with their category.
|
||||
|
||||
### Go Programming Language
|
||||
|
||||
One of Golang's biggest advantages is that it offers the clarity and
|
||||
ease of use that other languages lack. Golang's advantages make it easy
|
||||
for new programmers to quickly understand the language and for seasoned
|
||||
veterans to easily read each other's code.
|
||||
|
||||
- [Official Go Documentation](https://go.dev/doc/) - *Start from here*
|
||||
- [Go by Example](https://gobyexample.com/) - *bite-size examples for
|
||||
most of the golang features*
|
||||
- [Golang tutorial series -
|
||||
GOLANGBOT.COM](https://golangbot.com/learn-golang-series/) - *in-depth
|
||||
tutorial of golang*
|
||||
- [Effective Go](https://go.dev/doc/effective_go) - *writing good golang
|
||||
programs*
|
||||
- [The Go Playground](https://go.dev/play/) - *official online golang
|
||||
ide*
|
||||
- [The Go Programming Language - Book](https://www.gopl.io/) *for
|
||||
learning advanced level golang*
|
||||
- [Golang Tutorial for Beginners | Full Go Course - TechWorld with
|
||||
Nana](https://youtu.be/yyUHQIec83I) *if you prefer video tutorials, I
|
||||
don't :)*
|
||||
|
||||
### Docker
|
||||
|
||||
Docker takes away repetitive, mundane configuration tasks and is used
|
||||
throughout the development lifecycle for fast, easy, and portable
|
||||
application development - desktop and cloud. Docker's comprehensive
|
||||
end-to-end platform includes UIs, CLIs, APIs, and security that are
|
||||
engineered to work together across the entire application delivery
|
||||
lifecycle.
|
||||
|
||||

|
||||
|
||||
- [Docker and Containers -
|
||||
Katacoda](https://www.katacoda.com/courses/docker) *interactive
|
||||
lessons on docker and containers*
|
||||
- [Docker for beginners](https://docker-curriculum.com/)
|
||||
- [Docker Tutorial for Beginners | TechWorld with
|
||||
Nana](https://youtu.be/3c-iBn73dDE) *video tutorial*
|
||||
|
||||
### Kubernetes
|
||||
|
||||

|
||||
|
||||
**Kubernetes** is the Greek word for a ship's captain. We get the words
|
||||
Cybernetic and Gubernatorial from it. The Kubernetes project focuses on
|
||||
building a robust platform for running thousands of containers in
|
||||
production.
|
||||
|
||||
- [Learn Kubernetes -
|
||||
Katacoda](https://www.katacoda.com/courses/kubernetes) *interactive
|
||||
lessons with kubernetes*
|
||||
- [kube by example](https://kubebyexample.com/) *learn by doing*
|
||||
- [Kubernetes Tutorial for Beginners](https://youtu.be/X48VuDVv0do)
|
||||
*video tutorial*
|
||||
|
||||
## *Not so Minimal* Tekton Server
|
||||
|
||||
In late January, we were asked to implement our learnings and deep dive
|
||||
into Kubernetes and TektonCD through an assignment project. Soon we
|
||||
realized that whatever we were learning so far was not even close to
|
||||
what we were going to implement. We were given a document containing the
|
||||
requirements of the applications we were supposed to create along with
|
||||
all the documentation and architectural diagrams.
|
||||
|
||||
The application was called **Minimal Tekton Server**. It is a set of
|
||||
three different applications, i.e a server, a CLI, and a dashboard. In
|
||||
short, this application is supposed to *listen to custom resources being
|
||||
created and then transfer the request to Tekton API to create the
|
||||
corresponding resource on the OpenShift/Kubernetes cluster.*
|
||||
|
||||
So are you interested in how it went? Please follow up with my [next
|
||||
blog](https://avinal.space/posts/development/lovely-dangerous-things-redhat).
|
||||
|
||||
[^1]: [MDN Web
|
||||
Docs](https://developer.mozilla.org/en-US/docs/Glossary/Developer_Tools)
|
||||
@@ -0,0 +1,220 @@
|
||||
---
|
||||
category: development
|
||||
date: 2022-02-27T20:47:00
|
||||
description: This blog is a descreptive account of the development of Minimal Tekton
|
||||
Server. This is highly technical in nature, so please make sure that you have sufficient
|
||||
knowledge about Golang, Docker, Kubernetes and TektonCD. You can refer to my [previous
|
||||
blog]("https://avinal.space/posts/development/i-am-loving-it-redhat.html") to know
|
||||
about these topics.
|
||||
image: /images/development.webp
|
||||
modified: 2022-03-07T22:47:00
|
||||
tags:
|
||||
- tekton
|
||||
- go
|
||||
- kubernetes
|
||||
- openshift
|
||||
- redhat
|
||||
- intern
|
||||
- golang
|
||||
- openshift-pipelines
|
||||
title: Developing Minimal Tekton Server
|
||||
---
|
||||
|
||||
This blog is a descreptive account of the development of Minimal Tekton Server.
|
||||
This is highly technical in nature, so please make sure that you have sufficient
|
||||
knowledge about Golang, Docker, Kubernetes and TektonCD. You can refer to my
|
||||
[previous blog]("https://avinal.space/posts/development/i-am-loving-it-redhat.html")
|
||||
to know about these topics.
|
||||
|
||||
As mentioned in my last blog, we were given to implement an application
|
||||
named **Minimal Tekton Server**. The problem statement reads:
|
||||
|
||||
> We will be designing and implementing an application that will be
|
||||
> talking to Tekton APIs to create resources on a Kubernetes/OpenShift
|
||||
> Cluster. The application will expose some fields of the Tekton
|
||||
> Resources which the user will provide and then this application will
|
||||
> create Tekton resources by talking to Tekton APIs available on the
|
||||
> cluster to create the resources based on the user-provided fields.
|
||||
|
||||
There are three parts in this project for the application and two more
|
||||
parts for the CI/CD using TektonCD and Kubernetes/OpenShift. I will go
|
||||
through each part descriptively and try to explain what we did.
|
||||
|
||||
## The Architecture of MKS
|
||||
|
||||
The first task in the development of the Minimal Tekton Server was
|
||||
creating its architectural diagram. Our first diagram was trash compared
|
||||
to the final diagram. Yeah, we learned. I will be explaining our
|
||||
final(obviously) architectural diagram and try to make some sense out of
|
||||
band-aids and duct tapes.
|
||||
|
||||

|
||||
|
||||
Let me start with explaining **What are MKS Resources?**. I hope you
|
||||
know at least tidbits about Kubernetes and by the definition: *A
|
||||
resource is an endpoint in the Kubernetes API that stores a collection
|
||||
of API objects of a certain kind; for example, the built-in
|
||||
`pods` resource contains a collection of Pod objects.* But
|
||||
developers soon realized that these in-built resources were not enough
|
||||
for the ever-growing applications of Kubernetes. Here [custom
|
||||
resource](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)
|
||||
comes into the picture. *A custom resource is an extension of the
|
||||
Kubernetes API that is not necessarily available in a default Kubernetes
|
||||
installation.* To define a custom resource we use something called
|
||||
[Custom Resource
|
||||
Definition](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/).
|
||||
So MKS Resources are such custom resources that correspond to the
|
||||
TektonCD custom resources.
|
||||
|
||||

|
||||
|
||||
Let us now focus on the box containing `Controller` and `API server`.
|
||||
The controller can be said as a stimulus-response mechanism. Take the
|
||||
analogy of a Venus Flytrap plant. The trap is initially open. There are
|
||||
`trigger` hairs on the inside of the trap. Once an insect is detected,
|
||||
there is a change of state and the trap closes in a blick on the eye.
|
||||
The controller works the same way. It listens for the change in the
|
||||
state of the MKS resources and immediately transfers the request to the
|
||||
Tekton API to reflect the change in the corresponding Tekton resources.
|
||||
The changes can be creation, deletion, or updating. The API server
|
||||
ensures that there is a working connection between our controller and
|
||||
the Tekton API.
|
||||
|
||||
MKS Server also exposes APIs to introduce a change of state in the MKS
|
||||
resources. In technical terms these are called `verbs`. There are five
|
||||
such verbs that we have exposed: `create`, `update`, `get`, `delete`,
|
||||
and `list`. They can be utilized by a REST client, or in our case **MKS
|
||||
CLI** to introduce desired change. The MKS command-line interface
|
||||
provides commands and subcommands to do the desired tasks.
|
||||
|
||||
Whenever there is a change in the state, there is a logic running inside
|
||||
the controller to react on that and that also affects our database. We
|
||||
store four datapoints in our database: `created`, `deleted`,
|
||||
`completed`, and `failed`. They tell us about the current statistcs of
|
||||
our MKS resource using a single-page web app called **MKS Dashboard**
|
||||
(or UI).
|
||||
|
||||
This was about the architecture of the Minimal Tekton Server. Let us
|
||||
jump into more technical stuff.
|
||||
|
||||
## How to implement a CRD controller?
|
||||
|
||||
During this assignment, something that took the most time and effort was
|
||||
the implementation of a controller for our custom resources. This isn't
|
||||
very hard if you go by the rules and do the things according to the
|
||||
well-defined documents and blogs since this is a standard step in the
|
||||
implementation of any custom resource controller. But did we follow the
|
||||
rules? Hell no! But this time, let us go step-by-step.
|
||||
|
||||
1. The first step is to define a `CustomResourceDefinition` for our custom
|
||||
resource. Let us define a CRD called `spacetime`. To do this you can write a
|
||||
YAML file like below.
|
||||
|
||||
```yaml
|
||||
# file: spacetime-crd.yaml
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: spacetimes.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: example.com
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
# either Namespaced or Cluster
|
||||
scope: Namespaced
|
||||
names:
|
||||
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
|
||||
plural: spacetimes
|
||||
# singular name to be used as an alias on the CLI and for display
|
||||
singular: spacetime
|
||||
# kind is normally the CamelCased singular type. Your resource manifests use this.
|
||||
kind: SpaceTime
|
||||
# shortNames allow shorter string to match your resource on the CLI
|
||||
shortNames:
|
||||
- st
|
||||
```
|
||||
|
||||
You can learn more about the fields and options
|
||||
[here](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/).
|
||||
The CRD that we defined above corresponds to the `CustomResource` given
|
||||
below. Once you apply the above file you will be able to see the
|
||||
`spacetime` custom resource on your Kubernetes/OpenShift cluster.
|
||||
|
||||
```yaml
|
||||
# file: spacetime-cr.yaml
|
||||
apiVersion: spacetimes.example.com/v1alpha1
|
||||
kind: SpaceTime
|
||||
metadata:
|
||||
name: spacetime-cr
|
||||
spec:
|
||||
message: "Hello from space!"
|
||||
```
|
||||
|
||||
Apply them using the following commands:
|
||||
|
||||
```bash
|
||||
kubectl apply -f spacetime-crd.yaml
|
||||
kubectl apply -f spacetime-cr.yaml
|
||||
```
|
||||
|
||||
1. Once we have defined our custom resources, we need to define the
|
||||
types that will correspond to this custom resource definition. This
|
||||
can be done using `k8s.io/apimachinery/pkg/apis/meta/v1` package
|
||||
written in golang. Did I tell you that this is all in golang? Well,
|
||||
now you know. Create a package structure for a golang project and
|
||||
add the definition of the type as given below.
|
||||
|
||||
```bash
|
||||
mkdir -p pkg/api/spacetime/v1alpha1
|
||||
touch pkg/api/spacetime/v1alpha1/{spacetime_types,register,doc}.go pkg/api/spacetime/register.go
|
||||
```
|
||||
|
||||
Add the following content to the corresponding files.
|
||||
|
||||
```go
|
||||
// file: /pkg/api/spacetime/v1alpha1/spacetime_types.go
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type SpaceTime struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec SpaceTimeSpec `json:"spec"`
|
||||
}
|
||||
|
||||
type SpaceTimeSpec struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type SpaceTimeList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
|
||||
Items []SpaceTime `json:"items"`
|
||||
}
|
||||
```
|
||||
|
||||
### Attribution
|
||||
|
||||
- Photo by [Luca Bravo](https://unsplash.com/@lucabravo?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/XJXWbfSo2f0?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText).
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
---
|
||||
category: development
|
||||
date: 2021-02-02T21:47:00
|
||||
description: If you use WakaTime to track your coding activity. You can add that to
|
||||
your README as a bar graph or embed it in your blog/portfolio. Just add this action
|
||||
to any of your repositories and there you have it.
|
||||
image: /images/waka.webp
|
||||
tags:
|
||||
- wakatime
|
||||
- github-action
|
||||
- coding
|
||||
title: How I implemented WakaTime embeddable Coding Graph GHA?
|
||||
---
|
||||
|
||||
If you use WakaTime to track your coding activity. You can add that to
|
||||
your README as a bar graph or embed it in your blog/portfolio. Just add this
|
||||
action to any of your repositories and there you have it.
|
||||
|
||||
## Implementation Details
|
||||
|
||||
This GitHub Action is divided into three parts. I didn't want to use
|
||||
Docker but it seems it doesn't work well without it. Let dive a little
|
||||
into technical details. Three parts are as below.
|
||||
|
||||
1. [main.py](https://github.com/avinal/Profile-Readme-WakaTime/blob/master/main.py)
|
||||
python script. This script contains many procedures.
|
||||
|
||||
- [Getting JSON data file via WakaTime
|
||||
API](https://github.com/avinal/Profile-Readme-WakaTime/blob/master/main.py#L52)
|
||||
|
||||
```python
|
||||
def get_stats() -> list:
|
||||
...
|
||||
return data_list
|
||||
```
|
||||
|
||||
This function parses the JSON file received and scraps out the useful
|
||||
data as a list of lists. Data scraped are language list, time spent on
|
||||
each language, percentage of the time, start date, and end date. For
|
||||
this action, I have limited the number of languages to 5 however it
|
||||
should be very easy to increase that number.
|
||||
|
||||
- [Setting the
|
||||
Timeline](https://github.com/avinal/Profile-Readme-WakaTime/blob/master/main.py#L13)
|
||||
|
||||
```python
|
||||
def this_week(dates: list) -> str:
|
||||
...
|
||||
return f"Coding Activity During: {week_start.strftime('%d %B, %Y')} to {week_end.strftime('%d %B, %Y')}"
|
||||
```
|
||||
|
||||
The start date and end date scraped in the last function are used here
|
||||
to set the timeline. Because date in JSON is provided in UTC as below
|
||||
:
|
||||
|
||||
```json
|
||||
date: "YYYY-MM-DDTHH:MM:SSZ"
|
||||
```
|
||||
|
||||
I striped it to simple dates only. We can set them manually by taking
|
||||
the current time from the system. But that method is flawed. But this
|
||||
method ensures that JSON was received latest and the request was
|
||||
successful. Any anomaly will point to a failure in request.
|
||||
|
||||
- [Creating a bar
|
||||
graph](https://github.com/avinal/Profile-Readme-WakaTime/blob/master/main.py#L21)
|
||||
|
||||
```python
|
||||
def make_graph(data: list):
|
||||
...
|
||||
savefig(...)
|
||||
```
|
||||
|
||||
Lastly, it is time to generate the graph and save them as an image.
|
||||
This function uses the data scraped in the first step. Creating a bar
|
||||
graph using matplotlib is easy.
|
||||
Decorating was a bit difficult. I wanted this graph to merge with
|
||||
GitHub's look so I chose to color the bar as GitHub colors the
|
||||
languages. That data is stored as colors.json. Many of the languages have
|
||||
slightly different spelling in GitHub as compared to WakaTime. So some
|
||||
languages are shown in default color. That can be improved if we
|
||||
notice that language and change its color manually. Lastly, the graph
|
||||
is saved both as SVG and PNG. SVGs are better to put on a responsive
|
||||
page.
|
||||
|
||||
2. [entrypoint.py](https://github.com/avinal/Profile-Readme-WakaTime/blob/master/entrypoint.sh)
|
||||
shell script. This shell script clones the repository copies the
|
||||
image and pushes changes to the master. There were several problems.
|
||||
First of all authentication. This was solved by using a remote
|
||||
repository address using GitHub Token. And it seems that GitHub
|
||||
doesn't allow to commit without a username and email. So I used
|
||||
**github-actions** bot email.
|
||||
|
||||
```bash
|
||||
remote_repo-"https://${GITHUB_ACTOR}:${INPUT_GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config user.name "GitHub Actions"
|
||||
```
|
||||
|
||||
`41898282` is the id assigned to the github-actions bot. Don't ask
|
||||
where I found them 🙂.
|
||||
|
||||
Another problem was to separate repository name from combined
|
||||
*username/repository-name* provided by `${GITHUB_REPOSITORY}`. GitHub doesn't
|
||||
provides a direct way to get just the repo name. We used *Internal
|
||||
Field Separator*. It returns an array and works similar to `split()`
|
||||
command in Python and Java.
|
||||
|
||||
```bash
|
||||
# '/' is the seperator
|
||||
IFS-'/' read -ra reponame <<< "${GITHUB_REPOSITORY}"
|
||||
# returned {username, repository}
|
||||
repository-"${reponame[1]}"
|
||||
```
|
||||
|
||||
After that, all other commands are pretty straight. Commit the added
|
||||
files and push them.
|
||||
|
||||
3. [Dockerfile](https://github.com/avinal/Profile-Readme-WakaTime/blob/master/Dockerfile)
|
||||
**IMPORTANT** It took a lot of time to reach this state 🥱. This is
|
||||
where all the magic happens. I am running <span
|
||||
class="title-ref">ubuntu:latest</span> inside the container. I first
|
||||
update the distribution. Then install the required python packages.
|
||||
Lastly, I invoke the python script and shell script.
|
||||
|
||||
There was an almost impossible problem, I searched hundreds of posts
|
||||
that *how can I access the generated files inside Docker container*, but
|
||||
no luck. But at last, I found a workaround(obviously otherwise you
|
||||
wouldn't be reading this by now 🤣) each command is run in a separate
|
||||
virtual sub-container. As the command ends its output is also lost but
|
||||
not when you club multiple commands together. At least not until every
|
||||
command is finished. The generated files are available to the next
|
||||
clubbed process. I did that by combining the python script run and shell
|
||||
script run.
|
||||
|
||||
```dockerfile
|
||||
CMD python3 /main.py && /entrypoint.sh
|
||||
```
|
||||
|
||||
This part is the smallest yet took the most time and tries while
|
||||
developing this action.
|
||||
|
||||
## How to use this GitHub Actions?
|
||||
|
||||
1. First get your WakaTime API Key. You can get it from your
|
||||
[WakaTime](<https://wakatime.com>) account settings.
|
||||
|
||||
2. Save WakaTime API Key to Repository Secret. Find that by clicking
|
||||
the Settings tab. Keep the name of the secret as
|
||||
**WAKATIME_API_KEY**.
|
||||
|
||||
3. Add the following line in your README.md of your repo.
|
||||
|
||||
```html
|
||||
<img src="https://github.com/<username>/<repository-name>/blob/<branch-name>/images/stat.svg" alt="Alternative Text"/>
|
||||
Example: <img src="https://github.com/avinal/avinal/blob/main/images/stat.svg" alt="Avinal WakaTime Activity"/>
|
||||
```
|
||||
|
||||
> You can use this method to embed in web pages too. **Do not use the
|
||||
> markdown method of inserting images. It does not work sometimes.**
|
||||
|
||||
4. Click the **Action** tab and **choose to set up a workflow
|
||||
yourself**.
|
||||
|
||||
5. Copy the following code into the opened file, you can search for
|
||||
**WakaTime Stat** in the marketplace tab for assistance.
|
||||
|
||||
```yaml
|
||||
name: WakaTime status update
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Runs at 12 am '0 0 * * *' UTC
|
||||
- cron: "1 0 * * *"
|
||||
|
||||
jobs:
|
||||
update-readme:
|
||||
name: Update the WakaTime Stat
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Use avinal/Profile-Readme-WakaTime@<latest-release-tag> for latest stable release
|
||||
# Do not change the line below except the word master with tag number maybe
|
||||
# If you have forked this project you can use <username>/Profile-Readme-WakaTime@master instead
|
||||
- uses: avinal/Profile-Readme-WakaTime@master
|
||||
with:
|
||||
# WakaTime API key stored in secrets, do not directly paste it here
|
||||
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
|
||||
# Automatic github token
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
# Branch - newer GitHub repositories have "main" as default branch, change to main in that case, default is master
|
||||
BRANCH: "master"
|
||||
# Manual Commit messages - write your own messages here
|
||||
COMMIT_MSG: "Automated Coding Activity Update :alien:"
|
||||
```
|
||||
|
||||
6. Please wait till 12 AM UTC to run this workflow automatically. Or
|
||||
you can force run it by going to the Actions tab. Or you can add the
|
||||
following lines under `on:` to run with
|
||||
every push. Search for 12 AM UTC to find the equivalent time in your
|
||||
time zone.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '1 0 * * *'
|
||||
```
|
||||
|
||||
## My Coding Activity
|
||||
|
||||

|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
category: development
|
||||
date: 2020-12-31T19:07:00
|
||||
description: It is real pain when you have small SSD and Windows Subsystem for Linux
|
||||
(WSL) is growing exponentially in size. There is no easy way to move the WSL installation
|
||||
to another drive. Here in this blog I will discuss how to tackle this problem with
|
||||
bite size steps.
|
||||
image: /images/windows-wsl2.webp
|
||||
tags:
|
||||
- wsl
|
||||
- wsl2
|
||||
title: Move WSL 2 Safely to another Drive
|
||||
---
|
||||
|
||||
It is real pain when you have small SSD and Windows Subsystem for Linux
|
||||
(WSL) is growing exponentially in size. There is no easy way to move the
|
||||
WSL installation to another drive. Here in this blog I will discuss how
|
||||
to tackle this problem with bite size steps.
|
||||
|
||||
1. Open a PowerShell or Command Prompt with *Admin* access. For this you can
|
||||
use WinKey + X shortcut and select **Windows PowerShell(Admin)**.
|
||||
2. Check if the WSL 2 installation you are planning to move is is
|
||||
currently running/stopped.
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> wsl -l -v
|
||||
PS C:\\Users\\Avinal>
|
||||
NAME STATE VERSION
|
||||
* Ubuntu Running 2
|
||||
Kali Stopped 2
|
||||
```
|
||||
|
||||
3. If its running then you must stop the particular WSL distribution.
|
||||
(*Ubuntu* used as example)
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> wsl -t Ubuntu
|
||||
```
|
||||
|
||||
4. Export to some folder. (Here exporting *Ubuntu* as *ubuntu-ex.tar*
|
||||
to *Z:wsl2*)
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> wsl --export Ubuntu "Z:\\export\\ubuntu-ex.tar"
|
||||
```
|
||||
|
||||
5. Unregister previous WSL installation
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> wsl --unregister Ubuntu
|
||||
```
|
||||
|
||||
6. Create a new folder and import your WSL installation to that folder.
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> New-Item -Path "Z:\\wsl2" -ItemType Directory
|
||||
|
||||
Directory: Z:\\
|
||||
|
||||
Mode LastWriteTime Length Name
|
||||
---- ------------- ------ ----
|
||||
d----- 31-12-2020 21:03 wsl2
|
||||
|
||||
PS C:\\Users\\Avinal> wsl --import Ubuntu "Z:\\wsl2" "Z:\\export\\ubuntu-ex.tar"
|
||||
```
|
||||
|
||||
7. Check after import is complete
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> wsl -l -v
|
||||
PS C:\\Users\\Avinal>
|
||||
NAME STATE VERSION
|
||||
* Ubuntu Running 2
|
||||
Kali Stopped 2
|
||||
```
|
||||
|
||||
8. Mark one of your WSL distribution as *(default)*.
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> wsl -s Ubuntu
|
||||
```
|
||||
|
||||
9. After exporting your default user will be set as
|
||||
<i style="color:red">root</i> , to change it to your desired
|
||||
username, run following command
|
||||
|
||||
```powershell
|
||||
PS C:\\Users\\Avinal> ubuntu config --default-user user_name
|
||||
```
|
||||
|
||||
10. Finally run `wsl` and you have successfully moved your WSL 2
|
||||
installation to another drive.
|
||||
|
||||
## Attribution
|
||||
|
||||
- [Image](https://www.atwix.com/magento/magento-2-with-docker-for-windows-and-wsl-2/)
|
||||
Reference in New Issue
Block a user