cloudfoundry-community/cyoi

View on GitHub
lib/cyoi/providers/clients/openstack_provider_client.rb

Summary

Maintainability
A
0 mins
Test Coverage
# Copyright (c) 2012-2013 Stark & Wayne, LLC

module Cyoi; module Providers; module Clients; end; end; end

require "ipaddr"
require "cyoi/providers/clients/fog_provider_client"
require "cyoi/providers/constants/openstack_constants"

class Cyoi::Providers::Clients::OpenStackProviderClient < Cyoi::Providers::Clients::FogProviderClient
  # @return [boolean] true if target OpenStack running Neutron networks
  def networks?
    fog_network
  end

  def subnets
    fog_network.subnets
  end

  # @return [String] provisions a new public IP address in target region
  def provision_public_ip_address(options={})
    pool_name = options.delete("pool_name")
    pool_name ||= begin
      pool = fog_compute.addresses.get_address_pools.first
      pool["name"]
    end
    address = fog_compute.addresses.create(:pool => pool_name)
    address.ip
  rescue NoMethodError
    print "No Public IP Found"
  end

  def associate_ip_address_with_server(ip_address, server)
    address = fog_compute.addresses.find { |a| a.ip == ip_address }
    address.server = server
  end

  # @return [Array] of IPs that are not allocated to a server
  # Defaults to the first address pool unless
  # "pool_name" is provided in options
  def unallocated_floating_ip_addresses(options={})
    pool_name = options.delete("pool_name")
    pool_name ||= begin
      pool = fog_compute.addresses.get_address_pools.first
      pool["name"]
    end
    fog_compute.addresses.
      select { |a| a.pool == pool_name && a.instance_id.nil? }.
      map(&:ip)
  end

  # @return [String] IP that is available for a new VM to use
  # allocation_pools look like:
  # "allocation_pools" => [{"start"=>"192.168.101.2", "end"=>"192.168.101.254"}]
  def next_available_ip_in_subnet(subnet)
    ip = IPAddr.new(subnet.allocation_pools.first["start"])
    skip_ips = ip_addresses_assigned_to_servers
    while skip_ips.include?(ip.to_s)
      ip = ip.succ
    end
    ip.to_s
  end

  def ip_addresses_assigned_to_servers
    fog_compute.servers.map {|s| s.addresses}.map {|address_hash| address_hash.map {|name, addrs| addrs}}.flatten.map {|addr| addr["addr"]}
  end

  # Hook method for FogProviderClient#create_security_group
  def ip_permissions(sg)
    sg.security_group_rules
  end

  def port_open?(ip_permissions, port_range, protocol, ip_range)
    ip_permissions && ip_permissions.find do |ip|
      ip.ip_protocol == protocol \
      && ip.ip_range["cidr"] == ip_range \
      && ip.from_port <= port_range.min \
      && ip.to_port >= port_range.max
    end
  end

  # Hook method for FogProviderClient#create_security_group
  def authorize_port_range(sg, port_range, protocol, ip_range)
    rules = ip_permissions(sg)
    rules.create(parent_group_id: sg.id, from_port: port_range.min, to_port: port_range.max, ip_range: {"cidr" => ip_range}, ip_protocol: protocol)
  end

  def find_server_device(server, device)
    va = fog_compute.get_server_volumes(server.id).body['volumeAttachments']
    va.find { |v| v["device"] == device }
  end

  def create_and_attach_volume(name, disk_size, server, device)
    volume = fog_compute.volumes.create(:name => name,
                                        :description => "",
                                        :size => disk_size,
                                        :availability_zone => server.availability_zone)
    volume.wait_for { volume.status == 'available' }
    volume.attach(server.id, device)
    volume.wait_for { volume.status == 'in-use' }
  end

  def delete_security_group_and_servers(sg_name)
    raise "not implemented yet"
  end

  def configuration
    configuration = Fog.symbolize_credentials(attributes.credentials)
    configuration[:provider] = "OpenStack"
    if attributes.credentials.openstack_region && attributes.credentials.openstack_region.empty?
      configuration.delete(:openstack_region)
    end
    configuration
  end

  # May throw odd exception if OpenStack doesn't support Swift, like:
  #   NoMethodError: undefined method `join' for "object-store":String
  def fog_storage
    @fog_storage ||= Fog::Storage.new(configuration)
  end

  # Construct a Fog::Compute object
  # Uses +attributes+ which normally originates from +settings.provider+
  def setup_fog_connection
    @fog_compute = Fog::Compute.new(configuration)
  end

  def fog_network
    @fog_network ||= Fog::Network.new(configuration)
  rescue Fog::Errors::NotFound
    nil
  end

  def openstack_constants
    Cyoi::Providers::Constants::OpenStackConstants
  end
end