Browse Source

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>
changes/03/607603/14
Dimitrios Markou 9 months ago
parent
commit
1466835626

+ 73
- 0
python/drydock_provisioner/orchestrator/validations/storage_mountpoints.py View File

@@ -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
+
15
+from drydock_provisioner.orchestrator.validations.validators import Validators
16
+
17
+class 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

+ 2
- 0
python/drydock_provisioner/orchestrator/validations/validator.py View File

@@ -33,6 +33,7 @@ from drydock_provisioner.orchestrator.validations.oob_valid_ipmi import IpmiVali
33 33
 from drydock_provisioner.orchestrator.validations.oob_valid_libvirt import LibvirtValidity
34 34
 from drydock_provisioner.orchestrator.validations.bootaction_validity import BootactionDefined
35 35
 from drydock_provisioner.orchestrator.validations.bootaction_validity import BootactionPackageListValid
36
+from drydock_provisioner.orchestrator.validations.storage_mountpoints import StorageMountpoints
36 37
 
37 38
 
38 39
 class Validator():
@@ -92,6 +93,7 @@ rule_set = [
92 93
     RationalNetworkBond(),
93 94
     StoragePartitioning(),
94 95
     StorageSizing(),
96
+    StorageMountpoints(),
95 97
     UniqueNetworkCheck(),
96 98
     HostnameValidity(),
97 99
     IpmiValidity(),

+ 86
- 0
python/tests/unit/test_validation_rule_storage_mountpoint.py View File

@@ -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
+
16
+import re
17
+import logging
18
+
19
+from drydock_provisioner.orchestrator.orchestrator import Orchestrator
20
+from drydock_provisioner.orchestrator.validations.\
21
+        storage_mountpoints import StorageMountpoints
22
+
23
+LOG = logging.getLogger(__name__)
24
+
25
+class 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

+ 455
- 0
python/tests/yaml_samples/invalid_mountpoint.yaml View File

@@ -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
+---
21
+schema: 'drydock/Region/v1'
22
+metadata:
23
+  schema: 'metadata/Document/v1'
24
+  name: 'sitename'
25
+  storagePolicy: 'cleartext'
26
+  labels:
27
+    application: 'drydock'
28
+data:
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
+---
41
+schema: 'drydock/NetworkLink/v1'
42
+metadata:
43
+  schema: 'metadata/Document/v1'
44
+  name: oob
45
+  storagePolicy: 'cleartext'
46
+  labels:
47
+    application: 'drydock'
48
+data:
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
+---
59
+schema: 'drydock/NetworkLink/v1'
60
+metadata:
61
+  schema: 'metadata/Document/v1'
62
+  name: pxe
63
+  storagePolicy: 'cleartext'
64
+  labels:
65
+    application: 'drydock'
66
+data:
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
+---
77
+schema: 'drydock/NetworkLink/v1'
78
+metadata:
79
+  schema: 'metadata/Document/v1'
80
+  name: gp
81
+  storagePolicy: 'cleartext'
82
+  labels:
83
+    application: 'drydock'
84
+data:
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
+---
99
+schema: 'drydock/Rack/v1'
100
+metadata:
101
+  schema: 'metadata/Document/v1'
102
+  name: rack1
103
+  storagePolicy: 'cleartext'
104
+  labels:
105
+    application: 'drydock'
106
+data:
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
+---
120
+schema: 'drydock/Network/v1'
121
+metadata:
122
+  schema: 'metadata/Document/v1'
123
+  name: oob
124
+  storagePolicy: 'cleartext'
125
+  labels:
126
+    application: 'drydock'
127
+data:
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
+---
137
+schema: 'drydock/Network/v1'
138
+metadata:
139
+  schema: 'metadata/Document/v1'
140
+  name: pxe
141
+  storagePolicy: 'cleartext'
142
+  labels:
143
+    application: 'drydock'
144
+data:
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
+---
158
+schema: 'drydock/Network/v1'
159
+metadata:
160
+  schema: 'metadata/Document/v1'
161
+  name: mgmt
162
+  storagePolicy: 'cleartext'
163
+  labels:
164
+    application: 'drydock'
165
+data:
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
+---
181
+schema: 'drydock/Network/v1'
182
+metadata:
183
+  schema: 'metadata/Document/v1'
184
+  name: private
185
+  storagePolicy: 'cleartext'
186
+  labels:
187
+    application: 'drydock'
188
+data:
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
+---
200
+schema: 'drydock/Network/v1'
201
+metadata:
202
+  schema: 'metadata/Document/v1'
203
+  name: public
204
+  storagePolicy: 'cleartext'
205
+  labels:
206
+    application: 'drydock'
207
+data:
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
+---
223
+schema: 'drydock/HostProfile/v1'
224
+metadata:
225
+  schema: 'metadata/Document/v1'
226
+  name: defaults
227
+  storagePolicy: 'cleartext'
228
+  labels:
229
+    application: 'drydock'
230
+data:
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
+---
283
+schema: 'drydock/HostProfile/v1'
284
+metadata:
285
+  schema: 'metadata/Document/v1'
286
+  name: 'k8-node'
287
+  storagePolicy: 'cleartext'
288
+  labels:
289
+    application: 'drydock'
290
+data:
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
+---
315
+schema: 'drydock/BaremetalNode/v1'
316
+metadata:
317
+  schema: 'metadata/Document/v1'
318
+  name: controller01
319
+  storagePolicy: 'cleartext'
320
+  labels:
321
+    application: 'drydock'
322
+data:
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
+---
340
+schema: 'drydock/BaremetalNode/v1'
341
+metadata:
342
+  schema: 'metadata/Document/v1'
343
+  name: compute01
344
+  storagePolicy: 'cleartext'
345
+  labels:
346
+    application: 'drydock'
347
+data:
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
+---
361
+schema: 'drydock/HardwareProfile/v1'
362
+metadata:
363
+  schema: 'metadata/Document/v1'
364
+  name: HPGen9v3
365
+  storagePolicy: 'cleartext'
366
+  labels:
367
+    application: 'drydock'
368
+data:
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
+---
390
+schema: 'drydock/BootAction/v1'
391
+metadata:
392
+  schema: 'metadata/Document/v1'
393
+  name: helloworld
394
+  storagePolicy: 'cleartext'
395
+  labels:
396
+    application: 'drydock'
397
+data:
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
+---
420
+schema: 'drydock/BootAction/v1'
421
+metadata:
422
+  schema: 'metadata/Document/v1'
423
+  name: hw_filtered
424
+  storagePolicy: 'cleartext'
425
+  labels:
426
+    application: 'drydock'
427
+data:
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
+...

+ 2
- 1
python/tests/yaml_samples/invalid_validation.yaml View File

@@ -252,11 +252,12 @@ data:
252 252
 # FAILS HERE: root not set
253 253
 #############################################
254 254
 # FAILS HERE: partitions size > 99%
255
+# FAILS HERE: duplicate mount point
255 256
           - name: test
256 257
             size: 100%
257 258
             bootable: true
258 259
             filesystem:
259
-              mountpoint: '/'
260
+              mountpoint: '/boot'
260 261
               fstype: 'ext4'
261 262
               mount_options: 'defaults'
262 263
 ###############################################

Loading…
Cancel
Save