Nova cells support for nova_aggregate provider

Updates the nova_aggregate provider to support nova cells
routing info in the naming of hosts and hosts aggregate.

Change-Id: I29131e378184262a74b9e99a85a8215282787f65
Closes-bug: 1533423
This commit is contained in:
Mike Dorman
2016-01-14 17:08:45 -07:00
parent 32fb6134c0
commit 75660de04e
3 changed files with 144 additions and 18 deletions

View File

@@ -175,9 +175,10 @@ class Puppet::Provider::Nova < Puppet::Provider
def self.nova_get_host_by_name_and_type(host_name, service_type)
#find the host by name and service type
nova_hosts.each do |entry|
if entry["host_name"] == host_name
# (mdorman) Support api!cell_name@host_name -style output of nova host-list under nova cells
if entry["host_name"] =~ /^([a-zA-Z0-9\-_]+![a-zA-Z0-9\-_]+@)?#{Regexp.quote(host_name)}$/
if entry["service"] == service_type
return entry["host_name"]
return host_name
end
end
end
@@ -198,7 +199,10 @@ class Puppet::Provider::Nova < Puppet::Provider
@nova_aggregate_resources_ids = cliout2list(cmd_output)
#only interessted in Id and Name
@nova_aggregate_resources_ids.map{ |e| e.delete("Availability Zone")}
@nova_aggregate_resources_ids.map{ |e| e['Id'] = e['Id'].to_i}
@nova_aggregate_resources_ids.map{ |e|
if e['Id'] =~ /^[0-9]+$/
e['Id'] = e['Id'].to_i
end }
@nova_aggregate_resources_ids
end

View File

@@ -14,7 +14,7 @@ Puppet::Type.type(:nova_aggregate).provide(
def self.instances
nova_aggregate_resources_ids().collect do |el|
attrs = nova_aggregate_resources_attr(el['Id'])
attrs = nova_aggregate_resources_attr(el['Name'])
new(
:ensure => :present,
:name => attrs['Name'],
@@ -74,7 +74,7 @@ Puppet::Type.type(:nova_aggregate).provide(
#add metadata
if not @resource[:metadata].nil? and not @resource[:metadata].empty?
@resource[:metadata].each do |key, value|
set_metadata_helper(id, key, value)
set_metadata_helper(resource[:name], key, value)
end
@property_hash[:metadata] = resource[:metadata]
end
@@ -86,7 +86,7 @@ Puppet::Type.type(:nova_aggregate).provide(
# 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}")
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
@@ -101,12 +101,11 @@ Puppet::Type.type(:nova_aggregate).provide(
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)
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", id, "#{h}")
auth_nova("aggregate-remove-host", name, "#{h}")
end
end
@@ -114,7 +113,7 @@ Puppet::Type.type(:nova_aggregate).provide(
val.each do |h|
if not attrs['Hosts'].include? h
if is_host_in_nova?(h)
auth_nova("aggregate-add-host", id, "#{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
@@ -128,8 +127,7 @@ Puppet::Type.type(:nova_aggregate).provide(
def metadata
#get current metadata
id = self.class.nova_aggregate_resources_get_name_by_id(name)
attrs = self.class.nova_aggregate_resources_attr(id)
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']
@@ -137,8 +135,7 @@ Puppet::Type.type(:nova_aggregate).provide(
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)
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
@@ -147,7 +144,7 @@ Puppet::Type.type(:nova_aggregate).provide(
if obsolete_keys
obsolete_keys.each do |key|
if not key.include? 'availability_zone'
auth_nova("aggregate-set-metadata", id, "#{key}")
auth_nova("aggregate-set-metadata", name, "#{key}")
end
end
#handle keys (with obsolete keys)
@@ -160,14 +157,13 @@ Puppet::Type.type(:nova_aggregate).provide(
new_keys.each do |key|
if val[key] != attrs['Metadata'][key.to_s]
value = val[key]
set_metadata_helper(id, key, value)
set_metadata_helper(name, 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}")
auth_nova("aggregate-set-metadata", name, "availability_zone=#{val}")
end
end

View File

@@ -214,6 +214,76 @@ EOT
end
end
describe 'when parsing cli output with cells enabled' do
it 'should return a list with hashes' do
output = <<-EOT
+-------------+----------------+-------------------+
| Id | Name | Availability Zone |
+-------------+----------------+-------------------+
| api!cell@1 | api!cell@haha | haha2 |
| api!cell@2 | api!cell@haha2 | - |
+-------------+----------------+-------------------+
EOT
res = klass.cliout2list(output)
expect(res).to eq([{"Id"=>"api!cell@1", "Name"=>"api!cell@haha", "Availability Zone"=>"haha2"},
{"Id"=>"api!cell@2", "Name"=>"api!cell@haha2", "Availability Zone"=>""}])
end
it 'should return a list with hashes' do
output = <<-EOT
+-------------+----------------+-------------------+-------+--------------------------------------------------+
| Id | Name | Availability Zone | Hosts | Metadata |
+-------------+----------------+-------------------+-------+--------------------------------------------------+
| api!cell@16 | api!cell@agg94 | my_-zone1 | | 'a=b', 'availability_zone= my_-zone1', 'x_q-r=y' |
+-------------+----------------+-------------------+-------+--------------------------------------------------+
EOT
res = klass.cliout2list(output)
expect(res).to eq([{"Id"=>"api!cell@16",
"Name"=>"api!cell@agg94",
"Availability Zone"=>"my_-zone1",
"Hosts"=>"",
"Metadata"=> {
"a"=>"b",
"availability_zone"=>" my_-zone1",
"x_q-r"=>"y"
}
}])
end
it 'should return a empty list' do
output = <<-EOT
+----+------+-------------------+
| Id | Name | Availability Zone |
+----+------+-------------------+
+----+------+-------------------+
EOT
res = klass.cliout2list(output)
expect(res).to eq([])
end
it 'should return a empty list because no input available' do
output = <<-EOT
EOT
res = klass.cliout2list(output)
expect(res).to eq([])
end
it 'should return a list with hashes' do
output = <<-EOT
+-------------+-------------------------+-------------------+
| Id | Name | Availability Zone |
+-------------+-------------------------+-------------------+
| api!cell@6 | api!cell@my | zone1 |
| api!cell@8 | api!cell@my2 | - |
+-------------+-------------------------+-------------------+
EOT
res = klass.cliout2list(output)
expect(res).to eq([{"Id"=>"api!cell@6", "Name"=>"api!cell@my", "Availability Zone"=>"zone1"},
{"Id"=>"api!cell@8", "Name"=>"api!cell@my2", "Availability Zone"=>""}])
end
end
describe 'when handling cli output' do
it 'should return the availble Id' do
output = <<-EOT
@@ -245,6 +315,37 @@ EOT
end
end
describe 'when handling cli output with cells enabled' do
it 'should return the availble Id' do
output = <<-EOT
+-------------+----------------+-------------------+
| Id | Name | Availability Zone |
+-------------+----------------+-------------------+
| api!cell@1 | api!cell@haha | haha2 |
| api!cell@2 | api!cell@haha2 | - |
+-------------+----------------+-------------------+
EOT
klass.expects(:auth_nova).returns(output)
res = klass.nova_aggregate_resources_get_name_by_id("api!cell@haha2", true)
expect(res).to eq("api!cell@2")
end
it 'should return nil because given name is not available' do
output = <<-EOT
+----+-------+-------------------+
| Id | Name | Availability Zone |
+----+-------+-------------------+
| api!cell@1 | api!cell@haha | haha2 |
| api!cell@2 | api!cell@haha2 | - |
+----+-------+-------------------+
EOT
# used the cache copy, don't call nova again
klass.expects(:auth_nova).never()
res = klass.nova_aggregate_resources_get_name_by_id("notavailable")
expect(res).to eql(nil)
end
end
describe 'when getting details for given Id' do
it 'should return a Hash with the details' do
output = <<-EOT
@@ -270,6 +371,31 @@ EOT
end
end
describe 'when getting details for given Id with cells enabled' do
it 'should return a Hash with the details' do
output = <<-EOT
+-------------+----------------+-------------------+-------+--------------------------------------------------+
| Id | Name | Availability Zone | Hosts | Metadata |
+-------------+----------------+-------------------+-------+--------------------------------------------------+
| api!cell@16 | api!cell@agg94 | my_-zone1 | | 'a=b', 'availability_zone= my_-zone1', 'x_q-r=y' |
+-------------+----------------+-------------------+-------+--------------------------------------------------+
EOT
klass.expects(:auth_nova).returns(output)
res = klass.nova_aggregate_resources_attr(16)
expect(res).to eq({
"Id"=>"api!cell@16",
"Name"=>"api!cell@agg94",
"Availability Zone"=>"my_-zone1",
"Hosts"=>[],
"Metadata"=>{
"a"=>"b",
"availability_zone"=>" my_-zone1",
"x_q-r"=>"y"
}
})
end
end
describe 'when searching for a host/type combo' do
it 'should find the hostname if there is a match' do
output = <<-EOT