blob: df7d3c15cedce75974323125c380618bd6f7b89f [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
require 'rubygems'
require 'profitbricks'
module Deltacloud
module Drivers
module Profitbricks
class ProfitbricksDriver < Deltacloud::BaseDriver
define_hardware_profile('default') do
cpu 1..48, :default => 1
memory (1..196*4).collect { |i| i*256 }, :default => 1024
storage 20..2048, :default => 50
architecture 'x86_64'
end
def images(credentials, opts = {})
new_client(credentials)
results = []
safely do
#get all HDD images - filter by HDD, because only HDD images can be attached to a storage
results = ::Profitbricks::Image.all.select { | img | img.type == 'HDD'}.collect do | img |
Image.new(
:id => img.id,
:name => img.name,
:description => "CPU Hot-Plugging: #{img.cpu_hotpluggable}, Region: #{img.region}, Os: (#{img.os_type}), Type: #{img.type}",
:owner_id => credentials.user,
:state => 'AVAILABLE',
:architecture => 'x86_64',
)
end
end
# Add hardware profiles to each image
profiles = hardware_profiles(credentials)
results.each { |img| img.hardware_profiles = profiles }
filter_on( results, opts, :id, :region, :name)
end
def realms(credentials, opts = {})
new_client(credentials)
results = []
safely do
datacenters = if opts[:image] != nil
::Profitbricks::DataCenter.all.select { |dc| opts[:image].description.include? dc.region }
else
::Profitbricks::DataCenter.all
end
results = datacenters.collect do |data_center|
convert_data_center(data_center)
end
end
filter_on(results, :id, opts)
end
def instances(credentials, opts = {})
new_client(credentials)
results = safely do
if opts[:storage_id]
storage = ::Profitbricks::Storage.find(:id => opts[:storage_id])
::Profitbricks::DataCenter.find(:id => storage.data_center_id).servers.collect do |s|
convert_instance(s, credentials.user)
end
else
::Profitbricks::Server.all.collect do |s|
convert_instance(s, credentials.user)
end
end
end
filter_on(results, opts, :id, :state, :realm_id)
results
end
def create_instance( credentials, image_id, opts)
new_client(credentials)
params = {}
storage = nil
server = nil
safely do
#Create storage first
if opts[:hwp_storage]
params[:name] = "Storage#{rand(1000)}"
params[:size] = opts.delete("hwp_storage")
params[:mount_image_id] = opts.delete("image_id")
if opts[:realm_id]
params[:data_center_id] = opts[:realm_id]
end
storage = convert_storage(::Profitbricks::Storage.create(params))
end
#Create instange
opts.delete("hwp_id");
opts[:name] = opts.delete('name');
opts[:name] = opts[:name] == "" ? "Sever#{rand(1000)}" : opts[:name]
opts[:ram] = opts.delete("hwp_memory")
opts[:cores] = opts.delete("hwp_cpu")
opts[:availability_zone] = "AUTO"
opts[:internet_access] = true
opts[:lan_id] = "1"
if storage.respond_to?('id')
opts[:boot_from_storage_id] = storage.id
end
opts[:data_center_id] = opts.delete("realm_id")
if opts[:data_center_id] == nil && storage.respond_to?('realm_id')
opts[:data_center_id] = storage.realm_id
end
server = convert_instance(::Profitbricks::Server.create(opts), credentials.user)
end
server
end
def reboot_instance( credentials, instance_id )
new_client(credentials)
safely do
server = ::Profitbricks::Server.find(:id => instance_id)
server.reset
end
end
def stop_instance( credentials, instance_id )
new_client(credentials)
safely do
server = ::Profitbricks::Server.find(:id => instance_id)
server.stop
end
end
def start_instance( credentials, instance_id )
new_client(credentials)
safely do
server = ::Profitbricks::Server.find(:id => instance_id)
server.start
end
end
def destroy_instance( credentials, instance_id )
new_client(credentials)
safely do
server = ::Profitbricks::Server.find(:id => instance_id)
server.delete
end
end
def storage_volumes( credentials, opts = {} )
new_client(credentials)
results = safely do
if opts[:id]
[convert_storage(::Profitbricks::Storage.find(:id => opts[:id]))]
else
::Profitbricks::DataCenter.all.collect do |data_center|
(data_center.storages || []).collect do |storage|
convert_storage(storage)
end.flatten
end.flatten
end
end
results
end
def create_storage_volume(credentials, opts = {})
new_client(credentials)
result = nil
params = {}
safely do
opts[:size] = opts.delete("capacity") || 1
opts[:data_center_id] = opts.delete("realm_id") unless (opts["realm_id"].nil? || opts["realm_id"].empty?)
opts[:name] = opts.delete("name") || "Storage#{rand(1000)}"
opts.delete("commit")
opts.delete("snapshot_id")
opts.delete("description")
result = convert_storage(::Profitbricks::Storage.create(opts))
end
result
end
def destroy_storage_volume(credentials, opts = {})
new_client( credentials )
safely do
storage = ::Profitbricks::Storage.find(:id => opts[:id])
storage.delete
end
end
def attach_storage_volume( credentials, opts = {} )
new_client( credentials )
safely do
storage = ::Profitbricks::Storage.find(:id => opts[:id])
storage.connect(:server_id => opts[:instance_id])
end
end
def detach_storage_volume(credentials, opts = {})
new_client( credentials )
safely do
storage = ::Profitbricks::Storage.find(:id => opts[:id])
storage.disconnect(:server_id => opts[:instance_id])
end
end
def create_load_balancer(credentials, opts={})
new_client(credentials)
safely do
load_balancer = ::Profitbricks::LoadBalancer.create(:name => opts[:name], :data_center_id => opts[:realm_id])
load_balancer(credentials, :id => load_balancer.id)
end
end
def load_balancer(credentials, opts = {})
new_client(credentials)
safely do
load_balancer = ::Profitbricks::LoadBalancer.find(:id => opts[:id])
data_center = ::Profitbricks::DataCenter.find(:id => load_balancer.data_center_id)
convert_load_balancer(load_balancer, data_center)
end
end
def load_balancers(credentials, opts = {})
new_client(credentials)
safely do
::Profitbricks::DataCenter.all.collect do |data_center|
(data_center.load_balancers || []).collect do |lb|
convert_load_balancer(lb, data_center)
end.flatten
end.flatten
end
end
def lb_register_instance(credentials, opts={})
new_client(credentials)
safely do
load_balancer = ::Profitbricks::LoadBalancer.find(:id => opts[:id])
server = ::Profitbricks::Server.find(:id => opts[:instance_id])
load_balancer.register_servers([server])
load_balancer(credentials, :id => opts[:id])
end
end
def lb_unregister_instance(credentials, opts={})
new_client(credentials)
safely do
load_balancer = ::Profitbricks::LoadBalancer.find(:id => opts[:id])
server = ::Profitbricks::Server.find(:id => opts[:instance_id])
load_balancer.deregister_servers([server])
load_balancer(credentials, :id => opts[:id])
end
end
def destroy_load_balancer(credentials, id)
new_client(credentials)
safely do
load_balancer = ::Profitbricks::LoadBalancer.find(:id => id)
load_balancer.delete
end
end
def firewalls(credentials, opts={})
new_client(credentials)
safely do
::Profitbricks::Server.all.collect do |server|
(server.nics || []).collect do |nic|
convert_firewall(nic.firewall) if nic.firewall
end.flatten.compact
end.flatten
end
end
def create_firewall(credentials, opts={})
# TODO is this even possible?
raise "Error"
end
def delete_firewall(credentials, opts={})
new_client(credentials)
safely do
firewall = ::Profitbricks::Firewall.find(:id => opts[:id])
firewall.delete
end
end
def create_firewall_rule(credentials, opts={})
new_client(credentials)
safely do
firewall = ::Profitbricks::Firewall.find(:id => opts[:id])
rules = opts[:addresses].collect do |source_ip|
::Profitbricks::FirewallRule.new({
:protocol => opts[:protocol],
:port_range_start => opts[:port_from],
:port_range_end => opts[:port_to],
:source_ip => source_ip.split('/').first,
:target_ip => '0.0.0.0'
})
end
firewall.add_rules(rules)
end
end
def delete_firewall_rule(credentials, opts={})
new_client(credentials)
safely do
::Profitbricks::Firewall.find(:id => opts[:firewall]).rules.select { |rule|
rule.id == opts[:rule_id]
}.first.delete
end
end
def address(credentials, opts={})
new_client(credentials)
servers = safely do
::Profitbricks::Server.all()
end
convert_ip_block(find_ip_block_by_ip(opts[:id]), servers)
end
def addresses(credentials, opts={})
new_client(credentials)
safely do
servers = ::Profitbricks::Server.all()
::Profitbricks::IpBlock.all().collect do |ip_block|
convert_ip_block(ip_block, servers)
end
end
end
def create_address(credentials, opts={})
new_client(credentials)
safely do
convert_ip_block(::Profitbricks::IpBlock.reserve(1))
end
end
def destroy_address(credentials, opts={})
new_client(credentials)
safely do
ip_block = find_ip_block_by_ip(opts[:id])
ip_block.release
end
end
def associate_address(credentials, opts={})
new_client(credentials)
safely do
ip_block = find_ip_block_by_ip(opts[:id])
server = ::Profitbricks::Server.find(:id => opts[:instance_id])
server.nics.first.add_ip(opts[:id])
convert_ip_block(ip_block)
end
end
def disassociate_address(credentials, opts={})
new_client(credentials)
safely do
ip_block = find_ip_block_by_ip(opts[:id])
servers = ::Profitbricks::Server.all()
result = convert_ip_block(ip_block, servers)
server = ::Profitbricks::Server.find(:id => result.instance_id)
server.nics.first.remove_ip(opts[:id])
result
end
end
def network_interfaces(credentials, opts = {})
new_client(credentials)
safely do
::Profitbricks::Server.all.select { | server| server.nics!=nil}.collect do |server|
server.nics.collect do |nic|
convert_network_interface(nic)
end.flatten
end.flatten
end
end
def create_network_interface(credentials, opts={})
new_client(credentials)
safely do
opts[:server_id] = opts.delete("instance");
opts[:lan_id] = opts[:network].nil?? "1" : opts.delete("network");
opts[:name] = opts[:name].nil?? "eth#{rand(100)}" : opts.delete("name");
convert_network_interface(::Profitbricks::Nic.create(opts))
end
end
def destroy_network_interface(credentials, nic_id)
new_client(credentials)
safely do
nic = ::Profitbricks::Nic.find({:id => nic_id})
nic.delete
end
end
def networks(credentials, opts = {})
new_client(credentials)
safely do
::Profitbricks::Server.all.select { | server| server.nics!=nil}.collect do |server|
server.nics.collect do |nic|
Network.new({
:id => nic.lan_id,
:name => "Lan #{nic.lan_id} (Datacenter #{server.data_center_id})"
})
end.flatten
end.flatten
end
end
define_instance_states do
start.to( :pending ) .automatically
pending.to( :running ) .automatically
stopped.to( :running ) .on( :start )
stopped.to( :stopped ) .on( :destroy )
running.to( :running ) .on( :reboot )
running.to( :stopping ) .on( :stop )
stopping.to(:stopped) .automatically
stopping.to(:finish) .automatically
stopped.to( :finish ) .automatically
end
#
### Private declarations
#
private
def convert_instance(server, user_name)
inst = Instance.new(
:id => server.id,
:realm_id => server.data_center_id,
:owner_id => user_name,
:description => server.name,
:name => server.name,
:state => convert_instance_state(server),
:architecture => 'x86_64',
:image_id => find_instance_image(server),
:instance_profile => InstanceProfile::new('default'),
:public_addresses => server.public_ips,
:private_addresses => server.private_ips,
:username => nil,
:password => nil,
:storage_volumes => convert_instance_storages_volumes(server)
)
inst.actions = instance_actions_for( inst.state )
inst
end
def convert_instance_state(server)
state = server.respond_to?('virtual_machine_state')? (server.provisioned?? server.virtual_machine_state : server.provisioning_state) : "ERROR"
case state
when /INPROCESS/
"PENDING"
when /SHUTOFF/
"STOPPED"
when /SHUTDOWN/
"STOPPED"
when /PAUSED/
"STOPPED"
when /INACTIVE/
"STOPPED"
when /CRASHED/
"ERROR"
when /NOSTATE/
"ERROR"
when /ERROR/
"ERROR"
when /RUNNING/
"RUNNING"
else
"UNKNOWN"
end
end
def convert_instance_storages_volumes(server)
return [] if server.connected_storages.nil?
server.connected_storages.collect { |s| {s.id => nil} }
end
def find_instance_image(server)
return nil if server.connected_storages.nil?
server.connected_storages.each do |s|
# FIXME due to the api not returning the bootDevice flag we just use the first image we find
storage = ::Profitbricks::Storage.find(id: s.id)
return storage.mount_image.id if storage.mount_image
end
return nil
end
def convert_storage (storage)
result = StorageVolume.new(
:id => storage.id,
:name => storage.respond_to?(:name) ? storage.name : 'unknown',
:description => "Capacity: #{storage.size}GB",
:state => convert_storage_state(storage),
:capacity => storage.size,
:realm_id => storage.data_center_id,
:actions => [:attach, :detach, :destroy]
)
if storage.respond_to?("server_ids")
result.instance_id= storage.server_ids
end
if storage.respond_to?("creation_time")
result.created = storage.creation_time
end
result
end
def convert_storage_state(storage)
state = storage.respond_to?('provisioning_state')? storage.provisioning_state : "ERROR"
case state
when /INPROCESS/
"PENDING"
when /INACTIVE/
"ERROR"
when /ERROR/
"ERROR"
when /AVAILABLE/
"AVAILABLE"
else
"UNKNOWN"
end
end
def convert_data_center(data_center)
Realm.new(
:id => data_center.id,
:name => "#{data_center.name} (#{data_center.region})",
:state => 'AVAILABLE', # ProfitBricks doesn't return the states when calling getAllDataCenters()
:limit => :unlimited
)
end
def convert_load_balancer(lb, dc)
realms = []
balancer = LoadBalancer.new({
:id => lb.id,
:name => lb.name,
:created_at => lb.creation_time,
:public_addresses => [lb.ip],
:realms => [convert_data_center(dc)],
:instances => lb.balanced_servers ? lb.balanced_servers.collect { |s| convert_instance(s, "") } : [],
:listeners => []
})
balancer
end
def convert_network_interface(nic)
net = NetworkInterface.new({
:id => nic.id,
:name => nic.name,
:state => "UP",
:instance => nic.server_id,
:network => nic.lan_id,
:ip_address => nic.ips.first
})
end
def convert_firewall(firewall)
Firewall.new({
:id => firewall.id,
:description => "Firewall of #{firewall.nic_id}",
:owner_id => firewall.nic_id,
:rules => firewall.rules ? firewall.rules.collect { |r| convert_firewall_rule(r)} : []
})
end
def convert_firewall_rule(rule)
FirewallRule.new({
:id => rule.id,
:allow_protocol => rule.protocol,
:port_from => rule.port_range_start,
:port_to => rule.port_range_end,
:sources => [{:type => "address", :family=>"ipv4",
:address=>rule.source_ip,
:prefix=>''}],
:direction => 'ingress',
})
end
def convert_ip_block(ip_block, servers = [])
server = servers.select do |server|
server.public_ips.include? ip_block.ips.first
end.first
Address.new({
:id => ip_block.ips.first,
:instance_id => server ? server.id : nil
})
end
def find_ip_block_by_ip(ip)
::Profitbricks::IpBlock.all().each do |ip_block|
return ip_block if ip_block.ips.include? ip
end
end
def new_client(credentials)
client = nil
safely do
::Profitbricks.configure do |config|
config.username = credentials.user
config.password = credentials.password
end
end
end
exceptions do
on /Failed to authenticate/ do
status 401
end
on /Error/ do
status 500
end
end
end
end
end
end