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

Add remote file handling #30

Merged
merged 17 commits into from
Jul 26, 2024
Merged

Add remote file handling #30

merged 17 commits into from
Jul 26, 2024

Conversation

b-rowan
Copy link
Collaborator

@b-rowan b-rowan commented Jul 25, 2024

Adds remote firmware handling for files. Based on #29. Closes #28. Closes #29.

Adding independently so they can be merged independently if there are concerns on this PR.

Main concern here is that I don't have a better way to get the hash of the upgrade file (required for swupdate artifact) without just downloading the file when the link is added.

@b-rowan b-rowan requested a review from easybe July 25, 2024 00:24
Copy link
Collaborator

@easybe easybe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO downloading the artifact when creating a new DB entry to get the hashes is a reasonable approach.

I’ve only skimmed over the changes as reviewing on the phone is not that fun.

hw_revision = fields.CharField(max_length=255)


class FirmwareUpdate(Model):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just call it Firmware as it does not have to be an update, it could technically also be a downgrade (if we would start to allow that) or the initial image.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rollout model needs to be adjusted as well - instead of hw_model, hw_revision, fw_file it only should reference a firmware.

This then also means work in Manager.get_rollout to query the correct firmware.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rollout model needs to be adjusted as well - instead of hw_model, hw_revision, fw_file it only should reference a firmware.

This then also means work in Manager.get_rollout to query the correct firmware.

This can get really tricky, if I link Firmware directly then all the stuff that wants to check for rollout that uses the device as a backup need to return Firmware, which means fw_file on Device needs to be replaced with Firmware, but then that gets rid of latest and pinned, which can make things pretty complicated. Let me know what you guys think here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it triggers a few follow-up changes. I have a branch where I introduced update_mode on Device (enum with latest, rollout, assigned, and pinned), so that fw_file could be changed to firmware on Device.

Will re-implement those changes on top of this branch to see if it makes sense.

@easybe
Copy link
Collaborator

easybe commented Jul 25, 2024

Oh, and please note this comment: c553176#r144602289

@tsagadar
Copy link
Collaborator

I think we should slow down somewhat: as there are no automatic test in the code base, every PR breaks some functionality. Manual testing (what I was doing so far) takes forever. So we better ensure to have tests for the existing functionality before adding / refactoring code.

I created automated API integration tests (focus on the DDI) yesterday - and currently adjust the test code to match this PR. Ideally I could finish these tests (few of them will fail as the code is broken), integrate them into this PR and ensure that everything passes before merging.

Copy link
Collaborator

@tsagadar tsagadar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few things I saw while writing tests. Some if them cause my current tests to fail.

hw_revision = fields.CharField(max_length=255)


class FirmwareUpdate(Model):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rollout model needs to be adjusted as well - instead of hw_model, hw_revision, fw_file it only should reference a firmware.

This then also means work in Manager.get_rollout to query the correct firmware.

goosebit/db.py Outdated
@@ -22,6 +23,10 @@ async def init():
await command.migrate()
await command.upgrade(run_in_transaction=True)
await Tortoise.generate_schemas(safe=True)
for update in await FirmwareUpdate.all():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of all() better to filter on db using filter().

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what to filter by here, I suppose maybe uri starts with file?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought about using await Firmware.filter(url__startswith='file').all(). Debatable if a good idea, as logic of local is the implemented in two different places. On the upside: with a lot of remote firmware it will be very fast.

Copy link
Collaborator

@tsagadar tsagadar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finished a first set of integration test - they can be found at https://github.com/husqvarnagroup/goosebit/tree/mm/add_simple_ddi_integration_tests

Besides the commit adding the tests there is an additional one that makes the tests pass. Most of the things are also annotated in this PR.

Note: poetry run pytest does not pass all the tests. Single execution of tests work (I do it using PyCharm). Will look into this soon (but not today)

swdesc_attrs["version"] = semver.Version.parse(swdesc["software"]["version"])
swdesc_attrs["size"] = file.stat().st_size
swdesc_attrs["hash"] = sha1_hash_file(file)
swdesc_attrs["compatibility"] = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This parsing does not work for our images. Our swdesc looks (shortened) like the following:

{
    "software": {
        "version": "8.8.1-12-g302f635+189128",
        "description": "Linux System Firmware (hawkbit) for the GARDENA smart Gateway gardena-sg-mt7688",
        "smart-gateway-mt7688": {
            "hardware-compatibility": [
                "0.5",
                "1.0",
                "1.1.0",
                "1.2.0",
                "1.2.1"
            ],
            "stable": {
                "bootslot0": {
                    "images": [
                        {
                            "filename": "gardena-image-hawkbit-gardena-sg-mt7688.squashfs-xz",
                            "volume": "rootfs1",
                            "sha256": "a7fd6b6b3416efc3a58993280f7335f84826af6a73164624e9cb6b5201499c18",
                            "hook": "check_version_and_leds",
                            "installed-directly": true
                        }
                    ],
                    "bootenv": [
                    ]
                },
                "bootslot1": {
                    "images": [
                        {
                            "filename": "gardena-image-hawkbit-gardena-sg-mt7688.squashfs-xz",
                            "volume": "rootfs0",
                            "sha256": "a7fd6b6b3416efc3a58993280f7335f84826af6a73164624e9cb6b5201499c18",
                            "hook": "check_version_and_leds",
                            "installed-directly": true
                        }
                    ],
                    "bootenv": [
                    ]
                }
            }
        }
    }
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a standard on how this is supposed to be set? We use loadsync.v1 here, but I'm not sure if there is any standard here...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not my area of expertise. Maybe @easybe can provide information once he is back.

@b-rowan
Copy link
Collaborator Author

b-rowan commented Jul 25, 2024

I'll try to take a look at this later tonight, at a conference this week so I don't have a ton of time, but I'll fix what I can ASAP.

I think we should slow down somewhat: as there are no automatic test in the code base, every PR breaks some functionality.

Agreed, but I really want to get the important core functionality we want figured out ASAP. I'm not a big tests guy personally, I think it's definitely a good idea in this case, I just struggle with the differences between trying to finish important functionality and stabilizing the code/API. There seem to be a lot of cases where the dev API needs to change for important things to happen, so I wasn't sure if we wanted to wait to write tests until after that.

@b-rowan
Copy link
Collaborator Author

b-rowan commented Jul 26, 2024

I finished a first set of integration test - they can be found at https://github.com/husqvarnagroup/goosebit/tree/mm/add_simple_ddi_integration_tests

Besides the commit adding the tests there is an additional one that makes the tests pass. Most of the things are also annotated in this PR.

Note: poetry run pytest does not pass all the tests. Single execution of tests work (I do it using PyCharm). Will look into this soon (but not today)

Implemented these, and fixed your issue with pytest not working properly. Just need to add __init__.py files to all directories leading to the tests to make them identify as modules.

@b-rowan
Copy link
Collaborator Author

b-rowan commented Jul 26, 2024

Mostly everything fixed for now, just a couple things I want to clarify on before I change anything else, check comments on unresolved when you get a chance @tsagadar @easybe. Appreciate the pointers, this was a pretty large PR, but I think a pretty important one to deal with early on.

@tsagadar
Copy link
Collaborator

I think this PR is ready to be merged - great stuff. Follow-up work can be done in a new branch / PR. Will look replacing fw_file with firmware.

@b-rowan b-rowan merged commit fa5e0bd into master Jul 26, 2024
@b-rowan b-rowan deleted the dev_remote_files branch August 1, 2024 14:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CDN support for update files
3 participants