2015-08-03 15:09:04 +03:00
require " chef/json_compat "
2014-05-08 15:34:26 +04:00
require " providers/base_provider "
2014-06-18 15:11:47 +04:00
module Provider
# Provider for 'openstack'
class Openstack < BaseProvider
PROVIDER = " openstack "
def initialize config
self . certificate_path = config [ :openstack_certificate ]
self . ssh_key = config [ :openstack_ssh_key ]
self . connection_options = {
:provider = > PROVIDER ,
:openstack_username = > config [ :openstack_username ] ,
:openstack_api_key = > config [ :openstack_api_key ] ,
:openstack_auth_url = > config [ :openstack_auth_url ] ,
:openstack_tenant = > config [ :openstack_tenant ]
}
2014-11-20 15:08:42 +03:00
self . run_list = config [ :openstack_integration_run_list ] || [ ]
2014-06-18 15:11:47 +04:00
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
# Returns 'true' if all parameters defined
def configured?
o = self . connection_options
super and ! ( empty_param? ( o [ :openstack_username ] ) or empty_param? ( o [ :openstack_api_key ] ) or empty_param? ( o [ :openstack_auth_url ] ) or empty_param? ( o [ :openstack_tenant ] ) )
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def name
PROVIDER
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def groups filter = nil
convert_groups ( compute . list_security_groups . body [ " security_groups " ] )
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def flavors
self . compute . list_flavors_detail . body [ " flavors " ] . map do | f |
{
" id " = > f [ " name " ] ,
" v_cpus " = > f [ " vcpus " ] ,
" ram " = > f [ " ram " ] ,
" disk " = > f [ " disk " ]
}
2014-05-08 15:34:26 +04:00
end
2014-06-18 15:11:47 +04:00
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def images filters
self . compute . list_images_detail . body [ " images " ] . select { | i | filters . include? ( i [ " id " ] ) and i [ " status " ] == " ACTIVE " } . map do | i |
{
" id " = > i [ " id " ] ,
" name " = > i [ " name " ] ,
" status " = > i [ " status " ]
}
2014-05-08 15:34:26 +04:00
end
2014-06-18 15:11:47 +04:00
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def networks_detail
net = self . network
subnets = net . list_subnets . body [ " subnets " ] . select { | s | net . current_tenant [ " id " ] == s [ " tenant_id " ] }
net . list_networks . body [ " networks " ] . select { | n | n [ " router:external " ] == false and n [ " status " ] == " ACTIVE " and net . current_tenant [ " id " ] == n [ " tenant_id " ] } . map { | n |
sn = subnets . detect { | s | n [ " subnets " ] [ 0 ] == s [ " id " ] }
{
" cidr " = > sn [ " cidr " ] ,
" name " = > n [ " name " ] ,
" id " = > n [ " id " ]
2014-05-08 15:34:26 +04:00
}
2014-06-18 15:11:47 +04:00
}
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def networks
net = self . network
net . list_networks . body [ " networks " ] . select { | n | n [ " router:external " ] == false and n [ " status " ] == " ACTIVE " and net . current_tenant [ " id " ] == n [ " tenant_id " ] } . map { | n |
{
" name " = > n [ " name " ] ,
" id " = > n [ " id " ]
2014-05-08 15:34:26 +04:00
}
2014-06-18 15:11:47 +04:00
}
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def servers
list = self . compute . list_servers_detail . body [ " servers " ]
list . map do | s |
o = { " state " = > s [ " status " ] , " name " = > s [ " name " ] , " image " = > s [ " image " ] [ " id " ] , " flavor " = > s [ " flavor " ] [ " name " ] , " keypair " = > s [ " key_name " ] , " instance_id " = > s [ " id " ] }
s [ " addresses " ] . each_value do | a |
a . each do | addr |
o [ " private_ip " ] = addr [ " addr " ] if addr [ " OS-EXT-IPS:type " ] == " fixed "
2014-05-08 15:34:26 +04:00
end
end
2014-06-18 15:11:47 +04:00
o
2014-05-08 15:34:26 +04:00
end
2014-06-18 15:11:47 +04:00
end
2014-05-08 15:34:26 +04:00
2015-08-05 14:05:14 +03:00
def create_server s , image , flavor , subnets , groups , out
2014-06-18 15:11:47 +04:00
out << " Creating server for project ' #{ s . project } - #{ s . deploy_env } ' \n "
2015-08-03 16:18:03 +03:00
if s . chef_node_name . nil?
out << " Generate new instance name: "
out << s . chef_node_name = create_default_chef_node_name ( s )
out << " \n "
end
2015-08-05 14:05:14 +03:00
networks = self . networks . select { | n | subnets . include? ( n [ " name " ] ) }
buf = subnets - networks . map { | n | n [ " name " ] }
2014-06-18 15:11:47 +04:00
unless buf . empty?
out << " No networks with names ' #{ buf . join ( " ', ' " ) } ' found "
return false
end
2015-08-05 14:05:14 +03:00
flavor = self . compute . list_flavors_detail . body [ " flavors " ] . detect { | f | f [ " name " ] == flavor } [ " id " ]
out << " Creating server with name ' #{ s . chef_node_name } ', image ' #{ image } ', flavor ' #{ flavor } ', key ' #{ s . key } ' and networks ' #{ networks . map { | n | n [ " name " ] } . join ( " ', ' " ) } '... \n \n "
2014-06-18 15:11:47 +04:00
compute = self . compute
begin
2015-08-05 14:05:14 +03:00
o_server = compute . create_server ( s . chef_node_name , image , flavor ,
2014-06-18 15:11:47 +04:00
" nics " = > networks . map { | n | { " net_id " = > n [ " id " ] } } ,
2015-08-05 14:05:14 +03:00
" security_groups " = > groups ,
2014-06-18 15:11:47 +04:00
" key_name " = > s . key )
rescue Excon :: Errors :: BadRequest = > e
response = :: Chef :: JSONCompat . from_json ( e . response . body )
if response [ 'badRequest' ] [ 'code' ] == 400
if response [ 'badRequest' ] [ 'message' ] =~ / Invalid flavorRef /
2015-08-05 14:05:14 +03:00
out << " \n ERROR: Bad request (400): Invalid flavor id specified: #{ flavor } "
2014-06-18 15:11:47 +04:00
elsif response [ 'badRequest' ] [ 'message' ] =~ / Invalid imageRef /
2015-08-05 14:05:14 +03:00
out << " \n ERROR: Bad request (400): Invalid image specified: #{ image } "
2014-05-08 15:34:26 +04:00
else
2014-06-18 15:11:47 +04:00
out << " \n ERROR: Bad request (400): #{ response [ 'badRequest' ] [ 'message' ] } "
2014-05-08 15:34:26 +04:00
end
2014-05-15 15:05:16 +04:00
out << " \n "
return false
2014-06-18 15:11:47 +04:00
else
out << " \n ERROR: Unknown server error ( #{ response [ 'badRequest' ] [ 'code' ] } ): #{ response [ 'badRequest' ] [ 'message' ] } "
2014-05-15 15:05:16 +04:00
out << " \n "
2014-05-08 15:34:26 +04:00
return false
end
2014-06-18 15:11:47 +04:00
rescue Excon :: Errors :: InternalServerError = > ise
out << " \n Error: openstack internal server error " + ise . message
out << " \n "
return false
rescue = > e2
out << " \n Error: Unknown error: " + e2 . message
out << " \n "
return false
end
sbody = o_server . body
s . id = sbody [ " server " ] [ " id " ]
out << " \n Waiting for server... "
details , status = nil , nil
until status == " ACTIVE "
sleep ( 1 )
details = compute . get_server_details ( s . id ) . body
status = details [ " server " ] [ " status " ] . upcase
if status == " ERROR "
2015-08-04 13:20:35 +03:00
out << " error \n Server returns status 'ERROR' "
out << details [ " server " ]
2014-06-18 15:11:47 +04:00
return false
2014-05-08 15:34:26 +04:00
end
end
2014-06-18 15:11:47 +04:00
network = networks [ 0 ] [ " name " ]
s . private_ip = details [ " server " ] [ " addresses " ] [ network ] [ 0 ] [ " addr " ]
2015-08-04 13:20:35 +03:00
out << " done \n \n "
2014-06-18 15:11:47 +04:00
out << s . info
true
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def create_default_chef_node_name s
" #{ self . ssh_key } - #{ s . project } - #{ s . deploy_env } - #{ Time . now . to_i } "
end
2014-06-11 12:13:02 +04:00
2014-06-18 15:11:47 +04:00
def delete_server s
r = self . compute . delete_server ( s . id )
return r . status == 204 ? " Server with id ' #{ s . id } ' terminated " : r . body
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def pause_server s
begin
self . compute . pause_server s . id
rescue Excon :: Errors :: Conflict = > e
return " pause "
2014-05-08 15:34:26 +04:00
end
2014-06-18 15:11:47 +04:00
return nil
end
2014-05-08 15:34:26 +04:00
2014-06-18 15:11:47 +04:00
def unpause_server s
begin
self . compute . unpause_server s . id
rescue Excon :: Errors :: Conflict = > e
return " unpause "
2014-05-08 15:34:26 +04:00
end
2014-06-18 15:11:47 +04:00
return nil
end
2014-05-08 15:34:26 +04:00
2014-06-20 12:59:17 +04:00
def compute
2015-07-21 19:47:16 +03:00
@compute || = connection_compute ( connection_options )
2014-06-20 12:59:17 +04:00
end
def network
connection_network ( self . connection_options )
end
2015-02-12 13:01:05 +03:00
def create_stack ( stack )
2015-04-16 17:54:40 +03:00
begin
2015-07-13 20:26:13 +03:00
response = orchestration . create_stack (
stack_name : stack . id ,
2015-04-16 17:54:40 +03:00
template : stack . template_body ,
tenant_id : connection_options [ :openstack_tenant ] ,
parameters : stack . parameters
2015-07-13 20:26:13 +03:00
)
2015-04-16 17:54:40 +03:00
response [ :body ] [ 'stack' ] [ 'id' ]
rescue Excon :: Errors :: Conflict = > e
raise ProviderErrors :: NameConflict
end
2015-02-12 13:01:05 +03:00
end
2015-04-16 17:54:40 +03:00
def delete_stack ( stack )
2015-07-15 18:37:27 +03:00
fog_stack ( stack ) . destroy
2015-04-16 17:54:40 +03:00
end
2015-07-14 16:51:40 +03:00
def stack_details ( stack )
2015-07-30 02:14:45 +03:00
fog_stack ( stack ) . details
2015-07-15 18:37:27 +03:00
end
def stack_resources ( stack )
fog_stack ( stack ) . resources
2015-07-14 16:51:40 +03:00
end
2015-07-16 16:01:53 +03:00
def stack_resource ( stack , resource_id )
2015-07-21 19:47:16 +03:00
physical_id = fog_stack ( stack ) . resources . get ( resource_id ) . physical_resource_id
2015-07-30 02:14:45 +03:00
compute . servers . get ( physical_id )
2015-07-16 16:01:53 +03:00
end
2014-06-18 15:11:47 +04:00
private
def convert_groups list
res = { }
list . map do | g |
res [ g [ " name " ] ] = {
" description " = > g [ " description " ]
}
rules = [ ]
g [ " rules " ] . each do | r |
rules . push ( {
" protocol " = > r [ " ip_protocol " ] ,
" from " = > r [ " from_port " ] ,
" to " = > r [ " to_port " ] ,
" cidr " = > r [ " ip_range " ] [ " cidr " ]
} )
2014-05-08 15:34:26 +04:00
end
2014-06-18 15:11:47 +04:00
res [ g [ " name " ] ] [ " rules " ] = rules
2014-05-08 15:34:26 +04:00
end
2014-06-18 15:11:47 +04:00
res
end
2014-05-08 15:34:26 +04:00
2015-02-12 13:01:05 +03:00
def orchestration
2015-04-16 17:54:40 +03:00
@connection || = Fog :: Orchestration . new ( connection_options )
2015-02-12 13:01:05 +03:00
end
2015-07-15 18:37:27 +03:00
def fog_stack ( stack )
orchestration . stacks . get ( stack . id , stack . cloud_stack_id )
end
2014-05-08 15:34:26 +04:00
end
end