December 15, 2011

How to setup several GitHub accounts on multiple machines with separate SSH keys

Problem

So you've got a personal GitHub account, one for one client, one for another and you want to keep them all separate. How do you setup your box to clone private repositories based on which account you're using? Here's the simple guide on how to do this

Assumptions

I have set this up on Linux (Ubuntu 11.10) and Windows, but only via the Git Bash and/or Cygwin. This post will not cover how to setup and where to store SSH keys for Windows or Mac, though Mac should be fairly similar to Linux.

Setup first SSH key

I'm not going to go into depth on how to setup SSH keys, you can read more about that here. However, I will show the steps I used to get there. For first-account: (please replace "first-account" with your GitHub account)
  1. Change to your home .ssh folder
    cd ~/.ssh
    
  2. Setup your RSA key
    ssh-keygen -t rsa -f ~/.ssh/first-account-rsa -C "first-account@example.com"
    
  3. After following the directions, you should get something that looks like:
    The key fingerprint is:
    00:ff:00:cc:13:00:bb:ll:aa:hh
    
    The key's randomart image is:
    +--[ RSA 2048]----+
    |     .+   +      |
    |       = o P .   |
    |        = * *    |
    |       o = +     |
    |      o S .      |
    |     o o =       |
    |      o . E      |
    |                 |
    |                 |
    +-----------------+
    
    
  4. Open your GitHub.com account setup page, click on the "SSH Public Keys" tab.
  5. Create a new SSH key and copy the contents of ~/.ssh/first-account-rsa.pub and place into the new text field. Name it something unique so you can remember which machine you're using for your account.

    If you plan on each of your accounts needing access, open each of those accounts and add your SSH key to each account. This isn't very common, so only do this if you need to.
  6. To test, type in:
    ssh -t git@github.com
    

    As long as you do not see "access denied", you're good. You might see "failed on channel 0", this is ok.

Adding a second account

Now you should have your first account working, let's setup and add the second account.

  1. Repeat process 1-5 and stop (using the next account)
  2. Create a file named "config" in your ~/.ssh folder
    echo '' > ~/.ssh/config
    
    –or–
    touch ~/.ssh/config
    
  3. Use your favorite editor to add the configuration information for the SSH client to determine which RSA key to use:
    # first-account GitHub account
    Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/first-account-rsa # Note, this is the private key matching the .pub
    
    # second-account
    Host github-second-account  # NOTE: The host is NOT github.com, more on this further down
    HostName github.com
    User git
    IdentityFile ~/.ssh/second-account-rsa # Private key for the second account
    
    # repeat for the third and so on
    
  4. Save the file and your configuration is done

Let's look at the config file in a bit more detail. The first account is the base github.com host name, and you typically see a git URL as git@github.com:user/project.git. With your first account, you will leave this the domain the same**.

NOTE: This doesn't stop you from modifying your ~/.ssh/config file and instead of using "github.com" as your default host, setting the value to "github-first-account".

Now, for your second account, you will need to modify the URL you are using to clone the repository. This is done by changing the domain from "github.com" to "github-second-account". For example: git@github-second-account:user/project.git

Summary

You should now have the setup to clone and modify code for multiple accounts on the same machine. Repeat this process for each machine you would like to make available to GitHub.

December 3, 2011

Spring 3.1 + Cloud Foundry + Local Development

This post will help you build a Spring 3.1 web application using MongoDB on Cloud Foundry.  In addition to pushing to Cloud Foundry, you will also be able to develop in your local environment with a MongoDB instance.

Goals
The goals for this blog posting will be to build the application locally, then publish to your local Cloud Foundry instance.  We will utilize the Cloud Foundry runtime, and the new Spring Profiles

Setup
  1. Create an account with Cloud Foundry (https://www.cloudfoundry.com/micro)
  2. Follow instructions to setup your own Micro Cloud
    1. I use VMWare's player
    2. Verify "vmc info" that the micro cloud console matches
  3. Download MongoDB (at least version 2.0)
  4. Install and be familiar with Maven 3 (http://maven.apache.org)
  5. Familiarize yourself with Spring 3.1, Spring Data and Spring MongoDB
  6. Clone or download the source (https://github.com/mike-ensor/first-cloud-app)
  7. Run the app locally with:
    mvn clean package cargo:run -DskipTests
  8. Go to http://localhost:8080/home

Profiles
New in Spring 3.1 are the environment profiles which allow a developer to activate groups of beans based on an environment parameter.  There are several "gotchas" that I've discovered, one being an undocumented ordering for beans using profiles.

Take a look at data-services.xml.  Notice how the MongoTemplate is defined before the .  This is against my intuition because the MongoTemplate takes a reference to the MongoFactory object, which is defined below the MongoTemplate definition.

The second "gotcha" came from when and where to set the parameter to enable Spring's profiles.  The documentation and blogs do not explicitly mention that the developer must specify the profile that is active.  It was implied by the documentation that "default" was active by default, but this is not true.  In order for the default profile to be active, I added it as a system property in my cargo settings.  (as long as it is a system environment property, feel free to set it anywhere or any way you'd like).  Take a look at the pom.xml file around line 40 for the local Maven property and then around line 253 for the environment variable to be set.

Local development vs. Cloud Development
One of the main goals I had for interacting with Cloud Foundry is that I wanted a local development environment to speed up and ease development and reduce complexity with debugging.  Notice that in data-services.xml there is a "cloud" profile and a "default".  The point of the "default" profile is to have beans that are constructed when on a local environment.  You can see that there are two definitions of MongoFactory, one using Spring Data MongoDB's XML namespace and one using CloudFoundry Runtime's namespace.  I am not going to cover why these work the way they do, so if you'd like information, refer to http://blog.springsource.org/2011/04/12/cloud-foundry-for-spring-developers/ and http://blog.springsource.org/2011/11/09/using-cloud-foundry-services-with-spring-applications-part-3-the-cloud-namespace/

Pushing to Cloud Foundry
Now that you have a local running instance of the webapp, you will notice that the artifact is called "first-cloud-app.war", which you can find in the "/target" folder.  This is a problem when pushing to the Cloud Foundry instance since the name cannot contain any non-alpha characters.  Cloud Foundry's vmc tool is built from the VCAP open source project that is responsible for the open source PaaS services.  Another PaaS service includes App Fog, which allows you to basically use the same commands, but replace "vmc" for "af".  Both services fall victim to the naming problem.

In order to get around the naming problem, I have created a Maven profile cloud that builds the WAR artifact as "mikeensor.war".  Please change this to match your application's name since you won't have the user/password to publish (or the DNS) to publish to my micro instance.  The name will need to fit into the URL pattern http://<applicationname>..cloudfoundry.me.

To publish to your local cloud foundry micro instance, goto the root folder and type the following.  (this is assuming your micro instance is running and there are no "red" errors.

mvn clean package -Pcloud
vmc push <application name> -path target/

(if you have already pushed before, you will need to type:
vmc update <application name> -path target/

Note: It is possible to use the Maven Plugin for Cloud Foundry, however, I have still not been able to get it to work without changing the name of the artifact.

Enabling and connecting to services
You must create a service(s) so that your application can bind to the data source.  The VCAP (vmc) application handles how the configuration works when loading your application into Cloud Foundry.  It does this via an environment variable that is consumed in the namespaced configuration element.

In my example, I created a MongoDB service by typing:
vmc create-service mongodb --name <what you want to call your instance>

I named mine "second" (because I had created a first) and you will see that in data-services.xml the cloud XML configuration refers to the name of the service.
 
Note that if you have multiple MongoDB instances, you will need to do some Spring configuration (@Qualifier) when you want to use different instances.  This is not covered by this blog posting.

Now you will need to "bind" the service to your application.  This is done by typing:
vmc bind-service <name above> <application name>


Testing it out
You should be able to goto http://..cloudfoundry.me/home (example: http://mikeensor.mikeensor.cloudfoundry.me/home)

Congratulations!  You should have not only successfully deployed to Cloud Foundry (micro instance), bound to a MongoDB instance, but should be able to run in your local environment too!  As I get time, I will try to add in more detailed features such as multiple types of storage and post other "gotchas" as I find them.