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['Name']) 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(resource[:name], 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", resource[:name], "#{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 attrs = self.class.nova_aggregate_resources_attr(name) #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", name, "#{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", name, "#{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 attrs = self.class.nova_aggregate_resources_attr(name) #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 attrs = self.class.nova_aggregate_resources_attr(name) #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", name, "#{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(name, key, value) end end end def availability_zone=(val) auth_nova("aggregate-set-metadata", name, "availability_zone=#{val}") end end