Project

General

Profile

« Previous | Next » 

Revision ab3d6fb4

Added by Daniel Lobato Garcia about 8 years ago

Fixes #11332 - DigitalOcean API v2 support

This should allow provisioning using API v2. It relies on Fog 1.36 at
least to work, so 1.10 and older versions of Foreman will not work with
this plugin unfortunately.

The plugin now:
  • Uses slug instead of id for image, region and flavor (size)
  • Uses .delete instead of .destroy to destroy the droplet on DO
  • Just requests the API key when creating the compute resource, not the
    client_id
  • Has a few simple tests for the compute resource & enhances the Jenkins
    task

View differences:

app/models/foreman_digitalocean/digitalocean.rb
module ForemanDigitalocean
class Digitalocean < ComputeResource
alias_attribute :api_key, :password
alias_attribute :region, :url
has_one :key_pair, :foreign_key => :compute_resource_id, :dependent => :destroy
delegate :flavors, :to => :client
validates :user, :password, :presence => true
validates :api_key, :presence => true
before_create :test_connection
after_create :setup_key_pair
after_destroy :destroy_key_pair
# Not sure why it would need a url, but OK (copied from ec2)
alias_attribute :region, :url
attr_accessible :region, :api_key
def to_label
"#{name} (#{provider_friendly_name})"
end
def provided_attributes
super.merge({ :uuid => :identity_to_s, :ip => :public_ip_address })
super.merge(:uuid => :identity_to_s, :ip => :public_ip_address)
end
def self.model_name
......
raise(ActiveRecord::RecordNotFound)
end
def create_vm(args = { })
def create_vm(args = {})
args["ssh_keys"] = [ssh_key] if ssh_key
args['image'] = args['image_id']
super(args)
rescue Fog::Errors::Error => e
logger.error "Unhandled DigitalOcean error: #{e.class}:#{e.message}\n " + e.backtrace.join("\n ")
......
end
def regions
return [] if user.blank? || password.blank?
return [] if api_key.blank?
client.regions
end
def test_connection(options = {})
super
errors[:user].empty? and errors[:password].empty? and regions.count
errors[:password].empty? && regions.count
rescue Excon::Errors::Unauthorized => e
errors[:base] << e.response.body
rescue Fog::Errors::Error => e
......
def destroy_vm(uuid)
vm = find_vm_by_uuid(uuid)
vm.destroy if vm.present?
vm.delete if vm.present?
true
end
# not supporting update at the moment
def update_required?(old_attrs, new_attrs)
def update_required?(*)
false
end
......
end
def associated_host(vm)
Host.authorized(:view_hosts, Host).where(:ip => [vm.public_ip_address, vm.private_ip_address]).first
Host.authorized(:view_hosts, Host).
where(:ip => [vm.public_ip_address, vm.private_ip_address]).first
end
def user_data_supported?
......
end
def default_region_name
@default_region_name ||= client.regions.get(region.to_i).try(:name)
@default_region_name ||= client.regions[region.to_i].try(:name)
rescue Excon::Errors::Unauthorized => e
errors[:base] << e.response.body
end
......
def client
@client ||= Fog::Compute.new(
:provider => "DigitalOcean",
:digitalocean_client_id => user,
:digitalocean_api_key => password,
:version => 'V2',
:digitalocean_token => api_key
)
end
def vm_instance_defaults
super.merge(
:flavor_id => client.flavors.first.id
:size => client.flavors.first.slug
)
end
# this method creates a new key pair for each new DigitalOcean compute resource
# it should create the key and upload it to DigitalOcean
# Creates a new key pair for each new DigitalOcean compute resource
# After creating the key, it uploads it to DigitalOcean
def setup_key_pair
public_key, private_key = generate_key
key_name = "foreman-#{id}#{Foreman.uuid}"
key = client.create_ssh_key key_name, public_key
KeyPair.create! :name => key_name, :compute_resource_id => self.id, :secret => private_key
client.create_ssh_key key_name, public_key
KeyPair.create! :name => key_name, :compute_resource_id => id, :secret => private_key
rescue => e
logger.warn "failed to generate key pair"
logger.error e.message
......
def ssh_key
@ssh_key ||= begin
key = client.list_ssh_keys.data[:body]["ssh_keys"].select{|i| i["name"] == key_pair.name}.first
if key
#the vm creator expects objects which respond to id, OpenStruct is the shortest solution.
OpenStruct.new(key)
else
nil
end
key = client.list_ssh_keys.data[:body]["ssh_keys"].find { |i| i["name"] == key_pair.name }
key['id'] if key.present?
end
end
def generate_key
key = OpenSSL::PKey::RSA.new 2048
type = key.ssh_type
data = [ key.to_blob ].pack('m0')
data = [key.to_blob].pack('m0')
openssh_format_public_key = "#{type} #{data}"
[openssh_format_public_key, key.to_pem]
end
end
end

Also available in: Unified diff