Looped Network

Looped Links

In my opinion, there's nothing quite like actual projects to really help me learn how to do something. Case in point, I posted last weekend about working on a Python WriteFreely client. I mainly work on it on weekends since, when I finish a day of coding for actual work during the week I usually don't have the motivation to do work on a side project of my own.

While working on it today, I realized that a method in my Post class was actually needed outside of that: check_collection

This method takes the collection passed by the user (think of it like an individual blog, if you're unfamiliar with the API) and validates that it is legitimate. While I initially included this in my Post class, as I added functionality to retrieve a list of posts I realized I needed it in areas where I wouldn't have all of the information to instantiate the Post class.

One immediate option was to just make my Post class more generic so that it could be instantiated and used with less up-front information. However, I didn't particularly like that setup. Instead, I realized that the solution was to simply make a new class, which I called WriteFreely that would serve as a super class. Then I made my Post class a subclass of it via:

from client import WriteFreely
class Post(WriteFreely):

In this way, my only change to the Post class was to delete the check_collection method which it will now naturally inherit from the WriteFreely parent class. I've honestly never really done anything with class inheritance before in a real-world scenario, so to me it's just further proof that I'll never get better experience with something than by simply doing it.

I recently found myself working on a project which required the GSS-NTLMSSP library. The application is going to be delivered via Kubernetes, so I needed to build a Docker image with this library. The project's build instructions are pretty clear about what the dependencies are, but given that this was going to be a Docker image, I wanted to use Alpine Linux as the base image in order to keep the image size as small as possible. The problem with this is that Alpine is just different enough to require different dependencies, publish their packages under different names, etc.

I started off by just doing things manually where I fired up a local Docker container running the base Docker image and then manually installing each package via apk add {package_name} to make troubleshooting easier. Once I had all of the packages from the aforementioned build documentation, I ran ./configure, looked at the errors, figured out which package was missing, installed it, and tried again. After several iterations of this process, ./configure executed successfully and it was time to attempt running make.

make ran for a minute but then would error out with:

undefined reference to 'libintl_dgettext'

This seemed odd to me because while running ./configure I had received an error that msgfmt couldn't be found, and I had installed gettext-dev in order to accommodate that. After some additional packages searches, I discovered the musl-libintl library is also available. I attempted to install that but received an error that it was attempting to modify a file controlled by the gettext-dev package. I uninstalled that via apk del gettext-dev and then ran into another error that—duh—msgfmt was now missing again. I handled that by just installing the vanilla gettext package, not the -dev version, and then finally everything compiled successfully.

The following is the full list of packages that I needed in order to get the build to succeed:

  • autoconf
  • automake
  • build-base
  • docbook-xsl
  • doxygen
  • findutils
  • gettext
  • git
  • krb5-dev
  • libwbclient
  • libtool
  • libxml2
  • libxslt
  • libunistring-dev
  • m4
  • musl-libintl
  • pkgconfig
  • openssl-dev
  • samba-dev
  • zlib-dev

Note that git is included just to clone the repo, and build-base is the meta package I used for compiling C software since just installing something like gcc will not include everything needed.

I'm potentially going to be working on a side project at work which would have me using C#... which I'm not particularly familiar with outside of any similarities it lent to PowerShell, which I use frequently. I did some tutorials on C# about a decade ago of which I remember absolutely nothing. As a result, I've been looking for some tutorials or guides that I can use to get up to speed at least a little bit. Maybe I'm terrible at searching, but C# tutorials are... not good.

Microsoft offers a ton of material, but it all seems to mostly assume that you either:

  1. Are completely new to programming.
  2. Are already experienced with C# and just need to know either advanced topics or what's new in the language.

I really need something that shows me the syntax, how code is organized, etc. Then I can start working on some personal projects and familiarizing myself with more of the specifics from there. This gist is very helpful, especially because I do a lot of work in Python right now. However, I don't think it quite had the depth I wanted.

I'm going to try reading Microsoft's slightly longer Tour of C# and see if that provides enough to get me started.

I had previously posted that I was going to work on a CLI client for posting content to Write Freely. I ended up having some distractions on that front as I got busy with things at work and briefly toyed with the idea of writing my client in Go instead of Python. While I may still circle back at some point on the language (I'm debating between using it as an excuse to learn Go or learn Rust at this point), I ultimately decided that—considering I use Python for the majority of my projects at work and I'm not exactly a master with it—it made the most sense to stick with Python for this project. I need to get good with one thing before I start trying to learn the next thing.

I actually made a decent bit of progress tonight, as is visible by the 2 commits I pushed. The big items I got nailed down were:

  • Authentication to provide credentials and get an API key which is locally cached for future use.
  • Logging out to invalidate the aforementioned API key and clear the locally cached content.
  • Pushing posts via a path to a file.
  • Pushing posts via content piped to STDIN.

All of this is subject to change as I'm currently just trying to get something working, and I'll clean things up later. Right now, testing is a little weird because I call __main__ directly, given that I eventually intend to package this.

Regardless, it's cool to start seeing progress come together. I've worked on—and subsequently abandoned—similar projects for things like Mastodon and Tumblr, and I always end up running into hurdles with authentication. I could, and arguably should, skip the complexities of that immediately and circle back to it later, but I always end up feeling like I should work in order. Luckily, the API for Write Freely is very straight forward with respect to authentication.

In fact, it's very straightforward with respect to basically everything, and it's very well documented on top of that. Huge kudos for that.

Immediate next steps are going to include:

  • Refining the output when posts are made. I'm not sure if it's possible from a quick glance at the documentation, but if it is I'd like to include a URL to the final post for ease of access to see the finished product.
  • Allow for post deletion by running a command to query for post titles and IDs followed by a command to remove a post by ID.

Longer term next steps will be:

  • Adding an interactive mode so that the writepyly command drops the user into a TUI, preferably created with something like Rich so that it looks swanky.
  • Allow post management from the TUI.
  • Allowing for post creation from the TUI.

In my next commit I'll probably try to update the project's README to reflect this as well. In the meantime, look for more garbage posts on my test blog that I set up so that I don't pollute this one with nonsense content in order to test my client.

I've recently been working on a project that requires me to use PowerShell. I actually feel relatively fluent in PowerShell since it was my main scripting language for a little over a decade while I worked as a sysadmin in highly Windows-centric environments that involved me automating as much of my job as possible in order to be able to do things like sleep on occasion. However, my PowerShell work rarely (read: never) went beyond single file scripts.

With this project being a decent bit more complicated and with the potential for some of the code to be useful in future projects, I wanted to figure out how to actually break things up into useful chunks, just like I would do when writing something in Python. Fortunately, it wasn't terribly difficult to figure out, though, as is typically the case with PowerShell, the documentation was a bit wanting. I had to put information together from a few different resource and go through a little trial-and-error to actually figure it out since Microsoft can never just seem to give clear, concise examples of anything PowerShell-related.

The first thing I needed to realize is that I wanted to create my files not with a normal .ps1 extension but with a .psm1 extension to indicate that they were PowerShell modules. Only the file that would normally be executed directly has a .ps1 extension. I kind of hate this since it makes things more difficult to test individually; in Python, for example, I could just create a main function that executes when:

if __name__ == "__main__":

Then I can add things in main while building it out that are later ignored when the code is called from elsewhere. PowerShell doesn't offer anything like this, though it's not a huge ordeal. After creating a .psm1 file, it can contain functions, classes, and/or methods. For example, here's a sample file called helloFunc.psm1 with just a function:

function Write-Hello {
    param(
        [Parameter(Mandatory=$true)][string]$Name
    )

    Write-Output "Hello, $Name."
}

And here's a file called personClass.psm1 with both a class and a couple of methods:

class Person {
    [String]$Name
    [int]$Age

    # Constructor.
    Person([String]$Name, [int]$Age) {
        $this.Name = $Name
        $this.Age = $Age
    }

    [String]GreetPerson([String]$PreferredGreeting) {
        if($PreferredGreeting -eq "" -or $null -eq $PreferredGreeting) {
            $PreferredGreeting = "Hello"
        }
        return "$PreferredGreeting, $($this.Name). I can't believe you're $($this.Age) years old."
    }

    [void]HaveBirthday() {
        $this.Age++
    }
}

Neither file has an entrypoint, though that's expected since they're designed to be called from somewhere else. Here's the main.ps1 file which ties them all together:

#!/usr/bin/env pwsh
using module ./personClass.psm1
using module ./helloFunc.psm1

Write-Hello -Name "Garrett"

$me = [Person]::new("Garrett", 9000)
Write-Output $me.GreetPerson("Salutations")
$me.HaveBirthday()
Write-Output $me.GreetPerson("Salutations")

The most important thing here are the two using statements, which specify that I'm going to import the two aforementioned files. Once I do this, I can then call classes, methods, and functions in those files directly.

I had to laugh when I received the following after attempting to run some Go code I've been working on:

The last error in particular was funny:

too many errors

Don't I know it.

No Starch Press seems to so consistently produce terrific books. I buy from them pretty regularly, and they always seem to offer up sales on pre-orders. Just today I got an email about getting 30% off The Book of Kubernetes, and it sounds like a great read. Here’s to hoping I can knock a few things off my to-read docket before it releases.

This post easily falls into the “so ridiculous that it shouldn’t be a post” category. However, considering how long I ended up stuck on it earlier today, I figure it’s worth making if it stands a chance of helping even one other person avoid the same fate as me. 😅

I’ve started doing a little bit of work with the Terraform Cloud API. Specifically, I was looking at being able to update a workspace variable through code. In this case, I was trying to change a variable I called replica_count which, if the name wasn’t enough of a giveaway, I was using to track how many replicas should be used in a Kubernetes container spec.

I found that I was able to easily get back all of my workspace variables via a GET to:

https://app.terraform.io/api/v2/workspaces/{workspace_id}/vars/

However, trying to make a PATCH to...

https://app.terraform.io/api/v2/workspaces/{workspace_id}/vars/{variable_id}

... with a body in JSON to specify the change resulted in a 500 internal server error response.

The JSON in the body wasn’t very complex. I only needed to modify the value. As the documentation specifies, and the type must be set to “vars” and the id must be set to the ID of the variable to change. This is a bit odd to me since I also have to give the ID in the URL, but it’s not a big deal. The attributes property then can optionally contain whatever property or properties need to be updated. In my case, the JSON just looked like:

{
    “data”: {
        “id”: var_id,
        “type”: “vars”,
        “attributes”: {
            “value”: 2
        }
    }
}

There isn’t a lot to go wrong here... but I managed to do it! I finally figured out what was wrong when I changed my PATCH to a GET just to validate that my JSON had to be the culprit. The GET responds with JSON which is very similar to what I needed to send, and that’s what tipped me off to the fact that the value of the variable is always a string, even if I’m thinking of it as a number in my head. So my value line needed to be:

“value”: “2”

After seeing that in the response to my GET, I updated my JSON, re-PATCHed, and saw that everything was successful.

After some debate and testing this morning, I think I’ve decided that I’ll most likely use Python for my proposed Write Freely CLI/TUI client. I created a repo for it, though I don’t have anything committed yet. I was initially debating between Python—a language with which I’m moderately familiar and trying to work with as much as I can since most of the things I do for work leverage it—and Go—a language which interests me but which I don’t know very well at all.

I have to admit that I was initially leaning toward Go for a few reason. First is that, in a perfect world, I eventually work on this project for a long time and it becomes something that other people may want to use. In that case, packaging things up for other people to use outside of something like a Docker container is a bit of a pain with Python. You can’t really expect most people to leverage a Python virtual environment to run your code. I also don’t particularly like making virtual environments all the time since my VPS doesn’t exactly have a ton of storage space. I figured Go would solve both of these problems since I wouldn’t need a virtual environment, and I could easily bundle my finished code up as a single executable, one which I could cross-compile for every platform if I so desired.

In practice, however, the space efficiency wasn’t great. Part of the problem is that I wanted to use the vim-go plugin, which requires a fairly hefty download of extras, accomplished via running :GoInstallBinaries from within Vim; if you don’t do this, you’ll see errors whenever you open or attempt to save a new .go file.

My bigger issue, though, is that it was pretty confusing to me off the bat just how to organize a Go application. I’ve written several very small Go applications before, and all of them were contained to a single file. Doing this is a nightmare as far as keeping things organized goes, and it very quickly becomes difficult to remember what is where as I scroll endlessly back and forth in a single file. I did some research on how projects should be organized, but despite having a page documenting exactly that, I honestly found the documentation very difficult. It doesn’t give concrete examples showing the file structure and seems to make a lot of assumptions about what people already know. It’s entirely possible there’s other documentation I should be reading prior to reading the link I just shared, but if that’s the case then I wish it was linked to from within that page.

Ultimately, I decided that trying to figure out things like this with Go seemed like a bit too much of a hurdle on top of also just learning how to do pretty much everything I need with the language. I do have some Udemy courses on Go that cover more in-depth topics than the books I’ve previously read (e.g. creating a full stack web application), so I may try to watch some of those in order to figure out if they help me any from an organization standpoint. I would like to take the opportunity to learn Go, but the documentation I’ve seen thus far doesn’t make me feel good about it.

I’ve been attempting to work through having fewer distractions in my life, especially throughout the day and especially stemming from my phone. I spend more time looking at my phone than I really like, despite the fact that my first inclination is to reach for it at literally any moment of downtime. No one else has joined the call yet for a work meeting? Better doomscroll for a bit. I need to upload a freshly built Docker image to the development lab via VPN, and it’s going to take about 2 minutes? That’s 2 minutes I can spend looking at nonsense on the Internet.

Ideally I could just avoid having my phone in the room with me while I’m working, but the reality of the situation is that I typically need to have it on hand. I get calls related to work on it, and I use it for MFA across a wide swath of services. Instead, I tried to make myself feel less inclined to constantly reach for it with less things that I want to check all the time. One of my first attempts at minimizing how much my phone distracts me was to get off Mastodon. Mastodon, much like how I used Twitter before it, almost immediately became the thing that I would always feel the need to look at, as if missing a single post was going to somehow make a big difference. I should have realized how far down the Mastodon rabbit hole I had gone when one of the main things I noticed about any Mastodon iOS app I tried was how it handled refreshing my timeline.

Moving away from Mastodon wasn’t too bad, but I still like the idea of having somewhere that I could post random nonsense, quick quips, etc. I wanted somewhere for content that wasn’t really “blog post” worthy but felt like fun to put online somewhere. I initially started with Tumblr. This actually worked pretty well, as Tumblr functinos decently well for both long form content and shorter content, especially when I wanted to post links, images, or even quotes. I actually even started working on a CLI Tumblr client that I could use from a VPS I was SSH’d into. I haven’t made it very far other than an extremely early build that allows for a few different post types, but I found their API pleasant to work with, especially via their SDK. The problem, however, is that Tumblr didn’t really solve the problem. I still ended up following a handful of other blogs, and before long I was still finding myself absentmindedly reaching for my phone so that I could spend a few minutes scrolling through memes and anime GIFs. Like many other social media platforms which aren’t Mastodon, Tumblr also has a vested interest in keeping my eyes glued to their platform as much as possible. As a result, a specially curated timeline of content their algorithms thought I would like was always waiting for me if nothing had recently been posted from the accounts I followed.

I went back to the drawing board and eventually realized that Write.as could work even better for this. Naturally, it has support for both long form posts like this one as well as shorter content that doesn’t even require a title. So that’s what I’ll be giving it a shot with, especially while I still have more than 6 months of time left on my Pro subscription. What’s also cool is that it has an API, so I may shift my focus into working on a CLI client for it rather than continuing with the Tumblr one that I (hopefully) won’t be leveraging much going forward. This would allow me to easily write content from any web browser, from my iOS devices via the Write Freely app, and from an SSH session if I have my (eventual) app installed.