dop_common 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +176 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +177 -0
- data/README.md +48 -0
- data/Rakefile +49 -0
- data/Vagrantfile +25 -0
- data/bin/dop-puppet-autosign +56 -0
- data/doc/examples/example_deploment_plan_v0.0.1.yaml +302 -0
- data/doc/plan_format_v0.0.1.md +919 -0
- data/doc/plan_format_v0.0.2_snippets.md +56 -0
- data/dop_common.gemspec +44 -0
- data/lib/dop_common/affinity_group.rb +57 -0
- data/lib/dop_common/cli/global_options.rb +37 -0
- data/lib/dop_common/cli/log.rb +51 -0
- data/lib/dop_common/cli/node_selection.rb +62 -0
- data/lib/dop_common/command.rb +125 -0
- data/lib/dop_common/config/helper.rb +39 -0
- data/lib/dop_common/config.rb +66 -0
- data/lib/dop_common/configuration.rb +37 -0
- data/lib/dop_common/credential.rb +152 -0
- data/lib/dop_common/data_disk.rb +62 -0
- data/lib/dop_common/dns.rb +55 -0
- data/lib/dop_common/hash_parser.rb +241 -0
- data/lib/dop_common/hooks.rb +81 -0
- data/lib/dop_common/infrastructure.rb +160 -0
- data/lib/dop_common/infrastructure_properties.rb +185 -0
- data/lib/dop_common/interface.rb +113 -0
- data/lib/dop_common/log.rb +78 -0
- data/lib/dop_common/network.rb +85 -0
- data/lib/dop_common/node/config.rb +159 -0
- data/lib/dop_common/node.rb +442 -0
- data/lib/dop_common/node_filter.rb +74 -0
- data/lib/dop_common/plan.rb +188 -0
- data/lib/dop_common/plan_cache.rb +83 -0
- data/lib/dop_common/plan_store.rb +263 -0
- data/lib/dop_common/pre_processor.rb +73 -0
- data/lib/dop_common/run_options.rb +56 -0
- data/lib/dop_common/signal_handler.rb +58 -0
- data/lib/dop_common/state_store.rb +95 -0
- data/lib/dop_common/step.rb +200 -0
- data/lib/dop_common/step_set.rb +41 -0
- data/lib/dop_common/thread_context_logger.rb +77 -0
- data/lib/dop_common/utils.rb +106 -0
- data/lib/dop_common/validator.rb +53 -0
- data/lib/dop_common/version.rb +3 -0
- data/lib/dop_common.rb +32 -0
- data/lib/hiera/backend/dop_backend.rb +94 -0
- data/lib/hiera/dop_logger.rb +20 -0
- data/spec/data/fake_hook_file_invalid +1 -0
- data/spec/data/fake_hook_file_valid +5 -0
- data/spec/data/fake_keyfile +1 -0
- data/spec/dop-puppet-autosign_spec_disable.rb +33 -0
- data/spec/dop_common/affinity_group_spec.rb +41 -0
- data/spec/dop_common/command_spec.rb +83 -0
- data/spec/dop_common/credential_spec.rb +73 -0
- data/spec/dop_common/data_disk_spec.rb +165 -0
- data/spec/dop_common/dns_spec.rb +33 -0
- data/spec/dop_common/hash_parser_spec.rb +181 -0
- data/spec/dop_common/hooks_spec.rb +33 -0
- data/spec/dop_common/infrastructure_properties_spec.rb +224 -0
- data/spec/dop_common/infrastructure_spec.rb +77 -0
- data/spec/dop_common/interface_spec.rb +192 -0
- data/spec/dop_common/network_spec.rb +92 -0
- data/spec/dop_common/node_filter_spec.rb +70 -0
- data/spec/dop_common/node_spec.rb +623 -0
- data/spec/dop_common/plan_cache_spec.rb +46 -0
- data/spec/dop_common/plan_spec.rb +136 -0
- data/spec/dop_common/plan_store_spec.rb +194 -0
- data/spec/dop_common/pre_processor_spec.rb +27 -0
- data/spec/dop_common/run_options_spec.rb +65 -0
- data/spec/dop_common/signal_handler_spec.rb +31 -0
- data/spec/dop_common/step_set_spec.rb +21 -0
- data/spec/dop_common/step_spec.rb +175 -0
- data/spec/dop_common/utils_spec.rb +27 -0
- data/spec/dop_common/validator_spec.rb +47 -0
- data/spec/example_plans_spec.rb +16 -0
- data/spec/fixtures/example_ssh_key +27 -0
- data/spec/fixtures/example_ssh_key.pub +1 -0
- data/spec/fixtures/incl/root_part.yaml +1 -0
- data/spec/fixtures/incl/some_list.yaml +2 -0
- data/spec/fixtures/other_plan_same_nodes.yaml +19 -0
- data/spec/fixtures/simple_include.yaml +6 -0
- data/spec/fixtures/simple_include_with_errors.yaml +4 -0
- data/spec/fixtures/simple_plan.yaml +19 -0
- data/spec/fixtures/simple_plan_invalid.yaml +18 -0
- data/spec/fixtures/simple_plan_modified.yaml +21 -0
- data/spec/spec_helper.rb +106 -0
- metadata +381 -0
@@ -0,0 +1,160 @@
|
|
1
|
+
#
|
2
|
+
# DOP Common infrastructure hash parser
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module DopCommon
|
8
|
+
class Infrastructure
|
9
|
+
include Validator
|
10
|
+
include HashParser
|
11
|
+
include RunOptions
|
12
|
+
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
VALID_PROVIDER_TYPES = [:baremetal, :openstack, :ovirt, :vsphere]
|
16
|
+
|
17
|
+
VALID_PROVIDER_ALIASES = {
|
18
|
+
:rhev => :ovirt,
|
19
|
+
:rhevm => :ovirt,
|
20
|
+
:rhos => :openstack,
|
21
|
+
:vmware => :vsphere
|
22
|
+
}
|
23
|
+
|
24
|
+
def initialize(name, hash, parent={})
|
25
|
+
@name = name
|
26
|
+
@hash = symbolize_keys(hash)
|
27
|
+
@parsed_credentials = parent[:parsed_credentials]
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate
|
31
|
+
valitdate_shared_options
|
32
|
+
log_validation_method(:provider_valid?)
|
33
|
+
log_validation_method(:endpoint_valid?)
|
34
|
+
log_validation_method(:networks_valid?)
|
35
|
+
log_validation_method(:affinity_groups_valid?)
|
36
|
+
log_validation_method(:credentials_valid?)
|
37
|
+
try_validate_obj("Infrastructure #{name}: Can't validate the networks part because of a previous error") { networks }
|
38
|
+
try_validate_obj("Infrastructure #{name}: Can't validate the affinity groups part because of a previous error") { affinity_groups }
|
39
|
+
end
|
40
|
+
|
41
|
+
def provider
|
42
|
+
@provider ||= provider_valid? ? @hash[:type].downcase.to_sym : nil
|
43
|
+
end
|
44
|
+
alias_method :type, :provider
|
45
|
+
|
46
|
+
def provides?(*t)
|
47
|
+
t.any? do |p|
|
48
|
+
p = p.downcase.to_sym if p.kind_of?(String)
|
49
|
+
p == provider || p == VALID_PROVIDER_ALIASES[provider]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
alias_method :type?, :provides?
|
53
|
+
|
54
|
+
def endpoint
|
55
|
+
@endpoint ||= endpoint_valid? ? create_endpoint : nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def credentials
|
59
|
+
@credentials ||= credentials_valid? ? create_credentials : nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def networks
|
63
|
+
@networks ||= networks_valid? ? create_networks : []
|
64
|
+
end
|
65
|
+
|
66
|
+
def affinity_groups
|
67
|
+
@affinity_groups ||= affinity_groups_valid? ? create_affinity_groups : []
|
68
|
+
end
|
69
|
+
|
70
|
+
def default_security_groups
|
71
|
+
@defalut_security_groups ||= default_security_groups_valid? ? create_default_security_groups : []
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def provider_valid?
|
77
|
+
case @hash[:type]
|
78
|
+
when nil
|
79
|
+
raise PlanParsingError, "Infrastructure #{@name}: provider type is a required property"
|
80
|
+
when String
|
81
|
+
p = @hash[:type].downcase.to_sym
|
82
|
+
raise PlanParsingError, "Infrastructure #{@name}: invalid provider type" unless
|
83
|
+
VALID_PROVIDER_TYPES.include?(p) || VALID_PROVIDER_ALIASES.keys.include?(p)
|
84
|
+
else
|
85
|
+
raise PlanParsingError, "Infrastructure #{@name}: provider type must be a string"
|
86
|
+
end
|
87
|
+
true
|
88
|
+
end
|
89
|
+
alias_method :type_valid?, :provider_valid?
|
90
|
+
|
91
|
+
def endpoint_valid?
|
92
|
+
return false if provides?(:baremetal) && @hash[:endpoint].nil?
|
93
|
+
raise PlanParsingError, "Infrastructure #{@name}: endpoint is a required property" if @hash[:endpoint].nil?
|
94
|
+
::URI.parse(@hash[:endpoint])
|
95
|
+
true
|
96
|
+
rescue URI::InvalidURIError
|
97
|
+
raise PlanParsingError, "Infrastructure #{@name}: the specified endpoint URL is invalid"
|
98
|
+
end
|
99
|
+
|
100
|
+
def credentials_valid?
|
101
|
+
return false if provides?(:baremetal) && @hash[:credentials].nil?
|
102
|
+
raise PlanParsingError, "Infrastructure #{@name}: Credentials pointer must be a string" unless
|
103
|
+
@hash[:credentials].kind_of?(String)
|
104
|
+
raise PlanParsingError, "Infrastructure #{@name}: Missing definition of endpoint credentials" unless
|
105
|
+
@parsed_credentials.has_key?(@hash[:credentials])
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
def networks_valid?
|
110
|
+
return false if provides?(:baremetal) && @hash[:networks].nil? # Network is optional for baremetal
|
111
|
+
raise PlanParsingError, "Infrastructure #{@name}: network is a required property" if
|
112
|
+
!provides?(:baremetal) && @hash[:networks].nil?
|
113
|
+
raise PlanParsingError, "Infrastructure #{@name}: networks must be a hash" unless
|
114
|
+
@hash[:networks].kind_of?(Hash)
|
115
|
+
raise PlanParsingError, "Infrastructure #{@name}: network names have to be string" unless
|
116
|
+
@hash[:networks].keys.all? { |name| name.kind_of?(String) }
|
117
|
+
raise PlanParsingError, "Infrastructure #{@name}: each network has to be defined as hash" unless
|
118
|
+
@hash[:networks].values.all? { |network| network.kind_of?(Hash) }
|
119
|
+
true
|
120
|
+
end
|
121
|
+
|
122
|
+
def affinity_groups_valid?
|
123
|
+
return false if @hash[:affinity_groups].nil?
|
124
|
+
@hash[:affinity_groups].kind_of?(Hash) or
|
125
|
+
raise PlanParsingError, "Infrastructure #{@name}: affinity_groups must be a hash"
|
126
|
+
@hash[:affinity_groups].keys.all? { |name| name.kind_of?(String) } or
|
127
|
+
raise PlanParsingError, "Infrastructure #{@name}: affinity group names have to be string"
|
128
|
+
@hash[:affinity_groups].values.all? { |ag| ag.kind_of?(Hash) } or
|
129
|
+
raise PlanParsingError, "Infrastructure #{@name}: affinity groups have to be defined as hash"
|
130
|
+
end
|
131
|
+
|
132
|
+
def default_security_groups_valid?
|
133
|
+
return false if @hash[:default_security_groups].nil?
|
134
|
+
@hash[:default_security_groups].kind_of?(Array) or
|
135
|
+
raise PlanParsingError, "Infrastructure #{@name}: default_security_groups must be an array"
|
136
|
+
@hash[:default_security_groups].all? { |name| name.kind_of?(String) } or
|
137
|
+
raise PlanParsingError, "Infrastructure #{@name}: security group names have to be strings"
|
138
|
+
end
|
139
|
+
|
140
|
+
def create_endpoint
|
141
|
+
::URI.parse(@hash[:endpoint])
|
142
|
+
end
|
143
|
+
|
144
|
+
def create_credentials
|
145
|
+
@parsed_credentials[@hash[:credentials]]
|
146
|
+
end
|
147
|
+
|
148
|
+
def create_networks
|
149
|
+
@hash[:networks].collect { |name,hash| ::DopCommon::Network.new(name, hash) }
|
150
|
+
end
|
151
|
+
|
152
|
+
def create_affinity_groups
|
153
|
+
@hash[:affinity_groups].collect { |name,hash| ::DopCommon::AffinityGroup.new(name, hash) }
|
154
|
+
end
|
155
|
+
|
156
|
+
def create_default_security_groups
|
157
|
+
@hash[:default_security_groups]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
#
|
2
|
+
# DOP Common infrastructure properties parser
|
3
|
+
#
|
4
|
+
|
5
|
+
module DopCommon
|
6
|
+
class InfrastructureProperties
|
7
|
+
include Validator
|
8
|
+
include HashParser
|
9
|
+
|
10
|
+
def initialize(hash, parsed_infrastructure)
|
11
|
+
@hash = symbolize_keys(hash)
|
12
|
+
@parsed_infrastructure = parsed_infrastructure
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate
|
16
|
+
log_validation_method(:affinity_groups_valid?)
|
17
|
+
log_validation_method(:keep_ha_valid?)
|
18
|
+
log_validation_method(:datacenter_valid?)
|
19
|
+
log_validation_method(:cluster_valid?)
|
20
|
+
log_validation_method(:default_pool_valid?)
|
21
|
+
log_validation_method(:dest_folder_valid?)
|
22
|
+
log_validation_method(:tenant_valid?)
|
23
|
+
log_validation_method(:use_config_drive_valid?)
|
24
|
+
log_validation_method(:domain_id_valid?)
|
25
|
+
log_validation_method(:endpoint_type_valid?)
|
26
|
+
end
|
27
|
+
|
28
|
+
def affinity_groups
|
29
|
+
@affinity_groups ||= affinity_groups_valid? ? @hash[:affinity_groups] : []
|
30
|
+
end
|
31
|
+
|
32
|
+
def security_groups
|
33
|
+
@security_groups ||= security_groups_valid? ? create_security_groups : @parsed_infrastructure.default_security_groups
|
34
|
+
end
|
35
|
+
|
36
|
+
def keep_ha?
|
37
|
+
@keep_ha ||= keep_ha_valid? ? @hash[:keep_ha] : true
|
38
|
+
end
|
39
|
+
alias_method :keep_ha, :keep_ha?
|
40
|
+
|
41
|
+
def datacenter
|
42
|
+
@datacenter ||= datacenter_valid? ? @hash[:datacenter] : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def cluster
|
46
|
+
@cluster ||= cluster_valid? ? @hash[:cluster] : nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_pool
|
50
|
+
@default_pool ||= default_pool_valid? ? @hash[:default_pool] : nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def dest_folder
|
54
|
+
@dest_folder ||= dest_folder_valid? ? @hash[:dest_folder] : nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def tenant
|
58
|
+
@tenant ||= tenant_valid? ? @hash[:tenant] : nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def use_config_drive?
|
62
|
+
@use_config_drive ||= use_config_drive_valid? ? @hash[:use_config_drive] : false
|
63
|
+
end
|
64
|
+
alias_method :use_config_drive, :use_config_drive?
|
65
|
+
|
66
|
+
def domain_id
|
67
|
+
@domain_id ||= domain_id_valid? ? create_domain_id : nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def endpoint_type
|
71
|
+
@endpoint_type ||= endpoint_type_valid? ? create_endpoint_type : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def affinity_groups_valid?
|
77
|
+
ags = @hash[:affinity_groups]
|
78
|
+
return false if ags.nil?
|
79
|
+
raise PlanParsingError, "Infrastructure properties: Affinity groups, if specified, must be a non-empty array" if
|
80
|
+
!ags.kind_of?(Array) || ags.empty?
|
81
|
+
raise PlanParsingError, "Infrastructure properties: Each affinity group must be a non-empty string" if
|
82
|
+
ags.any? { |ag| !ag.kind_of?(String) || ag.empty? }
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
def security_groups_valid?
|
87
|
+
return false unless @hash[:security_groups] or @hash[:additional_security_groups]
|
88
|
+
raise PlanParsingError, "Infrastructure properties: security_groups and additional_security_groups are mutually exclusive" if
|
89
|
+
@hash[:security_groups] and @hash[:additional_security_groups]
|
90
|
+
sgs = @hash[:security_groups] || @hash[:additional_security_groups]
|
91
|
+
raise PlanParsingError, "Infrastructure properties: (additional_)security_groups must be non-empty arrays" if
|
92
|
+
!sgs.kind_of?(Array) || sgs.empty?
|
93
|
+
raise PlanParsingError, "Infrastructure properties: (additional_)security_groups must be non-empty strings" if
|
94
|
+
sgs.any? {|sg| !sg.kind_of?(String) || sg.empty? }
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def keep_ha_valid?
|
99
|
+
return false if @hash[:keep_ha].nil?
|
100
|
+
raise PlanParsingError, "Infrastructure properties: The 'keep_ha' is valid only for OVirt/RHEVm infrastructure types" unless
|
101
|
+
@parsed_infrastructure.provides?(:ovirt)
|
102
|
+
raise PlanParsingError, "Infrastructure properties: The 'keep_ha' must be boolean" unless
|
103
|
+
@hash[:keep_ha].kind_of?(TrueClass) || @hash[:keep_ha].kind_of?(FalseClass)
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
def datacenter_valid?
|
108
|
+
return false unless @parsed_infrastructure.provides?(:ovirt, :vsphere)
|
109
|
+
raise PlanParsingError, "Infrastructure properties: The 'datacenter' must be defined" if
|
110
|
+
@parsed_infrastructure.provides?(:ovirt, :vsphere) && @hash[:datacenter].nil?
|
111
|
+
raise PlanParsingError, "Infrastructure properties: The 'datacenter' must be a non-empty string" if
|
112
|
+
!@hash[:datacenter].kind_of?(String) || @hash[:datacenter].empty?
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
def cluster_valid?
|
117
|
+
return false unless @parsed_infrastructure.provides?(:ovirt, :vsphere)
|
118
|
+
raise PlanParsingError, "Infrastructure properties: The 'cluster' must be defined" if
|
119
|
+
@parsed_infrastructure.provides?(:ovirt, :vsphere) && @hash[:cluster].nil?
|
120
|
+
raise PlanParsingError, "Infrastructure properties: The 'cluster' must be a non-empty string" if
|
121
|
+
!@hash[:cluster].kind_of?(String) || @hash[:cluster].empty?
|
122
|
+
true
|
123
|
+
end
|
124
|
+
|
125
|
+
def default_pool_valid?
|
126
|
+
return false if @hash[:default_pool].nil?
|
127
|
+
raise PlanParsingError, "Infrastructure properties: The 'default_pool' must be a non-empty string" if
|
128
|
+
!@hash[:default_pool].kind_of?(String) || @hash[:default_pool].empty?
|
129
|
+
true
|
130
|
+
end
|
131
|
+
|
132
|
+
def dest_folder_valid?
|
133
|
+
return false if @hash[:dest_folder].nil?
|
134
|
+
raise PlanParsingError, "Infrastructure properties: The 'dest_folder' must be a non-empty string" if
|
135
|
+
!@hash[:dest_folder].kind_of?(String) || @hash[:dest_folder].empty?
|
136
|
+
true
|
137
|
+
end
|
138
|
+
|
139
|
+
def tenant_valid?
|
140
|
+
return false unless @parsed_infrastructure.provides?(:openstack)
|
141
|
+
raise PlanParsingError, "Infrastructure properties: The 'tenant' must be defined" if
|
142
|
+
@parsed_infrastructure.provides?(:openstack) && @hash[:tenant].nil?
|
143
|
+
raise PlanParsingError, "Infrastructure properties: The 'tenant' must be a non-empty string" if
|
144
|
+
!@hash[:tenant].kind_of?(String) || @hash[:tenant].empty?
|
145
|
+
true
|
146
|
+
end
|
147
|
+
|
148
|
+
def domain_id_valid?
|
149
|
+
return false unless @parsed_infrastructure.provides?(:openstack)
|
150
|
+
return true if @hash[:domain_id].nil?
|
151
|
+
raise PlanParsingError, "Infrastructure properties: The domain_id must be a non-empty string" if
|
152
|
+
!@hash[:domain_id].kind_of?(String) || @hash[:domain_id].empty?
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
def endpoint_type_valid?
|
157
|
+
return false unless @parsed_infrastructure.provides?(:openstack)
|
158
|
+
return true if @hash[:endpoint_type].nil?
|
159
|
+
raise PlanParsingError, "Infrastructure properties: The endpoint must be 'publicURL', 'internalURL' or 'adminURL'" unless
|
160
|
+
@hash[:endpoint_type].kind_of?(String) && %w(publicURL internalURL adminURL).include?(@hash[:endpoint_type])
|
161
|
+
true
|
162
|
+
end
|
163
|
+
|
164
|
+
def use_config_drive_valid?
|
165
|
+
return false if @hash[:use_config_drive].nil?
|
166
|
+
raise PlanParsingError, "Infrastructure properties: The 'use_config_drive' is valid only for OpenStack infrastructure types" unless @parsed_infrastructure.provides?(:openstack)
|
167
|
+
raise PlanParsingError, "Infrastructure properties: The 'use_config_drive' must be boolean" unless
|
168
|
+
@hash[:use_config_drive].kind_of?(TrueClass) || @hash[:use_config_drive].kind_of?(FalseClass)
|
169
|
+
true
|
170
|
+
end
|
171
|
+
|
172
|
+
def create_security_groups
|
173
|
+
sgs = @hash[:security_groups]
|
174
|
+
sgs ? sgs : (@parsed_infrastructure.default_security_groups + @hash[:additional_security_groups]).uniq
|
175
|
+
end
|
176
|
+
|
177
|
+
def create_domain_id
|
178
|
+
@hash[:domain_id].nil? ? 'default' : @hash[:domain_id]
|
179
|
+
end
|
180
|
+
|
181
|
+
def create_endpoint_type
|
182
|
+
@hash[:endpoint_type].nil? ? 'publicURL' : @hash[:endpoint_type]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
#
|
2
|
+
# DOP Common configuration lookup
|
3
|
+
#
|
4
|
+
require 'ipaddr'
|
5
|
+
|
6
|
+
module DopCommon
|
7
|
+
class Interface
|
8
|
+
include Validator
|
9
|
+
include HashParser
|
10
|
+
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
def initialize(name, hash, parent={})
|
14
|
+
@name = name
|
15
|
+
@hash = symbolize_keys(hash)
|
16
|
+
@parsed_networks = parent[:parsed_networks]
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate
|
20
|
+
log_validation_method('network_valid?')
|
21
|
+
log_validation_method('ip_valid?')
|
22
|
+
log_validation_method('set_gateway_valid?')
|
23
|
+
log_validation_method('virtual_switch_valid?')
|
24
|
+
log_validation_method('floating_network_valid?')
|
25
|
+
end
|
26
|
+
|
27
|
+
def network
|
28
|
+
@network ||= network_valid? ? network_obj.name : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def ip
|
32
|
+
@ip ||= ip_valid? ? @hash[:ip] : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def netmask
|
36
|
+
@netmask ||= network_obj.ip_netmask.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_gateway?
|
40
|
+
@set_gateway ||= set_gateway_valid? ? (gateway == false ? false : @hash[:set_gateway]) : true
|
41
|
+
end
|
42
|
+
alias_method :set_gateway, :set_gateway?
|
43
|
+
|
44
|
+
def gateway
|
45
|
+
@gateway ||= false == network_obj.ip_defgw ? false : network_obj.ip_defgw.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def virtual_switch
|
49
|
+
@virtual_switch ||= virtual_switch_valid? ? @hash[:virtual_switch] : nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def floating_network
|
53
|
+
@floating_network ||= floating_network_valid? ? @hash[:floating_network] : nil
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def network_valid?
|
58
|
+
raise PlanParsingError, "Interface #{@name}: 'network' must be specified" if
|
59
|
+
@hash[:network].nil?
|
60
|
+
raise PlanParsingError, "Interface #{@name}: 'network' must be a non-empty string" if
|
61
|
+
!@hash[:network].kind_of?(String) || @hash[:network].empty?
|
62
|
+
raise PlanParsingError, "Interface #{@name}: no such network definition '#{@hash[:network]}'" unless
|
63
|
+
network_obj
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def ip_valid?
|
68
|
+
raise PlanParsingError, "Interface #{@name}: 'ip' must be a string or symbol" unless
|
69
|
+
[String, Symbol].include?(@hash[:ip].class)
|
70
|
+
case @hash[:ip]
|
71
|
+
when :dhcp, 'dhcp'
|
72
|
+
@hash[:ip] = :dhcp
|
73
|
+
when :none, 'none'
|
74
|
+
@hash[:ip] = :none
|
75
|
+
else
|
76
|
+
ip_addr = IPAddr.new(@hash[:ip])
|
77
|
+
raise PlanParsingError, "Interface #{name}: IP address '#{@hash[:ip]}' " \
|
78
|
+
"is outside of '#{network_obj.ip_pool[:from]} - #{network_obj.ip_pool[:to]}' range" if
|
79
|
+
ip_addr < network_obj.ip_pool[:from] || ip_addr > network_obj.ip_pool[:to]
|
80
|
+
end
|
81
|
+
true
|
82
|
+
rescue ArgumentError
|
83
|
+
raise PlanParsingError, "Interface #{@name}: the specified IP is not valid"
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_gateway_valid?
|
87
|
+
return (gateway == false ? true : false) if @hash[:set_gateway].nil?
|
88
|
+
raise PlanParsingError, "Interface #{@name}: The 'set_gateway', must be true or false" unless
|
89
|
+
[TrueClass, FalseClass].include?(@hash[:set_gateway].class)
|
90
|
+
raise PlanParsingError, "Interface #{@name}: No gateway specified for network '#{network}'" if
|
91
|
+
gateway == false && @hash[:set_gateway] == true
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
def virtual_switch_valid?
|
96
|
+
return false if @hash[:virtual_switch].nil?
|
97
|
+
raise PlanParsingError, "Interface #{@name}: The 'virtual_switch' must be a non-empty string" if
|
98
|
+
!@hash[:virtual_switch].kind_of?(String) || @hash[:virtual_switch].empty?
|
99
|
+
true
|
100
|
+
end
|
101
|
+
|
102
|
+
def floating_network_valid?
|
103
|
+
return false if @hash[:floating_network].nil?
|
104
|
+
raise PlanParsingError, "Interface #{@name}: the floating network must be a non-empty string" if
|
105
|
+
!@hash[:floating_network].kind_of?(String) || @hash[:floating_network].empty?
|
106
|
+
true
|
107
|
+
end
|
108
|
+
|
109
|
+
def network_obj
|
110
|
+
@network_obj ||= @parsed_networks.find { |n| n.name == @hash[:network] }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#
|
2
|
+
# This builds a multi-destination logger and pluggable filters for
|
3
|
+
# around the standard ruby logger.
|
4
|
+
#
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
module DopCommon
|
8
|
+
|
9
|
+
def self.log
|
10
|
+
@log ||= create_logger(STDOUT)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.logger=(logger)
|
14
|
+
logger.formatter = DopCommon.filter_formatter
|
15
|
+
@log = logger
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.formatter
|
19
|
+
@formatter ||= Logger::Formatter.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.formatter=(formatter_proc)
|
23
|
+
@formatter ||= formatter_proc
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.reset_logger
|
27
|
+
@log = nil
|
28
|
+
@log_filters = []
|
29
|
+
@log_junction = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.log_filters
|
33
|
+
@log_filters ||= []
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.add_log_filter(filter_proc)
|
37
|
+
log_filters << filter_proc
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.log_junctions
|
41
|
+
@log_junction ||= []
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.add_log_junction(logger)
|
45
|
+
log_junctions << logger
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.remove_log_junction(logger)
|
49
|
+
log_junctions.delete(logger)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def self.create_logger(logdev = STDOUT)
|
55
|
+
logger = Logger.new(logdev)
|
56
|
+
logger.formatter = DopCommon.filter_formatter
|
57
|
+
logger
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.filter_formatter
|
61
|
+
Proc.new do |severity, datetime, progname, msg|
|
62
|
+
filtered_message = msg
|
63
|
+
log_filters.each do |filter|
|
64
|
+
filtered_message = case filtered_message
|
65
|
+
when Exception
|
66
|
+
filtered_message.exception(filter.call(filtered_message.message))
|
67
|
+
when String
|
68
|
+
filter.call(filtered_message)
|
69
|
+
else
|
70
|
+
filter.call(filtered_message.inspect)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
log_junctions.each {|logger| logger.log(::Logger.const_get(severity), filtered_message, progname)}
|
74
|
+
formatter.call(severity, datetime, progname, filtered_message)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#
|
2
|
+
# DOP Common infrastructure hash parser
|
3
|
+
#
|
4
|
+
|
5
|
+
module DopCommon
|
6
|
+
class Network
|
7
|
+
include Validator
|
8
|
+
include HashParser
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize(name, hash)
|
13
|
+
@name = name
|
14
|
+
@hash = deep_symbolize_keys(hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate
|
18
|
+
log_validation_method(:ip_pool_valid?)
|
19
|
+
log_validation_method(:ip_defgw_valid?)
|
20
|
+
log_validation_method(:ip_netmask_valid?)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ip_netmask
|
24
|
+
@ip_netmask ||= ip_netmask_valid? ? IPAddr.new(@hash[:ip_netmask]) : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def ip_defgw
|
28
|
+
@ip_defgw ||= ip_defgw_valid? ? (@hash[:ip_defgw] == false ? false : IPAddr.new(@hash[:ip_defgw])) : nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def ip_pool
|
32
|
+
@ip_pool ||= ip_pool_valid? ? create_ip_pool : {}
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def ip_netmask_valid?
|
38
|
+
return false if @hash.empty?
|
39
|
+
IPAddr.new(@hash[:ip_netmask])
|
40
|
+
true
|
41
|
+
rescue ArgumentError
|
42
|
+
raise PlanParsingError, "Network #{@name}: Invalid network mask definition"
|
43
|
+
end
|
44
|
+
|
45
|
+
def ip_defgw_valid?
|
46
|
+
return false if @hash.empty?
|
47
|
+
return true if @hash[:ip_defgw] == false
|
48
|
+
IPAddr.new(@hash[:ip_defgw])
|
49
|
+
true
|
50
|
+
rescue ArgumentError
|
51
|
+
raise PlanParsingError, "Network #{@name}: Invalid default gateway definition"
|
52
|
+
end
|
53
|
+
|
54
|
+
def ip_pool_valid?
|
55
|
+
return false if @hash.empty? # An empty network specification is valid
|
56
|
+
# It must be a hash with from and to keys if defined
|
57
|
+
raise PlanParsingError, "Network #{@name}: An IP pool must be a hash with 'from' and 'to' keys" unless
|
58
|
+
@hash[:ip_pool].kind_of?(Hash) and
|
59
|
+
@hash[:ip_pool].has_key?(:from) and
|
60
|
+
@hash[:ip_pool].has_key?(:to)
|
61
|
+
# The IP defined by from must be lower than the IP defined by to keyword
|
62
|
+
ip_from = IPAddr.new(@hash[:ip_pool][:from])
|
63
|
+
ip_to = IPAddr.new(@hash[:ip_pool][:to])
|
64
|
+
raise PlanParsingError, "Network #{@name}: The IP defined by 'from' must to be lower than the IP defined by in 'to'" unless ip_from < ip_to
|
65
|
+
if ip_defgw
|
66
|
+
# The IP of default gateway must be out of IP pool range
|
67
|
+
raise PlanParsingError, "Network #{@name}: The default gateway must be out of IP pool range" unless ip_defgw < ip_from || ip_defgw > ip_to
|
68
|
+
# IPs specified by IP pool and the default gateway must belong to the same network
|
69
|
+
net = ip_defgw.mask(ip_netmask.to_s)
|
70
|
+
raise PlanParsingError, "Network #{@name}: IPs specified by IP pool and the default gateway must belong to the same network" unless
|
71
|
+
net.include?(ip_from) && net.include?(ip_to)
|
72
|
+
elsif ip_defgw.nil?
|
73
|
+
raise PlanParsingError, "Network #{@name}: The default gateway must either be a valid IP or false if there is no default gateway"
|
74
|
+
end
|
75
|
+
true
|
76
|
+
rescue ArgumentError
|
77
|
+
# Invalide IP/Netmasl definition
|
78
|
+
raise PlanParsingError, "Network #{@name}: Invalid IP and/or netmask definition"
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_ip_pool
|
82
|
+
Hash[@hash[:ip_pool].collect { |k,v| [k.to_sym, IPAddr.new(v)] }]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|