summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitrios Markou <mardim@intracom-telecom.com>2018-10-03 17:47:13 +0300
committerDimitrios Markou <mardim@intracom-telecom.com>2018-10-11 13:54:36 +0000
commit1466835626f5cf7a2426404a4058789640fd3ad9 (patch)
tree1fdd065787374b830a9c91bd719d6f0a6e490f4e
parent3a09522ac7a2aa1f5bfdcb1939254712d8900dc9 (diff)
Validate mountpoints in a HostProfile
Prevent the partitions and logical volumes to use the same mount point on the same baremetal node Story: #2002951 Change-Id: Ie936b5b20859d511e4cb858202c4ed50378bb72d Signed-off-by: Dimitrios Markou <mardim@intracom-telecom.com>
Notes
Notes (review): Code-Review+1: Roman Gorshunov <roman.gorshunov@att.com> Code-Review+2: Bryan Strassner <bryan.strassner@gmail.com> Code-Review+2: Scott Hussey <sthussey@att.com> Workflow+1: Scott Hussey <sthussey@att.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Fri, 12 Oct 2018 19:31:41 +0000 Reviewed-on: https://review.openstack.org/607603 Project: openstack/airship-drydock Branch: refs/heads/master
-rw-r--r--python/drydock_provisioner/orchestrator/validations/storage_mountpoints.py73
-rw-r--r--python/drydock_provisioner/orchestrator/validations/validator.py2
-rw-r--r--python/tests/unit/test_validation_rule_storage_mountpoint.py86
-rw-r--r--python/tests/yaml_samples/invalid_mountpoint.yaml455
-rw-r--r--python/tests/yaml_samples/invalid_validation.yaml3
5 files changed, 618 insertions, 1 deletions
diff --git a/python/drydock_provisioner/orchestrator/validations/storage_mountpoints.py b/python/drydock_provisioner/orchestrator/validations/storage_mountpoints.py
new file mode 100644
index 0000000..ce0535c
--- /dev/null
+++ b/python/drydock_provisioner/orchestrator/validations/storage_mountpoints.py
@@ -0,0 +1,73 @@
1# Copyright 2018, Intracom-Telecom
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from drydock_provisioner.orchestrator.validations.validators import Validators
16
17class StorageMountpoints(Validators):
18 def __init__(self):
19 super().__init__('Storage Mountpoint', "DD2004")
20
21 def run_validation(self, site_design, orchestrator=None):
22 """
23 Ensures that any partitioned physical device or logical volumes
24 in a volume group do not use duplicate mount points.
25 """
26 baremetal_nodes = site_design.baremetal_nodes or []
27
28 for baremetal_node in baremetal_nodes:
29 mountpoint_list = []
30 storage_device_list = baremetal_node.storage_devices or []
31 for storage_device in storage_device_list:
32 # Parsing the partitions and volume group of
33 # physical storage devices
34
35 partition_list = storage_device.partitions or []
36 device_volume_group = storage_device.volume_group
37
38 for partition in partition_list:
39 # Load the mount point of each partition
40 # to a list
41
42 mountpoint = partition.mountpoint
43 if mountpoint in mountpoint_list:
44 msg = ('Mountpoint "{}" already exists'
45 .format(mountpoint))
46 self.report_error(
47 msg, [baremetal_node.doc_ref],
48 'Please use unique mountpoints.')
49 return
50 else:
51 mountpoint_list.append(mountpoint)
52
53 if device_volume_group:
54 volume_groups = baremetal_node.volume_groups or []
55 for volume_group in volume_groups:
56 if volume_group.name == device_volume_group:
57 logical_volume_list = volume_group.logical_volumes or []
58 for logical_volume in logical_volume_list:
59 # Load the mount point of each logical volume
60 # which belongs to the assigned volume group
61 # to a list
62
63 mountpoint = logical_volume.mountpoint
64 if mountpoint in mountpoint_list:
65 msg = ('Mountpoint "{}" already exists'
66 .format(mountpoint))
67 self.report_error(
68 msg, [baremetal_node.doc_ref],
69 'Please use unique mountpoints.')
70 return
71 else:
72 mountpoint_list.append(mountpoint)
73 return
diff --git a/python/drydock_provisioner/orchestrator/validations/validator.py b/python/drydock_provisioner/orchestrator/validations/validator.py
index 3f73cea..e36eef0 100644
--- a/python/drydock_provisioner/orchestrator/validations/validator.py
+++ b/python/drydock_provisioner/orchestrator/validations/validator.py
@@ -33,6 +33,7 @@ from drydock_provisioner.orchestrator.validations.oob_valid_ipmi import IpmiVali
33from drydock_provisioner.orchestrator.validations.oob_valid_libvirt import LibvirtValidity 33from drydock_provisioner.orchestrator.validations.oob_valid_libvirt import LibvirtValidity
34from drydock_provisioner.orchestrator.validations.bootaction_validity import BootactionDefined 34from drydock_provisioner.orchestrator.validations.bootaction_validity import BootactionDefined
35from drydock_provisioner.orchestrator.validations.bootaction_validity import BootactionPackageListValid 35from drydock_provisioner.orchestrator.validations.bootaction_validity import BootactionPackageListValid
36from drydock_provisioner.orchestrator.validations.storage_mountpoints import StorageMountpoints
36 37
37 38
38class Validator(): 39class Validator():
@@ -92,6 +93,7 @@ rule_set = [
92 RationalNetworkBond(), 93 RationalNetworkBond(),
93 StoragePartitioning(), 94 StoragePartitioning(),
94 StorageSizing(), 95 StorageSizing(),
96 StorageMountpoints(),
95 UniqueNetworkCheck(), 97 UniqueNetworkCheck(),
96 HostnameValidity(), 98 HostnameValidity(),
97 IpmiValidity(), 99 IpmiValidity(),
diff --git a/python/tests/unit/test_validation_rule_storage_mountpoint.py b/python/tests/unit/test_validation_rule_storage_mountpoint.py
new file mode 100644
index 0000000..2847b53
--- /dev/null
+++ b/python/tests/unit/test_validation_rule_storage_mountpoint.py
@@ -0,0 +1,86 @@
1# Copyright 2018, Intracom-Telecom
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Test Validation Rule Storage Mountpoints"""
15
16import re
17import logging
18
19from drydock_provisioner.orchestrator.orchestrator import Orchestrator
20from drydock_provisioner.orchestrator.validations.\
21 storage_mountpoints import StorageMountpoints
22
23LOG = logging.getLogger(__name__)
24
25class TestStorageMountpoints(object):
26 def test_storage_mountpoints(self, deckhand_ingester, drydock_state,
27 input_files):
28
29 input_file = input_files.join("validation.yaml")
30 design_ref = "file://%s" % str(input_file)
31
32 orch = Orchestrator(
33 state_manager=drydock_state, ingester=deckhand_ingester)
34 status, site_design = Orchestrator.get_effective_site(orch, design_ref)
35
36 validator = StorageMountpoints()
37 message_list = validator.execute(site_design, orchestrator=orch)
38 msg = message_list[0].to_dict()
39
40 assert len(message_list) == 1
41 assert msg.get('error') is False
42
43 def test_invalid_partition_mountpoints(self, deckhand_ingester,
44 drydock_state, input_files,
45 mock_get_build_data):
46
47 input_file = input_files.join("invalid_validation.yaml")
48 design_ref = "file://%s" % str(input_file)
49
50 orch = Orchestrator(
51 state_manager=drydock_state, ingester=deckhand_ingester)
52
53 status, site_design = Orchestrator.get_effective_site(orch, design_ref)
54
55 validator = StorageMountpoints()
56 message_list = validator.execute(site_design, orchestrator=orch)
57
58 regex = re.compile('Mountpoint .+ already exists')
59
60 for msg in message_list:
61 msg = msg.to_dict()
62 LOG.debug(msg)
63 assert regex.search(msg.get('message')) is not None
64 assert msg.get('error') is True
65
66 def test_invalid_vg_mountpoints(self, deckhand_ingester, drydock_state,
67 input_files, mock_get_build_data):
68
69 input_file = input_files.join("invalid_mountpoint.yaml")
70 design_ref = "file://%s" % str(input_file)
71
72 orch = Orchestrator(
73 state_manager=drydock_state, ingester=deckhand_ingester)
74
75 status, site_design = Orchestrator.get_effective_site(orch, design_ref)
76
77 validator = StorageMountpoints()
78 message_list = validator.execute(site_design, orchestrator=orch)
79
80 regex = re.compile('Mountpoint .+ already exists')
81
82 for msg in message_list:
83 msg = msg.to_dict()
84 LOG.debug(msg)
85 assert regex.search(msg.get('message')) is not None
86 assert msg.get('error') is True
diff --git a/python/tests/yaml_samples/invalid_mountpoint.yaml b/python/tests/yaml_samples/invalid_mountpoint.yaml
new file mode 100644
index 0000000..6d1ad17
--- /dev/null
+++ b/python/tests/yaml_samples/invalid_mountpoint.yaml
@@ -0,0 +1,455 @@
1# Copyright 2018, Intracom-Telecom
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14####################
15#
16# bootstrap_seed.yaml - Site server design definition for physical layer
17#
18####################
19# version the schema in this file so consumers can rationally parse it
20---
21schema: 'drydock/Region/v1'
22metadata:
23 schema: 'metadata/Document/v1'
24 name: 'sitename'
25 storagePolicy: 'cleartext'
26 labels:
27 application: 'drydock'
28data:
29 tag_definitions:
30 - tag: 'test'
31 definition_type: 'lshw_xpath'
32 definition: "//node[@id=\"display\"]/'clock units=\"Hz\"' > 1000000000"
33 authorized_keys:
34 - |
35 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDENeyO5hLPbLLQRZ0oafTYWs1ieo5Q+XgyZQs51Ju
36 jDGc8lKlWsg1/6yei2JewKMgcwG2Buu1eqU92Xn1SvMZLyt9GZURuBkyjcfVc/8GiU5QP1Of8B7CV0c
37 kfUpHWYJ17olTzT61Hgz10ioicBF6cjgQrLNcyn05xoaJHD2Vpf8Unxzi0YzA2e77yRqBo9jJVRaX2q
38 wUJuZrzb62x3zw8Knz6GGSZBn8xRKLaw1SKFpd1hwvL62GfqX5ZBAT1AYTZP1j8GcAoK8AFVn193SEU
39 vjSdUFa+RNWuJhkjBRfylJczIjTIFb5ls0jpbA3bMA9DE7lFKVQl6vVwFmiIVBI1 samplekey
40---
41schema: 'drydock/NetworkLink/v1'
42metadata:
43 schema: 'metadata/Document/v1'
44 name: oob
45 storagePolicy: 'cleartext'
46 labels:
47 application: 'drydock'
48data:
49 bonding:
50 mode: disabled
51 mtu: 1500
52 linkspeed: 100full
53 trunking:
54 mode: disabled
55 default_network: oob
56 allowed_networks:
57 - oob
58---
59schema: 'drydock/NetworkLink/v1'
60metadata:
61 schema: 'metadata/Document/v1'
62 name: pxe
63 storagePolicy: 'cleartext'
64 labels:
65 application: 'drydock'
66data:
67 bonding:
68 mode: disabled
69 mtu: 1500
70 linkspeed: auto
71 trunking:
72 mode: disabled
73 default_network: pxe
74 allowed_networks:
75 - pxe
76---
77schema: 'drydock/NetworkLink/v1'
78metadata:
79 schema: 'metadata/Document/v1'
80 name: gp
81 storagePolicy: 'cleartext'
82 labels:
83 application: 'drydock'
84data:
85 bonding:
86 mode: 802.3ad
87 hash: layer3+4
88 peer_rate: slow
89 mtu: 9000
90 linkspeed: auto
91 trunking:
92 mode: 802.1q
93 default_network: mgmt
94 allowed_networks:
95 - public
96 - private
97 - mgmt
98---
99schema: 'drydock/Rack/v1'
100metadata:
101 schema: 'metadata/Document/v1'
102 name: rack1
103 storagePolicy: 'cleartext'
104 labels:
105 application: 'drydock'
106data:
107 tor_switches:
108 switch01name:
109 mgmt_ip: 1.1.1.1
110 sdn_api_uri: polo+https://api.sdn.example.com/switchmgmt?switch=switch01name
111 switch02name:
112 mgmt_ip: 1.1.1.2
113 sdn_api_uri: polo+https://api.sdn.example.com/switchmgmt?switch=switch02name
114 location:
115 clli: HSTNTXMOCG0
116 grid: EG12
117 local_networks:
118 - pxe-rack1
119---
120schema: 'drydock/Network/v1'
121metadata:
122 schema: 'metadata/Document/v1'
123 name: oob
124 storagePolicy: 'cleartext'
125 labels:
126 application: 'drydock'
127data:
128 cidr: 172.16.100.0/24
129 ranges:
130 - type: static
131 start: 172.16.100.15
132 end: 172.16.100.254
133 dns:
134 domain: ilo.sitename.att.com
135 servers: 172.16.100.10
136---
137schema: 'drydock/Network/v1'
138metadata:
139 schema: 'metadata/Document/v1'
140 name: pxe
141 storagePolicy: 'cleartext'
142 labels:
143 application: 'drydock'
144data:
145 dhcp_relay:
146 self_ip: 172.16.0.4
147 upstream_target: 172.16.5.5
148 mtu: 1500
149 cidr: 172.16.0.0/24
150 ranges:
151 - type: dhcp
152 start: 172.16.0.5
153 end: 172.16.0.254
154 dns:
155 domain: admin.sitename.att.com
156 servers: 172.16.0.10
157---
158schema: 'drydock/Network/v1'
159metadata:
160 schema: 'metadata/Document/v1'
161 name: mgmt
162 storagePolicy: 'cleartext'
163 labels:
164 application: 'drydock'
165data:
166 vlan: '100'
167 mtu: 1500
168 cidr: 172.16.1.0/24
169 ranges:
170 - type: static
171 start: 172.16.1.15
172 end: 172.16.1.254
173 routes:
174 - subnet: 0.0.0.0/0
175 gateway: 172.16.1.1
176 metric: 10
177 dns:
178 domain: mgmt.sitename.example.com
179 servers: 172.16.1.9,172.16.1.10
180---
181schema: 'drydock/Network/v1'
182metadata:
183 schema: 'metadata/Document/v1'
184 name: private
185 storagePolicy: 'cleartext'
186 labels:
187 application: 'drydock'
188data:
189 vlan: '101'
190 mtu: 9000
191 cidr: 172.16.2.0/24
192 ranges:
193 - type: static
194 start: 172.16.2.15
195 end: 172.16.2.254
196 dns:
197 domain: priv.sitename.example.com
198 servers: 172.16.2.9,172.16.2.10
199---
200schema: 'drydock/Network/v1'
201metadata:
202 schema: 'metadata/Document/v1'
203 name: public
204 storagePolicy: 'cleartext'
205 labels:
206 application: 'drydock'
207data:
208 vlan: '102'
209 mtu: 1500
210 cidr: 172.16.3.0/24
211 ranges:
212 - type: static
213 start: 172.16.3.15
214 end: 172.16.3.254
215 routes:
216 - subnet: 0.0.0.0/0
217 gateway: 172.16.3.1
218 metric: 10
219 dns:
220 domain: sitename.example.com
221 servers: 8.8.8.8
222---
223schema: 'drydock/HostProfile/v1'
224metadata:
225 schema: 'metadata/Document/v1'
226 name: defaults
227 storagePolicy: 'cleartext'
228 labels:
229 application: 'drydock'
230data:
231 oob:
232 type: ipmi
233 network: oob
234 account: admin
235 credential: admin
236 storage:
237 physical_devices:
238 sda:
239 labels:
240 role: rootdisk
241 partitions:
242 - name: root
243 size: 20g
244 bootable: true
245 filesystem:
246 mountpoint: '/'
247 fstype: 'ext4'
248 mount_options: 'defaults'
249 - name: boot
250 size: 1g
251 bootable: false
252 filesystem:
253 mountpoint: '/boot'
254 fstype: 'ext4'
255 mount_options: 'defaults'
256 sdb:
257 volume_group: 'log_vg'
258 volume_groups:
259 log_vg:
260 logical_volumes:
261 - name: 'log_lv'
262 size: '500m'
263 filesystem:
264 mountpoint: '/var/log'
265 fstype: 'xfs'
266 mount_options: 'defaults'
267 - name: 'log_lv_two'
268 size: '500m'
269 filesystem:
270 mountpoint: '/var/log'
271 fstype: 'xfs'
272 mount_options: 'defaults'
273 platform:
274 image: 'xenial'
275 kernel: 'ga-16.04'
276 kernel_params:
277 quiet: true
278 console: ttyS2
279 metadata:
280 owner_data:
281 foo: bar
282---
283schema: 'drydock/HostProfile/v1'
284metadata:
285 schema: 'metadata/Document/v1'
286 name: 'k8-node'
287 storagePolicy: 'cleartext'
288 labels:
289 application: 'drydock'
290data:
291 host_profile: defaults
292 hardware_profile: HPGen9v3
293 primary_network: mgmt
294 interfaces:
295 pxe:
296 device_link: pxe
297 labels:
298 noconfig: true
299 slaves:
300 - prim_nic01
301 networks:
302 - pxe
303 bond0:
304 device_link: gp
305 slaves:
306 - prim_nic01
307 - prim_nic02
308 networks:
309 - mgmt
310 - private
311 metadata:
312 tags:
313 - 'test'
314---
315schema: 'drydock/BaremetalNode/v1'
316metadata:
317 schema: 'metadata/Document/v1'
318 name: controller01
319 storagePolicy: 'cleartext'
320 labels:
321 application: 'drydock'
322data:
323 host_profile: k8-node
324 interfaces:
325 bond0:
326 networks:
327 - '!private'
328 addressing:
329 - network: pxe
330 address: dhcp
331 - network: mgmt
332 address: 172.16.1.20
333 - network: public
334 address: 172.16.3.20
335 - network: oob
336 address: 172.16.100.20
337 metadata:
338 rack: rack1
339---
340schema: 'drydock/BaremetalNode/v1'
341metadata:
342 schema: 'metadata/Document/v1'
343 name: compute01
344 storagePolicy: 'cleartext'
345 labels:
346 application: 'drydock'
347data:
348 host_profile: k8-node
349 addressing:
350 - network: pxe
351 address: dhcp
352 - network: mgmt
353 address: 172.16.1.21
354 - network: private
355 address: 172.16.2.21
356 - network: oob
357 address: 172.16.100.21
358 metadata:
359 rack: rack2
360---
361schema: 'drydock/HardwareProfile/v1'
362metadata:
363 schema: 'metadata/Document/v1'
364 name: HPGen9v3
365 storagePolicy: 'cleartext'
366 labels:
367 application: 'drydock'
368data:
369 vendor: HP
370 generation: '8'
371 hw_version: '3'
372 bios_version: '2.2.3'
373 boot_mode: bios
374 bootstrap_protocol: pxe
375 pxe_interface: 0
376 device_aliases:
377 prim_nic01:
378 address: '0000:00:03.0'
379 dev_type: '82540EM Gigabit Ethernet Controller'
380 bus_type: 'pci'
381 prim_nic02:
382 address: '0000:00:04.0'
383 dev_type: '82540EM Gigabit Ethernet Controller'
384 bus_type: 'pci'
385 primary_boot:
386 address: '2:0.0.0'
387 dev_type: 'VBOX HARDDISK'
388 bus_type: 'scsi'
389---
390schema: 'drydock/BootAction/v1'
391metadata:
392 schema: 'metadata/Document/v1'
393 name: helloworld
394 storagePolicy: 'cleartext'
395 labels:
396 application: 'drydock'
397data:
398 assets:
399 - path: /var/tmp/hello.sh
400 type: file
401 permissions: '555'
402 data: |-
403 IyEvYmluL2Jhc2gKCmVjaG8gJ0hlbGxvIFdvcmxkISAtZnJvbSB7eyBub2RlLmhvc3RuYW1lIH19
404 Jwo=
405 data_pipeline:
406 - base64_decode
407 - utf8_decode
408 - template
409 - path: /lib/systemd/system/hello.service
410 type: unit
411 permissions: '600'
412 data: |-
413 W1VuaXRdCkRlc2NyaXB0aW9uPUhlbGxvIFdvcmxkCgpbU2VydmljZV0KVHlwZT1vbmVzaG90CkV4
414 ZWNTdGFydD0vdmFyL3RtcC9oZWxsby5zaAoKW0luc3RhbGxdCldhbnRlZEJ5PW11bHRpLXVzZXIu
415 dGFyZ2V0Cg==
416 data_pipeline:
417 - base64_decode
418 - utf8_decode
419---
420schema: 'drydock/BootAction/v1'
421metadata:
422 schema: 'metadata/Document/v1'
423 name: hw_filtered
424 storagePolicy: 'cleartext'
425 labels:
426 application: 'drydock'
427data:
428 node_filter:
429 filter_set_type: 'union'
430 filter_set:
431 - filter_type: 'union'
432 node_names:
433 - 'compute01'
434 assets:
435 - path: /var/tmp/hello.sh
436 type: file
437 permissions: '555'
438 data: |-
439 IyEvYmluL2Jhc2gKCmVjaG8gJ0hlbGxvIFdvcmxkISAtZnJvbSB7eyBub2RlLmhvc3RuYW1lIH19
440 Jwo=
441 data_pipeline:
442 - base64_decode
443 - utf8_decode
444 - template
445 - path: /lib/systemd/system/hello.service
446 type: unit
447 permissions: '600'
448 data: |-
449 W1VuaXRdCkRlc2NyaXB0aW9uPUhlbGxvIFdvcmxkCgpbU2VydmljZV0KVHlwZT1vbmVzaG90CkV4
450 ZWNTdGFydD0vdmFyL3RtcC9oZWxsby5zaAoKW0luc3RhbGxdCldhbnRlZEJ5PW11bHRpLXVzZXIu
451 dGFyZ2V0Cg==
452 data_pipeline:
453 - base64_decode
454 - utf8_decode
455...
diff --git a/python/tests/yaml_samples/invalid_validation.yaml b/python/tests/yaml_samples/invalid_validation.yaml
index 37d27b2..b24ec3e 100644
--- a/python/tests/yaml_samples/invalid_validation.yaml
+++ b/python/tests/yaml_samples/invalid_validation.yaml
@@ -252,11 +252,12 @@ data:
252# FAILS HERE: root not set 252# FAILS HERE: root not set
253############################################# 253#############################################
254# FAILS HERE: partitions size > 99% 254# FAILS HERE: partitions size > 99%
255# FAILS HERE: duplicate mount point
255 - name: test 256 - name: test
256 size: 100% 257 size: 100%
257 bootable: true 258 bootable: true
258 filesystem: 259 filesystem:
259 mountpoint: '/' 260 mountpoint: '/boot'
260 fstype: 'ext4' 261 fstype: 'ext4'
261 mount_options: 'defaults' 262 mount_options: 'defaults'
262############################################### 263###############################################