
Sort the list of hosts in the aggregate, both from the provider/nova API as well as from the resource definition in the manifest. This allows for more accurate comparison to determine if the resource really needs to be updated or not. Change-Id: I10a1995eb58e4bcd492bb7d6f94453a29cb31097 Closes-bug: 1534845
174 lines
5.1 KiB
Ruby
174 lines
5.1 KiB
Ruby
require File.join(File.dirname(__FILE__), '..','..','..',
|
|
'puppet/provider/nova')
|
|
|
|
Puppet::Type.type(:nova_aggregate).provide(
|
|
:nova,
|
|
:parent => Puppet::Provider::Nova
|
|
) do
|
|
|
|
desc "Manage nova aggregations"
|
|
|
|
commands :nova => 'nova'
|
|
|
|
mk_resource_methods
|
|
|
|
def self.instances
|
|
nova_aggregate_resources_ids().collect do |el|
|
|
attrs = nova_aggregate_resources_attr(el['Id'])
|
|
new(
|
|
:ensure => :present,
|
|
:name => attrs['Name'],
|
|
:id => attrs['Id'],
|
|
:availability_zone => attrs['Availability Zone'],
|
|
:metadata => attrs['Metadata'],
|
|
:hosts => attrs['Hosts'].sort
|
|
)
|
|
end
|
|
end
|
|
|
|
def self.prefetch(resources)
|
|
instances_ = instances
|
|
resources.keys.each do |name|
|
|
if provider = instances_.find{ |instance| instance.name == name }
|
|
resources[name].provider = provider
|
|
end
|
|
end
|
|
end
|
|
|
|
def exists?
|
|
@property_hash[:ensure] == :present
|
|
end
|
|
|
|
def destroy
|
|
#delete hosts first
|
|
if not @property_hash[:hosts].nil?
|
|
@property_hash[:hosts].each do |h|
|
|
auth_nova("aggregate-remove-host", name, h)
|
|
end
|
|
end
|
|
#now delete aggregate
|
|
auth_nova("aggregate-delete", name)
|
|
@property_hash[:ensure] = :absent
|
|
end
|
|
|
|
def create
|
|
extras = Array.new
|
|
#check for availability zone
|
|
if not @resource[:availability_zone].nil? and not @resource[:availability_zone].empty?
|
|
extras << "#{@resource[:availability_zone]}"
|
|
end
|
|
#run the command
|
|
result = auth_nova("aggregate-create", resource[:name], extras)
|
|
|
|
#get Id by Name
|
|
#force a refresh of the aggregate list on creation
|
|
id = self.class.nova_aggregate_resources_get_name_by_id(resource[:name], true)
|
|
|
|
@property_hash = {
|
|
:ensure => :present,
|
|
:name => resource[:name],
|
|
:id => id,
|
|
:availability_zone => resource[:availability_zone]
|
|
}
|
|
|
|
#add metadata
|
|
if not @resource[:metadata].nil? and not @resource[:metadata].empty?
|
|
@resource[:metadata].each do |key, value|
|
|
set_metadata_helper(id, key, value)
|
|
end
|
|
@property_hash[:metadata] = resource[:metadata]
|
|
end
|
|
|
|
#add hosts - This throws an error if the host is already attached to another aggregate!
|
|
if not @resource[:hosts].nil? and not @resource[:hosts].empty?
|
|
@resource[:hosts].each do |host|
|
|
# make sure the host exists in nova, or nova will fail the call
|
|
# this solves weird ordering issues with a compute node that's
|
|
# not 100% up being added to the host aggregate
|
|
if is_host_in_nova?(host)
|
|
auth_nova("aggregate-add-host", id, "#{host}")
|
|
else
|
|
warning("Cannot add #{host} to host aggregate, it's not available yet in nova host-list")
|
|
end
|
|
end
|
|
@property_hash[:hosts] = resource[:hosts]
|
|
end
|
|
end
|
|
|
|
def is_host_in_nova?(host)
|
|
return host==self.class.nova_get_host_by_name_and_type(host, "compute")
|
|
end
|
|
|
|
def hosts=(val)
|
|
#get current hosts
|
|
id = self.class.nova_aggregate_resources_get_name_by_id(name)
|
|
attrs = self.class.nova_aggregate_resources_attr(id)
|
|
#remove all hosts which are not in new value list
|
|
attrs['Hosts'].each do |h|
|
|
if not val.include? h
|
|
auth_nova("aggregate-remove-host", id, "#{h}")
|
|
end
|
|
end
|
|
|
|
#add hosts from the value list
|
|
val.each do |h|
|
|
if not attrs['Hosts'].include? h
|
|
if is_host_in_nova?(h)
|
|
auth_nova("aggregate-add-host", id, "#{h}")
|
|
else
|
|
warning("Cannot add #{h} to host aggregate, it's not available yet in nova host-list")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def set_metadata_helper(agg_id, key, value)
|
|
auth_nova("aggregate-set-metadata", agg_id, "#{key}=#{value}")
|
|
end
|
|
|
|
def metadata
|
|
#get current metadata
|
|
id = self.class.nova_aggregate_resources_get_name_by_id(name)
|
|
attrs = self.class.nova_aggregate_resources_attr(id)
|
|
#just ignore the availability_zone. that's handled directly by nova
|
|
attrs['Metadata'].delete('availability_zone')
|
|
return attrs['Metadata']
|
|
end
|
|
|
|
def metadata=(val)
|
|
#get current metadata
|
|
id = self.class.nova_aggregate_resources_get_name_by_id(name)
|
|
attrs = self.class.nova_aggregate_resources_attr(id)
|
|
#get keys which are in current metadata but not in val. Make sure it has data first!
|
|
if attrs['Metadata'].length > 0
|
|
obsolete_keys = attrs['Metadata'].keys - val.keys
|
|
end
|
|
# clear obsolete keys. If there are any!
|
|
if obsolete_keys
|
|
obsolete_keys.each do |key|
|
|
if not key.include? 'availability_zone'
|
|
auth_nova("aggregate-set-metadata", id, "#{key}")
|
|
end
|
|
end
|
|
#handle keys (with obsolete keys)
|
|
new_keys = val.keys - obsolete_keys
|
|
else
|
|
#handle keys (without obsolete keys)
|
|
new_keys = val.keys
|
|
end
|
|
#set new metadata if value changed
|
|
new_keys.each do |key|
|
|
if val[key] != attrs['Metadata'][key.to_s]
|
|
value = val[key]
|
|
set_metadata_helper(id, key, value)
|
|
end
|
|
end
|
|
end
|
|
|
|
def availability_zone=(val)
|
|
id = self.class.nova_aggregate_resources_get_name_by_id(name)
|
|
auth_nova("aggregate-set-metadata", id, "availability_zone=#{val}")
|
|
end
|
|
|
|
end
|