Skip to content

Conversation

@jakecorrenti
Copy link
Member

Add support for the use of OCI annotations to configure the microVM. In Podman, we can take advantage of modules to make creating krun containers highly configurable and reproducible.

@gemini-code-assist
Copy link

Summary of Changes

Hello @jakecorrenti, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the configurability of krun microVMs by integrating support for OCI annotations. This change allows users to define microVM resources and characteristics directly through container annotations, offering a more dynamic and reproducible configuration method that aligns well with container orchestration practices, while maintaining backward compatibility with existing JSON configuration files.

Highlights

  • OCI Annotation Support: Introduced the ability to configure krun microVM parameters, specifically CPU count, RAM, and VM flavor/variant, using OCI annotations. This provides a flexible alternative to traditional configuration files.
  • Configuration Priority: The system now prioritizes configuration values provided via OCI annotations (e.g., 'krun.cpus', 'krun.ram_mib', 'krun.variant') over those specified in the 'krun_vm.json' configuration file.
  • Fallback Mechanism: A robust fallback mechanism has been implemented. If the relevant OCI annotations are not found for a specific configuration parameter, the system will gracefully revert to reading that parameter from the existing 'krun_vm.json' file.
  • Function Signature Updates: The libkrun_configure_vm and libkrun_configure_flavor functions have been updated to accept a libcrun_container_t *container parameter, enabling them to access and process container-specific OCI annotations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for configuring the microVM using OCI annotations, which is a great feature for configurability. The implementation correctly prioritizes annotations over the krun_vm.json file.

However, I've found a few issues in the implementation:

  • A critical bug that can lead to a crash due to a NULL pointer being passed to strcmp.
  • Some high-severity issues in the parsing logic for integer values from both annotations and the JSON configuration file, which can lead to incorrect behavior or using garbage values. These include unsafe use of strtol and incorrect handling of floating-point numbers from JSON.
  • Minor issues include printing warnings to stdout instead of stderr.

I've left detailed comments with suggestions to fix these issues. Addressing them will make the new feature more robust and reliable.

@packit-as-a-service
Copy link

TMT tests failed. @containers/packit-build please check.

Support the use of OCI annotations as a way for the container engine to
configure the microVM.

The user may add the `krun.variant` annotation to specify the flavor of
libkrun they want to use. The current supported values are ["sev",
"aws-nitro"].

Signed-off-by: Jake Correnti <[email protected]>
Support the use of OCI annotations as a way for the container engine to
configure the microVM's CPU count and RAM amount via `krun.cpus` and
`krun.ram_mib` respectively.

Signed-off-by: Jake Correnti <[email protected]>
@jakecorrenti
Copy link
Member Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for configuring the krun microVM using OCI annotations, falling back to the existing krun_vm.json file. This is a great feature for improving configurability.

The implementation looks good overall, but I've found a few issues:

  • A critical issue in libkrun_configure_flavor that could lead to a segmentation fault due to a missing NULL check.
  • A high-severity issue in the new libkrun_parse_resource_configuration function regarding incorrect error handling for missing JSON keys and lack of validation for negative resource values.
  • A medium-severity issue related to type correctness (char * vs const char *) in a couple of places.

I've provided detailed comments and suggestions to address these points. Once these are fixed, the PR should be in good shape.

if (val_flavor != NULL && YAJL_IS_STRING (val_flavor))
// Check if the user provided the krun variant through OCI annotations.
flavor = (char *) find_annotation (container, "krun.variant");
if (flavor == NULL)

Choose a reason for hiding this comment

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

critical

There is a potential null pointer dereference on the next line. *config_tree can be NULL if libkrun_read_vm_config doesn't find or fails to parse the VM config file. yajl_tree_get will then be called with a NULL node, leading to a crash. You should add a check that *config_tree is not NULL before dereferencing it.

  if (flavor == NULL && *config_tree)

Comment on lines +189 to +221
libkrun_parse_resource_configuration (yajl_val *config_tree, libcrun_container_t *container, char *annotation, const char *path[], int default_val)
{
char *annotation_val;
char *endptr;
int resource_val = default_val;
yajl_val krun_file_val = NULL;

annotation_val = (char *) find_annotation (container, annotation);
if (annotation_val != NULL)
{
errno = 0;
resource_val = strtol (annotation_val, &endptr, 10);
if (errno != 0 || endptr == annotation_val || *endptr != '\0')
{
fprintf (stderr, "failed to convert %s value to an integer: falling back to the default value %d\n", annotation, default_val);
return default_val;
}
}
else
{
krun_file_val = yajl_tree_get (*config_tree, path, yajl_t_number);
if (! YAJL_IS_INTEGER (krun_file_val))
{
fprintf (stderr, "failed to convert %s value in krun_vm.json to an integer: falling back to the default value %d\n", path[0], default_val);
return default_val;
}

if (krun_file_val != NULL)
resource_val = YAJL_GET_INTEGER (krun_file_val);
}

return resource_val;
}

Choose a reason for hiding this comment

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

high

The function libkrun_parse_resource_configuration has a few areas for improvement for correctness and robustness:

  1. The annotation parameter should be const char * since it is not modified. The cast (char *) on the return value of find_annotation would then be unnecessary.
  2. The logic for parsing the JSON configuration prints an error message if a key is not found. It should only show an error if the key exists but has an incorrect type.
  3. The function does not validate against negative values for resources like CPUs and RAM, which could lead to undefined behavior when these values are cast to unsigned types later.

Here is a suggested refactoring of the function to address these points:

static int
libkrun_parse_resource_configuration (yajl_val *config_tree, libcrun_container_t *container, const char *annotation, const char *path[], int default_val)
{
  const char *annotation_val;
  char *endptr;
  int resource_val = default_val;
  yajl_val krun_file_val;

  annotation_val = find_annotation (container, annotation);
  if (annotation_val != NULL)
    {
      errno = 0;
      long val = strtol (annotation_val, &endptr, 10);
      if (errno != 0 || endptr == annotation_val || *endptr != '\0' || val < 0)
        {
          fprintf (stderr, "failed to convert annotation '%s' value to a non-negative integer: falling back to the default value %d\n", annotation, default_val);
          return default_val;
        }
      resource_val = (int)val;
    }
  else if (*config_tree)
    {
      krun_file_val = yajl_tree_get (*config_tree, path, yajl_t_any);
      if (krun_file_val)
        {
          if (YAJL_IS_INTEGER (krun_file_val))
            {
              long long val = YAJL_GET_INTEGER (krun_file_val);
              if (val < 0)
                {
                  fprintf (stderr, "value for '%s' in krun_vm.json is negative: falling back to the default value %d\n", path[0], default_val);
                  return default_val;
                }
              resource_val = (int)val;
            }
          else
            {
              fprintf (stderr, "value for '%s' in krun_vm.json is not an integer: falling back to the default value %d\n", path[0], default_val);
              return default_val;
            }
        }
    }

  return resource_val;
}

val_flavor = yajl_tree_get (*config_tree, path_flavor, yajl_t_string);
if (val_flavor != NULL && YAJL_IS_STRING (val_flavor))
// Check if the user provided the krun variant through OCI annotations.
flavor = (char *) find_annotation (container, "krun.variant");

Choose a reason for hiding this comment

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

medium

The cast to (char *) is incorrect as find_annotation returns a const char *. The flavor variable (declared on line 266) should be changed to const char * to match the types of the values it is assigned from both find_annotation and YAJL_GET_STRING.

  flavor = find_annotation (container, "krun.variant");

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.

1 participant