dop_common 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +176 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE.txt +177 -0
  8. data/README.md +48 -0
  9. data/Rakefile +49 -0
  10. data/Vagrantfile +25 -0
  11. data/bin/dop-puppet-autosign +56 -0
  12. data/doc/examples/example_deploment_plan_v0.0.1.yaml +302 -0
  13. data/doc/plan_format_v0.0.1.md +919 -0
  14. data/doc/plan_format_v0.0.2_snippets.md +56 -0
  15. data/dop_common.gemspec +44 -0
  16. data/lib/dop_common/affinity_group.rb +57 -0
  17. data/lib/dop_common/cli/global_options.rb +37 -0
  18. data/lib/dop_common/cli/log.rb +51 -0
  19. data/lib/dop_common/cli/node_selection.rb +62 -0
  20. data/lib/dop_common/command.rb +125 -0
  21. data/lib/dop_common/config/helper.rb +39 -0
  22. data/lib/dop_common/config.rb +66 -0
  23. data/lib/dop_common/configuration.rb +37 -0
  24. data/lib/dop_common/credential.rb +152 -0
  25. data/lib/dop_common/data_disk.rb +62 -0
  26. data/lib/dop_common/dns.rb +55 -0
  27. data/lib/dop_common/hash_parser.rb +241 -0
  28. data/lib/dop_common/hooks.rb +81 -0
  29. data/lib/dop_common/infrastructure.rb +160 -0
  30. data/lib/dop_common/infrastructure_properties.rb +185 -0
  31. data/lib/dop_common/interface.rb +113 -0
  32. data/lib/dop_common/log.rb +78 -0
  33. data/lib/dop_common/network.rb +85 -0
  34. data/lib/dop_common/node/config.rb +159 -0
  35. data/lib/dop_common/node.rb +442 -0
  36. data/lib/dop_common/node_filter.rb +74 -0
  37. data/lib/dop_common/plan.rb +188 -0
  38. data/lib/dop_common/plan_cache.rb +83 -0
  39. data/lib/dop_common/plan_store.rb +263 -0
  40. data/lib/dop_common/pre_processor.rb +73 -0
  41. data/lib/dop_common/run_options.rb +56 -0
  42. data/lib/dop_common/signal_handler.rb +58 -0
  43. data/lib/dop_common/state_store.rb +95 -0
  44. data/lib/dop_common/step.rb +200 -0
  45. data/lib/dop_common/step_set.rb +41 -0
  46. data/lib/dop_common/thread_context_logger.rb +77 -0
  47. data/lib/dop_common/utils.rb +106 -0
  48. data/lib/dop_common/validator.rb +53 -0
  49. data/lib/dop_common/version.rb +3 -0
  50. data/lib/dop_common.rb +32 -0
  51. data/lib/hiera/backend/dop_backend.rb +94 -0
  52. data/lib/hiera/dop_logger.rb +20 -0
  53. data/spec/data/fake_hook_file_invalid +1 -0
  54. data/spec/data/fake_hook_file_valid +5 -0
  55. data/spec/data/fake_keyfile +1 -0
  56. data/spec/dop-puppet-autosign_spec_disable.rb +33 -0
  57. data/spec/dop_common/affinity_group_spec.rb +41 -0
  58. data/spec/dop_common/command_spec.rb +83 -0
  59. data/spec/dop_common/credential_spec.rb +73 -0
  60. data/spec/dop_common/data_disk_spec.rb +165 -0
  61. data/spec/dop_common/dns_spec.rb +33 -0
  62. data/spec/dop_common/hash_parser_spec.rb +181 -0
  63. data/spec/dop_common/hooks_spec.rb +33 -0
  64. data/spec/dop_common/infrastructure_properties_spec.rb +224 -0
  65. data/spec/dop_common/infrastructure_spec.rb +77 -0
  66. data/spec/dop_common/interface_spec.rb +192 -0
  67. data/spec/dop_common/network_spec.rb +92 -0
  68. data/spec/dop_common/node_filter_spec.rb +70 -0
  69. data/spec/dop_common/node_spec.rb +623 -0
  70. data/spec/dop_common/plan_cache_spec.rb +46 -0
  71. data/spec/dop_common/plan_spec.rb +136 -0
  72. data/spec/dop_common/plan_store_spec.rb +194 -0
  73. data/spec/dop_common/pre_processor_spec.rb +27 -0
  74. data/spec/dop_common/run_options_spec.rb +65 -0
  75. data/spec/dop_common/signal_handler_spec.rb +31 -0
  76. data/spec/dop_common/step_set_spec.rb +21 -0
  77. data/spec/dop_common/step_spec.rb +175 -0
  78. data/spec/dop_common/utils_spec.rb +27 -0
  79. data/spec/dop_common/validator_spec.rb +47 -0
  80. data/spec/example_plans_spec.rb +16 -0
  81. data/spec/fixtures/example_ssh_key +27 -0
  82. data/spec/fixtures/example_ssh_key.pub +1 -0
  83. data/spec/fixtures/incl/root_part.yaml +1 -0
  84. data/spec/fixtures/incl/some_list.yaml +2 -0
  85. data/spec/fixtures/other_plan_same_nodes.yaml +19 -0
  86. data/spec/fixtures/simple_include.yaml +6 -0
  87. data/spec/fixtures/simple_include_with_errors.yaml +4 -0
  88. data/spec/fixtures/simple_plan.yaml +19 -0
  89. data/spec/fixtures/simple_plan_invalid.yaml +18 -0
  90. data/spec/fixtures/simple_plan_modified.yaml +21 -0
  91. data/spec/spec_helper.rb +106 -0
  92. 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