-
Notifications
You must be signed in to change notification settings - Fork 285
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
Support livepatch - part 1 #4678
Support livepatch - part 1 #4678
Conversation
ocaml/xapi/livepatch.ml
Outdated
type component = Xen | Kernel | ||
|
||
let component_of_string = function | ||
| "Xen" | "xen" -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to use String.lowercase_ascii
before the match is made.
* livepatch_4_19_19__8_0_20__4_19_19__8_0_22 | ||
*) | ||
Re.Posix.compile_pat | ||
{|^[ ]*livepatch_([^ \[]+)__([^ \[]+)__([^ \[]+)__([^ \[]+).*$|} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this regex stronger? ([0-9_]+)
seems to capture the expected version strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version and release strings may contain other characters. Actually we don't have any expectations on the strings. Here we only need to separate them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option might be to chop off the livepatch_
prefix and then split the string on __
. I suppose it doesn't really matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can describe the operation with a regular expression (because the number of fields is known in advance) I would prefer that over a procedural approach of chopping an splitting - let the regex engine do the work. A regex doesn't work if this becomes context sensitive - earlier information informs later decisions. In that case I would again consider using Angstrom because it is still quite declarative.
ocaml/xapi/livepatch.ml
Outdated
| true -> | ||
(acc, true) | ||
| false -> | ||
if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be expressed as when
clause on the match case.
) | ||
|> get_latest_livepatch | ||
|
||
let get_base_build_id () = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this code doing? It seems quite repetitive and using low-level operations. Parsing binary data could be easier using Angstrom
which has operations to read bytes and Big Endian, Small Endian numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is going to read ELF notes from file /sys/kernel/notes
to find out the running kernel's build id.
The file content is organized as some consecutive sections. For each section, at beginning of it, it's a header structure described by headers_struct
. And the length of a section is determined by its headers. This function needs to find a specific section and read build id in it.
If Angstrom
works for this in better way, I will look into it. Thanks :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example, this is code I wrote to read the (binary) header of a FIT file. There is more complex code in that file but it gives you a flavor how to read bytes, multi-byte numbers, and strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's another example of using angstrom for decoding the output of a command, it might prove useful as well: https://github.com/xapi-project/xen-api/blob/47fae74032aa6ade0fc12e867c530eaf2a96bf75/ocaml/xapi/bios_strings.ml (and tests: https://github.com/xapi-project/xen-api/blob/47fae74032aa6ade0fc12e867c530eaf2a96bf75/ocaml/tests/test_bios_strings.ml)
Looking at the documentation of angstrom was useful when I developed the module: https://docs.ocaml.pro/docs/LIBRARY.angstrom@angstrom.0.15.0/Angstrom/index.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* GNU Lesser General Public License for more details. | ||
*) | ||
|
||
module Epoch : sig |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs doucumentation. What are these modules describing?
11498b6
to
9b0e275
Compare
Hi Reviewers, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code to extract the build information is much better now.
type t = { | ||
component: component | ||
; base_build_id: string | ||
; to_version: string option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am bit surprised about to_
- it is somewhat unusual. Does this indicate the version and release reached after applying the patch? Maybe a comment could clarify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. It indicates that the version and release reached after applying the live patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that there are comments that explain this in the mli file.
ocaml/xapi/livepatch.ml
Outdated
module BuildId = struct | ||
let one_byte = | ||
let open Angstrom in | ||
any_char >>= fun c -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use any_uint8
or any_int8
- which will result in an int
.
ocaml/xapi/livepatch.ml
Outdated
section' () | ||
) | ||
|
||
let section = section' () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we rename section'
to section
and get rid of this?
ocaml/xapi/livepatch.ml
Outdated
let align x = | ||
(* The actual size is aligned with 4. *) | ||
let open Int32 in | ||
(if rem x 4l = 0l then x else add x (sub 4l (rem x 4l))) |> to_int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is using 41
but the comment says something is 4-byte aligned. What is the relevance of 41
? What is the result of this function for a given x?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I misread this. The 1
is actually an l
- a size indicator. A comment what align 6
would do would be still helpful. Are we rounding up or down to a multiple of 4? I assume align x
rounds x up to the next multiple of 4. I believe it could be simplified (here for integers):
let align4 n = ((n + 3) / 4) * 4
utop # align4 12;;
- : int = 12
utop # align4 10;;
- : int = 12
utop # align4 13;;
- : int = 16
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is great. Thanks.
ocaml/xapi/livepatch.ml
Outdated
let get_installed_livepatch_file ~component ~base_build_id = | ||
let lp_dir = get_livepatch_dir ~component ~base_build_id in | ||
let installed_symlink = Filename.concat lp_dir "livepatch.livepatch" in | ||
if not (Sys.file_exists installed_symlink) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be done with a single match:
match Unix.lstat installed_symlink with
| Unix.{st_kind = S_LNK;_} -> ... Option .some
| exception _ -> None
|
||
let error_msg = Printf.sprintf "Failed to parse '%s'" | ||
|
||
let parse_epoch_version_release epoch_ver_rel = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This module looks too complicated to me. I would expect that a version is represented as a list of numbers and that we are comparing two strings to establish their order. I think it needs to be spelled out how strings and numbers are treated: is every string that can be read as a number considered a number, and or still a string? This makes a difference because "01" and "1" are different strings but the same number. Likewise, how is any string that cannot be read as a number treated? I am not sure but I would have started with:
type comp = Number of int | String of string
type version = comp list (* assuming a version is a list of components, each either a string or a number *)
val parse: string -> string * version (* split into package and version *)
val compare: version -> version -> int (* -1, 0, 1 *)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These bits are some existing lines which are moved into a new file only in this PR.
type comp = Number of int | String of string
This is defined as similarly as:
https://github.com/xapi-project/xen-api/pull/4678/files#diff-3c831fd11744c8735ff48fa1f9e436f357cb4316e4394855770ac300ed41dc69R55
val parse: string -> string * version (* split into package and version *)
is implemented like:
https://github.com/xapi-project/xen-api/pull/4678/files#diff-3c831fd11744c8735ff48fa1f9e436f357cb4316e4394855770ac300ed41dc69R183
and val compare: version -> version -> int (* -1, 0, 1 *)
is implemented as:
https://github.com/xapi-project/xen-api/pull/4678/files#diff-3c831fd11744c8735ff48fa1f9e436f357cb4316e4394855770ac300ed41dc69R160
There are some examples to explain the rules of comparison:
https://github.com/xapi-project/xen-api/pull/4678/files#diff-3c831fd11744c8735ff48fa1f9e436f357cb4316e4394855770ac300ed41dc69R166
91a5854
to
0dd784a
Compare
ocaml/xapi/livepatch.ml
Outdated
type component = Xen | Kernel | ||
|
||
let component_of_string x = | ||
match Astring.String.Ascii.lowercase x with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is deprecated; use lowercase_ascii
instead
@@ -304,6 +334,17 @@ let set_available_updates ~__context = | |||
Helpers.run_in_parallel funs capacity_in_parallel | |||
) | |||
in | |||
let applied_livepatches_of_hosts = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many lines is this function long? I would encourage to split out more functions that are defined in this function. If this is done just to keep the name space clean, I would use a local module rather than making this function larger and larger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I split some functions out. Indeed, the set_available_updates
function was too long.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not easy to get a good overview of the logic and control flow because there is a lot going on in the >1000 changed lines. I think it comes down to testing well. It mostly looks fine.
Please do not merge yet: we are sorting out some build issues first. |
Sure. I will re-do tests before merging this one. And the following PRs will be unit tests and applying live patches. |
Looks like there are now a few conflicts due to the warning-removal PR... |
Signed-off-by: Ming Lu <ming.lu@citrix.com>
This commit doesn't change any code. It only move some codes to a few new files so that they could be used more easily later. Signed-off-by: Ming Lu <ming.lu@citrix.com>
Signed-off-by: Ming Lu <ming.lu@citrix.com>
Signed-off-by: Ming Lu <ming.lu@citrix.com>
…atches Signed-off-by: Ming Lu <ming.lu@citrix.com>
Signed-off-by: Ming Lu <ming.lu@citrix.com>
Signed-off-by: Ming Lu <ming.lu@citrix.com>
Signed-off-by: Ming Lu <ming.lu@citrix.com>
This commit fixes the bug introduced in c081442: prior to c081442, the bool value is for [up_to_date], while after the commit, it is for [pkg_updates_available]. If there is(are) RPM package updates, it means a host is NOT up to date. This commit is just for this bug. Signed-off-by: Ming Lu <ming.lu@citrix.com>
170e6c9
to
8017dcf
Compare
a9189b4
to
4c0cbc1
Compare
Signed-off-by: Ming Lu <ming.lu@citrix.com>
4c0cbc1
to
de7c897
Compare
This series contains the first part of changes to support live patch: