Using Fog Google

Two weeks ago I started experimenting with fog and specifically with fog-google. I used fog with AWS at a previous job and wanted to see if the support for Google Cloud Platform was comparable.

I have to say the experiment was rocky. Fog has the unenviable task of trying to provide a logical unified interface to a large number of cloud providers that have different functionality and philosophies. Also, since this is Ruby, it should do that while maintaining the principle of least surprise. That is probably an impossible task. That said I was able to create a VM using Compute Engine and upload a file to Cloud Storage using fog, so I know the basics work.

Authentication

There are many ways to set up authenticate using fog. I chose to use a .fog YAML file that I stored with my other dot files.

default:
  google_project: project-name
  google_client_email: service-account-email-address
  google_json_key_location: your-key-location-here

The only tricky bit is figuring out what the google_client_email key is. This is the auto-generated service account id that looks like an email address. You can get this from the service account page in the cloud console. I used the default config but the .fog file allows you to have multiple configurations if you need them. I can imagine having staging, production, and dev configurations could be handy for example.

Cloud Storage

The code to upload a file to cloud storage is simple.

require "fog/google"

connection = Fog::Storage::Google.new

connection.put_bucket("pictures.thagomizer.com")

f = File.open("my_picture.jpg")

connection.put_object("pictures.thagomizer.com", "my_picture", f)

All you need to do is connect to storage, create a bucket, and then put the object you want to upload in the bucket. There are other methods you can use, but the API might not be entirely intuitive. I recommend looking at the fog storage docs to learn best practices.

Compute Engine

Creating a VM on Compute Engine with fog is a two step process. First, you create a disk, and then you create a server that uses that disk.

Here’s the code to create the disk.

require "fog/google"

COMPUTE_ZONE = "us-central1-f"
MACHINE_TYPE = "f1-micro"

connection = Fog::Compute::Google.new

disk = connection.disks.create(
  :name => "new-disk",
  :size_gb => 10,
  :zone_name => COMPUTE_ZONE,
  :source_image => "debian-8-jessie-v20161020")

puts "Creating disk"

disk.wait_for { disk.ready? }

puts "Disk ready"

Lines 1 through 6 are connecting to Google Compute Engine and setting constants that are used later. The method to create a disk takes an options hash. I am specifying the desk name, size, zone (using the constant), and the OS image. Calling this method kicks off disk creation but the disk is not necessarily ready to mount right away. So I use disk.wait_for to pause my script until the disk is ready.

Once the disk is created, I can use it when I create a new VM.

server = connection.servers.create(
  :name => "new-server",
  :zone_name => COMPUTE_ZONE,
  :disks => [disk],
  :machine_type => MACHINE_TYPE,
  :private_key_path => File.expand_path("~/.ssh/id_rsa"),
  :public_key_path => File.expand_path("~/.ssh/id_rsa.pub"),
  :user => ENV["USER"])

puts "Creating server"

server.wait_for { server.ready? }

puts "Server ready"

Just like disk creation server creation takes an options hash. I am specifying a lot more options than I did for disk creation. I am passing in the name and compute zone like I did for a disk. I also pass a disks array that contains the disk I just created. I have to specify the machine type, and I can pass in ssh keys so that I can ssh to the server once it is ready. After calling servers.create I wait for the server to be ready before exiting my script.

Conclusion

This is a super basic introduction to fog and fog-google. Fog has been around for a long time, and there are many tutorials that cover more specific scenarios. Fog-google has some rough spots but I know several folks who are actively working on it right now, and I hope to contribute some as well.