Skip to content

31st Week of 2024

Activism

Free Knowledge

  • Correction: Update the way of seeding ill knowledge torrents.

    A good way to contribute is by seeding the ill torrents. You can generate a list of torrents that need seeding up to a limit in TB. If you follow this path, take care of IP leaking, they're

Conference organisation

  • New: Software to manage the conference.

    There are some open source software that can make your life easier when hosting a conference:

    In addition to the management of talks from the call for papers till the event itself it can help the users visualise the talks schedule with EventFahrplan which is what's used in the ChaosComputerClub congress.

    If you also want to coordinate helpers and shifts take a look to Engelsystem

Life Management

Time management

  • New: Keep on summing up Oliver Burkeman book.

    Efficiency doesn't necessarily give you more time

    We're eager to believe the promises of time management frameworks (like GTD) that if you improve your efficiency you'll get more time to enjoy your life. If you follow the right time management system, build the right habits, and apply sufficient self-discipline, you will win the struggle with time.

    Reality then kicks in you never win the struggle and only feel more stressed and unhappy. You realize that all the time you've saved is automatically filled up by more things to do in a never ending feedback loop. Time feels like an unstoppable conveyor belt, bringing us new actions as fast as we can dispatch the old ones; and becoming more efficient just seems to cause the belt to speed up. Or else, eventually, to break down. It's true that you get more done, and yet, paradoxically, you only feel busier, more anxious and somehow emptier as a result.

    It get's even worse because importance is relative and you may fall into efficiency traps.

    Heal yourself from FOMO

    Another problem that FOMO brings us is that it leads us to lives where you "truly lived" only if you've lived all the experiences you could live. This leads to a frustrating life as the world has infinite of them, so getting a handful of them under your belt brings you no closer to a sense of having feasted on life's possibilities. You lead yourself in another efficiency trap where the more you experience the more additional wonderful experiences you sarta to feel you could have on top of all those you've already had, with the result that the feeling of existential overwhelm gets worse. To fight this existential overwhelm you can resist the urge to consume more and more experiences and embrace the idea that you're going to miss most of them. You'll then be able to focus on fully enjoying the tiny slice of experiences you actually do have time for.

    This FOMO fever is normal given the facts that we're more conscious of the limits of our time (after deterring the after life), the increase of choices that the world has brought us, and the internet amplifier.

    You do what you can do

    It's usual to feel as though you absolutely must do more than you can do. We live overwhelmed in a constant anxiety of fearing, or knowing for certain, that the actions we want to carry out won't fit on our available time. It looks like this feeling arises on every step of the economic ladder (shown in the works of Daniel Markovits).

    The thing is that the idea in itself doesn't make any sense. You can't do more than you can do even if you must. If you truly don't have time for everything you want to do, or feel you ought to do, or that others are badgering you to do, then, well, you don't have time, no matter how grave the consequences of failing to do it all might prove to be. So technically it's irrational to feel troubled by an overwhelming to-do list. You'll do what you can, you won't do what you can't, and the tyrannical inner voice insisting that you must do everything is simply mistaken. We rarely stop to consider things so rationally, though, because that would mean confronting the painful truth of our limitations. We would be forced to acknowledge that there are hard choices to be made: which balls to let drop, which people to disappoint, which ambitions to abandon, which roles to fail at... Instead, in an attempt to avoid these unpleasant truths, we deploy the strategy that dominates most conventional advice on how to deal with busyness: we tell ourselves we'll just have to find a way to do more. So to address our busyness we're making ourselves busier still.

    Importance is relative

    The problem here is that you'll never be able to make time for everything that feels important. A similar mindset of the section Efficiency doesn't give you more time can be applied. The reason isn't that you haven't yet discovered the right time management tricks, or applied sufficient effort, or that you're generally useless. It's that the underlying assumption is unwarranted: there's no reason to believe you'll make time for everything that matters simply by getting more done. For a start, what "matters" is subjective, so you've no grounds for assuming that there will be time for everything that you, or anyone else deems important. But the other exasperating issue is that if you succeed in fitting more in, you'll find the goalposts start to shift: more things will begin to seem important, meaningful or obligatory. Acquire a reputation for doing your work at amazing speed, and you'll be given more of it. An example of this is gathered in Ruth Schwartz's book More work for mother, where it shows that when washing machines and vacuum cleaners appeared no time was saved at all, because society's standards of cleanliness rose to offset the benefits. What needs doing expands so as to fill the time available for its completion.

    Be mindful of the efficiency trap

    Sometimes improving your efficiency may lead you to a worse scenario ("efficiency trap") where you won't generally result in the feeling of having "enough time", because, all else being equal, the demands will increase to offset any benefits. Far from getting things done, you'll be creating new things to do. A clear example of this is email management. Every time you reply to an email, there's a good chance of provoking a reply to that email, which itself may require another reply, and so on and so on. At the same time, you'll become known as someone who responds promptly to email, so more people will consider it worth their while to message you to begin with. So it's not simply that you never get though your email; it's that the process of "getting through your email" actually generates more email.

    For most of us, most of the time, it isn't feasible to avoid the efficiency trap altogether, but you can stop believing you'll ever solve the challenge of busyness by cramming more in, because that just makes matters worse. And once you stop investing in the idea that you might one day achieve peace of mind that way, it becomes easier to find peace of mind in the present, in the midst of overwhelming demands, because you're no longer making your peace of mind dependent on dealing with all the demands. Once you stop believing that it might somehow be possible to avoid hard choices about time, it gets easier to make better ones.

    If you also have the knowledge of the existence of the efficiency traps you may detect them and try to get the benefits without the penalties.

    Do the important stuff

    The worst aspect of the trap is that it's also a matter of quality. The harder you struggle to fit everything in, the more of your time you'll find yourself spending on the least meaningful things. This is because the more firmly you believe it ought to be possible to find time for everything, the less pressure you'll feel to ask whether any given activity sis the best use of a portion of your time. Each time something new shows up, you'll be strongly biased in favor of accepting it, because you'll assume you needn't sacrifice any other tasks or opportunities in order to make space for it. Soon your life will be automatically filled with not just more things but with more trivial or tedious things.

    The important stuff gets postponed because such tasks need your full focus, which means to wait until you have a good chunk of free time and fewer small-but-urgent tasks tugging at your attention. So you spend your energy into clearing the decks, cranking through the smaller stuff to get it out of the way, only to discover that doing so takes the whole day, that the decks are filled up again overnight and that the moment for doing the important stuff never arrives. One can waste years this way, systematically postponing precisely the things one cares the most.

    What's needed in these situations is to resist the urges of being on top of everything and learn to live with the anxiety of feeling overwhelmed without automatically responding by trying to fit more in. Instead of clearing the decks, decline to do so, focusing instead on what's truly of greatest consequence while tolerating the discomfort of knowing that, as you do so, the decks will be filling up further, with emails and errands and other to-dos, many of which you may never get around to at all.

    You'll sometimes still decide to drive yourself hard in an effort to squeeze more in, when circumstances absolutely require it. But that won't be your default mode, because you'll no longer be operating under the illusion of one day making time for everything.

    Evaluate what you miss when you increase your efficiency

    Part of the benefits of efficiency is that you free yourself from tedious experiences, the side effect is that some times we're not conscious of being removing experiences that we valued. So even if everything runs more smoothly, smoothness is a dubious virtue, since it's often the unsmoothed textures of life that makes them livable, helping nurture the relationships that are crucial for mental and physical health, and for the resilience of our communities. For example if you buy online the groceries you miss the chance to regularly meet with your neighbours at your local grocery store.

    Convenience makes things easy, but without regard to whether easiness is truly what's most valuable in any given context. When you render the process more convenient you drain it of its meaning. The effect of convenience isn't just that the given activity starts to feel less valuable, but that we stop engaging in certain valuable activities altogether, in favour of more convenient ones. Because you can stay home, order food online, and watch sitcoms on a streaming service, you find yourself doing so although you might be perfectly aware that you'd have had a better time if you had met with your friends.

    Meanwhile, those aspects of life that resist being made to run more smoothly start to seem repellent. When you can skip the line and buy concert tickets on your phone, waiting in line to vote in an election is irritating. As convenience colonizes everyday life, activities gradually sort themselves into two types: the kind that are now far more convenient, but that feel empty or out of sync with our true preferences; and the kind that now seem intensely annoying because of how inconvenient they remain. Resisting all this is difficult because the Capital is winning this discourse and you'll have more pressure from your environment to stay convenient.

Life planning

  • Correction: Tweak the month planning.

    Add the next steps:

    • Clean your agenda and get an feeling of the busyness of the month:
    • Open the orgmode month view agenda and clean it
    • Read the rest of your calendars

    Then reorder the objectives in order of priority. Try to have at least one objective that improves your life.

    • For each of your month and trimester objectives:
    • Decide whether it makes sense to address it this month. If not, mark it as inactive
    • Create a clear plan of action for this month on that objective.

      • Reorder the projects as needed
      • Mark as INACTIVE the ones that you don't feel need to be focused on this month.
    • Refine the roadmap of each of the selected areas (change this to the trimestral planning)

    • Select at least one coding project in case you enter in programming mode
    • Clean your mobile browser tabs
  • New: Debug doesn't go up in the jump list.

    It's because is a synonym of , and org_cycle is mapped by default as If you're used to use zc then you can disable the org_cycle by setting the mapping org_cycle = "<nop>".

  • New: Python libraries.

    org-rw

    org-rw is a library designed to handle Org-mode files, offering the ability to modify data and save it back to the disk.

    • Pros:
    • Allows modification of data and saving it back to the disk
    • Includes tests to ensure functionality

    • Cons:

    • Documentation is lacking, making it harder to understand and use
    • The code structure is complex and difficult to read
    • Uses unittest instead of pytest, which some developers may prefer
    • Tests are not easy to read
    • Last commit was made five months ago, indicating potential inactivity
    • Not very popular, with only one contributor, three stars, and no forks

    orgparse

    orgparse is a more popular library for parsing Org-mode files, with better community support and more contributors. However, it has significant limitations in terms of editing and saving changes.

    • Pros:
    • More popular with 13 contributors, 43 forks, and 366 stars
    • Includes tests to ensure functionality
    • Provides some documentation, available here

    • Cons:

    • Documentation is not very comprehensive
    • Cannot write back to Org-mode files, limiting its usefulness for editing content
      • The author suggests using inorganic to convert Org-mode entities to text, with examples available in doctests and the orger library.
      • inorganic is not popular, with one contributor, four forks, 24 stars, and no updates in five years
      • The library is only 200 lines of code
      • The ast is geared towards single-pass document reading. While it is possible to modify the document object tree, writing back changes is more complicated and not a common use case for the author.

    Tree-sitter

    Tree-sitter is a powerful parser generator tool and incremental parsing library. It can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited.

    • Pros:
    • General enough to parse any programming language
    • Fast enough to parse on every keystroke in a text editor
    • Robust enough to provide useful results even in the presence of syntax errors
    • Dependency-free, with a runtime library written in pure C
    • Supports multiple languages through community-maintained parsers
    • Used by Neovim, indicating its reliability and effectiveness
    • Provides good documentation, available here
    • Python library, py-tree-sitter, simplifies the installation process

    • Cons:

    • Requires installation of Tree-sitter and the Org-mode language parser separately
    • The Python library does not handle the Org-mode language parser directly

    To get a better grasp of Tree-sitter you can check their talks:

    lazyblorg orgparser.py

    lazyblorg orgparser.py is another tool for working with Org-mode files. However, I didn't look at it.

  • Correction: Tweak area concept.

    Model a group of projects that follow the same interest, roles or accountabilities. These are not things to finish but rather to use as criteria for analyzing, defining a specific aspect of your life and to prioritize its projects to reach a higher outcome. We'll use areas to maintain balance and sustainability on our responsibilities as we operate in the world. Areas' titles don't contain verbs as they don't model actions. An example of areas can be health, travels or economy.

    To filter the projects by area I set an area tag that propagates downstream. To find the area documents easily I add a section in the index.org of the documentation repository. For example:

vdirsyncer

Roadmap Adjustment

  • New: Trimester review.

    The objectives of the trimester review are:

    • Identify the areas to focus on for the trimester
    • Identify the tactics you want to use on those areas.
    • Review the previous trimester tactics

    The objectives are not:

    • To review what you've done or why you didn't get there.

    When to do the trimester reviews

    As with personal integrity review, it's interesting to do analysis at representative moments. It gives it an emotional weight. You can for example use the solstices or my personal version of the solstices:

    • Spring analysis (1st of March): For me the spring is the real start of the year, it's when life explodes after the stillness of the winter. The sun starts to set later enough so that you have light in the afternoons, the climate gets warmer thus inviting you to be more outside, the nature is blooming new leaves and flowers. It is then a moment to build new projects and set the current year on track.
    • Summer analysis (1st of June): I hate heat, so summer is a moment of retreat. Everyone temporarily stop their lives, we go on holidays and all social projects slow their pace. Even the news have even less interesting things to report. It's so hot outside that some of us seek the cold refuge of home or remote holiday places. Days are long and people love to hang out till late, so usually you wake up later, thus having less time to actually do stuff. Even in the moments when you are alone the heat drains your energy to be productive. It is then a moment to relax and gather forces for the next trimester. It's also perfect to develop easy and chill personal projects that have been forgotten in a drawer. Lower your expectations and just flow with what your body asks you.
    • Autumn analysis (1st of September): September it's another key moment for many people. We have it hardcoded in our life since we were children as it was the start of school. People feel energized after the summer holidays and are eager to get back to their lives and stopped projects. You're already 6 months into the year, so it's a good moment to review your year plan and decide how you want to invest your energy reserves.
    • Winter analysis (1st of December): December is the cue that the year is coming to an end. The days grow shorter and colder, they basically invite you to enjoy a cup of tea under a blanket. It is then a good time to get into your cave and do an introspection analysis on the whole year and prepare the ground for the coming year. Some of the goals of this season are:
    • Think everything you need to guarantee a good, solid and powerful spring start.
    • Do the year review to adjust your principles.

    The year is then divided in two sets of an expansion trimester and a retreat one. We can use this information to adjust our life plan accordingly. In the expansion trimester we could invest more energies in the planning, and in the retreat ones we can do more throughout reviews.

    Listen to your desires

    The trimester review requires an analysis that doesn't fill in a day session. It requires slow thinking over some time. So I'm creating a task 10 days before the actual review to start thinking about the next trimester. Whether it's ideas, plans, desires, objectives, values, or principles.

    Is useful for that document to be available wherever you go, so that in any spare time you can pop it up and continue with the train of thought.

    Doing the reflection without seeing your life path prevents you from being tainted by it, thus representing the real you of right now.

    On the day to actually do the review, follow the steps of the Month review prepare adjusting them to the trimester case.

    Answer some meaningful guided questions

    To be done, until then you can read chapters 13, 14 and the epilogue of the book Four thousand weeks by Oliver Burkman.

    Refactor your gathered thoughts

    If you've followed the prepare steps, you've already been making up your mind on what do you want the next trimester to look like. Now it's the time to refine those thoughts.

    In your roadmap document add a new section for the incoming trimester similar to:

    * Roadmap
    ** 2024
    *** Summer 2024
    **** Essential intent
    **** Trimester analysis
    **** Trimester objectives
    ***** TODO Objective 1
    ****** TODO SubObjective 1
    
    Go one by one (don't peek!) of your gathered items and translate them in the next sections:

    • Trimester analysis: A text with as many paragraphs as you need to order your thoughts
    • Trimester objectives: These can be concrete emotional projects you want to carry through.
    • Essential intent: This is the main headline of your trimester, probably you won't be able to define it until the last parts of the review process. It should be concrete and emotional too, it's going to be the idea that gives you strength on your weak moments and your guide to decide which projects to do and which not to.

    Don't be too concerned on the format of the content of the objectives, this is the first draft, and we'll refine it through the planning.

Content Management

Jellyfin

Mediatracker

  • New: Add missing books.

    • Register an account in openlibrary.com
    • Add the book
    • Then add it to mediatracker

Knowledge Management

Aleph

  • New: Debug ingestion errors.

    Assuming that you've set up Loki to ingest your logs I've so far encountered the next ingest issues:

    • Cannot open image data using Pillow: broken data stream when reading image files: The log trace that has this message also contains a field trace_id which identifies the ingestion process. With that trace_id you can get the first log trace with the field logger = "ingestors.manager" which will contain the file path in the message field. Something similar to Ingestor [<E('9972oiwobhwefoiwefjsldkfwefa45cf5cb585dc4f1471','path_to_the_file_to_ingest.pdf')>]
    • A traceback with the next string Failed to process: Could not extract PDF file: FileDataError('cannot open broken document'): This log trace has the file path in the message field. Something similar to [<E('9972oiwobhwefoiwefjsldkfwefa45cf5cb585dc4f1471','path_to_the_file_to_ingest.pdf')>] Failed to process: Could not extract PDF file: FileDataError('cannot open broken document')

    I thought of making a python script to automate the files that triggered an error, but in the end I extracted the file names manually as they weren't many.

    Once you have the files that triggered the errors, the best way to handle them is to delete them from your investigation and ingest them again.

  • New: Add support channel.

    Support chat

Torrent management

qBittorrent

Health

Teeth

  • New: Suggestion on how to choose the toothpaste to buy.

    When choosing a toothpaste choose the one that has a higher percent of fluoride.

Coding

Languages

Bash snippets

  • New: Fix docker error: KeyError ContainerConfig.

    You need to run docker-compose down and then up again.

  • New: Set static ip with nmcli.

    nmcli con mod "your-ssid" ipv4.addresses
      ipv4.method "manual" \
      ipv4.addresses "your_desired_ip" \
      ipv4.gateway "your_desired_gateway" \
      ipv4.dns "1.1.1.1,2.2.2.2" \
      ipv4.routes "192.168.32.0 0.0.0.0" \
    

    The last one is to be able to connect to your LAN, change the value accordingly.

  • New: Fix unbound variable error.

    You can check if the variable is set and non-empty with:

    [ -n "${myvariable-}" ]
    

  • New: Compare two semantic versions with sort.

    If you want to make it work in non-Debian based systems you can use sort -V -C

    printf "2.0.0\n2.1.0\n" | sort -V -C  # Return code 0
    printf "2.2.0\n2.1.0\n" | sort -V -C  # Return code 1
    

Graphql

  • New: Introduce GraphQL.

    GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

    To use it with python you can use Ariadne (source)

Python Snippets

  • New: Compare file and directories.

    The filecmp module defines functions to compare files and directories, with various optional time/correctness trade-offs. For comparing files, see also the difflib module.

    from filecmp import dircmp
    
    def print_diff_files(dcmp):
        for name in dcmp.diff_files:
            print("diff_file %s found in %s and %s" % (name, dcmp.left, dcmp.right))
        for sub_dcmp in dcmp.subdirs.values():
            print_diff_files(sub_dcmp)
    dcmp = dircmp('dir1', 'dir2')
    print_diff_files(dcmp)
    

Coding tools

Singer

  • New: Introduce singer.

    Singer is an open-source standard for writing scripts that move data.

    It describes how data extraction scripts—called “taps” —and data loading scripts—called “targets”— should communicate, allowing them to be used in any combination to move data from any source to any destination. Send data between databases, web APIs, files, queues, and just about anything else you can think of.

    It has many "taps" and "targets" that can help you interact with third party tools without needing to write the code.

    References - Home

  • New: is not well mapped.

    It's because <c-i> is a synonym of <TAB>.

Coding with AI

  • New: Introduce ai coding prompts.

    These are some useful AI prompts to help you while you code:

    • create a function with type hints and docstring using google style called { } that { }
    • create the tests for the function { } adding type hints and following the AAA style where the Act section is represented contains a returns = (thing to test) line or if the function to test doesn't return any value append an # act comment at the end of the line. Use paragraphs to separate the AAA blocks and don't add comments inside the tests for the sections

    If you use espanso you can simplify the filling up of these prompts on the AI chats. For example:

    ---
    matches:
      - trigger: :function
        form: |
          Create a function with type hints and docstring using google style called [[name]] that:
          [[text]]
        form_fields:
          text:
            multiline: true
      - trigger: :tweak
        form: |
          Tweak the next code:
          [[code]]
    
          So that:
    
          [[text]]
        form_fields:
          text:
            multiline: true
          code:
            multiline: true
      - trigger: :test
        form: |
          create the tests for the function:
          [[text]]
    
          Following the next guidelines:
    
          - Add type hints
          - Follow the AAA style
          - In the Act section if the function to test returns a value always name that variable returns. If the function to test doesn't return any value append an # act comment at the end of the line.
          - Use paragraphs to separate the AAA blocks and don't add comments like # Arrange or # Act or # Act/Assert or # Assert
    
        form_fields:
          text:
            multiline: true
      - trigger: :refactor
        form: |
         Refactor the next code
         [[code]]
         with the next conditions
         [[conditions]]
        form_fields:
          code:
            multiline: true
          conditions:
            multiline: true
    
  • New: Introduce Kestra.

    Kestra is an open-source orchestrator designed to bring Infrastructure as Code (IaC) best practices to all workflows — from those orchestrating mission-critical operations, business processes, and data pipelines to simple Zapier-style automation. Built with an API-first philosophy, Kestra enables users to define and manage data pipelines through a simple YAML configuration file. This approach frees you from being tied to a specific client implementation, allowing for greater flexibility and easier integration with various tools and services.

    Look at this 4 minute video for a visual introduction

    References - Docs - Home - 4 minute introduction video

memorious

  • New: Introduce memorious.

    Memorious is a light-weight web scraping toolkit. It supports scrapers that collect structured or un-structured data. This includes the following use cases:

    • Make crawlers modular and simple tasks re-usable
    • Provide utility functions to do common tasks such as data storage, HTTP session management
    • Integrate crawlers with the Aleph and FollowTheMoney ecosystem

    References

Data orchestrators

  • New: Introduce data orchestrators.

    Data orchestration is the process of moving siloed data from multiple storage locations into a centralized repository where it can then be combined, cleaned, and enriched for activation.

    Data orchestrators are web applications that make this process easy. The most popular right now are:

    • Apache Airflow
    • Kestra
    • Prefect

    There are several comparison pages:

    When looking at the return on investment when choosing an orchestration tool, there are several points to consider:

    • Time of installation/maintenance
    • Time to write pipeline
    • Time to execute (performance)

    Kestra

    Pros:

    Cons:

    Kestra offers a higher ROI globally compared to Airflow:

    • Installing Kestra is easier than Airflow; it doesn’t require Python dependencies, and it comes with a ready-to-use docker-compose file using few services and without the need to understand what’s an executor to run task in parallel.
    • Creating pipelines with Kestra is simple, thanks to its syntax. You don’t need knowledge of a specific programming language because Kestra is designed to be agnostic. The declarative YAML design makes Kestra flows more readable compared to Airflow’s DAG equivalent, allowing developers to significantly reduce development time.
    • In this benchmark, Kestra demonstrates better execution time than Airflow under any configuration setup.

Scrapers

  • New: Introduce morph.io.

    morph.io is a web service that runs your scrapers for you.

    Write your scraper in the language you know and love, push your code to GitHub, and they take care of the boring bits. Things like running your scraper regularly, alerting you if there's a problem, storing your data, and making your data available for download or through a super-simple API.

    To sign in you'll need a GitHub account. This is where your scraper code is stored.

    The data is stored in an sqlite

    Usage limits

    Right now there are very few limits. They are trusting you that you won't abuse this.

    However, they do impose a couple of hard limits on running scrapers so they don't take up too many resources

    • max 512 MB memory
    • max 24 hours run time for a single run

    If a scraper runs out of memory or runs too long it will get killed automatically.

    There's also a soft limit:

    • max 10,000 lines of log output

    If a scraper generates more than 10,000 lines of log output the scraper will continue running uninterrupted. You just won't see any more output than that. To avoid this happening simply print less stuff to the screen.

    Note that they are keeping track of the amount of cpu time (and a whole bunch of other metrics) that you and your scrapers are using. So, if they do find that you are using too much they reserve the right to kick you out. In reality first they'll ask you nicely to stop.

    References

Espanso

  • New: Introduce espanso.

    Espanso is a cross-platform Text Expander written in Rust.

    A text expander is a program that detects when you type a specific keyword and replaces it with something else. This is useful in many ways:

    • Save a lot of typing, expanding common sentences or fixing common typos.
    • Create system-wide code snippets.
    • Execute custom scripts
    • Use emojis like a pro.

    Installation Espanso ships with a .deb package, making the installation convenient on Debian-based systems.

    Start by downloading the package by running the following command inside a terminal:

    wget https://github.com/federico-terzi/espanso/releases/download/v2.2.1/espanso-debian-x11-amd64.deb
    

    You can now install the package using:

    sudo apt install ./espanso-debian-x11-amd64.deb
    

    From now on, you should have the espanso command available in the terminal (you can verify by running espanso --version).

    At this point, you are ready to use espanso by registering it first as a Systemd service and then starting it with:

    espanso service register
    

    Start espanso

    espanso start
    

    Espanso ships with very few built-in matches to give you the maximum flexibility, but you can expand its capabilities in two ways: creating your own custom matches or installing packages.

    Configuration

    Your configuration lives at ~/.config/espanso. A quick way to find the path of your configuration folder is by using the following command espanso path.

    • The files contained in the match directory define what Espanso should do. In other words, this is where you should specify all the custom snippets and actions (aka Matches). The match/base.yml file is where you might want to start adding your matches.
    • The files contained in the config directory define how Espanso should perform its expansions. In other words, this is were you should specify all Espanso's parameters and options. The config/default.yml file defines the options that will be applied to all applications by default, unless an app-specific configuration is present for the current app.

    Using packages

    Custom matches are great, but sometimes it can be tedious to define them for every common operation, especially when you want to share them with other people.

    Espanso offers an easy way to share and reuse matches with other people, packages. In fact, they are so important that Espanso includes a built-in package manager and a store, the Espanso Hub.

    Installing a package

    Get the id of the package from the Espanso Hub and then run espanso install <<package_name>>.

    Of all the packages, I've found the next ones the most useful:

    Overwriting the snippets of a package

    For example the typofixer-en replaces si to is, although si is a valid spanish word. To override the fix you can create your own file on ~/.config/espanso/match/typofix_overwrite.yml with the next content:

    matches:
      # Simple text replacement
      - trigger: "si"
        replace: "si"
    

    Creating a package

    Auto-restart on config changes

    Set auto_restart: true on ~/.config/espanso/config/default.yml.

    Changing the search bar shortcut

    If the default search bar shortcut conflicts with your i3 configuration set it with:

    search_shortcut: CTRL+SHIFT+e
    

    Hiding the notifications

    You can hide the notifications by adding the following option to your $CONFIG/config/default.yml config:

    show_notifications: false
    

    Usage

    Just type and you'll see the text expanded.

    You can use the search bar if you don't remember your snippets.

    References - Code - Docs

Generic Coding Practices

Conventional comments

  • New: Introduce conventional comments.

    Conventional comments is the practice to use a specific format in the review comments to express your intent and tone more clearly. It's strongly inspired by semantic versioning.

    Let's take the next comment:

    This is not worded correctly.
    

    Adding labels you can tell the difference on your intent:

    **suggestion:** This is not worded correctly.
    
    Or
    **issue (non-blocking):** This is not worded correctly.
    

    Labels also prompt the reviewer to give more actionable comments.

    **suggestion:** This is not worded correctly.
    
    Can we change this to match the wording of the marketing page?
    

    Labeling comments encourages collaboration and saves hours of undercommunication and misunderstandings. They are also parseable by machines!

    Format

    Adhering to a consistent format improves reader's expectations and machine readability. Here's the format we propose:

    <label> [decorations]: <subject>
    
    [discussion]
    
    - label - This is a single label that signifies what kind of comment is being left. - subject - This is the main message of the comment. - decorations (optional) - These are extra decorating labels for the comment. They are surrounded by parentheses and comma-separated. - discussion (optional) - This contains supporting statements, context, reasoning, and anything else to help communicate the "why" and "next steps" for resolving the comment. For example:
    **question (non-blocking):** At this point, does it matter which thread has won?
    
    Maybe to prevent a race condition we should keep looping until they've all won?
    

    Can be automatically parsed into:

    {
      "label": "question",
      "subject": "At this point, does it matter which thread has won?",
      "decorations": ["non-blocking"],
      "discussion": "Maybe to prevent a race condition we should keep looping until they've all won?"
    }
    
    Labels

    We strongly suggest using the following labels: | | | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | praise: | Praises highlight something positive. Try to leave at least one of these comments per review. Do not leave false praise (which can actually be damaging). Do look for something to sincerely praise. | | quibble: | Quibbles are trivial preference-based requests. These should be non-blocking by nature. Similar to polish but clearly preference-based.| | suggestion: | Suggestions propose improvements to the current subject. It's important to be explicit and clear on what is being suggested and why it is an improvement. These are non-blocking proposals. If it's blocking use todo instead.| | todo: | TODO's are necessary changes. Distinguishing todo comments from issues or suggestions helps direct the reader's attention to comments requiring more involvement. | | issue: | Issues highlight specific problems with the subject under review. These problems can be user-facing or behind the scenes. It is strongly recommended to pair this comment with a suggestion. If you are not sure if a problem exists or not, consider leaving a question. | | question: | Questions are appropriate if you have a potential concern but are not quite sure if it's relevant or not. Asking the author for clarification or investigation can lead to a quick resolution. | | thought: | Thoughts represent an idea that popped up from reviewing. These comments are non-blocking by nature, but they are extremely valuable and can lead to more focused initiatives and mentoring opportunities. | | chore: | Chores are simple tasks that must be done before the subject can be "officially" accepted. Usually, these comments reference some common process. Try to leave a link to the process description so that the reader knows how to resolve the chore. | | note: | Notes are always non-blocking and simply highlight something the reader should take note of. |

    If you like to be a bit more expressive with your labels, you may also consider:

    typo: Typo comments are like todo:, where the main issue is a misspelling.
    polish: Polish comments are like a suggestion, where there is nothing necessarily wrong with the relevant content, there's just some ways to immediately improve the quality. Similar but not exactly the same as quibble.

    Decorations

    Decorations give additional context for a comment. They help further classify comments which have the same label (for example, a security suggestion as opposed to a test suggestion).

    **suggestion (security):** I'm a bit concerned that we are implementing our own DOM purifying function here...
    Could we consider using the framework instead?
    
    **suggestion (test,if-minor):** It looks like we're missing some unit test coverage that the cat disappears completely.
    

    Decorations may be specific to each organization. If needed, we recommend establishing a minimal set of decorations (leaving room for discretion) with no ambiguity. Possible decorations include: | | | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | (non-blocking) | A comment with this decoration should not prevent the subject under review from being accepted. This is helpful for organizations that consider comments blocking by default. | | (blocking) | A comment with this decoration should prevent the subject under review from being accepted, until it is resolved. This is helpful for organizations that consider comments non-blocking by default. | | (if-minor) | This decoration gives some freedom to the author that they should resolve the comment only if the changes ends up being minor or trivial. |

    Adding a decoration to a comment should improve understandability and maintain readability. Having a list of many decorations in one comment would conflict with this goal.

    More examples

    **quibble:** `little star` => `little bat`
    
    Can we update the other references as well?
    
    **chore:** Let's run the `jabber-walk` CI job to make sure this doesn't break any known references.
    Here are [the docs](https://en.wikipedia.org/wiki/Jabberwocky) for running this job. Feel free to reach out if you need any help!
    
    **praise:** Beautiful test!
    

    Best Practices

    Some best practices for writing helpful review feedback:

    • Mentoring pays off exponentially
    • Leave actionable comments
    • Combine similar comments
    • Replace "you" with "we"
    • Replace "should" with "could"

    References - Home

DevOps

Infrastructure as Code

Ansible Snippets

Infrastructure Solutions

Kubernetes

  • New: Add reloader to tools to test.

    stakater/reloader: A Kubernetes controller to watch changes in ConfigMap and Secrets and do rolling upgrades on Pods with their associated Deployment, StatefulSet, DaemonSet and DeploymentConfig. Useful for not that clever applications that need a reboot when a configmap changes.

Kubectl Commands

Volumes

  • New: Specify a path of a configmap.

    If you have a configmap with a key ssh-known-hosts and you want to mount it's content in a file, in the deployment volumeMounts section you can use the subPath field:

          - mountPath: /home/argocd/.ssh/known_hosts
            name: ssh-known-hosts
            subPath: ssh_known_hosts
            readOnly: true
    
  • New: List the size of the recovery points.

    BACKUP_VAULT_NAME="your-vault-name"
    
    RECOVERY_POINTS=$(aws backup list-recovery-points-by-backup-vault --backup-vault-name $BACKUP_VAULT_NAME --query 'RecoveryPoints[*].[RecoveryPointArn,BackupSizeInBytes,CreationDate]' --output text)
    echo -e "Creation Date\t\tRecovery Point ARN\t\t\t\t\t\t\t\t\tSize (TB)"
    echo "---------------------------------------------------------------------------------------------------------------------"
    
    while read -r RECOVERY_POINT_ARN BACKUP_SIZE_BYTES CREATION_DATE; do
        # Remove the decimal part from the epoch time
        EPOCH_TIME=$(echo $CREATION_DATE | cut -d'.' -f1)
        # Convert the creation date from epoch time to YYYY-MM-DD format
        FORMATTED_DATE=$(date -d @$EPOCH_TIME +"%Y-%m-%d")
        SIZE_TB=$(echo "scale=6; $BACKUP_SIZE_BYTES / (1024^4)" | bc)
        # echo -e "$FORMATTED_DATE\t$RECOVERY_POINT_ARN\t$SIZE_TB"
        printf "%-16s %-80s %10.6f\n" "$FORMATTED_DATE" "$RECOVERY_POINT_ARN" "$SIZE_TB"
    done <<< "$RECOVERY_POINTS"
    
  • New: List the size of the jobs.

    To list AWS Backup jobs and display their completion dates and sizes in a human-readable format, you can use the following AWS CLI command combined with jq for parsing and formatting the output. This command handles cases where the backup size might be null and rounds the size to the nearest whole number in gigabytes.

    aws backup list-backup-jobs --output json | jq -r '
      .BackupJobs[] |
      [
        (.CompletionDate | strftime("%Y-%m-%d %H:%M:%S")),
        (if .BackupSizeInBytes == null then "0GB" else ((.BackupSizeInBytes / 1024 / 1024 / 1024) | floor | tostring + " GB") end)
      ] |
      @tsv' | column -t -s$'\t'
    
    Explanation:

    • aws backup list-backup-jobs --output json: Lists all AWS Backup jobs in JSON format.
    • .BackupJobs[]: Iterates over each backup job.
    • (.CompletionDate | strftime("%Y-%m-%d %H:%M:%S")): Converts the Unix timestamp in CompletionDate to a human-readable date format (YYYY-MM-DD HH:MM:SS).
    • (if .BackupSizeInBytes == null then "0GB" else ((.BackupSizeInBytes / 1024 / 1024 / 1024) | floor | tostring + " GB") end): Checks if BackupSizeInBytes is null. If it is, outputs "0GB". Otherwise, converts the size from bytes to gigabytes, rounds it down to the nearest whole number, and appends " GB".
    • | @tsv: Formats the output as tab-separated values.
    • column -t -s$'\t': Formats the TSV output into a table with columns aligned.

Continuous Integration

ArgoCD

Security Checkers

  • New: Introduce pip-audit.

    pip-audit is the official pypa tool for scanning Python environments for packages with known vulnerabilities. It uses the Python Packaging Advisory Database (https://github.com/pypa/advisory-database) via the PyPI JSON API as a source of vulnerability reports.

    Installation

    pip install pip-audit
    

    Usage

    pip-audit
    
    On completion, pip-audit will exit with a code indicating its status.

    The current codes are:

    • 0: No known vulnerabilities were detected.
    • 1: One or more known vulnerabilities were found.

    pip-audit's exit code cannot be suppressed. See Suppressing exit codes from pip-audit for supported alternatives.

    References

Storage

OpenZFS

  • New: Manually create a backup.

    To create a snapshot of tank/home/ahrens that is named friday run:

    zfs snapshot tank/home/ahrens@friday
    
  • New: Tweak loki alerts.

          - alert: SyncoidCorruptedSnapshotSendError
            expr: |
              count_over_time({syslog_identifier="syncoid_send_backups"} |= `cannot receive incremental stream: invalid backup stream` [15m]) > 0
            for: 0m
            labels:
              severity: critical
            annotations:
              summary: "Error trying to send a corrupted snapshot at {{ $labels.hostname}}"
              message: "Look at the context on loki to identify the snapshot in question. Delete it and then run the sync again"
          - alert: SanoidNotRunningError
            expr: |
              sum by (hostname) (count_over_time({job="systemd-journal", syslog_identifier="sanoid"}[1h])) or sum by (hostname) (count_over_time({job="systemd-journal"}[1h]) * 0)
            for: 0m
            labels:
                severity: critical
            annotations:
                summary: "Sanoid has not shown signs to be alive for the last hour at least in arva and helm"
          - alert: SlowSpaSyncZFSError
            expr: |
              count_over_time({job="zfs"} |~ `spa_deadman.*slow spa_sync` [10m]) > 0
            for: 0m
            labels:
              severity: critical
            annotations:
              summary: "Slow sync traces found in the ZFS debug logs at {{ $labels.hostname}}"
              message: "This usually happens before the ZFS becomes unresponsible"
    

    The SanoidNotRunningError alert uses a broader search that ensures that all hosts are included and multiplies it to 0 to raise the alert if none is shown for the sanoid service.

ZFS Prometheus exporter

  • Correction: Tweak the ZfsPoolUnhealthy alert.

       - alert: ZfsPoolUnhealthy
         expr: last_over_time(zfs_pool_health[1h]) > 0
         for: 5m
         labels:
           severity: critical
    

Monitoring

Loki

  • Correction: Don't use vector(0) on aggregation over labels.

    If you're doing an aggregation over a label this approach won't work because it will add a new time series with value 0. In those cases use a broader search that includes other logs from the label you're trying to aggregate and multiply it by 0. For example:

    (
    sum by (hostname) (
      count_over_time({job="systemd-journal", syslog_identifier="sanoid"}[1h])
    )
    or
    sum by (hostname) (
      count_over_time({job="systemd-journal"}[1h]) * 0
    )
    ) < 1
    

    The first part of the query returns all log lines of the service sanoid for each hostname. If one hostname were not to return any line that query alone won't show anything for that host. The second part of the query counts all the log lines of each hostname, so if it's up it will probably be sending at least one line per hour. As we're not interested in those number of lines we multiply it by 0, so that the target is shown.

  • New: Interact with loki through python.

    There is no client library for python (1, 2) they suggest to interact with the API with requests. Although I'd rather use logcli with the sh library.

  • New: Download the logs.

    The web UI only allows you to download the logs that are loaded in the view, if you want to download big amounts of logs you need to either use logcli or interact with the API.

    One user did a query on loop:

    set -x
    
    JOB_ID=9079dc54-2f5c-4d74-a9aa-1d9eb39dd3c2
    
    for I in `seq 0 655`; do
        FILE=logs_$I.txt
        ID="$JOB_ID:$I"
        QUERY="{aws_job_id=\"$ID\",job=\"varlogs\"}"
        docker run grafana/logcli:main-1b6d0bf-amd64 --addr=http://localhost:3100/ -o raw -q query $QUERY --limit 100000 --batch 100 --forward --from "2022-09-25T10:00:00Z" > $FILE
    done
    

Logcli

  • New: Introduce logcli.

    logcli is the command-line interface to Grafana Loki. It facilitates running LogQL queries against a Loki instance.

    Installation Download the logcli binary from the Loki releases page and install it somewhere in your $PATH.

    Usage logcli points to the local instance http://localhost:3100 directly, if you want another one export the LOKI_ADDR environment variable.

    Run a query:

    logcli query '{job="loki-ops/consul"}'
    

    You can also set the time range and output format

    logcli query \
         --timezone=UTC  \
         --from="2024-06-10T07:23:36Z" \
         --to="2024-06-12T16:23:58Z" \
         --output=jsonl \
         '{job="docker", container="aleph_ingest-file_1"} | json | __error__=`` | severity =~ `WARNING|ERROR` | message !~ `Queueing failed task for retry.*` | logger!=`ingestors.manager`'
    

    References

Grafana

Hardware

GPU

  • New: Install cuda.

    CUDA is a parallel computing platform and programming model invented by NVIDIA®. It enables dramatic increases in computing performance by harnessing the power of the graphics processing unit (GPU). If you're not using Debian 11 follow these instructions

    Base Installer

    wget https://developer.download.nvidia.com/compute/cuda/12.5.1/local_installers/cuda-repo-debian11-12-5-local_12.5.1-555.42.06-1_amd64.deb
    sudo dpkg -i cuda-repo-debian11-12-5-local_12.5.1-555.42.06-1_amd64.deb
    sudo cp /var/cuda-repo-debian11-12-5-local/cuda-*-keyring.gpg /usr/share/keyrings/
    sudo add-apt-repository contrib
    sudo apt-get update
    sudo apt-get -y install cuda-toolkit-12-5
    

    Additional installation options are detailed here.

    Driver Installer

    To install the open kernel module flavor:

    sudo apt-get install -y nvidia-kernel-open-dkms
    sudo apt-get install -y cuda-drivers
    

    Install cuda:

    apt-get install cuda
    reboot
    

    Install nvidia card

    Check if your card is supported in the releases supported by your OS - If it's supported - If it's not supported

    Ensure the GPUs are Installed

    Install pciutils:

    Ensure that the lspci command is installed (which lists the PCI devices connected to the server):

    sudo apt-get -y install pciutils
    

    Check Installed Nvidia Cards: Perform a quick check to determine what Nvidia cards have been installed:

    lspci | grep VGA
    

    The output of the lspci command above should be something similar to:

    00:02.0 VGA compatible controller: Intel Corporation 4th Gen ...
    01:00.0 VGA compatible controller: Nvidia Corporation ...
    

    If you do not see a line that includes Nvidia, then the GPU is not properly installed. Otherwise, you should see the make and model of the GPU devices that are installed.

    Disable Nouveau

    Blacklist Nouveau in Modprobe: The nouveau driver is an alternative to the Nvidia drivers generally installed on the server. It does not work with CUDA and must be disabled. The first step is to edit the file at /etc/modprobe.d/blacklist-nouveau.conf.

    Create the file with the following content:

    cat <<EOF | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
    blacklist nouveau
    blacklist lbm-nouveau
    options nouveau modeset=0
    alias nouveau off
    alias lbm-nouveau off
    EOF
    

    Then, run the following commands:

    echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
    sudo update-initramfs -u
    

    Update Grub to Blacklist Nouveau:

    Backup your grub config template:

    sudo cp /etc/default/grub /etc/default/grub.bak
    

    Then, update your grub config template at /etc/default/grub. Add rd.driver.blacklist=nouveau and rcutree.rcu_idle_gp_delay=1 to the GRUB_CMDLINE_LINUX variable. For example, change:

    GRUB_CMDLINE_LINUX="quiet"
    

    to:

    GRUB_CMDLINE_LINUX="quiet rd.driver.blacklist=nouveau rcutree.rcu_idle_gp_delay=1"
    

    Then, rebuild your grub config:

    sudo grub2-mkconfig -o /boot/grub/grub.cfg
    

    Install prerequisites

    The following prerequisites should be installed before installing the Nvidia drivers:

    sudo apt-get -y install linux-headers-$(uname -r) make gcc-4.8
    sudo apt-get -y install acpid dkms
    

    Close X Server:

    Before running the install, you should exit out of any X environment, such as Gnome, KDE, or XFCE. To exit the X session, switch to a TTY console using Ctrl-Alt-F1 and then determine whether you are running lightdm or gdm by running:

    sudo ps aux | grep "lightdm|gdm|kdm"
    

    Depending on which is running, stop the service, running the following commands (substitute gdm or kdm for lightdm as appropriate):

    sudo service lightdm stop
    sudo init 3
    

    Install Drivers Only:

    To accommodate GL-accelerated rendering, OpenGL and GL Vendor Neutral Dispatch (GLVND) are now required and should be installed with the Nvidia drivers. OpenGL is an installation option in the *.run type of drivers. In other types of the drivers, OpenGL is enabled by default in most modern versions (dated 2016 and later). GLVND can be installed using the installer menus or via the --glvnd-glx-client command line flag.

    This section deals with installing the drivers via the *.run executables provided by Nvidia.

    To download only the drivers, navigate to http://www.nvidia.com/object/unix.html and click the Latest Long Lived Branch version under the appropriate CPU architecture. On the ensuing page, click Download and then click Agree and Download on the page that follows.

    The Unix drivers found in the link above are also compatible with all Nvidia Tesla models.

    If you'd prefer to download the full driver repository, Nvidia provides a tool to recommend the most recent available driver for your graphics card at http://www.Nvidia.com/Download/index.aspx?lang=en-us.

    If you are unsure which Nvidia devices are installed, the lspci command should give you that information:

    lspci | grep -i "nvidia"
    

    Download the recommended driver executable. Change the file permissions to allow execution:

    chmod +x ./NVIDIA-Linux-$(uname -m)-*.run
    

    Run the install.

    To check that the GPU is well installed and functioning properly, you can use the nvidia-smi command. This command provides detailed information about the installed Nvidia GPUs, including their status, utilization, and driver version.

    First, ensure the Nvidia drivers are installed. Then, run:

    nvidia-smi
    

    If the GPU is properly installed, you should see an output that includes information about the GPU, such as its model, memory usage, and driver version. The output will look something like this:

    +-----------------------------------------------------------------------------+
    | NVIDIA-SMI 450.66       Driver Version: 450.66       CUDA Version: 11.0     |
    |-------------------------------+----------------------+----------------------+
    | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
    | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
    |                               |                      |               MIG M. |
    |===============================+======================+======================|
    |   0  Tesla K80           Off  | 00000000:00:1E.0 Off |                    0 |
    | N/A   38C    P8    29W / 149W |      0MiB / 11441MiB |      0%      Default |
    |                               |                      |                  N/A |
    +-------------------------------+----------------------+----------------------+
    
    +-----------------------------------------------------------------------------+
    | Processes:                                                                  |
    |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
    |        ID   ID                                                   Usage      |
    |=============================================================================|
    |  No running processes found                                                 |
    +-----------------------------------------------------------------------------+
    

    If you encounter any errors or the GPU is not listed, there may be an issue with the installation or configuration of the GPU drivers.

    Measure usage

    For Nvidia GPUs there is a tool nvidia-smi that can show memory usage, GPU utilization and temperature of GPU.

    Load test the gpu

    First make sure you have CUDA installed, then install the gpu_burn tool

    git clone https://github.com/wilicc/gpu-burn
    cd gpu-burn
    make
    

    To run a test for 60 seconds run:

    ./gpu_burn 60
    

    Monitor it with Prometheus

    NVIDIA DCGM is a set of tools for managing and monitoring NVIDIA GPUs in large-scale, Linux-based cluster environments. It’s a low overhead tool that can perform a variety of functions including active health monitoring, diagnostics, system validation, policies, power and clock management, group configuration, and accounting. For more information, see the DCGM User Guide.

    You can use DCGM to expose GPU metrics to Prometheus using dcgm-exporter.

    • Install NVIDIA Container Kit: The NVIDIA Container Toolkit allows users to build and run GPU accelerated containers. The toolkit includes a container runtime library and utilities to automatically configure containers to leverage NVIDIA GPUs.
    sudo apt-get install -y nvidia-container-toolkit
    
    • Configure the container runtime by using the nvidia-ctk command:

    sudo nvidia-ctk runtime configure --runtime=docker
    
    - Restart the Docker daemon:

    sudo systemctl restart docker
    

    Determine the distribution name:

    distribution=$(. /etc/os-release;echo $ID$VERSION_ID | sed -e 's/\.//g')
    

    Download the meta-package to set up the CUDA network repository:

    wget https://developer.download.nvidia.com/compute/cuda/repos/$distribution/x86_64/cuda-keyring_1.1-1_all.deb
    

    Install the repository meta-data and the CUDA GPG key:

    sudo dpkg -i cuda-keyring_1.1-1_all.deb
    

    Update the Apt repository cache:

    sudo apt-get update
    

    Now, install DCGM:

    sudo apt-get install -y datacenter-gpu-manager
    

    Enable the DCGM systemd service (on reboot) and start it now:

    sudo systemctl --now enable nvidia-dcgm
    

    You should see output similar to this:

    ● dcgm.service - DCGM service
      Loaded: loaded (/usr/lib/systemd/system/dcgm.service; disabled; vendor preset: enabled)
      Active: active (running) since Mon 2020-10-12 12:18:57 PDT; 14s ago
    Main PID: 32847 (nv-hostengine)
        Tasks: 7 (limit: 39321)
      CGroup: /system.slice/dcgm.service
              └─32847 /usr/bin/nv-hostengine -n
    
    Oct 12 12:18:57 ubuntu1804 systemd[1]: Started DCGM service.
    Oct 12 12:18:58 ubuntu1804 nv-hostengine[32847]: DCGM initialized
    Oct 12 12:18:58 ubuntu1804 nv-hostengine[32847]: Host Engine Listener Started
    

    To verify installation, use dcgmi to query the system. You should see a listing of all supported GPUs (and any NVSwitches) found in the system:

    dcgmi discovery -l
    

    Output:

    8 GPUs found.
    +--------+----------------------------------------------------------------------+
    | GPU ID | Device Information                                                   |
    +--------+----------------------------------------------------------------------+
    | 0      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:07:00.0                                         |
    |        | Device UUID: GPU-1d82f4df-3cf9-150d-088b-52f18f8654e1                |
    +--------+----------------------------------------------------------------------+
    | 1      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:0F:00.0                                         |
    |        | Device UUID: GPU-94168100-c5d5-1c05-9005-26953dd598e7                |
    +--------+----------------------------------------------------------------------+
    | 2      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:47:00.0                                         |
    |        | Device UUID: GPU-9387e4b3-3640-0064-6b80-5ace1ee535f6                |
    +--------+----------------------------------------------------------------------+
    | 3      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:4E:00.0                                         |
    |        | Device UUID: GPU-cefd0e59-c486-c12f-418c-84ccd7a12bb2                |
    +--------+----------------------------------------------------------------------+
    | 4      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:87:00.0                                         |
    |        | Device UUID: GPU-1501b26d-f3e4-8501-421d-5a444b17eda8                |
    +--------+----------------------------------------------------------------------+
    | 5      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:90:00.0                                         |
    |        | Device UUID: GPU-f4180a63-1978-6c56-9903-ca5aac8af020                |
    +--------+----------------------------------------------------------------------+
    | 6      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:B7:00.0                                         |
    |        | Device UUID: GPU-8b354e3e-0145-6cfc-aec6-db2c28dae134                |
    +--------+----------------------------------------------------------------------+
    | 7      | Name: A100-SXM4-40GB                                                 |
    |        | PCI Bus ID: 00000000:BD:00.0                                         |
    |        | Device UUID: GPU-a16e3b98-8be2-6a0c-7fac-9cb024dbc2df                |
    +--------+----------------------------------------------------------------------+
    6 NvSwitches found.
    +-----------+
    | Switch ID |
    +-----------+
    | 11        |
    | 10        |
    | 13        |
    | 9         |
    | 12        |
    | 8         |
    +-----------+
    

    Install the dcgm-exporter

    As it doesn't need any persistence I've added it to the prometheus docker compose:

      dcgm-exporter:
        # latest didn't work
        image: nvcr.io/nvidia/k8s/dcgm-exporter:3.3.6-3.4.2-ubuntu22.04
        deploy:
          resources:
            reservations:
              devices:
                - capabilities: [gpu]
        restart: unless-stopped
        container_name: dcgm-exporter
    

    And added the next scraping config in prometheus.yml

      - job_name: dcgm-exporter
        metrics_path: /metrics
        static_configs:
        - targets:
          - dcgm-exporter:9400
    

    Adding alerts

    Tweak the next alerts for your use case.

    ---
    groups:
    - name: dcgm-alerts
      rules:
      - alert: GPUHighTemperature
        expr: DCGM_FI_DEV_GPU_TEMP > 80
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "GPU High Temperature (instance {{ $labels.instance }})"
          description: "The GPU temperature is above 80°C for more than 5 minutes.\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    
      - alert: GPUMemoryUtilizationHigh
        expr: DCGM_FI_DEV_MEM_COPY_UTIL > 90
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "GPU Memory Utilization High (instance {{ $labels.instance }})"
          description: "The GPU memory utilization is above 90% for more than 10 minutes.\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    
      - alert: GPUComputeUtilizationHigh
        expr: DCGM_FI_DEV_GPU_UTIL > 90
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "GPU Compute Utilization High (instance {{ $labels.instance }})"
          description: "The GPU compute utilization is above 90% for more than 10 minutes.\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    
      - alert: GPUPowerUsageHigh
        expr: DCGM_FI_DEV_POWER_USAGE > 160
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "GPU Power Usage High (instance {{ $labels.instance }})"
          description: "The GPU power usage is above 160W for more than 5 minutes.\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
    
      - alert: GPUUnavailable
        expr: up{job="dcgm-exporter"} == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "GPU Unavailable (instance {{ $labels.instance }})"
          description: "The DCGM Exporter instance is down or unreachable for more than 5 minutes.\n  LABELS: {{ $labels }}"
    

    Adding a dashboard

    I've tweaked this dashboard to simplify it. Check the article for the full json

Operating Systems

Linux

Alacritty

  • New: Introduce Alacritty.

    Alacritty is a modern terminal emulator that comes with sensible defaults, but allows for extensive configuration. By integrating with other applications, rather than reimplementing their functionality, it manages to provide a flexible set of features with high performance.

    Installation

    • Clone the repo
      git clone https://github.com/alacritty/alacritty.git
      cd alacritty
      
    • Install rustup
      curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
      
    • To make sure you have the right Rust compiler installed, run
      rustup override set stable
      rustup update stable
      
    • Install the dependencies
      apt install cmake pkg-config libfreetype6-dev libfontconfig1-dev libxcb-xfixes0-dev libxkbcommon-dev python3
      
    • Build the release
      cargo build --release
      
      If all goes well, this should place a binary at target/release/alacritty
    • Move the binary to somewhere in your PATH

    mv target/release/alacritty ~/.local/bin
    
    - Check the terminfo: To make sure Alacritty works correctly, either the alacritty or alacritty-direct terminfo must be used. The alacritty terminfo will be picked up automatically if it is installed. If the following command returns without any errors, the alacritty terminfo is already installed:

    infocmp alacritty
    

    If it is not present already, you can install it globally with the following command:

    sudo tic -xe alacritty,alacritty-direct extra/alacritty.info
    

    Configuration

    Alacritty's configuration file uses the TOML format. It doesn't create the config file for you, but it looks for one in ~/.config/alacrity/alacritty.toml

    Not there yet - Support for ligatures

    References - Homepage - Source - Docs

  • New: Set the vim filetype syntax in a comment.

    Add somewhere in your file:

    
    
  • New: Export environment variables in a crontab.

    If you need to expand the PATH in theory you can do it like this:

    PATH=$PATH:/usr/local/bin
    
    * * * * * /path/to/my/script
    

    I've found however that sometimes this doesn't work and you need to specify it in the crontab line:

    * * * * * PATH=$PATH:/usr/local/bin /path/to/my/script
    

Wezterm

  • New: Introduce wezterm.

    WezTerm is a powerful cross-platform terminal emulator and multiplexer implemented in Rust.

    Installation

    You can configure your system to use that APT repo by following these steps:

    curl -fsSL https://apt.fury.io/wez/gpg.key | sudo gpg --yes --dearmor -o /usr/share/keyrings/wezterm-fury.gpg
    echo 'deb [signed-by=/usr/share/keyrings/wezterm-fury.gpg] https://apt.fury.io/wez/ * *' | sudo tee /etc/apt/sources.list.d/wezterm.list
    

    Update your dependencies:

    sudo apt update
    

    Now you can install wezterm:

    sudo apt install wezterm
    

    or to install a nightly build:

    sudo apt install wezterm-nightly
    
    Troubleshooting

    Install in Debian 12 error

    Install from nightly.

    References

Terminals

  • New: Do terminal comparison.

    Alacritty

    Pros:

    Cons:

    • The installation is difficult if you're not used to Rust.
    • Doesn't support for ligatures so Fira Code with ligatures looks weird.
    • Awful docs
    • Difficult to keep updated

    Kitty

    Pros:

    • Built in python
    • Supports ligatures
    • Nice docs
    • Easy installation

    Cons:

    • Vim bindings to move around and copy the buffer don't work well
    • When you sudo su on a server you need to copy the ~/.terminfo otherwise the shell is broken
    • You need to replace ssh so that they copy that file.

    Wezterm

    Pros:

    • Nice docs

    Cons:

    • Dev is enough narcissistic enough to not only add it in the name of the terminal but also to say his name as the main developer.

Gotify

  • New: Complete installation.

    • Create the data directories:
      mkdir -p /data/config/gotify/ /data/gotify
      
    • Assuming you're using an external proxy create the next docker compose in /data/config/gotify.
    ---
    version: "3"
    
    services:
      gotify:
        image: gotify/server
        container_name: gotify
        networks:
          - swag
        env_file:
          - .env
        volumes:
          - gotify-data:/app/data
    
    networks:
      swag:
        external:
          name: swag
    
    volumes:
      gotify-data:
        driver: local
        driver_opts:
          type: none
          o: bind
          device: /data/gotify
    

    With the next .env file:

      GOTIFY_SERVER_SSL_ENABLED=false
    
      GOTIFY_DATABASE_DIALECT=sqlite3
      GOTIFY_DATABASE_CONNECTION=data/gotify.db
    
      GOTIFY_DEFAULTUSER_NAME=admin
      GOTIFY_DEFAULTUSER_PASS=changeme
    
      GOTIFY_PASSSTRENGTH=10
      GOTIFY_UPLOADEDIMAGESDIR=data/images
      GOTIFY_PLUGINSDIR=data/plugins
      GOTIFY_REGISTRATION=false
      ```
    
    * Create the service by adding a file `gotify.service` into `/etc/systemd/system/`
    
    [Unit] Description=gotify Requires=docker.service After=docker.service

    [Service] Restart=always User=root Group=docker WorkingDirectory=/data/config/gotify TimeoutStartSec=100 RestartSec=2s ExecStart=/usr/bin/docker-compose -f docker-compose.yaml up ExecStop=/usr/bin/docker-compose -f docker-compose.yaml down

    [Install] WantedBy=multi-user.target

    * Copy the nginx configuration in your `site-confs`
    
      ```
    
      server {
          listen 443 ssl;
          listen [::]:443 ssl;
    
          server_name gotify.*;
    
          include /config/nginx/ssl.conf;
    
          client_max_body_size 0;
    
          # enable for ldap auth (requires ldap-location.conf in the location block)
          #include /config/nginx/ldap-server.conf;
    
          # enable for Authelia (requires authelia-location.conf in the location block)
          #include /config/nginx/authelia-server.conf;
    
          location / {
              # enable the next two lines for http auth
              #auth_basic "Restricted";
              #auth_basic_user_file /config/nginx/.htpasswd;
    
              # enable for ldap auth (requires ldap-server.conf in the server block)
              #include /config/nginx/ldap-location.conf;
    
              # enable for Authelia (requires authelia-server.conf in the server block)
              #include /config/nginx/authelia-location.conf;
    
              include /config/nginx/proxy.conf;
              include /config/nginx/resolver.conf;
              set $upstream_app gotify;
              set $upstream_port 80;
              set $upstream_proto http;
              proxy_pass $upstream_proto://$upstream_app:$upstream_port;
          }
      }
      ```
    * Start the service `systemctl start gotify`
    * Restart the nginx service `systemctl restart swag`
    * Enable the service `systemctl enable gotify`.
    * Login with the `admin` user
    * Create a new user with admin permissions
    * Delete the `admin` user
    
    **Configuration**
    
    - [Android client](https://github.com/gotify/android)
    - Linux clients
      - [command line client](#command-line-client)
      - [Dunst client](https://github.com/ztpnk/gotify-dunst)
      - [gotify-desktop](https://github.com/desbma/gotify-desktop)
      - [rofi client](https://github.com/diddypod/rotify)
    
    **Connect it with Alertmanager**
    
    It's not trivial to connect it to Alertmanager([1](https://github.com/prometheus/alertmanager/issues/2120), [2](https://github.com/gotify/contrib/issues/21), [3](https://github.com/prometheus/alertmanager/issues/3729), [4](https://github.com/prometheus/alertmanager/issues/2120). The most popular way is to use [`alertmanager_gotify_bridge`](https://github.com/DRuggeri/alertmanager_gotify_bridge?tab=readme-ov-file).
    
    We need to tweak the docker-compose to add the bridge:
    
    ```yaml
    

    Connect it with Authentik

    Here are some guides to connect it to authentik. The problem is that the clients you want to use must support it

    References

Science

Artificial Intelligence

  • New: Add aider tool.

    • Aider lets you pair program with LLMs, to edit code in your local git repository. Start a new project or work with an existing git repo. Aider works best with GPT-4o & Claude 3.5 Sonnet and can connect to almost any LLM.

Whisper