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

DBUS API for GNOI System.SetPackage #171

Merged
merged 19 commits into from
Nov 8, 2024
Merged

Conversation

hdwhdw
Copy link
Contributor

@hdwhdw hdwhdw commented Oct 16, 2024

Create image_service class for supporting GNOI implementation for SetPackage.

TESTED: unit test.

"""

@host_service.method(host_service.bus_name(MOD_NAME), in_signature='ss', out_signature='is')
def download(self, image_url, save_as):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to verify this image_url?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think dbus services should be a thin layer above CLI and we can push the complexity of such to the caller (gNOI). So this one (download) is basically a wrapper for curl and we don't do additional logic here. What do you think?



@host_service.method(host_service.bus_name(MOD_NAME), in_signature='s', out_signature='is')
def install(self, path):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this path be a url?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes (didn't know that). Similar to above this is a thin layer around "sonic-installer install" so if sonic-installer supports url this also can be a url. Renamed the variable to reflect that.

Copy link

linux-foundation-easycla bot commented Oct 29, 2024

CLA Signed

The committers listed above are authorized under a signed CLA.

@hdwhdw hdwhdw changed the title Implements necessary host services for image download and installation Create ImageService with download and install. Oct 29, 2024
@hdwhdw hdwhdw requested a review from ganglyu October 29, 2024 20:06
@hdwhdw hdwhdw marked this pull request as ready for review October 30, 2024 19:20

MOD_NAME = "image_service"

DEFAULT_IMAGE_SAVE_AS = "/host/downloaded-sonic"
Copy link
Contributor

@qiluo-msft qiluo-msft Nov 4, 2024

Choose a reason for hiding this comment

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

host

host

/tmp/ is more safe as a default file location. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@host_service.method(
host_service.bus_name(MOD_NAME), in_signature="ss", out_signature="is"
)
def download(self, image_url, save_as):
Copy link
Contributor

@qiluo-msft qiluo-msft Nov 4, 2024

Choose a reason for hiding this comment

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

download

Do we need to support hash check? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, and added unit tests.

dir = os.path.dirname(save_as)
if not os.path.exists(dir):
os.makedirs(dir)
cmd = ["/usr/bin/curl", "-Lo", save_as, image_url]
Copy link
Contributor

@qiluo-msft qiluo-msft Nov 4, 2024

Choose a reason for hiding this comment

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

curl

curl

This is python code, it is better to use python library to download binary? like using requests. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

dir = os.path.dirname(save_as)
if not os.path.exists(dir):
os.makedirs(dir)
cmd = ["/usr/bin/curl", "-Lo", save_as, image_url]
Copy link
Contributor

Choose a reason for hiding this comment

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

save_as

Inspired by another gnoi API design:
target should initially write the file to a temporary location so a failure does not destroy the original file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

Choose a reason for hiding this comment

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

If save_as == TMP_IMAGE_FILE, what will happen? Does it harm?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. I use the tempfile library instead now. The library is designed to prevent collision.

@host_service.method(
host_service.bus_name(MOD_NAME), in_signature="ss", out_signature="is"
)
def download(self, image_url, save_as):
Copy link
Contributor

@qiluo-msft qiluo-msft Nov 4, 2024

Choose a reason for hiding this comment

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

save_as

always check absolute path. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

# Create parent directory.
dir = os.path.dirname(save_as)
if not os.path.exists(dir):
os.makedirs(dir)
Copy link
Contributor

@qiluo-msft qiluo-msft Nov 4, 2024

Choose a reason for hiding this comment

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

makedirs

makedirs

This function will be finally called by outside, and it is an attacking point. Can we enforce that the dir must exist, and every user has the "w" permission, similar to "/tmp" permission ? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

where: either a local path or a remote url pointing to the image.
"""
logger.info("Using sonic-installer to install the image at {}.".format(where))
cmd = ["sudo", "/usr/local/bin/sonic-installer", "install", "-y", where]
Copy link
Contributor

@qiluo-msft qiluo-msft Nov 4, 2024

Choose a reason for hiding this comment

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

sudo

sudo

Is sudo needed? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting. I deem it necessary because it is needed for manual run, but so as many config command in other modules. This is not needed.

@hdwhdw hdwhdw changed the title Create ImageService with download and install. Create image_service class for supporting GNOI implementation for SetPackage. Nov 5, 2024
@hdwhdw hdwhdw force-pushed the setpackage branch 3 times, most recently from 41b449f to b443096 Compare November 5, 2024 02:02
@hdwhdw
Copy link
Contributor Author

hdwhdw commented Nov 5, 2024

For the record: Force push to reset the email.

@hdwhdw hdwhdw requested a review from qiluo-msft November 5, 2024 02:29
for chunk in response.iter_content(chunk_size=8192):
tmp_file.write(chunk)
temp_file_path = tmp_file.name
os.rename(temp_file_path, save_as)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What will happen if this save_as already exists?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

os.rename will do nothing. Using os.replace instead.

with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_func.update(chunk)
return 0, hash_func.hexdigest()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we use md5sum directly? Is this hash result the same as md5sum result? How long will it take to calculate checksum for a typical sonic image?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

1-2 seconds. md5sum is slightly faster but not by a noticeable margin. And since this is python code, I think we should use python library to have better control over the logic.

$ python3
Python 3.11.2 (main, May  2 2024, 11:59:08) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from md5 import calculate_md5
>>> calculate_md5('sonic.bin')
(2.589256763458252, '489a131693a4c98803d5a520df409bf9')
>>>
$ time md5sum sonic.bin
489a131693a4c98803d5a520df409bf9  sonic.bin

real    0m1.879s
user    0m1.621s
sys     0m0.257s

@hdwhdw hdwhdw changed the title Create image_service class for supporting GNOI implementation for SetPackage. DBUS API for GNOI System.SetPackage Nov 8, 2024
@qiluo-msft qiluo-msft merged commit fec6080 into sonic-net:master Nov 8, 2024
5 checks passed
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.

3 participants