* generate node network data section (deduplication);

* fix validation for quantum params;
* update deploy and provision examples;
* up version to 0.0.2
This commit is contained in:
Vladmir Sharhsov(warpc) 2013-08-20 10:32:06 +04:00
parent 7aa7e9c15c
commit e9c21e6282
9 changed files with 197 additions and 96 deletions

View File

@ -1,6 +1,6 @@
# Nodes
nodes:
- name: controller-5
- name: controller-8
role: controller
public_br: br-ex
internal_br: br-mgmt
@ -8,42 +8,48 @@ nodes:
- name: eth2
ip_address: 10.20.0.187
netmask: 255.255.255.0
static: '0'
static: 0
mac_address: '08:00:27:31:09:34'
onboot: 'no'
peerdns: 'no'
network_name:
- fixed
- name: eth1
ip_address: 10.20.0.186
netmask: 255.255.255.0
static: '0'
static: 0
mac_address: 08:00:27:93:54:B0
onboot: 'no'
peerdns: 'no'
network_name:
- management
- storage
- name: eth0
#ip_address: 10.20.0.49 # ip, power_address
#netmask: 255.255.255.0
dns_name: controller-5.domain.tld # fqdn
static: '0'
mac_address: 08:00:27:53:0B:6C # mac
dns_name: controller-8.domain.tld # fqdn
static: 0
mac_address: 08:00:27:83:80:92 # mac
onboot: 'yes'
peerdns: 'no'
use_for_provision: true
#End data for provision
network_name:
- public
default_gateway: 10.20.0.1
network_data:
- name: public
ip: 172.18.94.41
dev: eth1
netmask: 255.255.255.0
gateway: 172.18.94.33
- name:
- management
- storage
ip: 10.20.0.45
dev: eth0
netmask: 255.255.255.0
- name: fixed
dev: eth2
# network_data:
# - name: public
# ip: 172.18.94.41
# dev: eth1
# netmask: 255.255.255.0
# gateway: 172.18.94.33
# - name:
# - management
# - storage
# ip: 10.20.0.45
# dev: eth0
# netmask: 255.255.255.0
# - name: fixed
# dev: eth2
attributes:
master_ip: 10.20.0.2
@ -92,6 +98,7 @@ attributes:
password: cinder
user: cinder
floating_network_range: 10.20.0.150/28
#fixed_network_range: CIDR
fixed_network_range: 10.20.1.0/24
base_syslog:
syslog_port: '514'

View File

@ -6,7 +6,6 @@ engine:
username: cobbler
password: cobbler
# These parameters can be overridden in the specification of a particular node
common_node_settings:
name_servers: "10.20.0.2"
@ -37,9 +36,9 @@ common_ks_meta:
# Nodes
nodes:
- name: controller-5
hostname: controller-5.domain.tld
- name: controller-8
hostname: controller-8.domain.tld
# Data for provision
profile: centos-x86_64
ks_meta:
@ -95,23 +94,23 @@ nodes:
- name: eth2
ip_address: 10.20.0.187
netmask: 255.255.255.0
static: '0'
static: 0
mac_address: '08:00:27:31:09:34'
onboot: 'no'
peerdns: 'no'
- name: eth1
ip_address: 10.20.0.186
netmask: 255.255.255.0
static: '0'
static: 0
mac_address: 08:00:27:93:54:B0
onboot: 'no'
peerdns: 'no'
- name: eth0
#ip_address: 10.20.0.49 # ip, power_address
#netmask: 255.255.255.0
dns_name: controller-22.domain.tld # fqdn
static: '0'
mac_address: 08:00:27:53:0B:6C # mac
dns_name: controller-8.domain.tld # fqdn
static: 1
mac_address: 08:00:27:83:80:92 # mac
onboot: 'yes'
peerdns: 'no'
use_for_provision: true

View File

@ -26,6 +26,9 @@ mapping:
type: text
required: true
enum: ["primary-controller", "controller", "storage", "swift-proxy", "primary-swift-proxy", "compute", "quantum"]
"status":
type: text
enum: ["ready", "provisioned", "discover"]
# Quantum true
"public_br":
type: text
@ -34,10 +37,53 @@ mapping:
"internal_br":
type: text
desc: Name of the internal bridge for Quantum-enabled configuration
"interfaces":
type: seq
required: true
sequence:
- type: map
mapping:
"name":
type: text
required: true
unique: yes
"ip_address":
type: text
unique: yes
"netmask":
type: text
"dns_name":
type: text
unique: yes
"static":
type: int
range: { min: 0, max: 1 }
"mac_address":
type: text
required: true
unique: yes
"onboot":
type: text
required: true
enum: ['yes', 'no']
"peerdns":
type: text
required: true
enum: ['yes', 'no']
"use_for_provision":
type: bool
default: false
name: use_for_provision
"network_name":
type: seq
desc: Array of OpenStack network names
sequence:
- type: text
enum: ["public", "management", "storage", "fixed"]
# Full config block
"network_data":
type: seq
desc: Array of network interfaces hashes
required: true
sequence:
- type: map
mapping:

View File

@ -34,10 +34,13 @@ module Astute
PROVISION_OPERATIONS = [:provision, :provision_and_deploy]
DEPLOY_OPERATIONS = [:deploy, :provision_and_deploy]
CIDR_REGEXP = '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|
2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$'
def initialize(file, operation)
@config = YAML.load_file(file)
validate_enviroment(operation)
to_full_config(operation)
to_full_config(operation)
end
def [](key)
@ -68,32 +71,65 @@ module Astute
if DEPLOY_OPERATIONS.include? operation
define_meta_interfaces(node)
define_fqdn(node)
define_network_data(node)
end
end
end
def validate_enviroment(operation)
validator = YamlValidator.new(operation)
errors = validator.validate(@config)
errors.each do |e|
title = e.message.include?("is undefined") ? "WARNING" : "ERROR"
puts "#{title}: [#{e.path}] #{e.message}"
if e.message.include?("is undefined")
Astute.logger.debug "WARNING: [#{e.path}] #{e.message}"
else
Astute.logger.error "ERROR: [#{e.path}] #{e.message}"
end
end
if errors.select {|e| !e.message.include?("is undefined") }.size > 0
raise Enviroment::ValidationError, "Environment validation failed"
end
if PROVISION_OPERATIONS.include? operation && @config['attributes']['quantum']
@config['nodes'].each do |node|
['public_br', 'internal_br'].each do |br|
if node[br].nil? || node[br].empty?
raise Enviroment::ValidationError, "Node #{node['name'] || node['hostname']}
required 'public_br' and 'internal_br' when quantum is 'true'"
if DEPLOY_OPERATIONS.include?(operation)
if @config['attributes']['quantum']
@config['nodes'].each do |node|
['public_br', 'internal_br'].each do |br|
if node[br].nil? || node[br].empty?
raise Enviroment::ValidationError, "Node #{node['name'] || node['hostname']}
required 'public_br' and 'internal_br' when quantum is 'true'"
end
end
end
errors = []
['quantum_parameters', 'quantum_access'].each do |param|
errors << param unless @config['attributes'].present?(param)
end
errors.each do |field|
msg = "#{field} is required when quantim is true"
raise Enviroment::ValidationError, msg
end
if !is_cidr_notation?(@config['attributes']['floating_network_range'])
msg = "'floating_network_range' is required CIDR notation when quantum is 'true'"
raise Enviroment::ValidationError, msg
end
if !is_cidr_notation?(@config['attributes']['floating_network_range'])
msg = "'floating_network_range' is required CIDR notation"
raise Enviroment::ValidationError, msg
end
else
if @config['attributes']['floating_network_range'].is_a?(Array)
msg = "'floating_network_range' is required array of IPs when quantum is 'false'"
raise Enviroment::ValidationError, msg
end
end
if !is_cidr_notation?(@config['attributes']['fixed_network_range'])
msg = "'fixed_network_range' is required CIDR notation"
raise Enviroment::ValidationError, msg
end
end
end
@ -105,8 +141,8 @@ module Astute
@api_data = JSON.parse(response).freeze
end
if node['mac']
node = @api_data.find{ |n| n['mac'].upcase == node['mac'].upcase }
return node if node
api_node = @api_data.find{ |n| n['mac'].upcase == node['mac'].upcase }
return api_node if api_node
end
raise Enviroment::ValidationError, "Node #{node['name']} with mac address #{node['mac']}
not find among discovered nodes"
@ -249,6 +285,44 @@ module Astute
def define_meta_interfaces(node)
node['meta']['interfaces'] = find_node_api_data(node)['meta']['interfaces']
end
# Add network_data section for node:
# network_data:
# - dev: eth1
# ip: 10.108.1.8
# name: public
# netmask: 255.255.255.0
# - dev: eth0
# ip: 10.108.0.8
# name:
# - management
# - storage
def define_network_data(node)
return if node['network_data'].is_a?(Array) && !node['network_data'].empty?
node['network_data'] = []
# If define_interfaces_and_interfaces_extra was call or format of config is full
if node['interfaces'].is_a?(Hash)
node['interfaces'].each do |key, value|
node['network_data'] << {
'dev' => key,
'ip' => value['ip_address'],
'name' => value['network_name'],
'netmask' => value['netmask']
}
end
else
node['interfaces'].each do |eth|
node['network_data'] << {
'dev' => eth['name'],
'ip' => eth['ip_address'],
'name' => eth['network_name'],
'netmask' => eth['netmask']
}
end
end
end
# Generate 'ks_spaces' param from 'ks_disks' param in section 'ks_meta'
# Example input for 'ks_disks' param:
@ -283,6 +357,12 @@ module Astute
node['ks_meta']['ks_spaces'] = '"' + node['ks_meta']['ks_disks'].to_json.gsub("\"", "\\\"") + '"'
node['ks_meta'].delete('ks_disks')
end
def is_cidr_notation?(value)
cidr = Regexp.new(CIDR_REGEXP)
!cidr.match(value).nil?
end
end # class end
class Enviroment::ValidationError < StandardError; end

View File

@ -141,9 +141,9 @@ mapping:
type: text
desc: Password/credentials for cobbler to manage power of this machine
"netboot_enabled":
type: text
type: int
range: { min: 0, max: 1 }
desc: Disable/enable netboot for this node.
enum: ['0', '1']
"ks_meta":
type: map
required: true
@ -240,8 +240,8 @@ mapping:
type: text
unique: yes
"static":
type: text
#range: { min: 0, max: 1 }
type: int
range: { min: 0, max: 1 }
"mac_address":
type: text
required: true

View File

@ -14,9 +14,6 @@
require 'kwalify'
CIDR_REGEXP = '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|
2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$'
module Astute
module Cli
class YamlValidator < Kwalify::Validator
@ -31,59 +28,18 @@ module Astute
end
schema_hashes = []
schema_dir_path = File.expand_path(File.dirname(__FILE__))
schema_dir_path = File.expand_path(File.dirname(__FILE__))
schemas.each do |schema_name|
schema_path = File.join(schema_dir_path, "#{schema_name}_schema.yaml")
schema_hashes << YAML.load_file(schema_path)
end
#p schema_hashes[0].recursive_merge!(schema_hashes[1])
#FIXME: key 'hostname:' is undefined for provision_and_deploy. Why?
@schema = schema_hashes.size == 1 ? schema_hashes.first : schema_hashes[0].deep_merge(schema_hashes[1])
super(@schema)
end
# hook method called by Validator#validate()
def validate_hook(value, rule, path, errors)
case rule.name
when 'Attributes'
require_field(value, path, errors, 'quantum', true, 'quantum_parameters')
require_field(value, path, errors, 'quantum', true, 'fixed_network_range')
require_field(value, path, errors, 'quantum', true, 'quantum_access')
#require_field(value, path, errors, 'quantum', false, 'floating_network_range')
if value['quantum']
is_cidr_notation?(value['floating_network_range'])
msg = "'floating_network_range' is required CIDR notation when quantum is 'true'"
errors << Kwalify::ValidationError.new(msg, path)
elsif !floating_network_range.is_a?(Array)
msg = "'floating_network_range' is required array of IPs when quantum is 'false'"
errors << Kwalify::ValidationError.new(msg, path)
end
if !is_cidr_notation?(value['fixed_network_range'])
msg = "'floating_network_range' is required CIDR notation"
errors << Kwalify::ValidationError.new(msg, path)
end
when 'Nodes'
#require_field(value, path, errors, 'quantum', true, 'public_br')
#require_field(value, path, errors, 'quantum', true, 'internal_br')
end
end
private
def is_cidr_notation?(value)
cidr = Regexp.new(CIDR_REGEXP)
!cidr.match(value).nil?
end
def require_field(value, path, errors, condition_key, condition_value, key)
return if value[condition_key] != condition_value
field_value = value[key]
if field_value.nil? || field_value.empty?
msg = "#{key} is required when #{condition_key} is '#{condition_value}'"
errors << Kwalify::ValidationError.new(msg, path)
end
end
end # YamlValidator
end # Cli

View File

@ -31,7 +31,7 @@ module Astute
attrs['use_cinder'] ||= nodes.any?{|n| n['role'] == 'cinder'}
@ctx.deploy_log_parser.deploy_type = attrs['deployment_mode']
Astute.logger.info "Deployment mode #{attrs['deployment_mode']}"
result = self.send("deploy_#{attrs['deployment_mode']}", nodes, attrs)
self.send("deploy_#{attrs['deployment_mode']}", nodes, attrs)
end
def method_missing(method, *args)

View File

@ -36,6 +36,19 @@ class Hash
!absent?(key)
end
# def recursive_merge!(other)
# other.keys.each do |k|
# if self[k].is_a?(Array) && other[k].is_a?(Array)
# self[k] += other[k]
# elsif self[k].is_a?(Hash) && other[k].is_a?(Hash)
# self[k].recursive_merge!(other[k])
# else
# self[k] = other[k]
# end
# end
# self
# end
def deep_merge(other_hash)
self.merge(other_hash) do |key, oldval, newval|
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)

View File

@ -14,5 +14,5 @@
module Astute
VERSION = '0.0.1'
VERSION = '0.0.2'
end