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.
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