[augeas-devel] [PATCH] Mdadm_conf: new lens for /etc/mdadm.conf

Matthew Booth mbooth at redhat.com
Mon Nov 7 16:53:16 UTC 2011


---
 lenses/mdadm_conf.aug            |  281 ++++++++++++++++++++++++++++++++++++++
 lenses/tests/test_mdadm_conf.aug |   96 +++++++++++++
 2 files changed, 377 insertions(+), 0 deletions(-)
 create mode 100644 lenses/mdadm_conf.aug
 create mode 100644 lenses/tests/test_mdadm_conf.aug

diff --git a/lenses/mdadm_conf.aug b/lenses/mdadm_conf.aug
new file mode 100644
index 0000000..615dd43
--- /dev/null
+++ b/lenses/mdadm_conf.aug
@@ -0,0 +1,281 @@
+(******************************************************************************
+Mdadm_conf module for Augeas
+
+Author: Matthew Booth <mbooth at redhat.com>
+
+Copyright (C):
+    2011 Red Hat Inc.
+
+Reference:
+    mdadm(5)
+    config.c and policy.c from mdadm-3.2.2
+
+License:
+    This file is licensed under the LGPLv2+.
+
+This is a lens for /etc/mdadm.conf. It aims to parse every valid configuration
+file as of version 3.2.2, and many invalid ones too. This last point is a
+feature, not a bug! madm will generate warnings for invalid configuration which
+do not prevent correct operation of the tool. Wherever possible, we try to
+allow for this behaviour.
+
+Keywords in mdadm.conf are matched with a case-insensitive prefix match of at
+least 3 characters. Keys in key/value pairs are also matched case-insensitively,
+but require a full match. The exception is POLICY and PART-POLICY, where keys
+are matched case-sensitively.
+
+N.B. We can't use case-insensitive regular expressions in most places due to bug
+#147.
+*******************************************************************************)
+
+module Mdadm_conf =
+
+   autoload xfm
+
+
+(******************************************************************************
+ * PRIMITIVES
+ ******************************************************************************)
+
+let eol             = Util.comment_or_eol
+let comment         = Util.comment
+let empty           = Util.empty
+let value           = /[^ \t\n#]+/
+let value_no_eq     = /[^ \t\n#=]+/
+let value_no_eq_sl  = /[^ \t\n#=\/]+/
+
+let continuation = /\n[ \t]+/
+let space = /[ \t]+/
+let value_sep = ( del ( continuation | space . continuation? ) " "
+                  | comment . del space " " )
+
+(* We parse specific keys rather than having a catch-all owing to the varying
+case of the syntax. This means the user can rely on 'array/uuid' rather than
+additionally testing for 'array/UUID'.
+
+It would be good to have an additional catchall, but I haven't been able to make
+that work.
+*)
+let keyvalue (r:regexp) (lc:string) (uc:string) =
+    [ del ( r . /=/ ) ( uc . "=" ) . label lc . store value ]
+
+let simplevalue (r:regexp) (lc:string) (uc:string) =
+    [ del r uc . label lc
+      . ( value_sep . [ label "value" . store value ] )* . eol ]
+
+
+(******************************************************************************
+ * DEVICES
+ ******************************************************************************)
+
+let dev_re = /[dD][eE][vV]([iI]([cC][eE]?)?)?/
+
+let dev_containers_re = /[cC][oO][nN][tT][aA][iI][nN][eE][rR][sS]/
+let dev_partitions_re = /[pP][aA][rR][tT][iI][tT][iI][oO][nN][sS]/
+
+let dev_containers = [ del dev_containers_re "containers" . label "containers" ]
+let dev_partitions = [ del dev_partitions_re "partitions" . label "partitions" ]
+let dev_device = [ label "name". store ( value
+                                         - dev_containers_re
+                                         - dev_partitions_re ) ]
+
+(* Strictly there must be at least 1 device, but we err on the side of parsing
+*)
+let dev_devices = ( value_sep . ( dev_containers
+                                  | dev_partitions
+                                  | dev_device ) )*
+
+let device = [ del dev_re "DEVICE" . label "device" . dev_devices . eol ]
+
+
+(******************************************************************************
+ * ARRAY
+ ******************************************************************************)
+
+let array_re  = /[aA][rR][rR]([aA][yY]?)?/
+
+let arr_auto_re         = /[aA][uU][tT][oO]/
+let arr_bitmap_re       = /[bB][iI][tT][mM][aA][pP]/
+let arr_container_re    = /[cC][oO][nN][tT][aA][iI][nN][eE][rR]/
+let arr_devices_re      = /[dD][eE][vV][iI][cC][eE][sS]/
+let arr_disks_re        = /[dD][iI][sS][kK][sS]/ (* Undocumented *)
+let arr_level_re        = /[lL][eE][vV][eE][lL]/
+let arr_member_re       = /[mM][eE][mM][bB][eE][rR]/
+let arr_metadata_re     = /[mM][eE][tT][aA][dD][aA][tT][aA]/
+let arr_name_re         = /[nN][aA][mM][eE]/
+let arr_num_devices_re  = /[nN][uU][mM]-[dD][eE][vV][iI][cC][eE][sS]/
+let arr_spare_group_re  = /[sS][pP][aA][rR][eE]-[gG][rR][oO][uU][pP]/
+let arr_spares_re       = /[sS][pP][aA][rR][eE][sS]/
+let arr_super_minor_re  = /[sS][uU][pP][eE][rR]-[mM][iI][nN][oO][rR]/
+let arr_uuid_re         = /[uU][uU][iI][dD]/
+
+let arr_devicename      = [ store value_no_eq . label "devicename" ]
+
+let arr_auto        = keyvalue arr_auto_re "auto" "AUTO"
+let arr_bitmap      = keyvalue arr_bitmap_re "bitmap" "BITMAP"
+let arr_container   = keyvalue arr_container_re "container" "CONTAINER"
+let arr_devices     = keyvalue arr_devices_re "devices" "DEVICES"
+let arr_disks       = keyvalue arr_disks_re "disks" "DISKS"
+let arr_level       = keyvalue arr_level_re "level" "LEVEL"
+let arr_member      = keyvalue arr_member_re "member" "MEMBER"
+let arr_metadata    = keyvalue arr_metadata_re "metadata" "METADATA"
+let arr_name        = keyvalue arr_name_re "name" "NAME"
+let arr_num_devices = keyvalue arr_num_devices_re "num-devices" "NUM-DEVICES"
+let arr_spare_group = keyvalue arr_spare_group_re "spare-group" "SPARE-GROUP"
+let arr_spares      = keyvalue arr_spares_re "spares" "SPARES"
+let arr_super_minor = keyvalue arr_super_minor_re "super-minor" "SUPER-MINOR"
+let arr_uuid        = keyvalue arr_uuid_re "uuid" "UUID"
+
+let arr_options = ( value_sep . ( arr_devicename
+                                  | arr_auto
+                                  | arr_bitmap
+                                  | arr_container
+                                  | arr_devices
+                                  | arr_disks
+                                  | arr_level
+                                  | arr_member
+                                  | arr_metadata
+                                  | arr_name
+                                  | arr_num_devices
+                                  | arr_spare_group 
+                                  | arr_spares
+                                  | arr_super_minor
+                                  | arr_uuid ) )*
+
+let array  = [ del array_re "ARRAY" . label "array" . arr_options . eol ]
+
+
+(******************************************************************************
+ * MAILADDR
+ ******************************************************************************)
+
+let mailaddr_re = /[mM][aA][iI]([lL]([aA]([dD]([dD][rR]?)?)?)?)?/
+
+(* We intentially allow multiple mailaddr values here, even though this is
+invalid and would produce a warning. This is better than not parsing the file.
+*)
+let mailaddr = simplevalue mailaddr_re "mailaddr" "MAILADDR"
+
+
+(******************************************************************************
+ * MAILFROM
+ ******************************************************************************)
+
+(* N.B. MAILFROM can only be abbreviated to 5 characters *)
+let mailfrom_re = /[mM][aA][iI][lL][fF]([rR]([oO][mM]?)?)?/
+
+let mailfrom = [ del mailfrom_re "MAILFROM" . label "mailfrom"
+                 . ( value_sep . [ label "value" . store value ] )* . eol ]
+
+
+(******************************************************************************
+ * PROGRAM
+ ******************************************************************************)
+
+let program_re = /[pP][rR][oO]([gG]([rR]([aA][mM]?)?)?)?/
+
+let program = simplevalue program_re "program" "PROGRAM"
+
+
+(******************************************************************************
+ * CREATE
+ ******************************************************************************)
+
+let create_re = /[cC][rR][eE]([aA]([tT][eE]?)?)?/
+
+let cre_auto_re     = /[aA][uU][tT][oO]/
+let cre_owner_re    = /[oO][wW][nN][eE][rR]/
+let cre_group_re    = /[gG][rR][oO][uU][pP]/
+let cre_mode_re     = /[mM][oO][dD][eE]/
+let cre_metadata_re = /[mM][eE][tT][aA][dD][aA][tT][aA]/
+let cre_symlinks_re = /[sS][yY][mM][lL][iI][nN][kK][sS]/
+
+let cre_auto        = keyvalue cre_auto_re "auto" "AUTO"
+let cre_group       = keyvalue cre_group_re "group" "GROUP"
+let cre_metadata    = keyvalue cre_metadata_re "metadata" "METADATA"
+let cre_mode        = keyvalue cre_mode_re "mode" "MODE"
+let cre_owner       = keyvalue cre_owner_re "owner" "OWNER"
+let cre_symlinks    = keyvalue cre_symlinks_re "symlinks" "SYMLINKS"
+
+let cre_options = ( value_sep . ( arr_auto
+                                  | cre_owner
+                                  | cre_group
+                                  | cre_mode
+                                  | cre_metadata
+                                  | cre_symlinks) )*
+
+let create  = [ del create_re "CREATE" . label "create" . cre_options . eol ]
+
+
+(******************************************************************************
+ * HOMEHOST
+ ******************************************************************************)
+
+let homehost_re = /[hH][oO][mM]([eE]([hH]([oO]([sS][tT]?)?)?)?)?/
+
+let homehost = simplevalue homehost_re "homehost" "HOMEHOST"
+
+
+(******************************************************************************
+ * AUTO
+ ******************************************************************************)
+
+let auto_re = /[aA][uU][tT][oO]?/
+
+let aut_plus        = [ key "+" . store value ]
+let aut_minus       = [ key "-" . store value ]
+let aut_homehost    = [ del /homehost/i "homehost" . label "homehost" ]
+
+let aut_list = ( value_sep . ( aut_plus | aut_minus | aut_homehost ) )*
+
+let auto = [ del auto_re "AUTO" . label "auto" . aut_list . eol ]
+
+
+(******************************************************************************
+ * POLICY and PART-POLICY
+ ******************************************************************************)
+
+(* PART-POLICY is undocumented. A cursory inspection of the parsing code
+suggests it's parsed the same way as POLICY, but treated slightly differently
+thereafter. *)
+
+let policy_re = /[pP][oO][lL]([iI]([cC][yY]?)?)?/
+let part_policy_re =
+    /[pP][aA][rR]([tT](-([pP]([oO]([lL]([iI]([cC][yY]?)?)?)?)?)?)?)?/
+
+(* Unlike everything else, policy keys are matched case sensitive. This means we
+don't have to mess around with explicit option matching, as the match string is
+fixed for a working configuration. *)
+
+let pol_option (act:string) =
+    [ del ( act . "=" ) ( act . "=" ) . label act . store value ]
+
+let pol_options = ( value_sep . [ key value_no_eq_sl . del "=" "="
+                                  . store value ] )*
+
+let policy      = [ del policy_re "POLICY" . label "policy"
+                    . pol_options . eol ]
+let part_policy = [ del part_policy_re "PART-POLICY" . label "part-policy"
+                    . pol_options . eol ]
+
+
+(******************************************************************************
+ * LENS
+ ******************************************************************************)
+
+let lns = (comment
+           | empty
+           | device
+           | array
+           | mailaddr
+           | mailfrom
+           | program
+           | create
+           | homehost
+           | auto
+           | policy
+           | part_policy )*
+
+let filter     = incl "/etc/mdadm.conf"
+
+let xfm        = transform lns filter
diff --git a/lenses/tests/test_mdadm_conf.aug b/lenses/tests/test_mdadm_conf.aug
new file mode 100644
index 0000000..db583c8
--- /dev/null
+++ b/lenses/tests/test_mdadm_conf.aug
@@ -0,0 +1,96 @@
+module Test_mdadm_conf =
+
+let conf = "
+# Comment
+device containers
+ # Comment
+DEVICE partitions  
+dev
+	/dev/hda*  
+  /dev/hdc*
+deVI
+ARRAY /dev/md0 UUID=c3d3134f-2aa9-4514-9da3-82ccd1cccc7b Name=foo=bar
+    supeR-minor=3 devicEs=/dev/hda,/dev/hdb Level=1 num-devices=5 spares=2
+    spare-group=bar auTo=yes BITMAP=/path/to/bitmap metadata=frob
+    container=/dev/sda member=1
+MAIL # Initial comment
+    user at example.com # End of line comment
+MAILF user at example.com # MAILFROM can only be abbreviated to 5 characters
+PROGRA /usr/sbin/handle-mdadm-events
+CREA group=system mode=0640 auto=part-8
+HOME <system>
+AUT +1.x Homehost -all
+POL domain=domain1 metadata=imsm path=pci-0000:00:1f.2-scsi-*
+           action=spare
+PART domain=domain1 metadata=imsm path=pci-0000:04:00.0-scsi-[01]*
+           action=include
+"
+
+test Mdadm_conf.lns get conf =
+    {}
+    { "#comment" = "Comment" }
+    { "device"
+        { "containers" }
+    }
+    { "#comment" = "Comment" }
+    { "device"
+        { "partitions" }
+    }
+    { "device"
+        { "name" = "/dev/hda*" }
+        { "name" = "/dev/hdc*" }
+    }
+    { "device" }
+    { "array"
+        { "devicename" = "/dev/md0" }
+        { "uuid" = "c3d3134f-2aa9-4514-9da3-82ccd1cccc7b" }
+        { "name" = "foo=bar" }
+        { "super-minor" = "3" }
+        { "devices" = "/dev/hda,/dev/hdb" }
+        { "level" = "1" }
+        { "num-devices" = "5" }
+        { "spares" = "2" }
+        { "spare-group" = "bar" }
+        { "auto" = "yes" }
+        { "bitmap" = "/path/to/bitmap" }
+        { "metadata" = "frob" }
+        { "container" = "/dev/sda" }
+        { "member" = "1" }
+    }
+    { "mailaddr"
+        { "#comment" = "Initial comment" }
+        { "value" = "user at example.com" }
+        { "#comment" = "End of line comment" }
+    }
+    { "mailfrom"
+        { "value" = "user at example.com" }
+        { "#comment" = "MAILFROM can only be abbreviated to 5 characters" }
+    }
+    { "program"
+        { "value" = "/usr/sbin/handle-mdadm-events" }
+    }
+    { "create"
+        { "group" = "system" }
+        { "mode" = "0640" }
+        { "auto" = "part-8" }
+    }
+    { "homehost"
+        { "value" = "<system>" }
+    }
+    { "auto"
+        { "+" = "1.x" }
+        { "homehost" }
+        { "-" = "all" }
+    }
+    { "policy"
+        { "domain" = "domain1" }
+        { "metadata" = "imsm" }
+        { "path" = "pci-0000:00:1f.2-scsi-*" }
+        { "action" = "spare" }
+    }
+    { "part-policy"
+        { "domain" = "domain1" }
+        { "metadata" = "imsm" }
+        { "path" = "pci-0000:04:00.0-scsi-[01]*" }
+        { "action" = "include" }
+    }
-- 
1.7.6.4




More information about the augeas-devel mailing list