Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Check init tasks #478

Merged
merged 27 commits into from
Jul 11, 2024
Merged

feat: Check init tasks #478

merged 27 commits into from
Jul 11, 2024

Commits on Jul 10, 2024

  1. feat: Make the launcher aware of cloud-init

    This affects only the registration time.
    Subsequent boots don't check for cloud-init in any way.
    
    We check if there is a `cloud-init` command in PATH,
    and launch `cloud-init status --wait` right after registration is complete.
    This will wait until cloud-init completes what's doing or report
    error/disabled states.
    
    Cloud-init could have created Linux user accounts. Users could have been
    created in many other ways, even pre-created during image build.
    We expect the desired default user to be set via `/etc/wsl.conf`.
    That would work even without the distro launcher, so it's reasonable to
    assume the desired default to be present there.
    
    We "parse" that file and, if there is the default user entry, then
    we set it via WSL API (which is faster than terminanting and restarting
    the instance).
    When "parsing" /etc/wsl.conf (which is INI like syntax), we deliberately
    stop on the first occurence of the [section].key we're looking for.
    That matches the behavior observed in WSL itself.
    
    If we don't find a default user set, we check if the current default
    user is still root, in which case we look for any non-system
    user in the NSS passwd database (by launching getent),
    i.e. any user with UID between 1000 and 65534 (the nobody).
    Finally, we fallback to the interative user creation,
    i.e. the default upstream prompting.
    
    We do some effort to keep /etc/wsl.conf and the Windows registry (via
    WSL API) in sync, in the sense that whatever user we set as default via
    one means we also set in the other.
    
    I originally intended to put this implementation inside
    DistributionInfo.h/cpp to ensure less files being touched (thus less
    diff compared to upstream) but that doesn't play nice with CI 'Refresh
    releases and assets' workflow.
    
    So I placed the code in its own component, and inside a subdirectory,
    so if there comes a time we need to revert that change (it becomes
    obsolete or so) it remains easy to drop.
    Also, being inside a subdirectory allows me to drop a .clang-format in
    there without worrying of reformatting upstream code :)
    
    Lessons learned from the launcher old times:
    - We can put cpp files inside a subdirectory and still work with
      precompiled headers in Visual Studio if we either adjust the include
      path for every cpp file or adjust the path to the precompiled header
      for every cpp file (no winner :) )
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    b1b6b3c View commit details
    Browse the repository at this point in the history
  2. Fix WLS typo

    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    23f99fd View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    4baff0e View commit details
    Browse the repository at this point in the history
  4. Remove e2e test relying on the OOBE

    And unnecessary assertion for empty stdout
    That's never the case.
    CarlosNihelton committed Jul 10, 2024
    1 Configuration menu
    Copy the full SHA
    8b7663b View commit details
    Browse the repository at this point in the history
  5. Implements TestFixturePath

    For now that's all we need from the golden testutils we have everywhere else.
    CarlosNihelton committed Jul 10, 2024
    1 Configuration menu
    Copy the full SHA
    679dd52 View commit details
    Browse the repository at this point in the history
  6. Fix testCorrectUpgradePolicy

    It assumed distroName to match the AppID
    Which is not the case.
    Ubuntu24.04LTS is the AppID for the distroName Ubuntu-24.04.
    Thus we need to check for Ubuntu-WX.YZ :)
    
    This is yet a bit tricky because nowadays we set the policy during image build,
    So a rootfs meant to build an LTS app (thus Prompt=never)
    could be recycled to build Ubuntu-Preview during tests and that would break the assertion.
    
    TODO: Verify if CI is happy with just this change.
    CarlosNihelton committed Jul 10, 2024
    1 Configuration menu
    Copy the full SHA
    fe75ee5 View commit details
    Browse the repository at this point in the history
  7. Implements testFileExists

    To check whether a file exists in the distro filesystem.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    8d64885 View commit details
    Browse the repository at this point in the history
  8. We can now specify if we want the user to be root or not.

    s/testUserNotRoot/testWhetherUserIsRoot
    
    Parameterized :)
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    a6f7ac9 View commit details
    Browse the repository at this point in the history
  9. Removes some t.Parallel()

    To allow reusing those test helpers inside testcases
    
    It pessimizes the existing TestBasicSetup a little bit
    But it's for a good reason.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    8a147a5 View commit details
    Browse the repository at this point in the history
  10. Implements tests that rely on cloud-init

    Every testcase wipes out the WSL instance
    So not a lot can run in a reasonable way in CI
    Let's see how long those two will take.
    
    We use `<launcher.exe> install` to avoid the interactive shell in the end.
    
    If we append `--root` then the launcher should still wait for cloud-init but skip checking the creation of the default user.
    We check for the specific user set as default, different combinations of
    cloud-config may create users in different order and set or not in
    /etc/wsl.conf. This way we check if the launcher does the right thing
    even without /etc/wsl.conf and if it skips doing anything else when
    `install --root`.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    3b4636a View commit details
    Browse the repository at this point in the history
  11. Runs all existing tests and increase timeout

    We have more to do
    It's reasonable to assume it will take longer :)
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    2ed7d6e View commit details
    Browse the repository at this point in the history
  12. End-to-end tests with the latest LTS

    Temporarily at least, as we don't have oracular images yet.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    2a46c82 View commit details
    Browse the repository at this point in the history
  13. fix test data

    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    fe16135 View commit details
    Browse the repository at this point in the history
  14. Add a TODO to use the Ubuntu app in end-to-end tests

    once we have backported everything and Ubuntu is transitionned to 24.04
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    5ace6b7 View commit details
    Browse the repository at this point in the history
  15. Comments to clarify the search for the default user

    Making sure to explain how we indirectly look for the registry.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    cbcc93d View commit details
    Browse the repository at this point in the history
  16. Replace custom ini "parser" by GetPrivateProfileString

    With a caveat: that function can only read local files, i.e.
    in the Windows OS filesystem.
    No shared mounts.
    Thus we make an effort to copy the instance's /etc/wsl.conf
    to a private (best effort) temporary path, using OS primitives to guaratee automatic deletion.
    From that place, it's just a function call to read the key we are interested in.
    Let's trust the OS can deliver us a suitable temporary file under %TEMP%.
    In production that's more likely, as the %TEMP% dir is private to the app when FS virtualization is ON.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    7585be3 View commit details
    Browse the repository at this point in the history
  17. Do not attempt to fix /etc/wsl.conf

    If the username is wrong, i.e. there is no matching UID in passwd
    ignore it and exit success.
    As a consequence we can totally remove writing into /etc/wsl.conf:
    1. We won't fix any mistakes
    2. If a default user is set from outside (WSL API/registry), it
        suffices to make such user the default, no need to keep both in sync.
    3. If no default user is set, we do so via the WSL API, which unfolds
       into the reasoning above.
    
    And just to clarify, if both are set to different users, registry takes
    precedence over /etc/wsl.conf even after reboot.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    a491c19 View commit details
    Browse the repository at this point in the history
  18. Ask for forgiveness, not permission

    When approaching cloud-init, run it unconditionally
    Added a not-so-beautiful trick to avoid printing
    /bin/bash: error 1: cloud-init command not found.
    Finally, if it doesn't exit 0, show the long status
    
    cloud-init status --long.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    49994b7 View commit details
    Browse the repository at this point in the history
  19. The most beautiful C++ passwd parser ever written ;)

    Relying only on the UID may be misleading
    So we wanted to check the login shell (the last field of the line) to determine
    whether an account is a system or real user.
    
    That required parsing the passwd more carefully
    Using istringstreams as before would incur in potentially lots of small memory allocations.
    Writing an iteration scheme by hand with string_views prevents most of the unnecessary allocations
    while offering an elegant, idiomatic iteration and parsing on-the-flight.
    
    Most of that code wouldn't be needed in C++20, std::ranges::split would do most of this job,
    but with C++17 we need to craft the iteration by hand.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    722054a View commit details
    Browse the repository at this point in the history
  20. Configuration menu
    Copy the full SHA
    f17b114 View commit details
    Browse the repository at this point in the history
  21. Adds a test case with the default user already set in the registry

    For that we need GoWSL, so let's import it.
    This whole idea is very prone to races.
    Let's see how it behaves in CI.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    8290991 View commit details
    Browse the repository at this point in the history
  22. [NEW!!!] Adds test cases for higher UIDs and broken passwd

    We could break passwd in one way at a time,
    but I'm affraid of having tons of test cases making CI run for too long.
    So, as the system happily ignores broken lines, I'm all for breaking them in all the ways we want in the same tests
    and have few tests running with broken passwd.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    84fc27f View commit details
    Browse the repository at this point in the history
  23. Configuration menu
    Copy the full SHA
    8ebea3d View commit details
    Browse the repository at this point in the history
  24. Allow bash.exe handle symlinks on Windows

    CI was failing because bash.exe didn't know how to handle symlinks.
    Powershell knows by default, but the resulting script would be uglier.
    It turns out it's just an MSYS toggle to fix bash.exe.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    4bf78f0 View commit details
    Browse the repository at this point in the history
  25. Sprinkles some "Setup:" in log and error lines

    Plus comments about the order we check for registry settnig errors.
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    64fc551 View commit details
    Browse the repository at this point in the history
  26. Fix syntax error on e2e workflow file

    Apparently quoting is necessary for globing with a single '*'
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    4eb3c22 View commit details
    Browse the repository at this point in the history
  27. Prevents 'cannot index into null array' exception in powershell

    When trying to download a rootfs
    CarlosNihelton committed Jul 10, 2024
    Configuration menu
    Copy the full SHA
    acfdc4a View commit details
    Browse the repository at this point in the history