osops-utils cookbook from https://github.com/rcbops-cookbooks/osops-utils, waiting for permission to push to community site, will remove once upstream version is published
This commit is contained in:
1
cookbooks/osops-utils/.gitignore
vendored
Normal file
1
cookbooks/osops-utils/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
metadata.json
|
||||
62
cookbooks/osops-utils/README.md
Normal file
62
cookbooks/osops-utils/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Description
|
||||
===========
|
||||
|
||||
Miscellaneous library functions for OpenStack. This currently includes:
|
||||
|
||||
* ip address location
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
Uses the Ruby libraries `chef/search/query`, `ipaddr` and `uri`
|
||||
|
||||
Attributes
|
||||
==========
|
||||
|
||||
`osops_networks` is a list of network names and associated CIDR. These are used in the `get_ip` functions.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
node['osops_networks']['localnet'] = 127.0.0.0/8
|
||||
|
||||
node['osops_networks']['management'] = 10.0.1.0/24
|
||||
|
||||
ip = get_ip_for_net("localnet") # returns 127.0.0.1
|
||||
|
||||
ip = get_ip_for_net("management") # returns the address on management, or error
|
||||
|
||||
License and Author
|
||||
==================
|
||||
|
||||
Author:: Justin Shepherd (<justin.shepherd@rackspace.com>)
|
||||
|
||||
Author:: Jason Cannavale (<jason.cannavale@rackspace.com>)
|
||||
|
||||
Author:: Ron Pedde (<ron.pedde@rackspace.com>)
|
||||
|
||||
Author:: Joseph Breu (<joseph.breu@rackspace.com>)
|
||||
|
||||
Author:: William Kelly (<william.kelly@rackspace.com>)
|
||||
|
||||
Author:: Darren Birkett (<darren.birkett@rackspace.co.uk>)
|
||||
|
||||
Author:: Evan Callicoat (<evan.callicoat@rackspace.com>)
|
||||
|
||||
Author:: Matt Ray (<matt@opscode.com>)
|
||||
|
||||
Copyright 2012 Rackspace, Inc.
|
||||
|
||||
Copyright 2012 Opscode, 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.
|
||||
36
cookbooks/osops-utils/libraries/database.rb
Normal file
36
cookbooks/osops-utils/libraries/database.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
module RCB
|
||||
def create_db_and_user(db, db_name, username, pw)
|
||||
db_info = nil
|
||||
case db
|
||||
when "mysql"
|
||||
mysql_info = get_settings_by_role("mysql-master", "mysql")
|
||||
connection_info = {:host => mysql_info["bind_address"], :username => "root", :password => mysql_info["server_root_password"]}
|
||||
|
||||
# create database
|
||||
mysql_database "create #{db_name} database" do
|
||||
connection connection_info
|
||||
database_name db_name
|
||||
action :create
|
||||
end
|
||||
|
||||
# create user
|
||||
mysql_database_user username do
|
||||
connection connection_info
|
||||
password pw
|
||||
action :create
|
||||
end
|
||||
|
||||
# grant privs to user
|
||||
mysql_database_user username do
|
||||
connection connection_info
|
||||
password pw
|
||||
database_name db_name
|
||||
host '%'
|
||||
privileges [:all]
|
||||
action :grant
|
||||
end
|
||||
db_info = mysql_info
|
||||
end
|
||||
db_info
|
||||
end
|
||||
end
|
||||
327
cookbooks/osops-utils/libraries/ip_location.rb
Normal file
327
cookbooks/osops-utils/libraries/ip_location.rb
Normal file
@@ -0,0 +1,327 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "chef/search/query"
|
||||
require "ipaddr"
|
||||
require "uri"
|
||||
|
||||
module RCB
|
||||
# These are the new endpoint functions, that return much more information about
|
||||
# endpoints. Sufficient to configure something, I hope. :/
|
||||
|
||||
# Get the bind information necessary for a service.
|
||||
# ex: IPManagement.get_bind_endpoint("keystone","admin")
|
||||
# { "host" => "10.1.0.2",
|
||||
# "port" => 35357,
|
||||
# "scheme" => "http",
|
||||
# "path" => "/v2.0",
|
||||
# "uri" => "http://10.1.0.2:35357/v2.0"
|
||||
# "network" => "management"
|
||||
#
|
||||
# To define this resource, there must be a service entries like...
|
||||
# node["keystone"]["services"]["admin"] =
|
||||
# { "network" => "management", "port" => 35357 }
|
||||
#
|
||||
# IP address is derived from required network, unless overridden
|
||||
# Protocol defaults to "http", path defaults to "/". If a URI
|
||||
# is specified, it overrides all other settings, otherwise it is
|
||||
# composed from the individual components
|
||||
|
||||
def rcb_exit_error(msg)
|
||||
Chef::Log.error(msg)
|
||||
raise msg
|
||||
end
|
||||
|
||||
def rcb_safe_deref(hash, path)
|
||||
current = hash
|
||||
|
||||
Chef::Log.debug("Searching for #{path} in #{hash}")
|
||||
path_ary = path.split(".")
|
||||
path_ary.each do |k|
|
||||
if current and current.has_key?(k)
|
||||
current = current[k]
|
||||
else
|
||||
current = nil
|
||||
end
|
||||
end
|
||||
|
||||
current
|
||||
end
|
||||
|
||||
# stub until we can migrate out the IPManagement stuff
|
||||
def get_ip_for_net(network, nodeish = nil)
|
||||
_, ip = get_if_ip_for_net(network, nodeish)
|
||||
return ip
|
||||
end
|
||||
|
||||
def get_if_for_net(network, nodeish = nil)
|
||||
iface, _ = get_if_ip_for_net(network, nodeish)
|
||||
return iface
|
||||
end
|
||||
|
||||
def get_if_ip_for_net(network, nodeish = nil)
|
||||
nodish = node unless nodeish
|
||||
|
||||
if network == "all"
|
||||
return "0.0.0.0"
|
||||
end
|
||||
|
||||
if network == "localhost"
|
||||
return "127.0.0.1"
|
||||
end
|
||||
|
||||
if not (node.has_key?("osops_networks") and node["osops_networks"].has_key?(network)) then
|
||||
error = "Can't find network #{network}"
|
||||
Chef::Log.error(error)
|
||||
raise error
|
||||
end
|
||||
|
||||
net = IPAddr.new(node["osops_networks"][network])
|
||||
node["network"]["interfaces"].each do |interface|
|
||||
interface[1]["addresses"].each do |k,v|
|
||||
if v["family"] == "inet6" or v["family"] == "inet" then
|
||||
addr=IPAddr.new(k)
|
||||
if net.include?(addr) then
|
||||
return [interface[0], k]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
error = "Can't find address on network #{network} for node"
|
||||
Chef::Log.error(error)
|
||||
raise error
|
||||
end
|
||||
|
||||
def get_bind_endpoint(server, service, nodeish=nil)
|
||||
retval = {}
|
||||
nodeish = node unless nodeish
|
||||
|
||||
if svc = rcb_safe_deref(nodeish, "#{server}.services.#{service}")
|
||||
retval["path"] = svc["path"] || "/"
|
||||
retval["scheme"] = svc["scheme"] || "http"
|
||||
retval["port"] = svc["port"] || "80"
|
||||
|
||||
# if we have an endpoint, we'll just parse the pieces
|
||||
if svc.has_key?("uri")
|
||||
uri = URI(svc["uri"])
|
||||
["path", "scheme", "port", "host"].each do |x|
|
||||
retval.merge(x => uri.send(x))
|
||||
end
|
||||
elsif svc.has_key?("host")
|
||||
retval["host"] = svc["host"]
|
||||
retval["uri"] = "#{retval['scheme']}://#{retval['host']}:#{retval['port']}"
|
||||
retval["uri"] += retval["path"]
|
||||
else
|
||||
# we'll get the network from the osops network
|
||||
retval["host"] = Chef::Recipe::IPManagement.get_ip_for_net(svc["network"], nodeish)
|
||||
retval["uri"] = "#{retval['scheme']}://#{retval['host']}:#{retval['port']}"
|
||||
retval["uri"] += retval["path"]
|
||||
end
|
||||
|
||||
retval
|
||||
else
|
||||
Chef::Log.warn("Cannot find server/service #{server}/#{service}")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Get the access endpoint for a role.
|
||||
#
|
||||
# If a role search returns no results, but the role is in our
|
||||
# current runlist, use the bind endpoint from the local node
|
||||
# attributes.
|
||||
#
|
||||
# If a role search returns more than one result, then return
|
||||
# the LB config for that service
|
||||
#
|
||||
# If the role search returns exactly one result, then use
|
||||
# the bind endpoint for the service according to that nodes attributes
|
||||
#
|
||||
|
||||
def get_access_endpoint(role, server, service)
|
||||
query = "roles:#{role} AND chef_environment:#{node.chef_environment}"
|
||||
result, _, _ = Chef::Search::Query.new.search(:node, query)
|
||||
|
||||
if result.length == 1 and result[0].name == node.name
|
||||
Chef::Log.debug("Found 1 result for #{role}/#{server}/#{service}, and it's me!")
|
||||
result = [node]
|
||||
elsif result.length == 0 and node["roles"].include?(role)
|
||||
Chef::Log.debug("Found 0 result for #{role}/#{server}/#{service}, but I'm a role-holder!")
|
||||
result = [node]
|
||||
end
|
||||
|
||||
if result.length == 0
|
||||
Chef::Log.warn("Cannot find #{server}/#{service} for role #{role}")
|
||||
nil
|
||||
elsif result.length > 1
|
||||
get_lb_endpoint(server,service)
|
||||
else
|
||||
get_bind_endpoint(server, service, result[0])
|
||||
end
|
||||
end
|
||||
|
||||
# return the endpoint info for all roles matching the
|
||||
# the service. This differs from access_endpoint, as it
|
||||
# returns all the candidates, not merely the LB vip
|
||||
#
|
||||
def get_realserver_endpoints(role, server, service)
|
||||
query = "roles:#{role} AND chef_environment:#{node.chef_environment}"
|
||||
result, _, _ = Chef::Search::Query.new.search(:node, query)
|
||||
|
||||
# if no query results, but role is in current runlist, use that
|
||||
result = [ node ] if result.length == 0 and node["roles"].include?(role)
|
||||
|
||||
result.map { |nodeish| get_bind_endpoint(server, service, nodeish) }
|
||||
end
|
||||
|
||||
# Get a specific node hash from another node by role
|
||||
#
|
||||
# In the event of a search with multiple results,
|
||||
# it returns the first match
|
||||
#
|
||||
# In the event of a search with a no matches, if the role
|
||||
# is held on the running node, then the current node hash
|
||||
# values will be returned
|
||||
#
|
||||
def get_settings_by_role(role, settings)
|
||||
if node["roles"].include?(role)
|
||||
node[settings]
|
||||
else
|
||||
query = "roles:#{role} AND chef_environment:#{node.chef_environment}"
|
||||
result, _, _ = Chef::Search::Query.new.search(:node, query)
|
||||
|
||||
if result.length == 0
|
||||
nil
|
||||
else
|
||||
result[0][settings]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Get a specific node hash from another node by recipe
|
||||
#
|
||||
# In the event of a search with multiple results,
|
||||
# it returns the first match
|
||||
#
|
||||
# In the event of a search with a no matches, if the role
|
||||
# is held on the running node, then the current node hash
|
||||
# values will be returned
|
||||
#
|
||||
def get_settings_by_recipe(recipe, settings)
|
||||
if node["recipes"].include?(recipe)
|
||||
node[settings]
|
||||
else
|
||||
query = "recipes:#{recipe} AND chef_environment:#{node.chef_environment}"
|
||||
result, _, _ = Chef::Search::Query.new.search(:node, query)
|
||||
|
||||
if result.length == 0
|
||||
Chef::Log.warn("Can't find node with recipe #{recipe}")
|
||||
nil
|
||||
else
|
||||
result[0][settings]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_lb_endpoint(server, service)
|
||||
rcb_exit_error("LB endpoints not yet defined")
|
||||
end
|
||||
end
|
||||
|
||||
class Chef::Recipe
|
||||
include RCB
|
||||
end
|
||||
|
||||
class Chef::Recipe::IPManagement
|
||||
# find the local ip for a host on a specific network
|
||||
def self.get_ip_for_net(network, node)
|
||||
if network == "all"
|
||||
return "0.0.0.0"
|
||||
end
|
||||
|
||||
if network == "localhost"
|
||||
return "127.0.0.1"
|
||||
end
|
||||
|
||||
# remap the network if a map is present
|
||||
if node.has_key?("osops_networks") and
|
||||
node["osops_networks"].has_key?("mapping") and
|
||||
node["osops_networks"]["mapping"].has_key?(network)
|
||||
network = node["osops_networks"]["mapping"][network]
|
||||
end
|
||||
|
||||
if not (node.has_key?("osops_networks") and node["osops_networks"].has_key?(network)) then
|
||||
error = "Can't find network #{network}"
|
||||
Chef::Log.error(error)
|
||||
raise error
|
||||
end
|
||||
|
||||
net = IPAddr.new(node["osops_networks"][network])
|
||||
node["network"]["interfaces"].each do |interface|
|
||||
interface[1]["addresses"].each do |k,v|
|
||||
if v["family"] == "inet6" or v["family"] == "inet" then
|
||||
addr=IPAddr.new(k)
|
||||
if net.include?(addr) then
|
||||
return k
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
error = "Can't find address on network #{network} for node"
|
||||
Chef::Log.error(error)
|
||||
raise error
|
||||
end
|
||||
|
||||
# find the realserver ips for a particular role
|
||||
def self.get_ips_for_role(role, network, node)
|
||||
if Chef::Config[:solo] then
|
||||
return [self.get_ip_for_net(network, node)]
|
||||
else
|
||||
candidates, _, _ = Chef::Search::Query.new.search(:node, "chef_environment:#{node.chef_environment} AND roles:#{role}")
|
||||
if candidates == nil or candidates.length <= 0
|
||||
if node["roles"].include?(role)
|
||||
candidates = [node]
|
||||
end
|
||||
end
|
||||
|
||||
if candidates == nil or candidates.length <= 0
|
||||
error = "Can't find any candidates for role #{role} in environment #{node.chef_environment}"
|
||||
Chef::Log.error(error)
|
||||
raise error
|
||||
end
|
||||
|
||||
return candidates.map { |x| get_ip_for_net(network, x) }
|
||||
end
|
||||
end
|
||||
|
||||
# find the loadbalancer ip for a particular role
|
||||
def self.get_access_ip_for_role(role, network, node)
|
||||
if Chef::Config[:solo] then
|
||||
return self.get_ip_for_net(network, node)
|
||||
else
|
||||
candidates, _, _ = Chef::Search::Query.new.search(:node, "chef_environment:#{node.chef_environment} AND roles:#{role}")
|
||||
if candidates == nil or candidates.length == 0
|
||||
if node["roles"].include?(role)
|
||||
candidates = [ node ]
|
||||
end
|
||||
end
|
||||
|
||||
if candidates.length == 1 then
|
||||
return get_ip_for_net(network, candidates[0])
|
||||
elsif candidates.length == 0 then
|
||||
error = "Can't find any candidates for role #{role} in environment #{node.chef_environment}"
|
||||
Chef::Log.error(error)
|
||||
raise error
|
||||
else
|
||||
if not node["osops_networks"] or not node["osops_networks"]["vips"] or not node["osops_networks"]["vips"][role] then
|
||||
error = "Can't find lb vip for #{role} (osops_networks/vips/#{role}) in environment, with #{candidates.length} #{role} nodes"
|
||||
Chef::Log.error(error)
|
||||
raise error
|
||||
else
|
||||
return node["osops_networks"]["vips"][role]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
6
cookbooks/osops-utils/metadata.rb
Normal file
6
cookbooks/osops-utils/metadata.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
maintainer "Rackspace Hosting"
|
||||
maintainer_email "osops@lists.launchpad.net"
|
||||
license "Apache 2.0"
|
||||
description "Installs/Configures osops-utils"
|
||||
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
||||
version "1.0.2"
|
||||
18
cookbooks/osops-utils/recipes/default.rb
Normal file
18
cookbooks/osops-utils/recipes/default.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Cookbook Name:: osops-utils
|
||||
# Recipe:: default
|
||||
#
|
||||
# Copyright 2012, Rackspace Hosting
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
Reference in New Issue
Block a user