Completely overhaul keystone types and providers
This commit refactors the existing keystone types and providers. The underlying functionally that the previous types relied on was deprecated as a part of the essex release. It adds the following types: keystone_user keystone_tenant keystone_role keystone_user_role keystone_service keystone_endpoint All of the types are implemented by the keystone client tool (keystone)
This commit is contained in:
parent
b5f32c2220
commit
ccb37d4ee5
Binary file not shown.
|
@ -0,0 +1,70 @@
|
|||
require 'puppet/util/inifile'
|
||||
class Puppet::Provider::Keystone < Puppet::Provider
|
||||
|
||||
# retrieves the current token from keystone.conf
|
||||
def self.admin_token
|
||||
@admin_token ||= get_admin_token
|
||||
end
|
||||
|
||||
def self.get_admin_token
|
||||
"#{keystone_file['DEFAULT']['admin_token'].strip}"
|
||||
end
|
||||
|
||||
def self.admin_endpoint
|
||||
@admin_endpoint ||= get_admin_endpoint
|
||||
end
|
||||
|
||||
def self.get_admin_endpoint
|
||||
"http://127.0.0.1:#{keystone_file['DEFAULT']['admin_port'].strip}/v2.0/"
|
||||
end
|
||||
|
||||
def self.keystone_file
|
||||
return @keystone_file if @keystone_file
|
||||
@keystone_file = Puppet::Util::IniConfig::File.new
|
||||
@keystone_file.read('/etc/keystone/keystone.conf')
|
||||
@keystone_file
|
||||
end
|
||||
|
||||
def self.tenant_hash
|
||||
@tenant_hash ||= build_tenant_hash
|
||||
end
|
||||
|
||||
def tenant_hash
|
||||
self.class.tenant_hash
|
||||
end
|
||||
|
||||
def self.auth_keystone(*args)
|
||||
keystone('--token', admin_token, '--endpoint', admin_endpoint, args)
|
||||
end
|
||||
|
||||
def auth_keystone(*args)
|
||||
self.class.auth_keystone(args)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.list_keystone_objects(type, number_columns)
|
||||
# this assumes that all returned objects are of the form
|
||||
# id, name, enabled_state, OTHER
|
||||
list = auth_keystone("#{type}-list").split("\n")[3..-2].collect do |line|
|
||||
row = line.split(/\s*\|\s*/)[1..-1]
|
||||
if row.size != number_columns
|
||||
raise(Puppet::Error, "Expected #{number_columns} columns for #{type} row, found #{row.size}. Line #{line}")
|
||||
end
|
||||
row
|
||||
end
|
||||
list
|
||||
end
|
||||
|
||||
def self.get_keystone_object(type, id, attr)
|
||||
auth_keystone("#{type}-get", id).split("\n")[3..-2].each do |line|
|
||||
if line =~ /^\|\s*#{attr}\s*\|\s*(.*)?\s+\|$/
|
||||
return $1.strip
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
raise(Puppet::Error, "Could not find colummn #{attr} when getting #{type} #{id}")
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,113 @@
|
|||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_endpoint).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone endpoints
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
|
||||
def self.endpoint_hash
|
||||
@endpoint_hash ||= build_endpoint_hash
|
||||
end
|
||||
|
||||
def endpoint_hash
|
||||
self.class.endpoint_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
endpoint_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
{
|
||||
:region => '--region',
|
||||
:public_url => '--publicurl',
|
||||
:internal_url => '--internalurl',
|
||||
:admin_url => '--adminurl'
|
||||
}.each do |param, opt|
|
||||
if resource[param]
|
||||
optional_opts.push(opt).push(resource[param])
|
||||
end
|
||||
end
|
||||
service_id = self.class.list_keystone_objects('service', 4).detect do |user|
|
||||
user[1] == resource[:name]
|
||||
end.first
|
||||
|
||||
auth_keystone(
|
||||
'endpoint-create',
|
||||
'--service', service_id,
|
||||
optional_opts
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
endpoint_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('endpoint-delete', endpoint_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def id
|
||||
endpoint_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
def region
|
||||
endpoint_hash[resource[:name]][:region]
|
||||
end
|
||||
|
||||
def public_url
|
||||
endpoint_hash[resource[:name]][:public_url]
|
||||
end
|
||||
|
||||
def internal_url
|
||||
endpoint_hash[resource[:name]][:internal_url]
|
||||
end
|
||||
|
||||
def admin_url
|
||||
endpoint_hash[resource[:name]][:admin_url]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_endpoint_hash
|
||||
hash = {}
|
||||
list_keystone_objects('endpoint', 5).each do |endpoint|
|
||||
service_id = get_service_id(endpoint[0])
|
||||
service_name = get_keystone_object('service', service_id, 'name')
|
||||
hash[service_name] = {
|
||||
:id => endpoint[0],
|
||||
:region => endpoint[1],
|
||||
:public_url => endpoint[2],
|
||||
:internal_url => endpoint[3],
|
||||
:admin_url => endpoint[4],
|
||||
:service_id => service_id
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
# TODO - this needs to be replaced with a call to endpoint-get
|
||||
# but endpoint-get is not currently supported from the admin url
|
||||
def self.get_service_id(endpoint_id)
|
||||
`python -c "from keystoneclient.v2_0 import client ; import os ; print [e.service_id for e in client.Client(endpoint='http://127.0.0.1:35357/v2.0/', token='service_token').endpoints.list() if e.id == u'#{endpoint_id}'][0]"`
|
||||
end
|
||||
|
||||
end
|
|
@ -1,92 +0,0 @@
|
|||
class Puppet::Provider::KeystoneManager < Puppet::Provider
|
||||
|
||||
# parent class that knows how to interact
|
||||
# with keystone-manager
|
||||
|
||||
def self.user_hash
|
||||
@user_hash ||= build_user_hash
|
||||
end
|
||||
|
||||
def self.tenant_hash
|
||||
@tenant_hash ||= build_tenant_hash
|
||||
end
|
||||
|
||||
def self.role_hash
|
||||
@role_hash ||= build_role_hash
|
||||
end
|
||||
|
||||
def user_hash
|
||||
self.class.user_hash
|
||||
end
|
||||
|
||||
def tenant_hash
|
||||
self.class.tenant_hash
|
||||
end
|
||||
|
||||
def role_hash
|
||||
self.class.role_hash
|
||||
end
|
||||
|
||||
def property_not_support(property_name)
|
||||
raise(Puppet::Error, "Provider #{self.class} does not yet support the ability to update the property #{property_name}")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_user_hash
|
||||
hash = {}
|
||||
list_keystone_objects('user', 4).each do |user|
|
||||
validate_enabled(user[2])
|
||||
hash[user[1]] = {
|
||||
:id => user[0],
|
||||
:enabled => user[2],
|
||||
:tenant => user[3]
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
def self.build_tenant_hash
|
||||
hash = {}
|
||||
list_keystone_objects('tenant', 3).each do |tenant|
|
||||
validate_enabled(tenant[2])
|
||||
hash[tenant[1]] = {
|
||||
:id => tenant[0],
|
||||
:enabled => tenant[2],
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
def self.build_role_hash
|
||||
hash = {}
|
||||
list_keystone_objects('role', 4).each do |role|
|
||||
Puppet.warning("Found deplicate role #{role[1]}") if hash[role[1]]
|
||||
hash[role[1]] = {
|
||||
:id => role[0],
|
||||
:service_id => role[2],
|
||||
:description => role[3]
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
def self.list_keystone_objects(type, number_columns)
|
||||
# this assumes that all returned objects are of the form
|
||||
# id, name, enabled_state, OTHER
|
||||
list = keystone_manage(type, 'list').split("\n")[5..-2].collect do |line|
|
||||
row = line.split(/\s*\|\s*/)[1..-1]
|
||||
if row.size != number_columns
|
||||
raise(Puppet::Error, "Expected #{number_columns} columns for #{type} row, found #{list.size}. Line #{line}")
|
||||
end
|
||||
row
|
||||
end
|
||||
list
|
||||
end
|
||||
|
||||
def self.validate_enabled(value)
|
||||
unless value == 'True' || value == 'False'
|
||||
raise(Puppet::Error, "Invalid value #{value} for enabled attribute")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,63 @@
|
|||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_role).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone roles
|
||||
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
|
||||
def self.role_hash
|
||||
@role_hash ||= build_role_hash
|
||||
end
|
||||
|
||||
def role_hash
|
||||
self.class.role_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
role_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
auth_keystone(
|
||||
'role-create',
|
||||
'--name', resource[:name]
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
role_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('role-delete', role_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def id
|
||||
role_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_role_hash
|
||||
hash = {}
|
||||
list_keystone_objects('role', 2).each do |role|
|
||||
hash[role[1]] = {
|
||||
:id => role[0],
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
|
@ -1,52 +0,0 @@
|
|||
require 'puppet/provider/keystone_manage'
|
||||
Puppet::Type.type(:keystone_role).provide(
|
||||
:keystone_manage,
|
||||
:parent => Puppet::Provider::KeystoneManager
|
||||
) do
|
||||
|
||||
optional_commands :keystone_manage => 'keystone-manage'
|
||||
|
||||
def self.instances
|
||||
role_hash.collect do |k, v|
|
||||
puts "|#{k}|"
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
keystone_manage('role', 'add', resource[:name], resource[:service])
|
||||
end
|
||||
|
||||
def exists?
|
||||
role_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
raise(Puppet::Error, "keystone-manage does not support removing roles")
|
||||
end
|
||||
|
||||
def id
|
||||
role_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
def service
|
||||
role_hash[resource[:name]][:service]
|
||||
end
|
||||
|
||||
def description
|
||||
role_hash[resource[:name]][:description]
|
||||
end
|
||||
|
||||
def id=(id)
|
||||
raise(Puppet::Error, "Id is a read only property")
|
||||
end
|
||||
|
||||
def service=(service_name)
|
||||
property_not_supported('service')
|
||||
end
|
||||
|
||||
def description=(description)
|
||||
property_not_supported('description')
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,95 @@
|
|||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_service).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone services
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
|
||||
Does not support the ability to list all
|
||||
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
|
||||
def self.service_hash
|
||||
@service_hash ||= build_service_hash
|
||||
end
|
||||
|
||||
def service_hash
|
||||
self.class.service_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
service_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
raise(Puppet::Error, "Required property type not specified for KeystoneService[#{resource[:name]}]") unless resource[:type]
|
||||
if resource[:description]
|
||||
optional_opts.push('--description').push(resource[:description])
|
||||
end
|
||||
auth_keystone(
|
||||
'service-create',
|
||||
'--name', resource[:name],
|
||||
'--type', resource[:type],
|
||||
optional_opts
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
service_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('service-delete', service_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def id
|
||||
service_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
def type
|
||||
service_hash[resource[:name]][:type]
|
||||
end
|
||||
|
||||
def type=(value)
|
||||
raise(Puppet::Error, "service-update is not currently supported by the keystone sql driver")
|
||||
end
|
||||
|
||||
def description
|
||||
service_hash[resource[:name]][:description]
|
||||
end
|
||||
|
||||
def description=(value)
|
||||
raise(Puppet::Error, "service-update is not currently supported by the keystone sql driver")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_service_hash
|
||||
hash = {}
|
||||
list_keystone_objects('service', 4).each do |user|
|
||||
hash[user[1]] = {
|
||||
:id => user[0],
|
||||
:type => user[2],
|
||||
:description => user[3]
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,108 @@
|
|||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_tenant).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone tenants
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
|
||||
One string difference, is that it does not know how to change the
|
||||
name of a tenant
|
||||
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
def self.keystone_type
|
||||
'tenant'
|
||||
end
|
||||
|
||||
def self.tenant_hash
|
||||
@tenant_hash ||= build_tenant_hash
|
||||
end
|
||||
|
||||
def tenant_hash
|
||||
self.class.tenant_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
tenant_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
if resource[:description]
|
||||
optional_opts.push('--description').push(resource[:description])
|
||||
end
|
||||
auth_keystone(
|
||||
'tenant-create',
|
||||
'--name', resource[:name],
|
||||
'--enabled', resource[:enabled],
|
||||
optional_opts
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
tenant_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('tenant-delete', tenant_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def enabled
|
||||
tenant_hash[resource[:name]][:enabled]
|
||||
end
|
||||
|
||||
def enabled=(value)
|
||||
Puppet.warning("I am not sure if this is supported yet")
|
||||
auth_keystone(
|
||||
"tenant-update",
|
||||
'--enabled', value,
|
||||
tenant_hash[resource[:name]][:id]
|
||||
)
|
||||
end
|
||||
|
||||
def description
|
||||
tenant_hash[resource[:name]][:description]
|
||||
end
|
||||
|
||||
def description=(value)
|
||||
auth_keystone(
|
||||
"tenant-update",
|
||||
'--description', value,
|
||||
tenant_hash[resource[:name]][:id]
|
||||
)
|
||||
end
|
||||
|
||||
def id
|
||||
tenant_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_tenant_hash
|
||||
hash = {}
|
||||
list_keystone_objects('tenant', 3).each do |tenant|
|
||||
# I may need to make a call to get to get the description
|
||||
description = get_keystone_object('tenant', tenant[0], 'description')
|
||||
hash[tenant[1]] = {
|
||||
:id => tenant[0],
|
||||
:description => description,
|
||||
:enabled => tenant[2],
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
end
|
|
@ -1,57 +0,0 @@
|
|||
require 'puppet/provider/keystone_manage'
|
||||
Puppet::Type.type(:keystone_tenant).provide(
|
||||
:keystone_manage,
|
||||
:parent => Puppet::Provider::KeystoneManager
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
Provider that uses the keystone-manage tool to
|
||||
manage keystone tenants
|
||||
|
||||
As of the essex release, there is no way to delete an existing
|
||||
tenant. A disabled tenant will be considered the same as an
|
||||
absent tenant (although they are not quite the same, I do not
|
||||
think it will be possible to create a tenant once it has been
|
||||
deleted)
|
||||
|
||||
EOT
|
||||
|
||||
optional_commands :keystone_manage => 'keystone-manage'
|
||||
|
||||
def self.instances
|
||||
tenant_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
keystone_manage('tenant', 'add', resource[:name])
|
||||
end
|
||||
|
||||
def exists?
|
||||
# a tenant is absent if it doesnt exist or if it is disabled
|
||||
tenant_hash[resource[:name]] and tenant_hash[resource[:name]][:enabled] == 'True'
|
||||
end
|
||||
|
||||
def destroy
|
||||
Puppet.warning("Deleting the tenant is not currently supported, it will be disabled")
|
||||
keystone_manage('tenant', 'disable', resource[:name])
|
||||
end
|
||||
|
||||
# def enabled=(state)
|
||||
# if state == 'True'
|
||||
# raise(Puppet::Error, 'Enabling a disabled Tenant is not currently supported')
|
||||
# else
|
||||
# keystone_manage('tenant', 'disable', resource[:name])
|
||||
# end
|
||||
# end
|
||||
|
||||
# def enabled
|
||||
# tenant_hash[resource['name']][:enabled]
|
||||
# end
|
||||
|
||||
def id
|
||||
tenant_hash[resource['name']][:id]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,133 @@
|
|||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_user).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone users
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
|
||||
Does not support the ability to update the user's name
|
||||
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
|
||||
def self.user_hash
|
||||
@user_hash ||= build_user_hash
|
||||
end
|
||||
|
||||
def user_hash
|
||||
self.class.user_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
user_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
if resource[:email]
|
||||
optional_opts.push('--email').push(resource[:email])
|
||||
end
|
||||
if resource[:password]
|
||||
optional_opts.push('--pass').push(resource[:password])
|
||||
end
|
||||
if resource[:tenant]
|
||||
# TODO - do I need to convert this from the name to id?
|
||||
optional_opts.push('--tenant_id').push(resource[:tenant])
|
||||
end
|
||||
auth_keystone(
|
||||
'user-create',
|
||||
'--name', resource[:name],
|
||||
'--enabled', resource[:enabled],
|
||||
optional_opts
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
user_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('user-delete', user_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def enabled
|
||||
user_hash[resource[:name]][:enabled]
|
||||
end
|
||||
|
||||
def enabled=(value)
|
||||
auth_keystone(
|
||||
"user-update",
|
||||
'--enabled', value,
|
||||
user_hash[resource[:name]][:id]
|
||||
)
|
||||
end
|
||||
|
||||
# def password
|
||||
# Puppet.warning("Cannot retrieve password")
|
||||
# user_hash[resource[:name]][:password]
|
||||
# end
|
||||
#
|
||||
# def password=(value)
|
||||
# Puppet.warning('Cannot update password')
|
||||
# # user-password-update does not support the ability know what the
|
||||
# # current value is
|
||||
# #auth_keystone(
|
||||
# # 'user-password-update',
|
||||
# # '--pass', value,
|
||||
# # user_hash[resource[:name]][:id]
|
||||
# end
|
||||
|
||||
def tenant
|
||||
user_hash[resource[:name]][:tenant]
|
||||
end
|
||||
|
||||
def email
|
||||
user_hash[resource[:name]][:email]
|
||||
end
|
||||
|
||||
def email=(value)
|
||||
auth_keystone(
|
||||
"user-update",
|
||||
'--email', value,
|
||||
user_hash[resource[:name]][:id]
|
||||
)
|
||||
end
|
||||
|
||||
def id
|
||||
user_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_user_hash
|
||||
hash = {}
|
||||
list_keystone_objects('user', 4).each do |user|
|
||||
tenant = get_keystone_object('user', user[0], 'tenantId')
|
||||
password = 'nil'
|
||||
hash[user[3]] = {
|
||||
:id => user[0],
|
||||
:enabled => user[1],
|
||||
:email => user[2],
|
||||
:name => user[3],
|
||||
:password => password,
|
||||
:tenant => tenant
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
|
@ -1,54 +0,0 @@
|
|||
require 'puppet/provider/keystone_manage'
|
||||
Puppet::Type.type(:keystone_user).provide(
|
||||
:keystone_manage,
|
||||
:parent => Puppet::Provider::KeystoneManager
|
||||
) do
|
||||
|
||||
optional_commands :keystone_manage => 'keystone-manage'
|
||||
|
||||
def self.instances
|
||||
user_hash.collect do |k, v|
|
||||
puts "|#{k}|"
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
['tenant', 'password'].each do |x|
|
||||
raise(Puppet::Error, "Cannot create keystone user without parameter: #{x}") unless self[x.to_sym]
|
||||
end
|
||||
keystone_manage(
|
||||
'user',
|
||||
'add',
|
||||
resource[:name],
|
||||
resource[:password],
|
||||
resource[:tenant]
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
user_hash[resource[:name]] and user_hash[resource[:name]][:enabled] == 'True'
|
||||
end
|
||||
|
||||
def destroy
|
||||
Puppet.warning("Deleting the user is not currently supported, it will be disabled")
|
||||
keystone_manage('user', 'disable', resource[:name])
|
||||
end
|
||||
|
||||
def tenant=(tenant)
|
||||
raise(Puppet::Error, "Setting the user tenant property is currently not supported")
|
||||
end
|
||||
|
||||
def tenant
|
||||
# I need to translate this from the other command
|
||||
tenant_id = user_hash[resource[:name]][:tenant]
|
||||
if tenant_id == 'None'
|
||||
'None'
|
||||
else
|
||||
# maybe I should check more explicityly
|
||||
# to see if the id is valid
|
||||
tenant_hash.find {|k,v| v[:id] == tenant_id }[0]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,167 @@
|
|||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_user_role).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone role assignments to users
|
||||
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
|
||||
def self.user_role_hash
|
||||
@user_role_hash ||= build_user_role_hash
|
||||
end
|
||||
|
||||
def user_role_hash
|
||||
self.class.user_role_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
user_role_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
resource[:roles].each do |role_name|
|
||||
role_id = self.class.get_roles[role_name]
|
||||
auth_keystone(
|
||||
'user-role-add',
|
||||
'--user', user_id,
|
||||
'--tenant_id', tenant_id,
|
||||
'--role', role_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def get_user_and_tenant
|
||||
user, tenant = resource[:name].split('@', 2)
|
||||
[self.class.get_users[user], self.class.get_tenants[tenant]]
|
||||
end
|
||||
|
||||
def exists?
|
||||
user_role_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
user_role_hash[resource[:name]][:role_ids].each do |role_id|
|
||||
auth_keystone(
|
||||
'user-role-remove',
|
||||
'--user', user_role_hash[resource[:name]][:user_id],
|
||||
'--tenant_id', user_role_hash[resource[:name]][:tenant_id],
|
||||
'--role', role_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def id
|
||||
user_role_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
def roles
|
||||
user_role_hash[resource[:name]][:role_names]
|
||||
end
|
||||
|
||||
def roles=(value)
|
||||
# determine the roles to be added and removed
|
||||
require 'ruby-debug';debugger
|
||||
remove = roles - Array(value)
|
||||
add = Array(value) - roles
|
||||
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
|
||||
add.each do |role_name|
|
||||
role_id = self.class.get_roles[role_name]
|
||||
auth_keystone(
|
||||
'user-role-add',
|
||||
'--user', user_id,
|
||||
'--tenant_id', tenant_id,
|
||||
'--role', role_id
|
||||
)
|
||||
end
|
||||
remove.each do |role_name|
|
||||
role_id = self.class.get_roles[role_name]
|
||||
auth_keystone(
|
||||
'user-role-remove',
|
||||
'--user', user_id,
|
||||
'--tenant_id', tenant_id,
|
||||
'--role', role_id
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_user_role_hash
|
||||
hash = {}
|
||||
get_users.each do |user_name, user_id|
|
||||
get_tenants.each do |tenant_name, tenant_id|
|
||||
list_user_roles(user_id, tenant_id).each do |role|
|
||||
hash["#{user_name}@#{tenant_name}"] ||= {
|
||||
:user_id => user_id,
|
||||
:tenant_id => tenant_id,
|
||||
:role_names => [],
|
||||
:role_ids => []
|
||||
}
|
||||
hash["#{user_name}@#{tenant_name}"][:role_names].push(role[1])
|
||||
hash["#{user_name}@#{tenant_name}"][:role_ids].push(role[0])
|
||||
end
|
||||
end
|
||||
end
|
||||
#require 'ruby-debug';debugger
|
||||
hash
|
||||
end
|
||||
|
||||
|
||||
def self.list_user_roles(user_id, tenant_id)
|
||||
# this assumes that all returned objects are of the form
|
||||
# id, name, enabled_state, OTHER
|
||||
number_columns = 2
|
||||
role_output = auth_keystone('role-list', '--user', user_id, '--tenant_id', tenant_id)
|
||||
list = role_output.split("\n")[3..-2].collect do |line|
|
||||
row = line.split(/\s*\|\s*/)[1..-1]
|
||||
if row.size != number_columns
|
||||
raise(Puppet::Error, "Expected #{number_columns} columns for #{type} row, found #{list.size}. Line #{line}")
|
||||
end
|
||||
row
|
||||
end
|
||||
list
|
||||
end
|
||||
|
||||
def self.get_users
|
||||
return @users if @users
|
||||
@users = {}
|
||||
list_keystone_objects('user', 4).each do |user|
|
||||
@users[user[3]] = user[0]
|
||||
end
|
||||
@users
|
||||
end
|
||||
|
||||
def self.get_tenants
|
||||
return @tenants if @tenants
|
||||
@tenants = {}
|
||||
list_keystone_objects('tenant', 3).each do |tenant|
|
||||
@tenants[tenant[1]] = tenant[0]
|
||||
end
|
||||
@tenants
|
||||
end
|
||||
|
||||
def self.get_roles
|
||||
return @roles if @roles
|
||||
@roles = {}
|
||||
list_keystone_objects('role', 2).each do |role|
|
||||
@roles[role[1]] = role[0]
|
||||
end
|
||||
@roles
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,36 @@
|
|||
Puppet::Type.newtype(:keystone_endpoint) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
This is currently used to model the management of
|
||||
keystone endpoint.
|
||||
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:region) do
|
||||
defaultto('regionOne')
|
||||
end
|
||||
|
||||
newproperty(:public_url) do
|
||||
|
||||
end
|
||||
|
||||
newproperty(:internal_url) do
|
||||
end
|
||||
|
||||
newproperty(:admin_url) do
|
||||
end
|
||||
|
||||
end
|
|
@ -1,20 +1,22 @@
|
|||
Puppet::Type.newtype(:keystone_role) do
|
||||
|
||||
desc <<-EOT
|
||||
Type to create new keystone roles.
|
||||
|
||||
This is currently used to model the creation of
|
||||
keystone roles.
|
||||
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:service) do
|
||||
end
|
||||
|
||||
newproperty(:description) do
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
Puppet::Type.newtype(:keystone_service) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
This is currently used to model the management of
|
||||
keystone services.
|
||||
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:type) do
|
||||
end
|
||||
|
||||
newproperty(:description) do
|
||||
end
|
||||
|
||||
end
|
|
@ -1,8 +1,11 @@
|
|||
Puppet::Type.newtype(:keystone_tenant) do
|
||||
|
||||
desc <<-EOT
|
||||
This type can be used to create
|
||||
This type can be used to manage
|
||||
keystone tenants.
|
||||
|
||||
This is assumed to be running on the same node
|
||||
as your keystone API server.
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
@ -11,12 +14,15 @@ Puppet::Type.newtype(:keystone_tenant) do
|
|||
newvalues(/\w+/)
|
||||
end
|
||||
|
||||
# newproperty(:enabled) do
|
||||
# newvalues(/(t|T)rue/, /(f|F)alse/)
|
||||
# munge do |value|
|
||||
# value.to_s.capitalize
|
||||
# end
|
||||
# end
|
||||
newproperty(:enabled) do
|
||||
newvalues(/(t|T)rue/, /(f|F)alse/)
|
||||
defaultto('True')
|
||||
munge do |value|
|
||||
value.to_s.capitalize
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:description)
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
|
|
|
@ -10,10 +10,22 @@ Puppet::Type.newtype(:keystone_user) do
|
|||
|
||||
EOT
|
||||
|
||||
# TODO support description??
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:enabled) do
|
||||
newvalues(/(t|T)rue/, /(f|F)alse/)
|
||||
defaultto('True')
|
||||
munge do |value|
|
||||
value.to_s.capitalize
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:password) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
@ -22,5 +34,14 @@ Puppet::Type.newtype(:keystone_user) do
|
|||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:email) do
|
||||
newvalues(/\S+@\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
Puppet::Type.newtype(:keystone_user_role) do
|
||||
|
||||
desc <<-EOT
|
||||
|
||||
This is currently used to model the creation of
|
||||
keystone users roles.
|
||||
|
||||
User roles are an assigment of a role to a user on
|
||||
a certain tenant. The combintation of all of these
|
||||
attributes is unique.
|
||||
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/^\S+@\S+$/)
|
||||
#munge do |value|
|
||||
# matchdata = /(\S+)@(\S+)/.match(value)
|
||||
# {
|
||||
# :user => matchdata[1],
|
||||
# :tenant => matchdata[2]
|
||||
# }
|
||||
#nd
|
||||
end
|
||||
|
||||
newproperty(:roles, :array_matching => :all) do
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue