Showing posts with label yast. Show all posts
Showing posts with label yast. Show all posts

Monday, April 27, 2015

SUSE HackWeek12 - YaST: Replacing Travis by Jenkins

Replacing Travis by Jenkins for YaST


I decided to look at the possible Travis replacement as my Hackweek 12 project.

Currently we use both Travis and Jenkins for continuous integration in YaST projects. Unfortunately there are many disadvantages with Travis which require additional work or limit us what we can run in a Travis job. See the hackweek project for the pros and cons summary.

The biggest Travis disadvantage is that the builds are run in a Ubuntu 12.04 system which is 3 years old and it's very difficult to find a recent compiler, Ruby interpreter, libraries,... for it. 

The Jenkins advantage is that it runs on our server and we can run the latest openSUSE very easily and avoid the problem with porting YaST packages to Ubuntu and backporting the development tools.

Jenkins Plugins


I found out that there are several Jenkins plugins which could be used to replace Travis with Jenkins:

You can install the plugins in your Jenkins instance like this:
  • Login into Jenkins
  • Go to Manage Jenkins -> Manage Plugins
  • In the tab Available select plugins GitHub Plugin, GitHub pull request builder plugin and Embeddable Build Status Plugin and install them

Configuring the GitHub Plugin

  • Generate a new access token at GitHub, select public_repo and repo:status. If you want to allow automatic webhook setup select write:repo_hook (you can add/remove the permissions later).
  • Add the token to Jenkins -> Manage Jenkins -> Configure System -> GitHub Web Hook section -> OAuth token field
  • Put the same token to the "GitHub Pull Request Builder" section, "Access Token" filed.

Create a new Jenkins job for building commits (pull requests are handled separately):

  • Select Freestyle project
  • Put the Github URL (https://github.com//) to the GitHub project filed
  • In the Source Code Management section select Git and put the same URL here
  • Make Branch Specifier field empty to build all branches
  • In the Build Triggers section - check Build when a change is pushed to GitHub
  • Add Build Step -> select Set build status to "pending" on GitHub commit
  • Add post-build action - Set build status on GitHub commit
  • Configure the other parameters of the build as needed
See more details here.

Configuring the GitHub Pull Request Builder

  • Add the created GitHub token to Jenkins -> Manage Jenkins -> Configure System -> GitHub Pull Request Builder section

Create a new job for building pull requests:

  • Select Free style project
  • Put the Github URL (https://github.com//) to the GitHub project filed
  • In the Source Code Management section select Git and put the same URL here
  • In Advanced option set Name to origin and Refspec to +refs/pull/*:refs/remotes/origin/pr/*
  • Set Branch Specifier to ${sha1}
  • In the Build Triggers section - check GitHub Pull Request Builder option
  • Check Use github hooks for build triggering option
  • Set Commit Status Context to continuous-integration/jenkins-ci/pr (or something like that to have a different ID for pull requests and avoid clashing with the GitHub plugin configured in the previous step
Set Admins or white list users so you do not have to manually trigger builds for trusted developers - the plugin avoids running trusted code at your

Using Both Plugins in One Job?


I tried to use both plugins in a single job to have less jobs but it did not work form me, the pull requests were not processed at all or it did not work at all.

If you find how to solve it let me know...


Coveralls Support?


The question was whether coveralls code coverage can run also outside the Travis environment.

I found out that it is possible, you just need to set the COVERALLS_REPO_TOKEN environment variable and some other variables containing the Git branch, build number, etc... See more details here.

You need to store the token into Jenkins and set it during build.  (You can put the token directly into the .coveralls.yml file, but that's not a good idea for a public Git repository...) Fortunately there is a Jenkins plugin which helps with this, it can inject a secret in to a environment variable. The nice feature is that it can also filter the console output to make sure your password/token does not leak in the build output.


The Current State


I have created some experimental jobs to try the plugins, e.g. yast-registration-github-ci, yast-devtools-github-ci or yast-journal-github-ci.

The jobs are not ready to fully replace the Travis integration, but they work and I my plan is to continue with this project later.


TODO?


There are still many thing to solve:

  • Coveralls - pass the Git data (branch name, etc.) from Jenkis, set the  COVERALLS_REPO_TOKEN variable, make sure it's not logged in the console to avoid compromising the value
  • Find a way how to define the scripts started in Jenkins. We need to replace the .travis.yml files with something equivalent and share the common parts effectively, very likely as a shared Rake task.
  • The current Jenkins jobs use active Git polling, we should switch that to use the GitHub web hooks 
So stay tuned, I'll post updates on this topic...

Bonus Section


During the implementation I found some other interesting possibilities:


Collecting Code Metrics and Code Coverage


The RubyMetrics Jenkins plugin can be used to collect Flog code metrics and RCov code coverage statistics:



That looks nice, but the practical value is low. The code coverage can be collected by Coveralls, which can comment the changes in pull requests, and code quality can be scanned e.g. by CodeClimate which provides more details about the code and better evaluates the code quality in general. More over it offers some hint what and how to fix, not just plain numbers without any clue what's wrong with the code.

So I decided to not use them for YaST.

Writing Jenkins Plugins in Ruby


I found an interesting possibility when playing with Jenkins - it's possible to write a Jenkins plugins in Ruby! There is also an example. Maybe we could simple enhance Jenkins if needed...

Monday, September 30, 2013

Yast "New Installer" Development Started

Yast "New Installer"


The Yast team started development of "new Yast installer". It actually won't be a complete rewrite of the Yast installer, it will be rather a refreshing, refactoring and adding some enterprise features (for SLE12 - SUSE Linux Enterprise 12). But of course, these enhancements will be also present in the next openSUSE release (openSUSE-13.2, 13.1 is almost done).

We just started public discussion about it, if you have some ideas about the Yast installer just join the discussion at yast-devel mailing list.

See the announcement, more details will be published later, stay tuned...

Friday, September 2, 2011

Improved Disk Usage Estimation in YaST Installer

Disk Usage

YaST installer estimates used disk space in the final installed system. This is possible thanks to the disk usage metadata in installation repository (located in file suse/setup/descr/packages.DU.gz).

This file contains disk usage statistics for every package, so YaST needs just to sum them for all selected packages. (Actually it's slightly more complicated, the disk usage is stored per directory, so YaST/libzypp has to sum it up according to the proposed disk partitioning. Imagine you have separate /usr or /boot partition...)

The Problem

This works well, but the problem is that the final sum does not match the real value you find after installation is completed.

For example in openSUSE-12.1-M3 in default KDE installation the installer estimates this disk usage:

Free: 3.3GB
Used: 3.1GB
Total: 6.4GB

But if you install the system and check the real disk usage you will find these numbers:

# df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2       6,4G  3,7G  2,5G  61% /

So the difference between estimated and real available free space is about 800MB! That's quite a lot!

In this case it was not a problem, but if the target partition was smaller, YaST could tell that there would be e.g. 500MB free space but the installation would actually fail because of not enough free space. This problem was reported several times in Novell bugzilla, e.g. bnc#263275, bnc#495251 and more.

Improvement


So where is the extra space spent? Why it doesn't match? There are basically these reasons:

  • Files not owned by any package - the repository metadata contains just disk usage for files owned by packages (the files which are in RPMs), it doesn't and cannot know anything about files which are created at runtime outside of RPM package files.

    The files are mainly (with usual size in default installation)
    • RPM database (contains info about the installed packages): 42MB
    • Zypp cache (contains info about the configured software repositories): 38MB
    • System logs: 14MB
    • Config backup files: 10MB
    • Kernel initrd: 10MB
    • ... and many more small files, but they almost don't affect the overall size so they can be ignored
  • File system fragmentation - space is allocated in blocks, so small files effectively take more space than their total size. (ReiserFS is an exception, it supports tail joining.)
  • File system's journal - modern file systems use journaling so the file system is in consistent state after system crash or power failure. On the other hand the journal takes some space, for example default Ext3/Ext4 journal size is 128MB (but it can be smaller, depending on partition size and block size). The journal decreases the usable free space.
  • Reserved space for root user - Ext file systems by default reserve 5% space for root user. RPM explicitly checks for non-root space (even if it is running as root and could actually use the space), the reserved space also decreases the usable free space.

Current State

I have added all the above mentioned extra space into the YaST installer (except the FS fragmentation, that is hard to implement and would not significantly change the estimation.)

The most difficult task was to figure out the default journal size depending the partition size. I had to look to the respective mkfs utility sources. Some options (like reserved space) might be also set in the YaST partitioner so the space calculation has to read and check the partitioning options.

If you are interested in the implementation details the relevant commit can be found in http://lists.opensuse.org/yast-commit/2011-08/msg00377.html

Result

After patching the installer the estimated sizes (for the same installation) are:

Free: 2.6GB
Used: 3.8GB
Total: 6.4GB

This pretty matches the real disk usage mentioned above. It's not exactly the same, but it's a big improvement. And it actually will never be perfect as it will be always a guess (just more or less good).

The improvement has been submitted to Factory and will be available in openSUSE-12.1-Beta.

To Do

The only thing which is missing is Btrfs support.I'll have to check the mkfs.btrfs utility or Btrfs documentation. So far I have found out that after formatting 8GB partition using Btrfs df reports about 7.2GB free space. I have to found out how the final free space corresponds to the partition size. Moreover Btrfs supports transparent file compression, snapshots, etc. which also make the estimation more complicated...

If you have any note on this feature just add a comment to this blog post. Thank you!