Automating Baremetal Node Creation for Ironic

Sometime your shell scripts get out of control. Sometimes you are proud of them. Sometimes….both.

I need to be able to re-add a bunch of nodes to an OpenStack cluster on a regular basis. Yes, I could do this with Ansible, but, well, Ansible is great for doing something via SSH, and this just needs to be done here and now. So shell is fine.

This started as a one liner, and got a bit bigger.

Continue reading

Changing the Output in (ARM64) Assembly

When ever I write new console based code from scratch, I start with “Hello World.” Then I make one small change at a time, test it, and commit. Then I move on. While this slow process might seem tedious, it is based on years of wasting time debugging my own poorly written code in interim changes.

Once I had “Hello, World!” working in assembly, I want to make a single character change to message and see it in the console. Here’s my steps.

Continue reading

Simplest (ARM64) Assembly Program that Runs without an error

In order for a program to run successfully, it needs two things: an entry symbol, and a return code that represents that success. The following program provides those two things.

.global _start
 
_start:     
            MOV     X0, #0
            MOV     X8, #93
            SVC     0

Compile it using the simple Makefile from the previous article.

The symbol _start is a special symbol expected by the linker. If you try to rename like this…….

.global _ADAM
 
_ADAM:     
            MOV     X0, #0
            MOV     X8, #93
            SVC     0

…you get the following error:

$ make other
as -o other.o other.s
ld -o other other.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078

Which will still compile and run.

If you leave off the three assembly instructions at the end, you do not return 0 indicating the program success.

.global _start
 
_start:

That gives you this error:

]$ ./bad_return -bash: ./bad_return: cannot execute binary file: Exec format error

To be honest, there are no instruction in the code, and I think that is a different problem. If we skip executing the function to send the return code:

.global _start
 
_start:     
            MOV     X0, #0
            MOV     X8, #93

That gives this error when run:

$ ./bad_return 
Illegal instruction (core dumped)

Simple Makefile for assembly executables

I want to automatically build assembly files into executable binaries. The following Makefile seems to be sufficient. I am sure I will add to it over time.

All I have to modify is the SRC_FILES line to add a new target

Note that html does not honor the tab characters.

EDIT: I swapped the SRC_ and B_ files so that the top list is the end result. This allows you to just run make and build all of your executables. It would also let you mix and match between assembly and other languages. But (most importantly) I like it better.

B_FILES=simple printer
SRC_FILES = $(B_FILES:%=%.s)
O_FILES = $(SRC_FILES:%.s=%.o)
 
all: $(B_FILES) 
 
%: %.s 
	as -o $@.o $<
	ld -o $@ $@.o
 
clean:
	rm -f $(O_FILES) $(B_FILES)


Building the Linux Kernel in a GitLab Runner

Git Lab provides a mechanism to run workloads triggered by a git commit. We try to let the automation do as much work as possible before interrupting a human code reviewer. We want to know if the code is right in as objective a manner as possible before we take the expensive context switch to perform a code review.

Continue reading

Make long running tasks short for development

COmpiling the Linux Kernel is a long running task. Oh, sure, you can put -j 32 and it speeds it up tremendously. But it still is a long running task. And by that, I mean it fits the following definition:

A Long Running task is one that takes so long that you start doing something else before it is done.

“aDAM YOUNG”

If you are familiar with the concept of Flow, then a long running task is one that breaks the flow.

It seems that these kind of “flow Blockers” are common in my line of work. I tend to work on distributed systems, and network based workflows are usually long running tasks. Things like:

  • Ansible Playbooks that allocate a bunch a virtual machines before install software on them.
  • Software install process like ipa-server install
  • Automatically build, install, and test the Linux Kernel

This last one is the thing I am working on now.

The funny part is that I don’t have to do the hard work of making the Kernel compile. This is the responsibility of the team I am building this for, and I can assume that it works OK. This assumption will allow me to skip actually building the Kernel for the majority of my effort.

What do I need to do? I need to write a small yaml file that gitlab will use to kick off a CI/CD Pipeline. This file is a fairly thin wrapper around a bash script (similar pattern to RPM spec files, Ansible, and so forth) that will be executed on the remote system when triggered by a new or modified merge-request. This code needs to install a bunch of RPMs via dnf, kick off the kernel build, and then upload the artifacts to an object store. Right now, I am working on that last bit.

If I wait for the Linux Kernel to build, each iteration of code changes in my development cycle will take more than an hour. Thus, I want to put off actually building the Kernel until I know the rest of the tasks work. All I need to do is test that something gets uploaded, I don’t really care what that thing is. So I comment out the make and replace it with the simplest command I can think of to create a file:

 #- make -j 16 rpm-pkg mkdir ./artifacts
 - touch  ./artifacts/test.test

There is actually a bunch of stuff I comment out including the part where I install packages from dnf. If I know that the code is working, there is little benefit to running it during the debug cycle for the upload stage.
However, I only want to comment out lines, not remove, Why? Because the code needs to be put back in to place in the final assembly, and I don’t want to have to debug the long running process.

With the actual build elided from my process, I can test the system by submiting a no-op merge request and see that gitlab triggers the runner to run my code. My round trip is now about a minute, short enough that I can keep myself on task.

Usually.

Date format suitable for file names

It is rare that you want to write something without later wanting to be able to read it back. One common way of organizing files that are generated regularly is by time stamp. If you want to add a timestamp to a file name, you can do so using the date command.

In order for the filenames to sort in the right order, you want the name to go from largest unit to smallest.

Here is an example that creates a filename-suitable string formed Year->second. I remove all unnecessary formatting characters.

date --rfc-3339=seconds | sed -E -e 's! |-|:!!g'

The date command reads the current date/time on the local system. –rfc-3339=seconds produces output that looks like this:

$ date --rfc-3339=seconds 
2021-11-03 10:57:14-04:00

In order to keep the regular expression concise inside the sed command, the -E switch tells it to use extended regular expressions, including the alternation character ‘|’ . Thus, the regex ‘ |-|:’ matches a space, a dash, and a colon.