I'd like to develop a feature for LXC! Advice/suggestions are welcome

Hello,

I’m a student studying Computer Science at the University of Texas at Austin in the United States and I would like to code a feature for LXC. I have taken two Computer Architecture courses as well as an Operating Systems course, and am currently in a Virtualization course so I have a decent grasp of the C language and systems concepts. I have used LXC in a beginners context as well, but I have good familiarity with Linux operating systems (Ubuntu/Debian in particular). I am however very new to the Open Source scene, and have never contributed to any projects before.

I have already glanced through the Issues tab on GitHub, and filtered even further into people who have feature requests. I have glanced through a couple that I feel like I might be able to accomplish, but I am unsure of the level of involvement or difficulty associated with them all, as well as if by chance they have already been implemented and the issue is stale.

Any advice or suggestions on how a feature, or how I would get started/up to speed with the code ASAP would be appreciated. I look forward to your replies!

Regards,
Austin Reichert

I suppose you can start with a small and easy feature request (from the github Issues) and implement it as a way to familiarize yourself with the process. It would be equally good if you find a new feature that you would like to have, implement it and make a pull request.

The github Issues list is the definitive place to discuss and ask questions on specific features. I do not think that there would be work done without some mention in the corresponding issue. If you have a question on a specific feature, you can ask in that issue report.

Other than that, @stgraber and @brauner can also help.

What were the issues you found suitable? If you point them out to me I can give you an estimate of how much work it would be. :slight_smile:
If there’s nothing immediately suitable I can look at my notes of what needs to be done and point you to something.

Thanks for the responses :slight_smile: @brauner, I have compiled the following list of issues to consider. Please let me know if my perceptions of difficulty are incorrect on any of these issues.

https://github.com/lxc/lxc/issues/<#>

Here are the ones I’ve skimmed that seem within my grasp (I could be wrong)
lxc-top: add iops column(s) #624
OVS port tagging support #806
Add tool for converting unprivileged container to privileged one #1099
improve bash completion #1236
Disabling link-local IPv6 on veth interfaces #1414
Docs about Template Scripts #1459

Here are the other ones I’ve considered, but seem difficult/require a stronger understanding of how LXC works.
Complete build options for Pthread API #84
lxc.mount.entry should support all the bdev modules #195
support variables in config files #240
Allow selecting the default backing store in global configuration file #318
allow default bdev to be set #328
ubuntu-cloud template image cache can get stale due to not saving release date #381
support multiple lxc paths by default #405
Machine readable output #726
LXC should provide a way to play with shared mount points #810
Introduce lxc.storage..* type configuration for container storage #1179
Loop mounted rootfs fails when source is read only. #1239
ZFS unprivileged ephemeral copy: Invalid argument - Overlayfs #1515

I would prefer something that would take about a month’s worth of time max, keeping in mind I have class and work part time up to 20 hours a week. I’ve been googling Open Source development tips and guides/best practices, but if you have any resources that you find particularly helpful please let me know :slight_smile:

The first issues you mentioned all sound fine from my perspective. The template scripts one not so much since we plan on deprecating the templates in favour of something more suitable.

However, I do have one thing on my list of things to do before releasing LXC 3.0 which seems like a nice task to start. All the lxc C binaries found in the tools/ subfolder in the LXC repo need to be moved to only use API functions. That task is a bigger one and not suitable for your time-frame but as part of this general rework we need to first remove all references to internal logging functions from the binaries. Specifically, this entails:

  • getting rid of all calls to lxc_log_define() calls in each binary
  • replacing all logging functions in those binaries with appropriate {f}printf calls:
    • internal logging functions include the following: TRACE(), DEBUG(), NOTICE(), INFO(), WARN(), ERROR(), SYSERROR(), CRIT(), ALERT(), FATAL()

Preferably, you would have a separate commit for each binary.

If your are done with this work and still have time left and still are interested in doing development I can guide you in moving specific binaries (or just one depending on how much time is left) from using internal symbols to using the API only. This likely involves some more interesting work as I expected that sometimes new helpers need to be written. We can negotiate on the complexity of the task once you’ve done the logging-work I mentioned above. Of course, these are just suggestions so don’t feel pressured to do any of that work.

Please note:

  • Please, do not rework lxc_init.c. This binary simply needs to be moved out of the tools/ subfolder and into the src/lxc/ subfolder where all liblxc files are located.
  • Please sign-off all your commits with git commit -s. The Signed-off-by-line should include your clear name and valid email address under which you can be reached. This is the same protocol as is used in Linux kernel development and nothing special or LXC specific.

Oh, and could you tell me when you start working on this. :slight_smile:

@brauner I’ve started looking into the logging stuff, but have not changed any code yet. I’ve got to prioritize something else for the next two weeks, but after that I’ll be a lot more free time to get through all these files.

First off, in that folder there are no lxc_log_define() calls, just the prototype at the top of the file, is that what you’d like me to remove? Next, to be clear you’d like TRACE(), DEBUG(), NOTICE(), INFO(), and WARN() to be printf() calls, and ERROR(), SYSERROR(), CRIT(), ALERT(), and FATAL() to be fprintf(stderr, ...)?

I would work on one *.c file containing these per commit to the master branch (excluding lxc_init.c), and sign off each with my contact info. For lxc_init.c, I need to mv lxc_init.c ../, adjust Makefile.am in that same src/lxc directory, and make sure it compiles.

Have I captured the scope of the work correctly? Also, if I have questions, what times (if any) are you active on the LXC freenode IRC? Or is there an alternate form of communication you’d prefer outside the forums? Looking forward to working with you :slight_smile:

To reach us, #lxc-dev on freenode is probably the best for development questions (#lxcontainers is mostly for support these days). Christian is based in Germany and Serge and I are in North America so we usually have pretty good time coverage and all are connected 24/7 so will see any message even if we’re not around.

@brauner I’ve started looking into the logging stuff, but have not changed any
code yet. I’ve got to prioritize something else for the next two weeks, but
after that I’ll be a lot more free time to get through all these files.

That’s fine with me.

First off, in that folder there are no lxc_log_define() calls, just the
prototype at the top of the file, is that what you’d like me to remove? Next,

Yes, that’s exactly what needs to go.

to be clear you’d like TRACE(), DEBUG(), NOTICE(), INFO(), and
WARN() to be printf() calls, and ERROR(), SYSERROR(), CRIT(),
ALERT(), and FATAL() to be fprintf(stderr, ...)?

Yes. I’ll leave you some freedom here. If you come up with a nice macro
involving fprintf() that’s fine with me. You can change a single binary first
and then make a PR we can discuss.

I would work on one *.c file containing these per commit to the master branch
(excluding lxc_init.c), and sign off each with my contact info. For
lxc_init.c, I need to mv lxc_init.c ../, adjust Makefile.am in that same
src/lxc directory, and make sure it compiles.

Yep, sounds like you got the gist. :slight_smile:

Have I captured the scope of the work correctly? Also, if I have questions,
what times (if any) are you active on the LXC freenode IRC? Or is there an
alternate form of communication you’d prefer outside the forums? Looking
forward to working with you :slight_smile:

Well, let’s say I’m on irc a lot. Since you’re doing development work it’s a
good idea to join #lxc-dev. There you can ask development questions.

Thanks!

Great! This gives me some good direction.

One other thing, I feel like the following issue might line up with the work I’m set to do with the refactoring of the error API calls.

Would you agree? I feel like it could be a natural extension of the work I’d be doing, although I’m sure there are more errors than just in the tools directory I’d be working in. Was any consensus ever made on the preferred method outside of the existing comments? Error handling seems to me like it’d be a good way to learn about the code base as well. Let me know if my assessment is correct.

Oh yeah, we can definitely look into this once you’re done with the binaries. That be a good thing and likely also involves some internal design work what this should look like.

I made the first PR for review before I do the rest of the tools directory:

Let me know if you’d like me to change anything.

1 Like

@brauner, I expect to finish the refactoring of the tools directory later today, and submit the PRs for them all for review. Since I’m close, I was hoping you could give me some more advice on the direction of how we should handle issue #723. I’ve read over the existing comments, and what I’m currently thinking is creating that lxc_error.h in the lxc/src/ directory and adding stuff with macros for like #define ELXCIDMAP 1 /* Indicates missing or invalid id mapping. */. To find them all, I’d grep for all the fprintf(), ERROR(), SYSERROR(), FATAL() etc and try to come up with a macro that fits the error.

As I come up with the macros, I was also thinking we could have a variable that uses a bit for each of the macros, and then just extract the bits to figure out the errors similar to how signals/interrupts are handled. This variable would be added to the struct current_config. These would be set right before all of the exit(EXIT_FAILURE)s. Looking forward to your feedback :slight_smile:

Right, once upon a time I was convinced that the custom LXC errno values would be beneficial I actually don’t think that they are anymore. I like @hallyn’s suggestion which is basically to categorize the errors into non-leaf and leaf errors ( https://github.com/lxc/lxc/issues/723#issuecomment-166383277 ) and to keep a variable size list of those errors. Let’s rope him and @stgraber in here. :slight_smile:

Fine with me. I’ve never really looked at the them anyway.

Alright I can work towards that. I have a couple questions though, and would appreciate any more outlining of the process for error handling you’d be willing to provide. I understand the concept of leaf-non leaf, but not necessarily how I’d apply that to deciding which errors are which. Does it basically mean that leaf errors end up with an exit(EXIT_FAILURE) call? And non leaf errors continue execution?

For the variable sized list, I’d just store the pointer and then malloc each time the size changes and copy the old buffer if necessary correct? Is there a better way to do it than constantly malloc/freeing on non-leaf errors?

I’m assuming I’d start in the tools/ directory, but is the goal for me to transfer everything that is being printed by the fprintfs, into the new error struct that gets selectively dumped when it encounters a leaf error? Everything should still be printing/exiting as it currently is now, it just needs to be stored in the error_struct so you might be able to follow a path of non-leaf to leaf errors? Am I understanding this correctly?

Perhaps I should ask @hallyn for clarification on the process since they proposed it.

Also, this time, so I don’t make 18 PRs and break Jenkins (sorry about that by the way), should I just create 1 branch, 1 PR, and make a one commit per file all in the same PR? Or would you still prefer the many PRs approach?

Final aside: there are a couple of files in the tools/ directory that use perror(). How should I incorporate those (if at all) into this error handling?

Looking forward to working through this :slight_smile:

I agree, we should ask @hallyn about this.

How to determine which are leaf and non-leaf issues might be unsolvable :slight_smile: But one approach would be to just say - anything in liblxc is non-leaf. leaf error is what the caller issues. So for instance if the caller is trying to create a container, and it fails at opening the container config file inside a directory it created, we would have a leaf error for “failed to create container $name”, an internal error saying “failed to create config”, and a deeper internal error saying “failed open(/var/lib/lxc/containers/c1/config, w, 0755)”.