Draft version of provision validations and params deduplications.

This commit is contained in:
Vladmir Sharhsov(warpc) 2013-08-06 15:29:18 +04:00
parent 32a1946453
commit 3b9c44f3c4
7 changed files with 372 additions and 76 deletions

View File

@ -14,6 +14,7 @@ Gem::Specification.new do |s|
s.add_dependency 'mcollective-client', '~> 2.2.4' #'2.3.1'
s.add_dependency 'symboltable', '1.0.2'
s.add_dependency 'rest-client', '~> 1.6.7'
s.add_dependency 'kwalify', '~> 0.7.2'
s.add_development_dependency 'rspec', '2.13.0'
s.add_development_dependency 'mocha', '0.13.3'

View File

@ -23,7 +23,7 @@ require 'optparse'
require 'yaml'
require 'astute'
require 'astute/version'
require 'astute/enviroment'
require 'astute/cli/enviroment'
class ConsoleReporter
def report(msg)
@ -64,8 +64,7 @@ end
reporter = ConsoleReporter.new
Astute.logger = Logger.new(STDOUT) if opts[:verbose]
environment = Astute::Enviroment.load_file(opts[:filename])
p environment['nodes'][0]['ip']
environment = Astute::Cli::Enviroment.load_file(opts[:filename])
deploy_engine = nil

View File

@ -1,3 +1,4 @@
---
# Base config
task_uuid: deployment_task
engine:
@ -5,77 +6,65 @@ engine:
username: cobbler
password: cobbler
power_info: &power_info
power_type: ssh
power_user: root
name_servers: ! '"10.20.0.2"'
power_pass: /root/.ssh/bootstrap.rsa
netboot_enabled: '1'
ks_meta: &ks_meta
mco_enable: 1
mco_vhost: mcollective
mco_pskey: unset
mco_user: mcollective
puppet_enable: 0
install_log_2_syslog: 1
mco_password: marionette
puppet_auto_setup: 1
puppet_master: fuelweb.domain.tld
mco_auto_setup: 1
auth_key: ! '""'
puppet_version: 2.7.19
mco_connector: rabbitmq
mco_host: 10.20.0.2
node_01: &node1
name: controller-5
hostname: controller-5.domain.tld
profile: centos-x86_64
# fqdn: controller-5.domain.tld
# id: 5
# uid: 5
# mac: 08:00:27:E3:BC:28
# ip: 10.20.0.41
# power_address: 10.20.0.41
<<: *power_info
#Write size in megabytes
ks_meta:
<<: *ks_meta
ks_spaces: ! '"[{\"type\": \"disk\", \"id\": \"disk/by-path/pci-0000:00:0d.0-scsi-0:0:0:0\",
\"volumes\": [{\"mount\": \"/boot\", \"type\": \"partition\", \"size\": 209715200},
{\"type\": \"mbr\"}, {\"size\": 16959668224, \"type\": \"pv\", \"vg\": \"os\"}],
\"size\": 17179869184}, {\"type\": \"disk\", \"id\": \"disk/by-path/pci-0000:00:0d.0-scsi-1:0:0:0\",
\"volumes\": [{\"size\": 536860426240, \"type\": \"pv\", \"vg\": \"os\"}], \"size\":
536870912000}, {\"type\": \"disk\", \"id\": \"disk/by-path/pci-0000:00:0d.0-scsi-2:0:0:0\",
\"volumes\": [{\"size\": 2411714314240, \"type\": \"pv\", \"vg\": \"os\"}],
\"size\": 2411724800000}, {\"type\": \"vg\", \"id\": \"os\", \"volumes\": [{\"mount\":
\"/\", \"type\": \"lv\", \"name\": \"root\", \"size\": 2963243016192}, {\"mount\":
\"swap\", \"type\": \"lv\", \"name\": \"swap\", \"size\": 2090065920}]}]"'
interfaces:
eth0:
ip_address: 10.20.0.41
netmask: 255.255.255.0
dns_name: controller-5.domain.tld
static: '1'
mac_address: 08:00:27:E3:BC:28
use_for_provision: true # ip, power_address, mac, fqdn
eth1:
mac_address: 08:00:27:0D:5C:B9
use_for_provision: false # ip, power_address, mac, fqdn
eth2:
mac_address: 08:00:27:D3:4F:6C
interfaces_extra:
eth2:
onboot: 'no'
peerdns: 'no'
eth1:
onboot: 'no'
peerdns: 'no'
eth0:
onboot: 'yes'
peerdns: 'no'
# Nodes
nodes:
- <<: *node1
- name: controller-22
hostname: controller-22.domain.tld
# Data for provision
profile: centos-x86_64
ks_meta:
mco_enable: 1
mco_vhost: mcollective
mco_pskey: unset
mco_user: mcollective
puppet_enable: 0
install_log_2_syslog: 1
mco_password: marionette
puppet_auto_setup: 1
puppet_master: fuelweb.domain.tld
mco_auto_setup: 1
auth_key: ! '""'
mco_connector: rabbitmq
mco_host: 10.20.0.2
ks_spaces: ! '"[{\"type\": \"disk\", \"id\": \"disk/by-path/pci-0000:00:0d.0-scsi-0:0:0:0\",
\"volumes\": [{\"mount\": \"/boot\", \"type\": \"partition\", \"size\": 209715200},
{\"type\": \"mbr\"}, {\"size\": 16959668224, \"type\": \"pv\", \"vg\": \"os\"}],
\"size\": 17179869184}, {\"type\": \"disk\", \"id\": \"disk/by-path/pci-0000:00:0d.0-scsi-1:0:0:0\",
\"volumes\": [{\"size\": 536860426240, \"type\": \"pv\", \"vg\": \"os\"}], \"size\":
536870912000}, {\"type\": \"disk\", \"id\": \"disk/by-path/pci-0000:00:0d.0-scsi-2:0:0:0\",
\"volumes\": [{\"size\": 2411714314240, \"type\": \"pv\", \"vg\": \"os\"}],
\"size\": 2411724800000}, {\"type\": \"vg\", \"id\": \"os\", \"volumes\": [{\"mount\":
\"/\", \"type\": \"lv\", \"name\": \"root\", \"size\": 2963243016192}, {\"mount\":
\"swap\", \"type\": \"lv\", \"name\": \"swap\", \"size\": 2090065920}]}]"'
power_type: ssh
power_user: root
name_servers: ! '"10.20.0.2"'
power_pass: /root/.ssh/bootstrap.rsa
netboot_enabled: '1'
interfaces:
- name: eth2
ip_address: 10.20.0.187
netmask: 255.255.255.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'
mac_address: 08:00:27:93:54:B0
onboot: 'no'
peerdns: 'no'
- name: eth0
ip_address: 10.20.0.6 # ip, power_address
netmask: 255.255.255.0
dns_name: controller-22.domain.tld # fqdn
static: '0'
mac_address: 08:00:27:DE:91:C5 # mac
onboot: 'yes'
peerdns: 'no'
use_for_provision: true
#End data for provision

View File

@ -0,0 +1,75 @@
# Copyright 2013 Mirantis, 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.
require 'yaml'
require 'astute/ext/hash'
require 'astute/cli/yaml_validator'
module Astute
class Cli::Enviroment
def self.load_file(file)
@config = YAML.load_file(file)
validate_env
convert_to_full_conf
end
def self.validate_env
validator = Cli::YamlValidator.new()
errors = validator.validate(@config)
errors.each do |e|
puts "[#{e.path}] #{e.message}"
end
end
def self.convert_to_full_conf
# Provision
@config['nodes'].each_with_index do |node, index|
provision_eth = node['interfaces'].find {|eth| eth['use_for_provision'] }
if provision_eth
node.reverse_merge!(
'ip' => provision_eth['ip_address'],
'power_address' => provision_eth['ip_address'],
'mac' => provision_eth['mac_address'],
'fqdn' => provision_eth['dns_name']
)
end
missing_keys = node.find_missing_keys(['ip', 'power_address', 'mac', 'fqdn'])
if provision_eth.nil? && missing_keys.empty?
raise "Please set 'use_for_provision' parameter for #{node['name']}
or set manually #{missing_keys.each {|k| p k}}"
end
node.reverse_merge!(
'id' => index,
'uid' => index
)
# Extend blocks interfaces and interfaces_extra to old formats
formated_interfaces = {}
interfaces_extra_interfaces = {}
node['interfaces'].each do |eth|
formated_interfaces[eth['name']] = eth
interfaces_extra_interfaces[eth['name']] = {
'onboot' => eth['onboot'],
'peerdns' => eth['onboot']
}
end
node['interfaces'] = formated_interfaces
node['extra_interfaces'] = interfaces_extra_interfaces
end
@config
end
end
end

152
lib/astute/cli/schema.yaml Normal file
View File

@ -0,0 +1,152 @@
type: map
mapping:
"task_uuid":
type: text
"engine":
type: map
mapping:
"url":
type: text
required: true
"username":
type: text
required: true
"password":
type: text
required: true
"nodes":
type: seq
sequence:
- type: map
mapping:
"id":
type: int
unique: yes
"uid":
type: int
unique: yes
"name":
type: text
required: true
unique: yes
"hostname":
type: text
required: true
"fqdn":
type: text
"profile":
type: text
required: true
enum: ["centos-x86_64", "ubuntu_1204_x86_64"]
"ip":
type: text
"mac":
type: text
"power_address":
type: text
"power_type":
type: text
required: true
"power_user":
type: text
required: true
"name_servers":
type: text
required: true
"power_pass":
type: text
required: true
"netboot_enabled":
type: text
required: true
"ks_meta":
type: map
mapping:
"mco_enable":
type: int
range: { min: 0, max: 1 }
required: true
"mco_vhost":
type: text
required: true
"mco_pskey":
type: text
required: true
"mco_user":
type: text
required: true
"mco_password":
type: text
required: true
"puppet_enable":
type: int
range: { min: 0, max: 1 }
required: true
"puppet_auto_setup":
type: int
range: { min: 0, max: 1 }
required: true
"puppet_master":
type: text
required: true
"mco_auto_setup":
type: int
range: { min: 0, max: 1 }
required: true
"auth_key":
type: text
required: true
"puppet_version":
type: text
"install_log_2_syslog":
type: int
range: { min: 0, max: 1 }
required: true
"mco_connector":
type: text
required: true
"mco_host":
type: text
required: true
"ks_spaces":
type: text
required: true
"interfaces":
type: seq
sequence:
- type: map
mapping:
"name":
type: text
required: true
unique: yes
"ip_address":
type: text
required: true
unique: yes
"netmask":
type: text
required: true
"dns_name":
type: text
required: true
unique: yes
"static":
type: text
#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

View File

@ -0,0 +1,43 @@
# Copyright 2013 Mirantis, 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.
require 'kwalify'
module Astute
module Cli
class YamlValidator < Kwalify::Validator
def initialize
gem_path = Gem.loaded_specs['astute'].full_gem_path
schema_path = File.join(gem_path, 'lib', 'astute', 'cli', 'schema.yaml')
@schema = Kwalify::Yaml.load_file(schema_path)
super(@schema)
end
# hook method called by Validator#validate()
def validate_hook(value, rule, path, errors)
# case rule.name
# when 'use_for_provision'
# if value['name'] == 'bad'
# reason = value['reason']
# if !reason || reason.empty?
# msg = "reason is required when answer is 'bad'."
# errors << Kwalify::ValidationError.new(msg, path)
# end
# end
# end
end
end
end
end

37
lib/astute/ext/hash.rb Normal file
View File

@ -0,0 +1,37 @@
# Copyright 2013 Mirantis, 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.
class Hash
# The value of the existing keys are not overridden
def reverse_merge(another_hash)
another_hash.merge(self)
end
def reverse_merge!(another_hash)
replace(reverse_merge(another_hash))
end
def find_missing_keys(array)
array.select { |key| is_missing_key?(key) }
#array.all? { |key| !self[key].nil? }
end
def is_missing_key?(key)
self[key].nil?
#array.all? { |key| !self[key].nil? }
end
end