Community

Profitbricks Ruby SDK speedup

Hi there,

I am trying to automate our servercreation with the profitbricks ruby sdk: https://github.com/profitbricks/profitbricks-sdk-ruby and I do have pretty big performance issues.

The code looks like this:

_bootvolume = {
      size: 20,
      name: 'gateway-hdd1',
      #ubuntu-15.04-server-amd64.iso
      image: '2315e831-ea7c-11e4-9660-52540066fee9',
      bus: 'VIRTIO'
  }
  bootvolume = ProfitBricks::Volume.create(datacenter.id, _bootvolume)

  _datavolume = {
      size: 100,
      name: 'gateway-hdd2',
      bus: 'VIRTIO',
      licenceType: 'LINUX'
  }
  datavolume = ProfitBricks::Volume.create(datacenter.id, _datavolume)

  _server = {
      :name => 'gateway',
      :ram => 2048,
      :cores => 1,
  }
  server = ProfitBricks::Server.create(datacenter.id, _server)

  bootvolume.wait_for(1000) { ready? }
  datavolume.wait_for(1000) { ready? }
  server.wait_for(1000) { ready? }
  bootvolume.attach(server.id)
  datavolume.attach(server.id)

  server.update(
      :bootVolume => {
          :id => bootvolume.id
      }
  )

The first wait_for runs into a timeout (the usual SDK timeout is 60 seconds, not the specified 1000 seconds => over 16 minutes).

So here my questions: - Do you have any experience in this topic? Is this creation-time "normal"? - Is there an error in my code?

I'd be glad for any hint.

Beste regards, Michael

 
  • **bold**
  • _italics_
  • `code`
  • ```code block```
  • # Heading 1
  • ## Heading 2
  • > Quote
 

Hello Michael,

I cannot speak toward whether the volume creation time is normal as I used much smaller volume sizes while building/testing the profitbricks-sdk-ruby library. Perhaps someone at ProfitBricks can chime in on that topic?

I did reply to the GitHub issue you opened. To summarize the ticket response, I plan to research and test the REST API behavior that should allow a server to be created with associated resources built and attached through a single API request. Once confirmed, I'll schedule some time to add the code and then we can begin testing parallel calls.

Thank you, Ethan

Hi Ethan, thank you very much for your replies. I'm looking forward for the changes and will let you know if there is any new information from my side.

Hello Michael,

I have updated your GitHub ticket. I have released a new gem that allows composite server creation where a server and associated volumes/nics/firewalls can all be provisioned with a single request. The ticket and repo docs have been updated with examples, but I will include an example here:

volumes = [ {name: 'server1-os', size: 10, image: '4dc4585c-505a-11e5-bfc6-52540066fee9', bus: 'VIRTIO', imagePassword: 'secretpassword'}, {name: 'server1-data', size: 5, bus: 'VIRTIO', licenceType: 'UNKNOWN'} ]
fwrules = [ {name: 'SSH', protocol: 'TCP', portRangeStart: 22, portRangeEnd: 22} ]
nics = [ {name: 'public', lan: 1, firewallrules: fwrules }, {name: 'private', lan: 2} ]

datacenter = Datacenter.get('825dee89-659a-492f-89b3-2ad5be27edee')
server = datacenter.create_server(name: 'server1', cores: 1, ram: 1024, volumes: volumes, nics: nics)

There may be a better way of doing this, but If you would like to experiment with multithreaded requests:

datacenter = Datacenter.create(name: 'Ruby SDK', location: 'us/lasdev')
datacenter.wait_for { ready? }

volumes = [ {name: 'system', size: 10, image: '6148aede-505a-11e5-bfc6-52540066fee9', bus: 'VIRTIO', imagePassword: 'secretpassword'} ]
fwrules = [ {name: 'SSH', protocol: 'TCP', portRangeStart: 22, portRangeEnd: 22} ]
nics = [ {name: 'public', lan: 1, firewallrules: fwrules} ]

puts Benchmark.measure {
  5.times do |i|
    threads << Thread.new do
      puts "Provisioning server#{i}..."
      start = Time.now
      server = datacenter.create_server(
        name: "server#{i}",
        cores: 1,
        ram: 1024,
        volumes: volumes,
        nics: nics
      )
      server.wait_for(1200) { ready? }
      finish = Time.now
      puts "Server #{server.properties['name']} provisioned in #{finish - start} seconds."
    end
  end
  threads.map(&:join)
}

Note that I am adjusting the wait_for() timeout to 20 minutes. The timeout can also be increased globally. Here are the results I encountered:

$ ruby provision.rb
Provisioning server0...
Provisioning server1...
Provisioning server2...
Provisioning server4...
Provisioning server3...
Server server0 provisioned in 84.808051 seconds.
Server server3 provisioned in 163.58047 seconds.
Server server4 provisioned in 242.067224 seconds.
Server server2 provisioned in 322.901173 seconds.
Server server1 provisioned in 404.822336 seconds.

While the composite server create requests are initiated immediately, it appears the backend is provisioning them one after another. Each build seems to take ~82 seconds. I hope this helps you or others who may be automating large deployments.

The previous comment made reference to location: 'us/lasdev' which is no longer available. Please substitute 'us/las' or another valid location.