saving my work (not even the initial commit)

This commit is contained in:
Dan Bode 2012-01-02 15:39:23 -08:00
commit 8e2008d99a
16 changed files with 657 additions and 0 deletions

View File

@ -0,0 +1,3 @@
This repo is not ready to be used.
These initial check-ins are just to save my current progress.

View File

@ -0,0 +1,14 @@
require 'rake'
task :default => [:spec]
desc "Run all module spec tests (Requires rspec-puppet gem)"
task :spec do
system("rspec spec/**/*_spec.rb")
end
desc "Build package"
task :build do
system("puppet-module build")
end

View File

@ -0,0 +1,92 @@
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

View File

@ -0,0 +1,52 @@
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

View File

@ -0,0 +1,57 @@
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

View File

@ -0,0 +1,54 @@
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

View File

@ -0,0 +1,20 @@
Puppet::Type.newtype(:keystone_role) do
desc <<-EOT
Type to create new keystone roles.
EOT
ensurable
newparam(:name, :namevar => true) do
end
newproperty(:id) do
end
newproperty(:service) do
end
newproperty(:description) do
end
end

View File

@ -0,0 +1,26 @@
Puppet::Type.newtype(:keystone_tenant) do
desc <<-EOT
This type can be used to create
keystone tenants.
EOT
ensurable
newparam(:name, :namevar => true) do
newvalues(/\w+/)
end
# newproperty(:enabled) do
# newvalues(/(t|T)rue/, /(f|F)alse/)
# munge do |value|
# value.to_s.capitalize
# end
# end
newproperty(:id) do
validate do |v|
raise(Puppet::Error, 'This is a read only property')
end
end
end

View File

@ -0,0 +1,26 @@
Puppet::Type.newtype(:keystone_user) do
desc <<-EOT
This is currently used to model the creation of
keystone users.
It currently requires that both the password
as well as the tenant are specified.
EOT
newparam(:name, :namevar => true) do
newvalues(/\S+/)
end
newparam(:password) do
newvalues(/\S+/)
end
newproperty(:tenant) do
newvalues(/\S+/)
end
end

View File

@ -0,0 +1,100 @@
#
# module for installing keystone
#
# does this always live on the nova API server?
#
class keystone(
$package_ensure = 'present',
$log_verbose = 'False',
$log_debug = 'False',
$default_store = 'sqlite',
$bind_host = '0.0.0.0',
$bind_port = '5000',
$admin_bind_host = '0.0.0.0',
$admin_bind_port = '5001'
) {
# may need to add a user for HA
# TODO does keystone need nova-common?
#Package['keystone'] ~> Service<| 'title' = 'nova-api' |>
# this package dependency needs to be removed when it
# is added as a package dependency
# I filed the following ticket against the packages: 909941
if(! defined(Package['python-migrate'])) {
package { 'python-migrate':
ensure => present,
}
}
package { 'keystone':
ensure => $package_ensure,
# I do not understand what this does??
#notify => Exec["fix_tools_tracer"],
}
file { '/etc/keystone':
ensure => directory,
owner => 'keystone',
group => 'keystone',
mode => 0755,
require => Package['keystone']
}
file { 'keystone.conf':
path => '/etc/keystone/keystone.conf',
ensure => present,
owner => 'keystone',
mode => 0600,
content => template('keystone/keystone.conf.erb'),
notify => Service['keystone'],
require => Package['keystone'], #Exec['fix_tools_tracer']]
}
# # I would prefer not to be loading initial data into keystone
# file { 'initial_data.sh':
# path => '/var/lib/keystone/initial_data.sh',
# ensure => present,
# owner => 'keystone',
# mode => 0700,
# content => template('keystone/initial_data.sh.erb'),
# require => Package['keystone']
# }
#
# exec { 'create_keystone_data':
# user => 'keystone',
# command => '/var/lib/keystone/initial_data.sh',
# path => [ '/bin', '/usr/bin' ],
# unless => 'keystone-manage user list | grep -q admin',
# require => [
# Package['keystone'],
# File['keystone.conf'],
# File['initial_data.sh']
# ]
# }
service { 'keystone':
ensure => running,
enable => true,
hasstatus => true,
hasrestart => true,
}
# TODO - figure out if I can remove this patching code?
# this can't be serious
# this Puppet code is patching keystone? Why?
#exec { "fix_tools_tracer":
# command => 'sed -e "s,^import tools.tracer,#import tools.tracer," -i /usr/lib/python2.6/dist-packages/keystone/middleware/auth_token.py /usr/bin/keystone',
# path => [ "/bin", "/usr/bin" ],
# notify => [Service["nova-api"]],
# refreshonly => true,
# require => [
# Package['keystone'],
# ]
#}
}

View File

@ -0,0 +1,75 @@
require 'spec_helper'
describe 'keystone' do
let :default_params do
{
'package_ensure' => 'present',
'log_verbose' => 'False',
'log_debug' => 'False',
'default_store' => 'sqlite',
'bind_host' => '0.0.0.0',
'bind_port' => '5000',
'admin_bind_host' => '0.0.0.0',
'admin_bind_port' => '5001'
}
end
[{},
{
'package_ensure' => 'latest',
'log_verbose' => 'True',
'log_debug' => 'True',
'default_store' => 'ldap',
'bind_host' => '127.0.0.1',
'bind_port' => '50000',
'admin_bind_host' => '127.0.0.1',
'admin_bind_port' => '50001'
}
].each do |param_set|
describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do
let :param_hash do
param_set == {} ? default_params : param_set
end
let :params do
param_set
end
it { should contain_package('keystone').with_ensure(param_hash['package_ensure']) }
it { should contain_file('/etc/keystone').with(
'ensure' => 'directory',
'owner' => 'keystone',
'group' => 'keystone',
'mode' => '0755',
'require' => 'Package[keystone]'
) }
# maybe keystone should always be with the API server?
it 'should refresh nova-api if they are on the same machine'
it { should contain_service('keystone').with(
'ensure' => 'running',
'enable' => 'true',
'hasstatus' => 'true',
'hasrestart' => 'true'
) }
it 'should compile the template based on the class parameters' do
content = param_value(subject, 'file', 'keystone.conf', 'content')
expected_lines = [
"verbose = #{param_hash['log_verbose']}",
"debug = #{param_hash['log_debug']}",
"default_store = #{param_hash['default_store']}",
"service_host = #{param_hash['bind_host']}",
"service_port = #{param_hash['bind_port']}",
"admin_host = #{param_hash['admin_bind_host']}",
"admin_port = #{param_hash['admin_bind_port']}"
]
(content.split("\n") & expected_lines).should == expected_lines
end
end
end
end

View File

@ -0,0 +1,6 @@
--format
s
--colour
--loadby
mtime
--backtrace

View File

@ -0,0 +1,11 @@
require 'puppet'
require 'rubygems'
require 'rspec-puppet'
def param_value(subject, type, title, param)
subject.resource(type, title).send(:parameters)[param.to_sym]
end
RSpec.configure do |c|
c.module_path = File.join(File.dirname(__FILE__), '../../')
end

View File

@ -0,0 +1,40 @@
#!/bin/bash
# Tenants
keystone-manage $* tenant add admin
keystone-manage $* tenant add demo
# Users
keystone-manage $* user add demo secrete demo
keystone-manage $* user add admin secrete admin
# Roles
keystone-manage $* role add Admin
keystone-manage $* role add Member
keystone-manage $* role grant Admin admin
#endpointTemplates
keystone-manage $* endpointTemplates add RegionOne swift http://<%= api_vip %>:8080/v1/AUTH_%tenant_id% http://<%= api_vip %>:8080/ http://<%= api_vip %>:8080/v1/AUTH_%tenant_id% 1 1
keystone-manage $* endpointTemplates add RegionOne nova_compat http://<%= api_vip %>:8774/v1.0/ http://<%= api_vip %>:8774/v1.0 http://<%= api_vip %>:8774/v1.0 1 1
keystone-manage $* endpointTemplates add RegionOne nova http://<%= api_vip %>:8774/v1.1/%tenant_id% http://<%= api_vip %>:8774/v1.1/%tenant_id% http://<%= api_vip %>:8774/v1.1/%tenant_id% 1 1
keystone-manage $* endpointTemplates add RegionOne glance http://<%= api_vip %>:9292/v1.1/%tenant_id% http://<%= api_vip %>:9292/v1.1/%tenant_id% http://<%= api_vip %>:9292/v1.1/%tenant_id% 1 1
keystone-manage $* endpointTemplates add RegionOne keystone http://<%= api_vip %>:5000/v2.0 http://<%= api_vip %>:5001/v2.0 http://<%= api_vip %>:5000/v2.0 1 1
keystone-manage $* endpointTemplates add RegionOne identity http://<%= api_vip %>:5000/v2.0 http://<%= api_vip %>:5001/v2.0 http://<%= api_vip %>:5000/v2.0 1 1
# Tokens
keystone-manage $* token add 999888777666 admin admin 2015-02-05T00:00
#Tenant endpoints
keystone-manage $* endpoint add admin 1
keystone-manage $* endpoint add admin 2
keystone-manage $* endpoint add admin 3
keystone-manage $* endpoint add admin 4
keystone-manage $* endpoint add admin 5
keystone-manage $* endpoint add admin 6
keystone-manage $* endpoint add demo 1
keystone-manage $* endpoint add demo 2
keystone-manage $* endpoint add demo 3
keystone-manage $* endpoint add demo 4
keystone-manage $* endpoint add demo 5
keystone-manage $* endpoint add demo 6

View File

@ -0,0 +1,81 @@
[DEFAULT]
# Show more verbose log output (sets INFO log level output)
verbose = <%= log_verbose %>
# Show debugging output in logs (sets DEBUG log level output)
debug = <%= log_debug %>
# Which backend store should Keystone use by default.
# Default: 'sqlite'
# Available choices are 'sqlite' [future will include LDAP, PAM, etc]
default_store = <%= default_store %>
# Log to this file. Make sure you do not set the same log
# file for both the API and registry servers!
log_file = /var/log/keystone/keystone.log
# List of backends to be configured
backends = keystone.backends.sqlalchemy
#For LDAP support, add: ,keystone.backends.ldap
# Dictionary Maps every service to a header.Missing services would get header
# X_(SERVICE_NAME) Key => Service Name, Value => Header Name
service-header-mappings = {
'nova' : 'X-Server-Management-Url',
'swift' : 'X-Storage-Url',
'cdn' : 'X-CDN-Management-Url'}
# Address to bind the API server
# TODO Properties defined within app not available via pipeline.
service_host = <%= bind_host %>
# Port the bind the API server to
service_port = <%= bind_port %>
# Address to bind the Admin API server
admin_host = <%= admin_bind_host %>
# Port the bind the Admin API server to
admin_port = <%= admin_bind_port %>
#Role that allows to perform admin operations.
keystone-admin-role = Admin
#Role that allows to perform service admin operations.
keystone-service-admin-role = KeystoneServiceAdmin
[keystone.backends.sqlalchemy]
# SQLAlchemy connection string for the reference implementation registry
# server. Any valid SQLAlchemy connection string is fine.
# See: http://bit.ly/ideIpI
sql_connection = sqlite:////var/lib/keystone/keystone.db
backend_entities = ['UserRoleAssociation', 'Endpoints', 'Role', 'Tenant',
'User', 'Credentials', 'EndpointTemplates', 'Token',
'Service']
# Period in seconds after which SQLAlchemy should reestablish its connection
# to the database.
sql_idle_timeout = 30
[pipeline:admin]
pipeline =
urlrewritefilter
admin_api
[pipeline:keystone-legacy-auth]
pipeline =
urlrewritefilter
legacy_auth
service_api
[app:service_api]
paste.app_factory = keystone.server:service_app_factory
[app:admin_api]
paste.app_factory = keystone.server:admin_app_factory
[filter:urlrewritefilter]
paste.filter_factory = keystone.middleware.url:filter_factory
[filter:legacy_auth]
paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory