initial pull from rcbops-cookbooks/keystone, monitoring removed

This commit is contained in:
mattray 2012-06-20 16:56:53 -05:00
parent 74eeb61440
commit 68f359c568
10 changed files with 1185 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
metadata.json

83
attributes/default.rb Normal file
View File

@ -0,0 +1,83 @@
########################################################################
# Toggles - These can be overridden at the environment level
default["enable_monit"] = false # OS provides packages
default["developer_mode"] = false # we want secure passwords by default
########################################################################
# Adding these as blank
# this needs to be here for the initial deep-merge to work
default["credentials"]["EC2"]["admin"]["access"] = ""
default["credentials"]["EC2"]["admin"]["secret"] = ""
default["keystone"]["db"]["name"] = "keystone"
default["keystone"]["db"]["username"] = "keystone"
# Replacing with OpenSSL::Password in recipes/server.rb
# default["keystone"]["db"]["password"] = "keystone"
default["keystone"]["verbose"] = "False"
default["keystone"]["debug"] = "False"
# new endpoint location stuff
default["keystone"]["services"]["admin-api"]["scheme"] = "http"
default["keystone"]["services"]["admin-api"]["network"] = "nova"
default["keystone"]["services"]["admin-api"]["port"] = "35357"
default["keystone"]["services"]["admin-api"]["path"] = "/v2.0"
default["keystone"]["services"]["service-api"]["scheme"] = "http"
default["keystone"]["services"]["service-api"]["network"] = "public"
default["keystone"]["services"]["service-api"]["port"] = "5000"
default["keystone"]["services"]["service-api"]["path"] = "/v2.0"
# default["keystone"]["roles"] = [ "admin", "Member", "KeystoneAdmin", "KeystoneServiceAdmin", "sysadmin", "netadmin" ]
default["keystone"]["roles"] = [ "admin", "Member", "KeystoneAdmin", "KeystoneServiceAdmin" ]
default["keystone"]["tenants"] = [ "admin", "demo", "service"]
default["keystone"]["admin_user"] = "admin"
default["keystone"]["users"] = {
default["keystone"]["admin_user"] => {
"password" => "secrete",
"default_tenant" => "admin",
"roles" => {
"admin" => [ "admin", "demo" ],
"KeystoneAdmin" => [ "admin" ],
"KeystoneServiceAdmin" => [ "admin" ]
}
},
"demo" => {
"password" => "secrete",
"default_tenant" => "demo",
"roles" => {
"Member" => [ "demo" ]
}
},
"monitoring" => {
"password" => "secrete",
"default_tenant" => "service",
"roles" => {
"Member" => [ "demo", "admin" ]
}
}
}
# platform defaults
case platform
when "fedora"
default["keystone"]["platform"] = {
"mysql_python_packages" => [ "MySQL-python" ],
"keystone_packages" => [ "openstack-keystone" ],
"keystone_service" => "openstack-keystone",
"package_options" => ""
}
when "ubuntu"
default["keystone"]["platform"] = {
"mysql_python_packages" => [ "python-mysqldb" ],
"keystone_packages" => [ "keystone" ],
"keystone_service" => "keystone",
"package_options" => "-o Dpkg::Options::='--force-confold' -o Dpkg::Options::='--force-confdef'"
}
end

View File

@ -0,0 +1,79 @@
from keystoneclient.v2_0 import Client as KeystoneClient
import collectd
global OS_USERNAME, OS_PASSWORD, OS_TENANT_NAME, OS_AUTH_URL, VERBOSE_LOGGING
OS_USERNAME = "username"
OS_PASSWORD = "password"
OS_TENANT_NAME = "tenantname"
OS_AUTH_URL = "http://localhost:5000/v2.0"
VERBOSE_LOGGING = False
def get_stats(user, passwd, tenant, url):
keystone = KeystoneClient(username=user, password=passwd, tenant_name=tenant, auth_url=url)
data = dict()
# Define list of keys to query for
keys = ('tenants','users','roles','services','endpoints')
for key in keys:
data["openstack.keystone.%s.count" % key] = len(keystone.__getattribute__(key).list())
tenant_list = keystone.tenants.list()
for tenant in tenant_list:
data["openstack.keystone.tenants.tenants.%s.users.count" % tenant.name] = len(keystone.tenants.list_users(tenant.id))
##########
# debug
#for key in data.keys():
# print "%s = %s" % (key, data[key])
##########
return data
def configure_callback(conf):
"""Received configuration information"""
global OS_USERNAME, OS_PASSWORD, OS_TENANT_NAME, OS_AUTH_URL, VERBOSE_LOGGING
for node in conf.children:
if node.key == "Username":
OS_USERNAME = node.values[0]
elif node.key == "Password":
OS_PASSWORD = node.values[0]
elif node.key == "TenantName":
OS_TENANT_NAME = node.values[0]
elif node.key == "AuthURL":
OS_AUTH_URL = node.values[0]
elif node.key == "Verbose":
VERBOSE_LOGGING = node.values[0]
else:
logger("warn", "Unknown config key: %s" % node.key)
def read_callback():
logger("verb", "read_callback")
info = get_stats(OS_USERNAME, OS_PASSWORD, OS_TENANT_NAME, OS_AUTH_URL)
if not info:
logger("err", "No information received")
return
for key in info.keys():
logger('verb', 'Dispatching %s : %i' % (key, int(info[key])))
val = collectd.Values(plugin=key)
val.type = 'gauge'
val.values = [int(info[key])]
val.dispatch()
def logger(t, msg):
if t == 'err':
collectd.error('%s: %s' % (NAME, msg))
if t == 'warn':
collectd.warning('%s: %s' % (NAME, msg))
elif t == 'verb' and VERBOSE_LOGGING == True:
collectd.info('%s: %s' % (NAME, msg))
collectd.register_config(configure_callback)
collectd.warning("Initializing keystone plugin")
collectd.register_read(read_callback)

128
providers/credentials.rb Normal file
View File

@ -0,0 +1,128 @@
action :create_ec2 do
Chef::Log.debug("Keystone/Providers/Credentials.rb")
Chef::Log.debug("Create_EC2 actions")
# construct a HTTP object
http = Net::HTTP.new(new_resource.auth_host, new_resource.auth_port)
# Check to see if connection is http or https
if new_resource.auth_protocol == "https"
http.use_ssl = true
end
# Build out the required header info
headers = _build_headers(new_resource.auth_token)
# lookup tenant_uuid
Chef::Log.debug("Looking up Tenant_UUID for Tenant_Name: #{new_resource.tenant_name}")
tenant_container = "tenants"
tenant_key = "name"
tenant_path = "/#{new_resource.api_ver}/tenants"
tenant_uuid, tenant_error = _find_id(http, tenant_path, headers, tenant_container, tenant_key, new_resource.tenant_name)
Chef::Log.error("There was an error looking up Tenant '#{new_resource.tenant_name}'") if tenant_error
# lookup user_uuid
Chef::Log.debug("Looking up User_UUID for User_Name: #{new_resource.user_name}")
user_container = "users"
user_key = "name"
user_path = "/#{new_resource.api_ver}/tenants/#{tenant_uuid}/users"
user_uuid, user_error = _find_id(http, user_path, headers, user_container, user_key, new_resource.user_name)
Chef::Log.error("There was an error looking up User '#{new_resource.user_name}'") if user_error
Chef::Log.debug("Found Tenant UUID: #{tenant_uuid}")
Chef::Log.debug("Found User UUID: #{user_uuid}")
# See if a set of credentials already exists for this user/tenant combo
cred_container = "credentials"
cred_key = "tenant_id"
cred_path = "/#{new_resource.api_ver}/users/#{user_uuid}/credentials/OS-EC2"
cred_tenant_uuid, cred_error = _find_cred_id(http, cred_path, headers, cred_container, cred_key, tenant_uuid)
Chef::Log.error("There was an error looking up EC2 Credentials for User '#{new_resource.user_name}' and Tenant '#{new_resource.tenant_name}'") if cred_error
error = (tenant_error or user_error or cred_error)
unless cred_tenant_uuid or error
# Construct the extension path
path = "/#{new_resource.api_ver}/users/#{user_uuid}/credentials/OS-EC2"
payload = _build_credentials_obj(tenant_uuid)
resp = http.send_request('POST', path, JSON.generate(payload), headers)
if resp.is_a?(Net::HTTPOK)
Chef::Log.info("Created EC2 Credentials for User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
# Need to parse the output here and update node attributes
data = JSON.parse(resp.body)
node.set['credentials']['EC2'][new_resource.user_name]['access'] = data['credential']['access']
node.set['credentials']['EC2'][new_resource.user_name]['secret'] = data['credential']['secret']
node.save unless Chef::Config[:solo]
new_resource.updated_by_last_action(true)
else
Chef::Log.error("Unable to create EC2 Credentials for User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
else
Chef::Log.info("Credentials already exist for User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'.. Not creating.")
new_resource.updated_by_last_action(false)
end
end
private
def _find_id(http, path, headers, container, key, match_value)
uuid = nil
error = false
resp = http.request_get(path, headers)
if resp.is_a?(Net::HTTPOK)
data = JSON.parse(resp.body)
data[container].each do |obj|
uuid = obj['id'] if obj[key] == match_value
break if uuid
end
else
Chef::Log.error("Unknown response from the Keystone Server")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
error = true
end
return uuid,error
end
private
def _find_cred_id(http, path, headers, container, key, match_value)
uuid = nil
error = false
resp = http.request_get(path, headers)
if resp.is_a?(Net::HTTPOK)
data = JSON.parse(resp.body)
data[container].each do |obj|
uuid = obj['tenant_id'] if obj[key] == match_value
break if uuid
end
else
Chef::Log.error("Unknown response from the Keystone Server")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
error = true
end
return uuid,error
end
private
def _build_credentials_obj(tenant_uuid)
ret = Hash.new
ret.store("tenant_id", tenant_uuid)
return ret
end
private
def _build_headers(token)
ret = Hash.new
ret.store('X-Auth-Token', token)
ret.store('Content-type', 'application/json')
ret.store('user-agent', 'Chef keystone_credentials')
return ret
end

445
providers/register.rb Normal file
View File

@ -0,0 +1,445 @@
action :create_service do
# construct a HTTP object
http = Net::HTTP.new(new_resource.auth_host, new_resource.auth_port)
# Check to see if connection is http or https
if new_resource.auth_protocol == "https"
http.use_ssl = true
end
# Build out the required header info
headers = _build_headers(new_resource.auth_token)
# Construct the extension path
path = "/#{new_resource.api_ver}/OS-KSADM/services"
# See if the service exists yet
service_uuid, error = _find_service_id(http, path, headers, new_resource.service_type)
unless service_uuid
# Service does not exist yet
payload = _build_service_object(new_resource.service_type, new_resource.service_name, new_resource.service_description)
resp = http.send_request('POST', path, JSON.generate(payload), headers)
if resp.is_a?(Net::HTTPOK)
Chef::Log.info("Created service '#{new_resource.service_name}'")
new_resource.updated_by_last_action(true)
else
Chef::Log.error("Unable to create service '#{new_resource.service_name}'")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
else
Chef::Log.info("Service Type '#{new_resource.service_type}' already exists.. Not creating.") if error
Chef::Log.info("Service UUID: #{service_uuid}")
new_resource.updated_by_last_action(false)
end
end
action :create_endpoint do
# construct a HTTP object
http = Net::HTTP.new(new_resource.auth_host, new_resource.auth_port)
# Check to see if connection is http or https
if new_resource.auth_protocol == "https"
http.use_ssl = true
end
# Build out the required header info
headers = _build_headers(new_resource.auth_token)
# Construct the extension path
path = "/#{new_resource.api_ver}/endpoints"
# Lookup the service_uuid for service_type
service_uuid, error = _find_service_id(http, "/#{new_resource.api_ver}/OS-KSADM/services", headers, new_resource.service_type)
unless service_uuid
Chef::Log.error("Unable to find service type '#{new_resource.service_type}'")
new_resource.updated_by_last_action(false)
return
end
# Make sure this endpoint does not already exist
resp = http.request_get(path, headers)
if resp.is_a?(Net::HTTPOK)
endpoint_exists = false
data = JSON.parse(resp.body)
data['endpoints'].each do |endpoint|
if endpoint['service_id'] == service_uuid
# Match found
endpoint_exists = true
break
end
end
if endpoint_exists
Chef::Log.info("Endpoint already exists for Service Type '#{new_resource.service_type}' already exists.. Not creating.")
new_resource.updated_by_last_action(false)
else
payload = _build_endpoint_object(
new_resource.endpoint_region,
service_uuid,
new_resource.endpoint_publicurl,
new_resource.endpoint_internalurl,
new_resource.endpoint_adminurl)
resp = http.send_request('POST', path, JSON.generate(payload), headers)
if resp.is_a?(Net::HTTPOK)
Chef::Log.info("Created endpoint for service type '#{new_resource.service_type}'")
new_resource.updated_by_last_action(true)
else
Chef::Log.error("Unable to create endpoint for service type '#{new_resource.service_type}'")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
end
else
Chef::Log.error("Unknown response from the Keystone Server")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
end
action :create_tenant do
# construct a HTTP object
http = Net::HTTP.new(new_resource.auth_host, new_resource.auth_port)
# Check to see if connection is http or https
if new_resource.auth_protocol == "https"
http.use_ssl = true
end
# Build out the required header info
headers = _build_headers(new_resource.auth_token)
# Construct the extension path
path = "/#{new_resource.api_ver}/tenants"
# See if the service exists yet
tenant_uuid, error = _find_tenant_id(http, path, headers, new_resource.tenant_name)
unless tenant_uuid
# Service does not exist yet
payload = _build_tenant_object(new_resource.tenant_name, new_resource.service_description, new_resource.tenant_enabled)
resp = http.send_request('POST', path, JSON.generate(payload), headers)
if resp.is_a?(Net::HTTPOK)
Chef::Log.info("Created tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(true)
else
Chef::Log.error("Unable to create tenant '#{new_resource.tenant_name}'")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
else
Chef::Log.info("Tenant '#{new_resource.tenant_name}' already exists.. Not creating.") if error
Chef::Log.info("Tenant UUID: #{tenant_uuid}")
new_resource.updated_by_last_action(false)
end
end
action :create_role do
# construct a HTTP object
http = Net::HTTP.new(new_resource.auth_host, new_resource.auth_port)
# Check to see if connection is http or https
if new_resource.auth_protocol == "https"
http.use_ssl = true
end
# Build out the required header info
headers = _build_headers(new_resource.auth_token)
# Construct the extension path
path = "/#{new_resource.api_ver}/OS-KSADM/roles"
container = "roles"
key = "name"
# See if the role exists yet
role_uuid, error = _find_id(http, path, headers, container, key, new_resource.role_name)
unless role_uuid
# role does not exist yet
payload = _build_role_obj(new_resource.role_name)
resp = http.send_request('POST', path, JSON.generate(payload), headers)
if resp.is_a?(Net::HTTPOK)
Chef::Log.info("Created Role '#{new_resource.role_name}'")
new_resource.updated_by_last_action(true)
else
Chef::Log.error("Unable to create role '#{new_resource.role_name}'")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
else
Chef::Log.info("Role '#{new_resource.role_name}' already exists.. Not creating.") if error
Chef::Log.info("Role UUID: #{role_uuid}")
new_resource.updated_by_last_action(false)
end
end
action :create_user do
# construct a HTTP object
http = Net::HTTP.new(new_resource.auth_host, new_resource.auth_port)
# Check to see if connection is http or https
if new_resource.auth_protocol == "https"
http.use_ssl = true
end
# Build out the required header info
headers = _build_headers(new_resource.auth_token)
# Lookup the tenant_uuid for tenant_name
tenant_uuid, error = _find_tenant_id(http, "/#{new_resource.api_ver}/tenants", headers, new_resource.tenant_name)
unless tenant_uuid
Chef::Log.error("Unable to find tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(false)
return
end
# Construct the extension path using the found tenant_uuid
path = "/#{new_resource.api_ver}/users"
# Make sure this endpoint does not already exist
resp = http.request_get("#{new_resource.api_ver}/tenants/#{tenant_uuid}/users", headers)
if resp.is_a?(Net::HTTPOK)
user_exists = false
data = JSON.parse(resp.body)
data['users'].each do |endpoint|
if endpoint['name'] == new_resource.user_name
# Match found
user_exists = true
break
end
end
if user_exists
Chef::Log.info("User '#{new_resource.user_name}' already exists for tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(false)
else
payload = _build_user_object(
tenant_uuid,
new_resource.user_name,
new_resource.user_pass,
new_resource.user_enabled)
resp = http.send_request('POST', path, JSON.generate(payload), headers)
if resp.is_a?(Net::HTTPOK)
Chef::Log.info("Created user '#{new_resource.user_name}' for tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(true)
else
Chef::Log.error("Unable to create user '#{new_resource.user_name}' for tenant '#{new_resource.tenant_name}'")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
end
else
Chef::Log.error("Unknown response from the Keystone Server")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
end
action :grant_role do
# construct a HTTP object
http = Net::HTTP.new(new_resource.auth_host, new_resource.auth_port)
# Check to see if connection is http or https
if new_resource.auth_protocol == "https"
http.use_ssl = true
end
# Build out the required header info
headers = _build_headers(new_resource.auth_token)
# lookup tenant_uuid
tenant_container = "tenants"
tenant_key = "name"
tenant_path = "/#{new_resource.api_ver}/tenants"
tenant_uuid, tenant_error = _find_id(http, tenant_path, headers, tenant_container, tenant_key, new_resource.tenant_name)
Chef::Log.error("There was an error looking up Tenant '#{new_resource.tenant_name}'") if tenant_error
# lookup user_uuid
user_container = "users"
user_key = "name"
# user_path = "/#{new_resource.api_ver}/tenants/#{tenant_uuid}/users"
user_path = "/#{new_resource.api_ver}/users"
user_uuid, user_error = _find_id(http, user_path, headers, user_container, user_key, new_resource.user_name)
Chef::Log.error("There was an error looking up User '#{new_resource.user_name}'") if user_error
# lookup role_uuid
role_container = "roles"
role_key = "name"
role_path = "/#{new_resource.api_ver}/OS-KSADM/roles"
role_uuid, role_error = _find_id(http, role_path, headers, role_container, role_key, new_resource.role_name)
Chef::Log.error("There was an error looking up Role '#{new_resource.role_name}'") if role_error
Chef::Log.debug("Found Tenant UUID: #{tenant_uuid}")
Chef::Log.debug("Found User UUID: #{user_uuid}")
Chef::Log.debug("Found Role UUID: #{role_uuid}")
# lookup roles assigned to user/tenant
assigned_container = "roles"
assigned_key = "name"
assigned_path = "/#{new_resource.api_ver}/tenants/#{tenant_uuid}/users/#{user_uuid}/roles"
assigned_role_uuid, assigned_error = _find_id(http, assigned_path, headers, assigned_container, assigned_key, new_resource.role_name)
Chef::Log.error("There was an error looking up Assigned Role '#{new_resource.role_name}' for User '#{new_resource.user_name}' and Tenant '#{new_resource.tenant_name}'") if assigned_error
error = (tenant_error or user_error or role_error or assigned_error)
unless role_uuid == assigned_role_uuid or error
# Construct the extension path
path = "/#{new_resource.api_ver}/tenants/#{tenant_uuid}/users/#{user_uuid}/roles/OS-KSADM/#{role_uuid}"
# needs a '' for the body, or it throws a 500
resp = http.send_request('PUT', path, '', headers)
if resp.is_a?(Net::HTTPOK)
Chef::Log.info("Granted Role '#{new_resource.role_name}' to User '#{new_resource.user_name}' in Tenant '#{new_resource.tenant_name}'")
new_resource.updated_by_last_action(true)
else
Chef::Log.error("Unable to grant role '#{new_resource.role_name}'")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
new_resource.updated_by_last_action(false)
end
else
Chef::Log.info("Role '#{new_resource.role_name}' already exists.. Not granting.")
Chef::Log.error("There was an error looking up '#{new_resource.role_name}'") if error
new_resource.updated_by_last_action(false)
end
end
private
def _find_service_id(http, path, headers, service_type)
service_uuid = nil
error = false
resp = http.request_get(path, headers)
if resp.is_a?(Net::HTTPOK)
data = JSON.parse(resp.body)
data['OS-KSADM:services'].each do |svc|
service_uuid = svc['id'] if svc['type'] == service_type
break if service_uuid
end
else
Chef::Log.error("Unknown response from the Keystone Server")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
error = true
end
return service_uuid,error
end
private
def _find_id(http, path, headers, container, key, match_value)
uuid = nil
error = false
resp = http.request_get(path, headers)
if resp.is_a?(Net::HTTPOK)
data = JSON.parse(resp.body)
data[container].each do |obj|
uuid = obj['id'] if obj[key] == match_value
break if uuid
end
else
Chef::Log.error("Unknown response from the Keystone Server")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
error = true
end
return uuid,error
end
private
def _find_tenant_id(http, path, headers, tenant_name)
tenant_uuid = nil
error = false
resp = http.request_get(path, headers)
if resp.is_a?(Net::HTTPOK)
data = JSON.parse(resp.body)
data['tenants'].each do |tenant|
tenant_uuid = tenant['id'] if tenant['name'] == tenant_name
break if tenant_uuid
end
else
Chef::Log.error("Unknown response from the Keystone Server")
Chef::Log.error("Response Code: #{resp.code}")
Chef::Log.error("Response Message: #{resp.message}")
error = true
end
return tenant_uuid,error
end
private
def _build_service_object(type, name, description)
service_obj = Hash.new
service_obj.store("type", type)
service_obj.store("name", name)
service_obj.store("description", description)
ret = Hash.new
ret.store("OS-KSADM:service", service_obj)
return ret
end
private
def _build_role_obj(name)
role_obj = Hash.new
role_obj.store("name", name)
ret = Hash.new
ret.store("role", role_obj)
return ret
end
private
def _build_tenant_object(name, description, enabled)
tenant_obj = Hash.new
tenant_obj.store("name", name)
tenant_obj.store("description", description)
tenant_obj.store("enabled", enabled)
ret = Hash.new
ret.store("tenant", tenant_obj)
return ret
end
private
def _build_endpoint_object(region, service_uuid, publicurl, internalurl, adminurl)
endpoint_obj = Hash.new
endpoint_obj.store("adminurl", adminurl)
endpoint_obj.store("internalurl", internalurl)
endpoint_obj.store("publicurl", publicurl)
endpoint_obj.store("service_id", service_uuid)
endpoint_obj.store("region", region)
ret = Hash.new
ret.store("endpoint", endpoint_obj)
return ret
end
private
def _build_user_object(tenant_uuid, name, password, enabled)
user_obj = Hash.new
user_obj.store("tenantId", tenant_uuid)
user_obj.store("name", name)
user_obj.store("password", password)
# Have to provide a null value for this because I dont want to have this in the LWRP
user_obj.store("email", nil)
user_obj.store("enabled", enabled)
ret = Hash.new
ret.store("user", user_obj)
return ret
end
private
def _build_headers(token)
ret = Hash.new
ret.store('X-Auth-Token', token)
ret.store('Content-type', 'application/json')
ret.store('user-agent', 'Chef keystone_register')
return ret
end

232
recipes/server.rb Normal file
View File

@ -0,0 +1,232 @@
#
# Cookbook Name:: keystone
# Recipe:: server
#
# Copyright 2009, Rackspace Hosting, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
::Chef::Recipe.send(:include, Opscode::OpenSSL::Password)
include_recipe "mysql::client"
include_recipe "osops-utils"
# Allow for using a well known db password
if node["developer_mode"]
node.set_unless["keystone"]["db"]["password"] = "keystone"
node.set_unless["keystone"]["admin_token"] = "999888777666"
else
node.set_unless["keystone"]["db"]["password"] = secure_password
node.set_unless["keystone"]["admin_token"] = secure_password
end
platform_options = node["keystone"]["platform"]
#creates db and user, returns connection info, defined in osops-utils/libraries
mysql_info = create_db_and_user("mysql",
node["keystone"]["db"]["name"],
node["keystone"]["db"]["username"],
node["keystone"]["db"]["password"])
##### NOTE #####
# https://bugs.launchpad.net/ubuntu/+source/keystone/+bug/931236
################
platform_options["mysql_python_packages"].each do |pkg|
package pkg do
action :install
end
end
platform_options["keystone_packages"].each do |pkg|
package pkg do
action :upgrade
options platform_options["package_options"]
end
end
execute "Keystone: sleep" do
command "sleep 10s"
action :nothing
end
service "keystone" do
service_name platform_options["keystone_service"]
supports :status => true, :restart => true
action [ :enable ]
notifies :run, resources(:execute => "Keystone: sleep"), :immediately
end
directory "/etc/keystone" do
action :create
owner "root"
group "root"
mode "0755"
end
file "/var/lib/keystone/keystone.db" do
action :delete
end
execute "keystone-manage db_sync" do
command "keystone-manage db_sync"
action :nothing
end
ks_admin_endpoint = get_bind_endpoint("keystone", "admin-api")
ks_service_endpoint = get_bind_endpoint("keystone", "service-api")
template "/etc/keystone/keystone.conf" do
source "keystone.conf.erb"
owner "root"
group "root"
mode "0644"
variables(
:debug => node["keystone"]["debug"],
:verbose => node["keystone"]["verbose"],
:user => node["keystone"]["db"]["username"],
:passwd => node["keystone"]["db"]["password"],
:ip_address => ks_admin_endpoint["host"],
:db_name => node["keystone"]["db"]["name"],
:db_ipaddress => mysql_info["bind_address"],
:service_port => ks_service_endpoint["port"],
:admin_port => ks_admin_endpoint["port"],
:admin_token => node["keystone"]["admin_token"]
)
notifies :run, resources(:execute => "keystone-manage db_sync"), :immediately
notifies :restart, resources(:service => "keystone"), :immediately
end
template "/etc/keystone/logging.conf" do
source "keystone-logging.conf.erb"
owner "root"
group "root"
mode "0644"
notifies :restart, resources(:service => "keystone"), :immediately
end
node["keystone"]["tenants"].each do |tenant_name|
## Add openstack tenant ##
keystone_register "Register '#{tenant_name}' Tenant" do
auth_host ks_admin_endpoint["host"]
auth_port ks_admin_endpoint["port"]
auth_protocol ks_admin_endpoint["schema"]
api_ver ks_admin_endpoint["path"]
auth_token node["keystone"]["admin_token"]
tenant_name tenant_name
tenant_description "#{tenant_name} Tenant"
tenant_enabled "true" # Not required as this is the default
action :create_tenant
end
end
## Add Roles ##
node["keystone"]["roles"].each do |role_key|
keystone_register "Register '#{role_key.to_s}' Role" do
auth_host ks_admin_endpoint["host"]
auth_port ks_admin_endpoint["port"]
auth_protocol ks_admin_endpoint["schema"]
api_ver ks_admin_endpoint["path"]
auth_token node["keystone"]["admin_token"]
role_name role_key
action :create_role
end
end
node["keystone"]["users"].each do |username, user_info|
keystone_register "Register '#{username}' User" do
auth_host ks_admin_endpoint["host"]
auth_port ks_admin_endpoint["port"]
auth_protocol ks_admin_endpoint["schema"]
api_ver ks_admin_endpoint["path"]
auth_token node["keystone"]["admin_token"]
user_name username
user_pass user_info["password"]
tenant_name user_info["default_tenant"]
user_enabled "true" # Not required as this is the default
action :create_user
end
user_info["roles"].each do |rolename, tenant_list|
tenant_list.each do |tenantname|
keystone_register "Grant '#{rolename}' Role to '#{username}' User in '#{tenantname}' Tenant" do
auth_host ks_admin_endpoint["host"]
auth_port ks_admin_endpoint["port"]
auth_protocol ks_admin_endpoint["schema"]
api_ver ks_admin_endpoint["path"]
auth_token node["keystone"]["admin_token"]
user_name username
role_name rolename
tenant_name tenantname
action :grant_role
end
end
end
end
## Add Services ##
keystone_register "Register Identity Service" do
auth_host ks_admin_endpoint["host"]
auth_port ks_admin_endpoint["port"]
auth_protocol ks_admin_endpoint["schema"]
api_ver ks_admin_endpoint["path"]
auth_token node["keystone"]["admin_token"]
service_name "keystone"
service_type "identity"
service_description "Keystone Identity Service"
action :create_service
end
## Add Endpoints ##
node["keystone"]["adminURL"] = ks_admin_endpoint["uri"]
node["keystone"]["internalURL"] = ks_service_endpoint["uri"]
node["keystone"]["publicURL"] = ks_service_endpoint["uri"]
Chef::Log.info "Keystone AdminURL: #{ks_admin_endpoint["uri"]}"
Chef::Log.info "Keystone InternalURL: #{ks_service_endpoint["uri"]}"
Chef::Log.info "Keystone PublicURL: #{ks_service_endpoint["uri"]}"
keystone_register "Register Identity Endpoint" do
auth_host ks_admin_endpoint["host"]
auth_port ks_admin_endpoint["port"]
auth_protocol ks_admin_endpoint["schema"]
api_ver ks_admin_endpoint["path"]
auth_token node["keystone"]["admin_token"]
service_type "identity"
endpoint_region "RegionOne"
endpoint_adminurl node["keystone"]["adminURL"]
endpoint_internalurl node["keystone"]["internalURL"]
endpoint_publicurl node["keystone"]["publicURL"]
action :create_endpoint
end
node["keystone"]["users"].each do |username, user_info|
keystone_credentials "Create EC2 credentials for '#{username}' user" do
auth_host ks_admin_endpoint["host"]
auth_port ks_admin_endpoint["port"]
auth_protocol ks_admin_endpoint["schema"]
api_ver ks_admin_endpoint["path"]
auth_token node["keystone"]["admin_token"]
user_name username
tenant_name user_info["default_tenant"]
end
end
# TODO(shep): this needs to be if blocked on env collectd toggle
# Include recipe(nova::network-monitoring)
include_recipe "keystone::server-monitoring"

17
resources/credentials.rb Normal file
View File

@ -0,0 +1,17 @@
actions :create_ec2
# In earlier versions of Chef the LWRP DSL doesn't support specifying
# a default action, so you need to drop into Ruby.
def initialize(*args)
super
@action = :create_ec2
end
attribute :auth_protocol, :kind_of => String, :equal_to => [ "http", "https" ]
attribute :auth_host, :kind_of => String
attribute :auth_port, :kind_of => String
attribute :api_ver, :kind_of => String, :default => "/v2.0"
attribute :auth_token, :kind_of => String
attribute :tenant_name, :kind_of => String
attribute :user_name, :kind_of => String

44
resources/register.rb Normal file
View File

@ -0,0 +1,44 @@
actions :create_service, :create_endpoint, :create_tenant, :create_user, :create_role, :grant_role
# In earlier versions of Chef the LWRP DSL doesn't support specifying
# a default action, so you need to drop into Ruby.
def initialize(*args)
super
@action = :create
end
attribute :auth_protocol, :kind_of => String, :equal_to => [ "http", "https" ]
attribute :auth_host, :kind_of => String
attribute :auth_port, :kind_of => String
attribute :api_ver, :kind_of => String, :default => "/v2.0"
attribute :auth_token, :kind_of => String
# Used by both :create_service and :create_endpoint
attribute :service_type, :kind_of => String, :equal_to => [ "image", "identity", "compute", "storage", "ec2", "volume", "object-store" ]
# :create_service specific attributes
attribute :service_name, :kind_of => String
attribute :service_description, :kind_of => String
# :create_endpoint specific attributes
attribute :endpoint_region, :kind_of => String, :default => "RegionOne"
attribute :endpoint_adminurl, :kind_of => String
attribute :endpoint_internalurl, :kind_of => String
attribute :endpoint_publicurl, :kind_of => String
# Used by both :create_tenant and :create_user
attribute :tenant_name, :kind_of => String
# :create_tenant specific attributes
attribute :tenant_description, :kind_of => String
attribute :tenant_enabled, :kind_of => String, :equal_to => [ "true", "false" ], :default => "true"
# :create_user specific attributes
attribute :user_name, :kind_of => String
attribute :user_pass, :kind_of => String
# attribute :user_email, :kind_of => String
attribute :user_enabled, :kind_of => String, :equal_to => [ "true", "false" ], :default => "true"
# Used by :create_role and :grant_role specific attributes
attribute :role_name, :kind_of => String

View File

@ -0,0 +1,49 @@
[loggers]
keys=root,keystone,combined
[formatters]
keys=normal,normal_with_name,debug
[handlers]
keys=production,file,devel
[logger_root]
level=NOTSET
handlers=file
[logger_keystone]
level=DEBUG
handlers=file
qualname=keystone
[logger_combined]
level=DEBUG
handlers=file
qualname=keystone-combined
[handler_production]
class=handlers.SysLogHandler
level=ERROR
formatter=normal_with_name
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
[handler_file]
class=FileHandler
level=DEBUG
formatter=normal_with_name
args=('/var/log/keystone/keystone.log', 'w')
[handler_devel]
class=StreamHandler
level=NOTSET
formatter=debug
args=(sys.stdout,)
[formatter_normal]
format=%(asctime)s %(levelname)s %(message)s
[formatter_normal_with_name]
format=(%(name)s): %(asctime)s %(levelname)s %(message)s
[formatter_debug]
format=(%(name)s): %(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s

View File

@ -0,0 +1,107 @@
[DEFAULT]
public_port = <%= @service_port %>
admin_port = <%= @admin_port %>
admin_token = <%= @admin_token %>
bind_host = <%= @ip_address %>
compute_port = 8774
verbose = True
debug = True
log_config = /etc/keystone/logging.conf
# ================= Syslog Options ============================
# Send logs to syslog (/dev/log) instead of to file specified
# by `log-file`
use_syslog = False
# Facility to use. If unset defaults to LOG_USER.
# syslog_log_facility = LOG_LOCAL0
[sql]
connection = mysql://<%= @user %>:<%= @passwd %>@<%= @db_ipaddress %>/<%= @db_name %>
idle_timeout = 200
min_pool_size = 5
max_pool_size = 10
pool_timeout = 200
[ldap]
#url = ldap://localhost
#tree_dn = dc=example,dc=com
#user_tree_dn = ou=Users,dc=example,dc=com
#role_tree_dn = ou=Roles,dc=example,dc=com
#tenant_tree_dn = ou=Groups,dc=example,dc=com
#user = dc=Manager,dc=example,dc=com
#password = freeipa4all
#suffix = cn=example,cn=com
[identity]
driver = keystone.identity.backends.sql.Identity
[catalog]
driver = keystone.catalog.backends.sql.Catalog
[token]
driver = keystone.token.backends.sql.Token
# Amount of time a token should remain valid (in seconds)
expiration = 86400
[policy]
driver = keystone.policy.backends.simple.SimpleMatch
[ec2]
driver = keystone.contrib.ec2.backends.sql.Ec2
[filter:debug]
paste.filter_factory = keystone.common.wsgi:Debug.factory
[filter:token_auth]
paste.filter_factory = keystone.middleware:TokenAuthMiddleware.factory
[filter:admin_token_auth]
paste.filter_factory = keystone.middleware:AdminTokenAuthMiddleware.factory
[filter:xml_body]
paste.filter_factory = keystone.middleware:XmlBodyMiddleware.factory
[filter:json_body]
paste.filter_factory = keystone.middleware:JsonBodyMiddleware.factory
[filter:crud_extension]
paste.filter_factory = keystone.contrib.admin_crud:CrudExtension.factory
[filter:ec2_extension]
paste.filter_factory = keystone.contrib.ec2:Ec2Extension.factory
[app:public_service]
paste.app_factory = keystone.service:public_app_factory
[app:admin_service]
paste.app_factory = keystone.service:admin_app_factory
[pipeline:public_api]
pipeline = token_auth admin_token_auth xml_body json_body debug ec2_extension public_service
[pipeline:admin_api]
pipeline = token_auth admin_token_auth xml_body json_body debug ec2_extension crud_extension admin_service
[app:public_version_service]
paste.app_factory = keystone.service:public_version_app_factory
[app:admin_version_service]
paste.app_factory = keystone.service:admin_version_app_factory
[pipeline:public_version_api]
pipeline = xml_body public_version_service
[pipeline:admin_version_api]
pipeline = xml_body admin_version_service
[composite:main]
use = egg:Paste#urlmap
/v2.0 = public_api
/ = public_version_api
[composite:admin]
use = egg:Paste#urlmap
/v2.0 = admin_api
/ = admin_version_api