Monday, June 27, 2016

Jenkins And Artifactory Npm Configuration

I had a need to setup Npm (Node Package Manager) on Jenkins to be able to publish/unpublish packages to Artifactory.  Using the Pivotal Cloud Foundry (PCF) tiles for Cloudbees Jenkins and Artifactory, I was able to configure this integration.  Let's start on the Artifactory configuration.

Artifactory Configuration
JFrog has a great guide to get you started with setting up a private Npm repository (repo).  Basically, you want to setup three repos; local, remote, and virtual.  The difference between them are the following:

  • Local - This repo will house all of your custom packaged artifacts.
  • Remote - This repo will proxy out to a public repo like https://registry.npmjs.org to pull down any dependencies. 
  • Virtual - This repo will house both the local and remote repo that way you can access both private and public artifacts using only one URL.
For publishing packages, we will use the local Npm repo and we will want to lock down who has access to perform a publish or unpublish.  One way to lock this access down is to only allow your CI/CD pipeline to perform these actions.  This fact is where the Jenkins and Artifactory integration kicks in.  Setting up a Jenkins publish user in Artifactory and using that same user inside of the Artifactory plugin for Jenkins is one suggested way.  Currently, Artifactory does not support the "npm adduser" command.  That being the case, we have to manually create a user inside of Artifactory for authentication.

For this example, an Artifactory user called JenkinsPublish was created.  This service account user has been granted the manage rights to the npm-local repository.  Basically, this user can create, delete, and update artifacts in this repo.

Now that the user has been created in Artifactory, we need to get the npm credentials to authenticate against Artifactory.  We can run a curl command against the Artifactory API to return these credentials.  An example of the command is below.

[user@linux]$ curl -uJenkinsPublish:password "http://server/artifactory/api/npm/auth"

Here is an example of the what will be returned.

_auth = ZWu4dkjSSDFKJLHUfghHJKHHJKLLYWRtaW46e0RFU2VkZX1u0=
email = fake@fake.com
always-auth = true

One thing to make sure is that the service account user has an email address in the profile.  Even if it is a non-functioning email address, it is needed for authentication to work.  Keep this information, it is what is needed to populate the .npmrc file.  I will discuss that file in the Jenkins configuration section.

Jenkins Configuration
For Jenkins, the npm commands are going to be run from the Jenkins slave/s that were deployed during the tile installation.  You will need to make sure that Node.js has been installed on the Jenkins slave/s.  Also, the Artifactory plugin needs to be installed on your Jenkins master and points to your local Artifactory server instance with the service account for Jenkins as the authenticated user.

Now that Node.js has been installed, we need to create a .npmrc file in the home directory of the VCAP user.  For the PCF Jenkins tile deployment, the VCAP user runs all of the jobs inside of Jenkins.  So SSH into the Jenkins slave as the vcap user and navigate to your home directory: /home/vcap/

Once you are there, create a file called .npmrc and add the following lines to the file.

_auth="ZWu4dkjSSDFKJLHUfghHJKHHJKLLYWRtaW46e0RFU2VkZX1u0="
always-auth=true
email=fake@fake.com
registry=http://server/artifactory/api/npm/npm-virtual/

The lines consist of the results of the curl command that you ran earlier.  But make sure you add quotes around the _auth line and take out any spaces before or after the = sign.  The registry line is the default registry when looking up dependencies.  Make sure to change "server" to your Artifactory URL.

After the file has been created, make sure the file has the correct permissions: the owner set to vcap and the group set to vcap with a mode of 600.

Testing Jenkins/Artifactory Integration
I found a great GitHub project, tutorial-artifactory-npm, that can be used to test this integration.  It is a simple project that has a package.json file in it.  You can clone the project to your code repository that is integrated with Jenkins so the files are available in your Jenkins workspace.  Here are the steps to run it.

  1. Create a new Jenkins Freestyle job.
  2. Make sure to check the option to add the Node.js installation into your PATH.
  3. Target your code repository with the cloned project.
  4. Create a build step that runs a script with the following lines in it.
    1. cd test-npm-publish
    2. npm publish --registry http://server/artifactory/api/npm/npm-local/
After building this job, you will now have an artifact called test-npm-publish.0.0.1 inside of the Artifactory npm-local repo.

Advanced Artifactory Configuration - Npm Scope Packages
For publishing Npm scope packages into Artifactory, you need to update the Tomcat configuration to allow encoded slashes or you will receive HTTP 400 errors during the publish.  

For the Artifactory tile in PCF, there are two Artifactory nodes that have a Tomcat instance on each.  The file you need to update is the catalina.properties file on each server.  The file is located in the following spot:

/var/vcap/packages/artifactory/tomcat/conf/catalina.properties

You will need to add the following line to this file.

org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

Once that line is added, just restart the Artifactory services, monit restart all.  

Artifactory Troubleshooting
One other issue I ran into when deploying this configuration was that the Artifactory service would restart during an npm unpublish command.  Of course, this fact is not really good for an environment.  I found when digging into the logs that Tomcat was restarting the Artifactory instance after an npm unpublish.  It was doing the restart due to thinking a memory leak was happening so it was going to restart the app to stop the memory leak.  

Looking at the current configuration of the Artifactory nodes, the servers only had 4 GB of memory each (default tile configuration).  I increased the memory to 8 GB of memory each and applied changes to the deployment.  Performing the npm unpublish no longer caused the service restart after memory was added.

Summary
Hopefully, you can start using Jenkins for npm builds and publishing to Artifactory.  

Make sure to capture the customization to these tiles in case you upgrade these PCF tiles.  During an upgrade or redeployment, these customizations could potentially disappear.  In a future blog post, I will go over how this problem can be solved using Ansible.

~RRRII

1 comment:

  1. GitHub is hosting some really amazing projects and I think this one is going to take them really far too. Lets see what happens and I hope that they do go far.

    ReplyDelete