From 5adc8c28ef74e4babab31dc0691dd1c183da0d91 Mon Sep 17 00:00:00 2001 From: code liturgy Date: Tue, 8 Nov 2022 12:57:02 -0500 Subject: [PATCH] Add tests --- README.md | 2 +- Sharp.Augeas.Test/AugeasTests.cs | 43 + .../Platform/Linux/libclAugeas.so | Bin 0 -> 209256 bytes Sharp.Augeas.Test/Sharp.Augeas.Test.csproj | 38 + Sharp.Augeas.Test/Usings.cs | 1 + .../copyLibrary.sh | 0 Sharp.Augeas.Test/lens/access.aug | 128 ++ Sharp.Augeas.Test/lens/activemq_conf.aug | 61 + Sharp.Augeas.Test/lens/activemq_xml.aug | 41 + Sharp.Augeas.Test/lens/afs_cellalias.aug | 60 + Sharp.Augeas.Test/lens/aliases.aug | 89 ++ Sharp.Augeas.Test/lens/anaconda.aug | 30 + Sharp.Augeas.Test/lens/anacron.aug | 87 ++ Sharp.Augeas.Test/lens/approx.aug | 59 + Sharp.Augeas.Test/lens/apt_update_manager.aug | 47 + .../lens/aptcacherngsecurity.aug | 25 + Sharp.Augeas.Test/lens/aptconf.aug | 151 ++ Sharp.Augeas.Test/lens/aptpreferences.aug | 69 + Sharp.Augeas.Test/lens/aptsources.aug | 70 + Sharp.Augeas.Test/lens/authinfo2.aug | 39 + Sharp.Augeas.Test/lens/authorized_keys.aug | 72 + Sharp.Augeas.Test/lens/authselectpam.aug | 85 ++ Sharp.Augeas.Test/lens/automaster.aug | 125 ++ Sharp.Augeas.Test/lens/automounter.aug | 131 ++ Sharp.Augeas.Test/lens/avahi.aug | 45 + Sharp.Augeas.Test/lens/backuppchosts.aug | 40 + Sharp.Augeas.Test/lens/bbhosts.aug | 130 ++ Sharp.Augeas.Test/lens/bootconf.aug | 130 ++ Sharp.Augeas.Test/lens/build.aug | 420 ++++++ Sharp.Augeas.Test/lens/cachefilesd.aug | 89 ++ Sharp.Augeas.Test/lens/carbon.aug | 54 + Sharp.Augeas.Test/lens/ceph.aug | 26 + Sharp.Augeas.Test/lens/cgconfig.aug | 120 ++ Sharp.Augeas.Test/lens/cgrules.aug | 85 ++ Sharp.Augeas.Test/lens/channels.aug | 155 ++ Sharp.Augeas.Test/lens/chrony.aug | 408 ++++++ Sharp.Augeas.Test/lens/clamav.aug | 55 + Sharp.Augeas.Test/lens/cmdline.aug | 21 + Sharp.Augeas.Test/lens/cobblermodules.aug | 17 + Sharp.Augeas.Test/lens/cobblersettings.aug | 72 + Sharp.Augeas.Test/lens/collectd.aug | 36 + Sharp.Augeas.Test/lens/cpanel.aug | 39 + Sharp.Augeas.Test/lens/cron.aug | 155 ++ Sharp.Augeas.Test/lens/cron_user.aug | 46 + Sharp.Augeas.Test/lens/crypttab.aug | 108 ++ Sharp.Augeas.Test/lens/csv.aug | 51 + Sharp.Augeas.Test/lens/cups.aug | 27 + Sharp.Augeas.Test/lens/cyrus_imapd.aug | 49 + Sharp.Augeas.Test/lens/darkice.aug | 29 + Sharp.Augeas.Test/lens/debctrl.aug | 131 ++ Sharp.Augeas.Test/lens/desktop.aug | 53 + Sharp.Augeas.Test/lens/devfsrules.aug | 24 + Sharp.Augeas.Test/lens/device_map.aug | 28 + Sharp.Augeas.Test/lens/dhclient.aug | 184 +++ Sharp.Augeas.Test/lens/dhcpd.aug | 518 +++++++ Sharp.Augeas.Test/lens/dns_zone.aug | 113 ++ Sharp.Augeas.Test/lens/dnsmasq.aug | 62 + Sharp.Augeas.Test/lens/dovecot.aug | 135 ++ Sharp.Augeas.Test/lens/dpkg.aug | 91 ++ Sharp.Augeas.Test/lens/dput.aug | 68 + Sharp.Augeas.Test/lens/erlang.aug | 196 +++ Sharp.Augeas.Test/lens/ethers.aug | 25 + Sharp.Augeas.Test/lens/exports.aug | 98 ++ Sharp.Augeas.Test/lens/fai_diskconfig.aug | 286 ++++ Sharp.Augeas.Test/lens/fail2ban.aug | 47 + Sharp.Augeas.Test/lens/fonts.aug | 37 + Sharp.Augeas.Test/lens/fstab.aug | 43 + Sharp.Augeas.Test/lens/fuse.aug | 45 + Sharp.Augeas.Test/lens/gdm.aug | 48 + Sharp.Augeas.Test/lens/getcap.aug | 49 + Sharp.Augeas.Test/lens/group.aug | 59 + Sharp.Augeas.Test/lens/grub.aug | 337 +++++ Sharp.Augeas.Test/lens/grubenv.aug | 19 + Sharp.Augeas.Test/lens/gshadow.aug | 80 ++ Sharp.Augeas.Test/lens/gtkbookmarks.aug | 36 + Sharp.Augeas.Test/lens/host_conf.aug | 71 + Sharp.Augeas.Test/lens/hostname.aug | 22 + Sharp.Augeas.Test/lens/hosts.aug | 15 + Sharp.Augeas.Test/lens/hosts_access.aug | 152 ++ Sharp.Augeas.Test/lens/htpasswd.aug | 41 + Sharp.Augeas.Test/lens/httpd.aug | 206 +++ Sharp.Augeas.Test/lens/inetd.aug | 185 +++ Sharp.Augeas.Test/lens/inifile.aug | 555 ++++++++ Sharp.Augeas.Test/lens/inittab.aug | 31 + Sharp.Augeas.Test/lens/inputrc.aug | 59 + Sharp.Augeas.Test/lens/interfaces.aug | 131 ++ Sharp.Augeas.Test/lens/iproute2.aug | 10 + Sharp.Augeas.Test/lens/iptables.aug | 87 ++ Sharp.Augeas.Test/lens/iscsid.aug | 28 + Sharp.Augeas.Test/lens/jaas.aug | 36 + Sharp.Augeas.Test/lens/jettyrealm.aug | 56 + Sharp.Augeas.Test/lens/jmxaccess.aug | 58 + Sharp.Augeas.Test/lens/jmxpassword.aug | 56 + Sharp.Augeas.Test/lens/json.aug | 50 + Sharp.Augeas.Test/lens/kdump.aug | 83 ++ Sharp.Augeas.Test/lens/keepalived.aug | 348 +++++ Sharp.Augeas.Test/lens/known_hosts.aug | 70 + Sharp.Augeas.Test/lens/koji.aug | 40 + Sharp.Augeas.Test/lens/krb5.aug | 182 +++ Sharp.Augeas.Test/lens/ldif.aug | 227 +++ Sharp.Augeas.Test/lens/ldso.aug | 44 + Sharp.Augeas.Test/lens/lightdm.aug | 56 + Sharp.Augeas.Test/lens/limits.aug | 71 + Sharp.Augeas.Test/lens/login_defs.aug | 29 + Sharp.Augeas.Test/lens/logrotate.aug | 126 ++ Sharp.Augeas.Test/lens/logwatch.aug | 46 + Sharp.Augeas.Test/lens/lokkit.aug | 84 ++ Sharp.Augeas.Test/lens/lvm.aug | 75 + Sharp.Augeas.Test/lens/mailscanner.aug | 65 + Sharp.Augeas.Test/lens/mailscanner_rules.aug | 75 + Sharp.Augeas.Test/lens/masterpasswd.aug | 148 ++ Sharp.Augeas.Test/lens/mcollective.aug | 41 + Sharp.Augeas.Test/lens/mdadm_conf.aug | 279 ++++ Sharp.Augeas.Test/lens/memcached.aug | 47 + Sharp.Augeas.Test/lens/mke2fs.aug | 194 +++ Sharp.Augeas.Test/lens/modprobe.aug | 111 ++ Sharp.Augeas.Test/lens/modules.aug | 35 + Sharp.Augeas.Test/lens/modules_conf.aug | 42 + Sharp.Augeas.Test/lens/mongodbserver.aug | 53 + Sharp.Augeas.Test/lens/monit.aug | 70 + Sharp.Augeas.Test/lens/multipath.aug | 136 ++ Sharp.Augeas.Test/lens/mysql.aug | 47 + Sharp.Augeas.Test/lens/nagioscfg.aug | 74 + Sharp.Augeas.Test/lens/nagiosobjects.aug | 62 + Sharp.Augeas.Test/lens/netmasks.aug | 65 + Sharp.Augeas.Test/lens/networkmanager.aug | 67 + Sharp.Augeas.Test/lens/networks.aug | 46 + Sharp.Augeas.Test/lens/nginx.aug | 134 ++ Sharp.Augeas.Test/lens/nrpe.aug | 85 ++ Sharp.Augeas.Test/lens/nslcd.aug | 263 ++++ Sharp.Augeas.Test/lens/nsswitch.aug | 81 ++ Sharp.Augeas.Test/lens/ntp.aug | 139 ++ Sharp.Augeas.Test/lens/ntpd.aug | 157 +++ Sharp.Augeas.Test/lens/odbc.aug | 43 + Sharp.Augeas.Test/lens/opendkim.aug | 60 + Sharp.Augeas.Test/lens/openshift_config.aug | 75 + Sharp.Augeas.Test/lens/openshift_http.aug | 36 + .../lens/openshift_quickstarts.aug | 43 + Sharp.Augeas.Test/lens/openvpn.aug | 655 +++++++++ Sharp.Augeas.Test/lens/oz.aug | 45 + Sharp.Augeas.Test/lens/pagekite.aug | 79 ++ Sharp.Augeas.Test/lens/pam.aug | 76 + Sharp.Augeas.Test/lens/pamconf.aug | 53 + Sharp.Augeas.Test/lens/passwd.aug | 128 ++ Sharp.Augeas.Test/lens/pbuilder.aug | 31 + Sharp.Augeas.Test/lens/pg_hba.aug | 92 ++ Sharp.Augeas.Test/lens/pgbouncer.aug | 55 + Sharp.Augeas.Test/lens/php.aug | 61 + Sharp.Augeas.Test/lens/phpvars.aug | 119 ++ Sharp.Augeas.Test/lens/postfix_access.aug | 29 + Sharp.Augeas.Test/lens/postfix_main.aug | 50 + Sharp.Augeas.Test/lens/postfix_master.aug | 58 + .../lens/postfix_passwordmap.aug | 52 + Sharp.Augeas.Test/lens/postfix_sasl_smtpd.aug | 23 + Sharp.Augeas.Test/lens/postfix_transport.aug | 61 + Sharp.Augeas.Test/lens/postfix_virtual.aug | 57 + Sharp.Augeas.Test/lens/postgresql.aug | 78 + Sharp.Augeas.Test/lens/properties.aug | 50 + Sharp.Augeas.Test/lens/protocols.aug | 47 + Sharp.Augeas.Test/lens/puppet.aug | 45 + Sharp.Augeas.Test/lens/puppet_auth.aug | 71 + Sharp.Augeas.Test/lens/puppetfile.aug | 69 + Sharp.Augeas.Test/lens/puppetfileserver.aug | 112 ++ Sharp.Augeas.Test/lens/pylonspaste.aug | 78 + Sharp.Augeas.Test/lens/pythonpaste.aug | 56 + Sharp.Augeas.Test/lens/qpid.aug | 32 + Sharp.Augeas.Test/lens/quote.aug | 264 ++++ Sharp.Augeas.Test/lens/rabbitmq.aug | 125 ++ Sharp.Augeas.Test/lens/radicale.aug | 44 + Sharp.Augeas.Test/lens/rancid.aug | 34 + Sharp.Augeas.Test/lens/redis.aug | 172 +++ Sharp.Augeas.Test/lens/reprepro_uploaders.aug | 200 +++ Sharp.Augeas.Test/lens/resolv.aug | 137 ++ Sharp.Augeas.Test/lens/rhsm.aug | 42 + Sharp.Augeas.Test/lens/rmt.aug | 30 + Sharp.Augeas.Test/lens/rsyncd.aug | 54 + Sharp.Augeas.Test/lens/rsyslog.aug | 98 ++ Sharp.Augeas.Test/lens/rtadvd.aug | 34 + Sharp.Augeas.Test/lens/rx.aug | 167 +++ Sharp.Augeas.Test/lens/samba.aug | 56 + Sharp.Augeas.Test/lens/schroot.aug | 69 + Sharp.Augeas.Test/lens/securetty.aug | 18 + Sharp.Augeas.Test/lens/semanage.aug | 37 + Sharp.Augeas.Test/lens/sep.aug | 57 + Sharp.Augeas.Test/lens/services.aug | 93 ++ Sharp.Augeas.Test/lens/shadow.aug | 81 ++ Sharp.Augeas.Test/lens/shells.aug | 37 + Sharp.Augeas.Test/lens/shellvars.aug | 338 +++++ Sharp.Augeas.Test/lens/shellvars_list.aug | 59 + Sharp.Augeas.Test/lens/simplelines.aug | 48 + Sharp.Augeas.Test/lens/simplevars.aug | 51 + Sharp.Augeas.Test/lens/sip_conf.aug | 57 + Sharp.Augeas.Test/lens/slapd.aug | 162 +++ Sharp.Augeas.Test/lens/smbusers.aug | 34 + Sharp.Augeas.Test/lens/solaris_system.aug | 109 ++ Sharp.Augeas.Test/lens/soma.aug | 43 + Sharp.Augeas.Test/lens/spacevars.aug | 44 + Sharp.Augeas.Test/lens/splunk.aug | 45 + Sharp.Augeas.Test/lens/squid.aug | 438 ++++++ Sharp.Augeas.Test/lens/ssh.aug | 134 ++ Sharp.Augeas.Test/lens/sshd.aug | 151 ++ Sharp.Augeas.Test/lens/sssd.aug | 39 + Sharp.Augeas.Test/lens/star.aug | 31 + Sharp.Augeas.Test/lens/strongswan.aug | 51 + Sharp.Augeas.Test/lens/stunnel.aug | 80 ++ Sharp.Augeas.Test/lens/subversion.aug | 96 ++ Sharp.Augeas.Test/lens/sudoers.aug | 549 ++++++++ Sharp.Augeas.Test/lens/sysconfig.aug | 74 + Sharp.Augeas.Test/lens/sysconfig_route.aug | 78 + Sharp.Augeas.Test/lens/sysctl.aug | 40 + Sharp.Augeas.Test/lens/syslog.aug | 269 ++++ Sharp.Augeas.Test/lens/systemd.aug | 184 +++ Sharp.Augeas.Test/lens/termcap.aug | 34 + Sharp.Augeas.Test/lens/tests/test_access.aug | 120 ++ .../lens/tests/test_activemq_conf.aug | 35 + .../lens/tests/test_activemq_xml.aug | 65 + .../lens/tests/test_afs_cellalias.aug | 42 + Sharp.Augeas.Test/lens/tests/test_aliases.aug | 111 ++ .../lens/tests/test_anaconda.aug | 89 ++ Sharp.Augeas.Test/lens/tests/test_anacron.aug | 39 + Sharp.Augeas.Test/lens/tests/test_approx.aug | 48 + .../lens/tests/test_apt_update_manager.aug | 41 + .../lens/tests/test_aptcacherngsecurity.aug | 34 + Sharp.Augeas.Test/lens/tests/test_aptconf.aug | 181 +++ .../lens/tests/test_aptpreferences.aug | 66 + .../lens/tests/test_aptsources.aug | 102 ++ .../lens/tests/test_authinfo2.aug | 44 + .../lens/tests/test_authorized_keys.aug | 128 ++ .../lens/tests/test_authselectpam.aug | 37 + .../lens/tests/test_automaster.aug | 64 + .../lens/tests/test_automounter.aug | 171 +++ Sharp.Augeas.Test/lens/tests/test_avahi.aug | 34 + .../lens/tests/test_backuppchosts.aug | 26 + Sharp.Augeas.Test/lens/tests/test_bbhosts.aug | 131 ++ .../lens/tests/test_bootconf.aug | 47 + Sharp.Augeas.Test/lens/tests/test_build.aug | 319 +++++ .../lens/tests/test_cachefilesd.aug | 30 + Sharp.Augeas.Test/lens/tests/test_carbon.aug | 84 ++ Sharp.Augeas.Test/lens/tests/test_ceph.aug | 180 +++ .../lens/tests/test_cgconfig.aug | 365 +++++ Sharp.Augeas.Test/lens/tests/test_cgrules.aug | 32 + .../lens/tests/test_channels.aug | 138 ++ Sharp.Augeas.Test/lens/tests/test_chrony.aug | 319 +++++ Sharp.Augeas.Test/lens/tests/test_clamav.aug | 299 ++++ Sharp.Augeas.Test/lens/tests/test_cmdline.aug | 22 + .../lens/tests/test_cobblermodules.aug | 30 + .../lens/tests/test_cobblersettings.aug | 46 + .../lens/tests/test_collectd.aug | 65 + Sharp.Augeas.Test/lens/tests/test_cpanel.aug | 48 + Sharp.Augeas.Test/lens/tests/test_cron.aug | 51 + .../lens/tests/test_cron_user.aug | 34 + .../lens/tests/test_crypttab.aug | 62 + Sharp.Augeas.Test/lens/tests/test_csv.aug | 91 ++ Sharp.Augeas.Test/lens/tests/test_cups.aug | 481 +++++++ .../lens/tests/test_cyrus_imapd.aug | 37 + Sharp.Augeas.Test/lens/tests/test_darkice.aug | 24 + Sharp.Augeas.Test/lens/tests/test_debctrl.aug | 434 ++++++ Sharp.Augeas.Test/lens/tests/test_desktop.aug | 47 + .../lens/tests/test_devfsrules.aug | 59 + .../lens/tests/test_device_map.aug | 34 + .../lens/tests/test_dhclient.aug | 150 ++ Sharp.Augeas.Test/lens/tests/test_dhcpd.aug | 606 ++++++++ .../lens/tests/test_dns_zone.aug | 384 +++++ Sharp.Augeas.Test/lens/tests/test_dnsmasq.aug | 64 + Sharp.Augeas.Test/lens/tests/test_dovecot.aug | 894 ++++++++++++ Sharp.Augeas.Test/lens/tests/test_dpkg.aug | 14 + Sharp.Augeas.Test/lens/tests/test_dput.aug | 115 ++ Sharp.Augeas.Test/lens/tests/test_erlang.aug | 117 ++ Sharp.Augeas.Test/lens/tests/test_ethers.aug | 61 + Sharp.Augeas.Test/lens/tests/test_exports.aug | 59 + .../lens/tests/test_fai_diskconfig.aug | 663 +++++++++ .../lens/tests/test_fail2ban.aug | 24 + Sharp.Augeas.Test/lens/tests/test_fonts.aug | 809 +++++++++++ Sharp.Augeas.Test/lens/tests/test_fstab.aug | 161 +++ Sharp.Augeas.Test/lens/tests/test_fuse.aug | 22 + Sharp.Augeas.Test/lens/tests/test_gdm.aug | 21 + Sharp.Augeas.Test/lens/tests/test_getcap.aug | 122 ++ Sharp.Augeas.Test/lens/tests/test_group.aug | 54 + Sharp.Augeas.Test/lens/tests/test_grub.aug | 301 ++++ Sharp.Augeas.Test/lens/tests/test_grubenv.aug | 36 + Sharp.Augeas.Test/lens/tests/test_gshadow.aug | 18 + .../lens/tests/test_gtkbookmarks.aug | 25 + .../lens/tests/test_host_conf.aug | 36 + .../lens/tests/test_hostname.aug | 4 + Sharp.Augeas.Test/lens/tests/test_hosts.aug | 64 + .../lens/tests/test_hosts_access.aug | 253 ++++ .../lens/tests/test_htpasswd.aug | 19 + Sharp.Augeas.Test/lens/tests/test_httpd.aug | 648 +++++++++ Sharp.Augeas.Test/lens/tests/test_inetd.aug | 181 +++ Sharp.Augeas.Test/lens/tests/test_inifile.aug | 396 ++++++ Sharp.Augeas.Test/lens/tests/test_inittab.aug | 69 + Sharp.Augeas.Test/lens/tests/test_inputrc.aug | 178 +++ .../lens/tests/test_interfaces.aug | 141 ++ .../lens/tests/test_iproute2.aug | 63 + .../lens/tests/test_iptables.aug | 240 ++++ Sharp.Augeas.Test/lens/tests/test_iscsid.aug | 69 + Sharp.Augeas.Test/lens/tests/test_jaas.aug | 144 ++ .../lens/tests/test_jettyrealm.aug | 51 + .../lens/tests/test_jmxaccess.aug | 35 + .../lens/tests/test_jmxpassword.aug | 35 + Sharp.Augeas.Test/lens/tests/test_json.aug | 512 +++++++ Sharp.Augeas.Test/lens/tests/test_kdump.aug | 102 ++ .../lens/tests/test_keepalived.aug | 493 +++++++ .../lens/tests/test_known_hosts.aug | 48 + Sharp.Augeas.Test/lens/tests/test_koji.aug | 65 + Sharp.Augeas.Test/lens/tests/test_krb5.aug | 1107 +++++++++++++++ Sharp.Augeas.Test/lens/tests/test_ldap.aug | 20 + Sharp.Augeas.Test/lens/tests/test_ldif.aug | 150 ++ Sharp.Augeas.Test/lens/tests/test_ldso.aug | 26 + Sharp.Augeas.Test/lens/tests/test_lightdm.aug | 125 ++ Sharp.Augeas.Test/lens/tests/test_limits.aug | 44 + .../lens/tests/test_login_defs.aug | 26 + .../lens/tests/test_logrotate.aug | 290 ++++ .../lens/tests/test_logwatch.aug | 15 + Sharp.Augeas.Test/lens/tests/test_lokkit.aug | 88 ++ Sharp.Augeas.Test/lens/tests/test_lvm.aug | 253 ++++ .../lens/tests/test_mailscanner.aug | 745 ++++++++++ .../lens/tests/test_mailscanner_rules.aug | 59 + .../lens/tests/test_masterpasswd.aug | 125 ++ .../lens/tests/test_mcollective.aug | 53 + .../lens/tests/test_mdadm_conf.aug | 94 ++ .../lens/tests/test_memcached.aug | 43 + Sharp.Augeas.Test/lens/tests/test_mke2fs.aug | 126 ++ .../lens/tests/test_modprobe.aug | 147 ++ Sharp.Augeas.Test/lens/tests/test_modules.aug | 13 + .../lens/tests/test_modules_conf.aug | 120 ++ .../lens/tests/test_mongodbserver.aug | 31 + Sharp.Augeas.Test/lens/tests/test_monit.aug | 35 + .../lens/tests/test_multipath.aug | 247 ++++ Sharp.Augeas.Test/lens/tests/test_mysql.aug | 283 ++++ .../lens/tests/test_nagioscfg.aug | 89 ++ .../lens/tests/test_nagiosobjects.aug | 61 + .../lens/tests/test_netmasks.aug | 26 + .../lens/tests/test_networkmanager.aug | 98 ++ .../lens/tests/test_networks.aug | 50 + Sharp.Augeas.Test/lens/tests/test_nginx.aug | 299 ++++ Sharp.Augeas.Test/lens/tests/test_nrpe.aug | 101 ++ Sharp.Augeas.Test/lens/tests/test_nslcd.aug | 415 ++++++ .../lens/tests/test_nsswitch.aug | 54 + Sharp.Augeas.Test/lens/tests/test_ntp.aug | 185 +++ Sharp.Augeas.Test/lens/tests/test_ntpd.aug | 80 ++ Sharp.Augeas.Test/lens/tests/test_odbc.aug | 69 + .../lens/tests/test_opendkim.aug | 183 +++ .../lens/tests/test_openshift_config.aug | 101 ++ .../lens/tests/test_openshift_http.aug | 71 + .../lens/tests/test_openshift_quickstarts.aug | 363 +++++ Sharp.Augeas.Test/lens/tests/test_openvpn.aug | 1254 +++++++++++++++++ Sharp.Augeas.Test/lens/tests/test_oz.aug | 36 + .../lens/tests/test_pagekite.aug | 111 ++ Sharp.Augeas.Test/lens/tests/test_pam.aug | 73 + Sharp.Augeas.Test/lens/tests/test_pamconf.aug | 35 + Sharp.Augeas.Test/lens/tests/test_passwd.aug | 104 ++ .../lens/tests/test_pbuilder.aug | 20 + Sharp.Augeas.Test/lens/tests/test_pg_hba.aug | 177 +++ .../lens/tests/test_pgbouncer.aug | 55 + Sharp.Augeas.Test/lens/tests/test_php.aug | 61 + Sharp.Augeas.Test/lens/tests/test_phpvars.aug | 72 + .../lens/tests/test_postfix_access.aug | 53 + .../lens/tests/test_postfix_main.aug | 26 + .../lens/tests/test_postfix_master.aug | 141 ++ .../lens/tests/test_postfix_passwordmap.aug | 43 + .../lens/tests/test_postfix_sasl_smtpd.aug | 19 + .../lens/tests/test_postfix_transport.aug | 58 + .../lens/tests/test_postfix_virtual.aug | 50 + .../lens/tests/test_postgresql.aug | 248 ++++ .../lens/tests/test_properties.aug | 175 +++ .../lens/tests/test_protocols.aug | 53 + Sharp.Augeas.Test/lens/tests/test_puppet.aug | 31 + .../lens/tests/test_puppet_auth.aug | 43 + .../lens/tests/test_puppetfile.aug | 158 +++ .../lens/tests/test_puppetfileserver.aug | 42 + .../lens/tests/test_pylonspaste.aug | 75 + .../lens/tests/test_pythonpaste.aug | 58 + Sharp.Augeas.Test/lens/tests/test_qpid.aug | 48 + Sharp.Augeas.Test/lens/tests/test_quote.aug | 369 +++++ .../lens/tests/test_rabbitmq.aug | 112 ++ .../lens/tests/test_radicale.aug | 77 + Sharp.Augeas.Test/lens/tests/test_rancid.aug | 30 + Sharp.Augeas.Test/lens/tests/test_redis.aug | 264 ++++ .../lens/tests/test_reprepro_uploaders.aug | 166 +++ Sharp.Augeas.Test/lens/tests/test_resolv.aug | 59 + Sharp.Augeas.Test/lens/tests/test_rhsm.aug | 151 ++ Sharp.Augeas.Test/lens/tests/test_rmt.aug | 38 + Sharp.Augeas.Test/lens/tests/test_rsyncd.aug | 56 + Sharp.Augeas.Test/lens/tests/test_rsyslog.aug | 261 ++++ Sharp.Augeas.Test/lens/tests/test_rtadvd.aug | 30 + Sharp.Augeas.Test/lens/tests/test_rx.aug | 70 + Sharp.Augeas.Test/lens/tests/test_samba.aug | 103 ++ Sharp.Augeas.Test/lens/tests/test_schroot.aug | 97 ++ .../lens/tests/test_securetty.aug | 31 + .../lens/tests/test_semanage.aug | 81 ++ .../lens/tests/test_services.aug | 88 ++ Sharp.Augeas.Test/lens/tests/test_shadow.aug | 81 ++ Sharp.Augeas.Test/lens/tests/test_shells.aug | 18 + .../lens/tests/test_shellvars.aug | 783 ++++++++++ .../lens/tests/test_shellvars_list.aug | 144 ++ .../lens/tests/test_simplelines.aug | 42 + .../lens/tests/test_simplevars.aug | 36 + .../lens/tests/test_sip_conf.aug | 113 ++ Sharp.Augeas.Test/lens/tests/test_slapd.aug | 94 ++ .../lens/tests/test_smbusers.aug | 31 + .../lens/tests/test_solaris_system.aug | 104 ++ Sharp.Augeas.Test/lens/tests/test_soma.aug | 15 + .../lens/tests/test_spacevars.aug | 21 + Sharp.Augeas.Test/lens/tests/test_splunk.aug | 160 +++ Sharp.Augeas.Test/lens/tests/test_squid.aug | 216 +++ Sharp.Augeas.Test/lens/tests/test_ssh.aug | 132 ++ Sharp.Augeas.Test/lens/tests/test_sshd.aug | 175 +++ Sharp.Augeas.Test/lens/tests/test_sssd.aug | 45 + Sharp.Augeas.Test/lens/tests/test_star.aug | 63 + .../lens/tests/test_strongswan.aug | 126 ++ Sharp.Augeas.Test/lens/tests/test_stunnel.aug | 38 + .../lens/tests/test_subversion.aug | 118 ++ Sharp.Augeas.Test/lens/tests/test_sudoers.aug | 383 +++++ .../lens/tests/test_sysconfig.aug | 162 +++ .../lens/tests/test_sysconfig_route.aug | 15 + Sharp.Augeas.Test/lens/tests/test_sysctl.aug | 51 + Sharp.Augeas.Test/lens/tests/test_syslog.aug | 356 +++++ Sharp.Augeas.Test/lens/tests/test_systemd.aug | 355 +++++ Sharp.Augeas.Test/lens/tests/test_termcap.aug | 443 ++++++ Sharp.Augeas.Test/lens/tests/test_thttpd.aug | 45 + Sharp.Augeas.Test/lens/tests/test_tinc.aug | 40 + .../lens/tests/test_tmpfiles.aug | 425 ++++++ Sharp.Augeas.Test/lens/tests/test_toml.aug | 333 +++++ .../lens/tests/test_trapperkeeper.aug | 141 ++ Sharp.Augeas.Test/lens/tests/test_tuned.aug | 13 + Sharp.Augeas.Test/lens/tests/test_up2date.aug | 209 +++ .../lens/tests/test_updatedb.aug | 32 + Sharp.Augeas.Test/lens/tests/test_util.aug | 24 + Sharp.Augeas.Test/lens/tests/test_vfstab.aug | 88 ++ .../lens/tests/test_vmware_config.aug | 49 + Sharp.Augeas.Test/lens/tests/test_vsftpd.aug | 74 + Sharp.Augeas.Test/lens/tests/test_webmin.aug | 11 + Sharp.Augeas.Test/lens/tests/test_wine.aug | 163 +++ .../lens/tests/test_xendconfsxp.aug | 334 +++++ Sharp.Augeas.Test/lens/tests/test_xinetd.aug | 90 ++ Sharp.Augeas.Test/lens/tests/test_xml.aug | 905 ++++++++++++ Sharp.Augeas.Test/lens/tests/test_xorg.aug | 94 ++ Sharp.Augeas.Test/lens/tests/test_xymon.aug | 179 +++ .../lens/tests/test_xymon_alerting.aug | 289 ++++ Sharp.Augeas.Test/lens/tests/test_yaml.aug | 94 ++ Sharp.Augeas.Test/lens/tests/test_yum.aug | 227 +++ Sharp.Augeas.Test/lens/thttpd.aug | 48 + Sharp.Augeas.Test/lens/tinc.aug | 37 + Sharp.Augeas.Test/lens/tmpfiles.aug | 107 ++ Sharp.Augeas.Test/lens/toml.aug | 145 ++ Sharp.Augeas.Test/lens/trapperkeeper.aug | 123 ++ Sharp.Augeas.Test/lens/tuned.aug | 21 + Sharp.Augeas.Test/lens/up2date.aug | 84 ++ Sharp.Augeas.Test/lens/updatedb.aug | 49 + Sharp.Augeas.Test/lens/util.aug | 198 +++ Sharp.Augeas.Test/lens/vfstab.aug | 67 + Sharp.Augeas.Test/lens/vmware_config.aug | 34 + Sharp.Augeas.Test/lens/vsftpd.aug | 31 + Sharp.Augeas.Test/lens/webmin.aug | 46 + Sharp.Augeas.Test/lens/wine.aug | 46 + Sharp.Augeas.Test/lens/xendconfsxp.aug | 37 + Sharp.Augeas.Test/lens/xinetd.aug | 108 ++ Sharp.Augeas.Test/lens/xml.aug | 168 +++ Sharp.Augeas.Test/lens/xorg.aug | 319 +++++ Sharp.Augeas.Test/lens/xymon.aug | 56 + Sharp.Augeas.Test/lens/xymon_alerting.aug | 199 +++ Sharp.Augeas.Test/lens/yaml.aug | 78 + Sharp.Augeas.Test/lens/yum.aug | 65 + .../root/boot/grub/grub.conf | 0 .../root/boot/grub/menu.lst | 0 .../root/etc/aliases | 0 .../root/etc/apache2/apache2.conf | 0 .../etc/apache2/conf-available/charset.conf | 0 .../conf-available/localized-error-pages.conf | 0 .../other-vhosts-access-log.conf | 0 .../etc/apache2/conf-available/security.conf | 0 .../apache2/conf-available/serve-cgi-bin.conf | 0 .../etc/apache2/conf-enabled/charset.conf | 0 .../conf-enabled/localized-error-pages.conf | 0 .../conf-enabled/other-vhosts-access-log.conf | 0 .../etc/apache2/conf-enabled/security.conf | 0 .../apache2/conf-enabled/serve-cgi-bin.conf | 0 .../root/etc/apache2/envvars | 0 .../root/etc/apache2/magic | 0 .../apache2/mods-available/access_compat.load | 0 .../etc/apache2/mods-available/actions.conf | 0 .../etc/apache2/mods-available/actions.load | 0 .../etc/apache2/mods-available/alias.conf | 0 .../etc/apache2/mods-available/alias.load | 0 .../apache2/mods-available/allowmethods.load | 0 .../root/etc/apache2/mods-available/asis.load | 0 .../apache2/mods-available/auth_basic.load | 0 .../apache2/mods-available/auth_digest.load | 0 .../etc/apache2/mods-available/auth_form.load | 0 .../apache2/mods-available/authn_anon.load | 0 .../apache2/mods-available/authn_core.load | 0 .../etc/apache2/mods-available/authn_dbd.load | 0 .../etc/apache2/mods-available/authn_dbm.load | 0 .../apache2/mods-available/authn_file.load | 0 .../apache2/mods-available/authn_socache.load | 0 .../apache2/mods-available/authnz_fcgi.load | 0 .../apache2/mods-available/authnz_ldap.load | 0 .../apache2/mods-available/authz_core.load | 0 .../etc/apache2/mods-available/authz_dbd.load | 0 .../etc/apache2/mods-available/authz_dbm.load | 0 .../mods-available/authz_groupfile.load | 0 .../apache2/mods-available/authz_host.load | 0 .../apache2/mods-available/authz_owner.load | 0 .../apache2/mods-available/authz_user.load | 0 .../etc/apache2/mods-available/autoindex.conf | 0 .../etc/apache2/mods-available/autoindex.load | 0 .../etc/apache2/mods-available/brotli.load | 0 .../etc/apache2/mods-available/buffer.load | 0 .../etc/apache2/mods-available/cache.load | 0 .../apache2/mods-available/cache_disk.conf | 0 .../apache2/mods-available/cache_disk.load | 0 .../apache2/mods-available/cache_socache.load | 0 .../etc/apache2/mods-available/cern_meta.load | 0 .../root/etc/apache2/mods-available/cgi.load | 0 .../root/etc/apache2/mods-available/cgid.conf | 0 .../root/etc/apache2/mods-available/cgid.load | 0 .../apache2/mods-available/charset_lite.load | 0 .../root/etc/apache2/mods-available/data.load | 0 .../root/etc/apache2/mods-available/dav.load | 0 .../etc/apache2/mods-available/dav_fs.conf | 0 .../etc/apache2/mods-available/dav_fs.load | 0 .../etc/apache2/mods-available/dav_lock.load | 0 .../root/etc/apache2/mods-available/dbd.load | 0 .../etc/apache2/mods-available/deflate.conf | 0 .../etc/apache2/mods-available/deflate.load | 0 .../etc/apache2/mods-available/dialup.load | 0 .../root/etc/apache2/mods-available/dir.conf | 0 .../root/etc/apache2/mods-available/dir.load | 0 .../etc/apache2/mods-available/dump_io.load | 0 .../root/etc/apache2/mods-available/echo.load | 0 .../root/etc/apache2/mods-available/env.load | 0 .../etc/apache2/mods-available/expires.load | 0 .../apache2/mods-available/ext_filter.load | 0 .../apache2/mods-available/file_cache.load | 0 .../etc/apache2/mods-available/filter.load | 0 .../etc/apache2/mods-available/headers.load | 0 .../etc/apache2/mods-available/heartbeat.load | 0 .../apache2/mods-available/heartmonitor.load | 0 .../etc/apache2/mods-available/http2.conf | 0 .../etc/apache2/mods-available/http2.load | 0 .../etc/apache2/mods-available/ident.load | 0 .../etc/apache2/mods-available/imagemap.load | 0 .../etc/apache2/mods-available/include.load | 0 .../root/etc/apache2/mods-available/info.conf | 0 .../root/etc/apache2/mods-available/info.load | 0 .../mods-available/lbmethod_bybusyness.load | 0 .../mods-available/lbmethod_byrequests.load | 0 .../mods-available/lbmethod_bytraffic.load | 0 .../mods-available/lbmethod_heartbeat.load | 0 .../root/etc/apache2/mods-available/ldap.conf | 0 .../root/etc/apache2/mods-available/ldap.load | 0 .../etc/apache2/mods-available/log_debug.load | 0 .../apache2/mods-available/log_forensic.load | 0 .../root/etc/apache2/mods-available/lua.load | 0 .../etc/apache2/mods-available/macro.load | 0 .../root/etc/apache2/mods-available/md.load | 0 .../root/etc/apache2/mods-available/mime.conf | 0 .../root/etc/apache2/mods-available/mime.load | 0 .../apache2/mods-available/mime_magic.conf | 0 .../apache2/mods-available/mime_magic.load | 0 .../etc/apache2/mods-available/mpm_event.conf | 0 .../etc/apache2/mods-available/mpm_event.load | 0 .../apache2/mods-available/mpm_prefork.conf | 0 .../apache2/mods-available/mpm_prefork.load | 0 .../apache2/mods-available/mpm_worker.conf | 0 .../apache2/mods-available/mpm_worker.load | 0 .../apache2/mods-available/negotiation.conf | 0 .../apache2/mods-available/negotiation.load | 0 .../etc/apache2/mods-available/proxy.conf | 0 .../etc/apache2/mods-available/proxy.load | 0 .../etc/apache2/mods-available/proxy_ajp.load | 0 .../mods-available/proxy_balancer.conf | 0 .../mods-available/proxy_balancer.load | 0 .../apache2/mods-available/proxy_connect.load | 0 .../apache2/mods-available/proxy_express.load | 0 .../apache2/mods-available/proxy_fcgi.load | 0 .../apache2/mods-available/proxy_fdpass.load | 0 .../etc/apache2/mods-available/proxy_ftp.conf | 0 .../etc/apache2/mods-available/proxy_ftp.load | 0 .../apache2/mods-available/proxy_hcheck.load | 0 .../apache2/mods-available/proxy_html.conf | 0 .../apache2/mods-available/proxy_html.load | 0 .../apache2/mods-available/proxy_http.load | 0 .../apache2/mods-available/proxy_http2.load | 0 .../apache2/mods-available/proxy_scgi.load | 0 .../apache2/mods-available/proxy_uwsgi.load | 0 .../mods-available/proxy_wstunnel.load | 0 .../etc/apache2/mods-available/ratelimit.load | 0 .../etc/apache2/mods-available/reflector.load | 0 .../etc/apache2/mods-available/remoteip.load | 0 .../apache2/mods-available/reqtimeout.conf | 0 .../apache2/mods-available/reqtimeout.load | 0 .../etc/apache2/mods-available/request.load | 0 .../etc/apache2/mods-available/rewrite.load | 0 .../root/etc/apache2/mods-available/sed.load | 0 .../etc/apache2/mods-available/session.load | 0 .../mods-available/session_cookie.load | 0 .../mods-available/session_crypto.load | 0 .../apache2/mods-available/session_dbd.load | 0 .../etc/apache2/mods-available/setenvif.conf | 0 .../etc/apache2/mods-available/setenvif.load | 0 .../apache2/mods-available/slotmem_plain.load | 0 .../apache2/mods-available/slotmem_shm.load | 0 .../apache2/mods-available/socache_dbm.load | 0 .../mods-available/socache_memcache.load | 0 .../apache2/mods-available/socache_redis.load | 0 .../apache2/mods-available/socache_shmcb.load | 0 .../etc/apache2/mods-available/speling.load | 0 .../root/etc/apache2/mods-available/ssl.conf | 0 .../root/etc/apache2/mods-available/ssl.load | 0 .../etc/apache2/mods-available/status.conf | 0 .../etc/apache2/mods-available/status.load | 0 .../apache2/mods-available/substitute.load | 0 .../etc/apache2/mods-available/suexec.load | 0 .../etc/apache2/mods-available/unique_id.load | 0 .../etc/apache2/mods-available/userdir.conf | 0 .../etc/apache2/mods-available/userdir.load | 0 .../etc/apache2/mods-available/usertrack.load | 0 .../apache2/mods-available/vhost_alias.load | 0 .../etc/apache2/mods-available/xml2enc.load | 0 .../apache2/mods-enabled/access_compat.load | 0 .../root/etc/apache2/mods-enabled/alias.conf | 0 .../root/etc/apache2/mods-enabled/alias.load | 0 .../etc/apache2/mods-enabled/auth_basic.load | 0 .../etc/apache2/mods-enabled/authn_core.load | 0 .../etc/apache2/mods-enabled/authn_file.load | 0 .../etc/apache2/mods-enabled/authz_core.load | 0 .../etc/apache2/mods-enabled/authz_host.load | 0 .../etc/apache2/mods-enabled/authz_user.load | 0 .../etc/apache2/mods-enabled/autoindex.conf | 0 .../etc/apache2/mods-enabled/autoindex.load | 0 .../etc/apache2/mods-enabled/deflate.conf | 0 .../etc/apache2/mods-enabled/deflate.load | 0 .../root/etc/apache2/mods-enabled/dir.conf | 0 .../root/etc/apache2/mods-enabled/dir.load | 0 .../root/etc/apache2/mods-enabled/env.load | 0 .../root/etc/apache2/mods-enabled/filter.load | 0 .../etc/apache2/mods-enabled/headers.load | 0 .../mods-enabled/lbmethod_byrequests.load | 0 .../root/etc/apache2/mods-enabled/mime.conf | 0 .../root/etc/apache2/mods-enabled/mime.load | 0 .../etc/apache2/mods-enabled/mpm_event.conf | 0 .../etc/apache2/mods-enabled/mpm_event.load | 0 .../etc/apache2/mods-enabled/negotiation.conf | 0 .../etc/apache2/mods-enabled/negotiation.load | 0 .../root/etc/apache2/mods-enabled/proxy.conf | 0 .../root/etc/apache2/mods-enabled/proxy.load | 0 .../apache2/mods-enabled/proxy_balancer.conf | 0 .../apache2/mods-enabled/proxy_balancer.load | 0 .../apache2/mods-enabled/proxy_connect.load | 0 .../etc/apache2/mods-enabled/proxy_ftp.conf | 0 .../etc/apache2/mods-enabled/proxy_ftp.load | 0 .../etc/apache2/mods-enabled/proxy_html.conf | 0 .../etc/apache2/mods-enabled/proxy_html.load | 0 .../etc/apache2/mods-enabled/proxy_http.load | 0 .../etc/apache2/mods-enabled/reqtimeout.conf | 0 .../etc/apache2/mods-enabled/reqtimeout.load | 0 .../etc/apache2/mods-enabled/rewrite.load | 0 .../etc/apache2/mods-enabled/setenvif.conf | 0 .../etc/apache2/mods-enabled/setenvif.load | 0 .../etc/apache2/mods-enabled/slotmem_shm.load | 0 .../apache2/mods-enabled/socache_shmcb.load | 0 .../root/etc/apache2/mods-enabled/ssl.conf | 0 .../root/etc/apache2/mods-enabled/ssl.load | 0 .../root/etc/apache2/mods-enabled/status.conf | 0 .../root/etc/apache2/mods-enabled/status.load | 0 .../etc/apache2/mods-enabled/xml2enc.load | 0 .../root/etc/apache2/ports.conf | 0 .../00-ci.codeliturgy.com-le-ssl.conf | 0 .../00-ci.codeliturgy.com.conf | 0 .../apache2/sites-available/000-default.conf | 0 .../01-git.codeliturgy.com.conf | 0 .../sites-available/02-codeliturgy.com.conf | 0 .../apache2/sites-available/default-ssl.conf | 0 .../sample_dotnet_apache_config.conf | 0 .../00-ci.codeliturgy.com-le-ssl.conf | 0 .../sites-enabled/01-git.codeliturgy.com.conf | 0 .../sites-enabled/02-codeliturgy.com.conf | 0 .../apache2/sites-enabled/default-ssl.conf | 0 .../root/etc/apt/apt.conf.d/01autoremove | 0 .../etc/apt/apt.conf.d/01autoremove-kernels | 0 .../etc/apt/apt.conf.d/50unattended-upgrades | 0 .../root/etc/apt/apt.conf.d/70debconf | 0 .../apt/apt.conf.d/90cloud-init-pipelining | 0 .../root/etc/apt/sources.list | 0 .../root/etc/ceph/ceph.conf | 0 .../root/etc/crontab | 0 .../root/etc/default/im-config | 0 .../root/etc/dput.cf | 0 .../root/etc/exports | 0 .../root/etc/fstab | 0 .../root/etc/group | 0 .../root/etc/grub.conf | 0 .../root/etc/gshadow | 0 .../root/etc/hosts | 0 .../root/etc/httpd/conf.d/ssl.conf | 0 .../etc/httpd/conf.modules.d/00-base.conf | 0 .../root/etc/httpd/conf.modules.d/00-dav.conf | 0 .../root/etc/httpd/conf.modules.d/00-lua.conf | 0 .../root/etc/httpd/conf.modules.d/00-mpm.conf | 0 .../etc/httpd/conf.modules.d/00-optional.conf | 0 .../etc/httpd/conf.modules.d/00-proxy.conf | 0 .../etc/httpd/conf.modules.d/00-systemd.conf | 0 .../root/etc/httpd/conf.modules.d/01-cgi.conf | 0 .../root/etc/httpd/conf.modules.d/10-h2.conf | 0 .../httpd/conf.modules.d/10-mod_dnssd.conf | 0 .../etc/httpd/conf.modules.d/10-proxy_h2.conf | 0 .../root/etc/httpd/conf.modules.d/README | 0 .../root/etc/inittab | 0 .../root/etc/kdump.conf | 0 .../root/etc/krb5.conf | 0 .../root/etc/logrotate.d/acpid | 0 .../root/etc/logrotate.d/rpm | 0 .../root/etc/modules.conf | 0 .../root/etc/multipath.conf | 0 .../root/etc/network/interfaces | 0 .../root/etc/nginx/nginx.conf | 0 .../root/etc/nrpe.cfg | 0 .../root/etc/nslcd.conf | 0 .../root/etc/ntp.conf | 0 .../root/etc/pam.d/login | 0 .../root/etc/pam.d/newrole | 0 .../root/etc/pam.d/postgresql | 0 .../root/etc/passwd | 0 .../root/etc/php.ini | 0 .../root/etc/puppet/puppet.conf | 0 .../root/etc/resolv.conf | 0 .../root/etc/samba/smb.conf | 0 .../root/etc/security/limits.conf | 0 .../root/etc/selinux/semanage.conf | 0 .../root/etc/services | 0 .../root/etc/shadow | 0 .../root/etc/squid/squid.conf | 0 .../root/etc/ssh/ssh_config | 0 .../root/etc/ssh/sshd_config | 0 .../root/etc/sudoers | 0 .../root/etc/sysconfig/anaconda | 0 .../root/etc/sysconfig/atd | 0 .../root/etc/sysconfig/authconfig | 0 .../root/etc/sysconfig/autofs | 0 .../root/etc/sysconfig/clock | 0 .../root/etc/sysconfig/cpuspeed | 0 .../root/etc/sysconfig/crond | 0 .../root/etc/sysconfig/crontab | 0 .../root/etc/sysconfig/firstboot | 0 .../root/etc/sysconfig/grub | 0 .../root/etc/sysconfig/hsqldb | 0 .../root/etc/sysconfig/httpd | 0 .../root/etc/sysconfig/hw-uuid | 0 .../root/etc/sysconfig/hwconf | 0 .../root/etc/sysconfig/i18n | 0 .../root/etc/sysconfig/init | 0 .../root/etc/sysconfig/iptables | 0 .../root/etc/sysconfig/iptables-config | 0 .../root/etc/sysconfig/irda | 0 .../root/etc/sysconfig/irqbalance | 0 .../root/etc/sysconfig/kdump | 0 .../root/etc/sysconfig/kernel | 0 .../root/etc/sysconfig/keyboard | 0 .../root/etc/sysconfig/kudzu | 0 .../root/etc/sysconfig/libvirtd | 0 .../root/etc/sysconfig/lircd | 0 .../root/etc/sysconfig/lm_sensors | 0 .../root/etc/sysconfig/nasd | 0 .../root/etc/sysconfig/netconsole | 0 .../root/etc/sysconfig/netdump_id_dsa.pub | 0 .../root/etc/sysconfig/network | 0 .../etc/sysconfig/network-scripts/ifcfg-br0 | 0 .../etc/sysconfig/network-scripts/ifcfg-eth0 | 0 .../etc/sysconfig/network-scripts/ifcfg-lo | 0 .../network-scripts/ifcfg-lo.rpmsave | 0 .../ifcfg-weird [!] (used to fail) | 0 .../etc/sysconfig/network-scripts/ifcfg-wlan0 | 0 .../root/etc/sysconfig/nfs | 0 .../root/etc/sysconfig/ntpd | 0 .../root/etc/sysconfig/prelink | 0 .../root/etc/sysconfig/puppet | 0 .../root/etc/sysconfig/readonly-root | 0 .../root/etc/sysconfig/rsyslog | 0 .../root/etc/sysconfig/samba | 0 .../root/etc/sysconfig/saslauthd | 0 .../root/etc/sysconfig/smartmontools | 0 .../root/etc/sysconfig/spamassassin | 0 .../root/etc/sysconfig/sysstat | 0 .../root/etc/sysconfig/sysstat.ioconf | 0 .../root/etc/sysconfig/system-config-firewall | 0 .../etc/sysconfig/system-config-securitylevel | 0 .../root/etc/sysconfig/system-config-users | 0 .../root/etc/sysconfig/vncservers | 0 .../root/etc/sysconfig/wpa_supplicant | 0 .../root/etc/sysconfig/xend | 0 .../root/etc/sysconfig/xendomains | 0 .../root/etc/sysctl.conf | 0 .../root/etc/syslog.conf | 0 .../root/etc/vsftpd.conf | 0 .../root/etc/xinetd.conf | 0 .../root/etc/xinetd.d/cvs | 0 .../root/etc/xinetd.d/rsync | 0 .../root/etc/yum.conf | 0 .../root/etc/yum.repos.d/fedora-updates.repo | 0 .../root/etc/yum.repos.d/fedora.repo | 0 .../root/etc/yum.repos.d/remi.repo | 0 .../root/pairs.txt | 0 .../root/var/spool/cron/root | 0 Sharp.Augeas.sln | 6 + Sharp.Augeas/.dockerignore | 25 - Sharp.Augeas/Augeas.cs | 63 +- Sharp.Augeas/AugeasExtern.cs | 4 +- Sharp.Augeas/Platform/Linux/libclAugeas.so | Bin 0 -> 209256 bytes Sharp.Augeas/Program.cs | 43 - Sharp.Augeas/Sharp.Augeas.csproj | 1 - .../VirtualHost/ApacheConfigExtensions.cs | 6 + 813 files changed, 55999 insertions(+), 82 deletions(-) create mode 100644 Sharp.Augeas.Test/AugeasTests.cs create mode 100644 Sharp.Augeas.Test/Platform/Linux/libclAugeas.so create mode 100644 Sharp.Augeas.Test/Sharp.Augeas.Test.csproj create mode 100644 Sharp.Augeas.Test/Usings.cs rename {Sharp.Augeas => Sharp.Augeas.Test}/copyLibrary.sh (100%) create mode 100644 Sharp.Augeas.Test/lens/access.aug create mode 100644 Sharp.Augeas.Test/lens/activemq_conf.aug create mode 100644 Sharp.Augeas.Test/lens/activemq_xml.aug create mode 100644 Sharp.Augeas.Test/lens/afs_cellalias.aug create mode 100644 Sharp.Augeas.Test/lens/aliases.aug create mode 100644 Sharp.Augeas.Test/lens/anaconda.aug create mode 100644 Sharp.Augeas.Test/lens/anacron.aug create mode 100644 Sharp.Augeas.Test/lens/approx.aug create mode 100644 Sharp.Augeas.Test/lens/apt_update_manager.aug create mode 100644 Sharp.Augeas.Test/lens/aptcacherngsecurity.aug create mode 100644 Sharp.Augeas.Test/lens/aptconf.aug create mode 100644 Sharp.Augeas.Test/lens/aptpreferences.aug create mode 100644 Sharp.Augeas.Test/lens/aptsources.aug create mode 100644 Sharp.Augeas.Test/lens/authinfo2.aug create mode 100644 Sharp.Augeas.Test/lens/authorized_keys.aug create mode 100644 Sharp.Augeas.Test/lens/authselectpam.aug create mode 100644 Sharp.Augeas.Test/lens/automaster.aug create mode 100644 Sharp.Augeas.Test/lens/automounter.aug create mode 100644 Sharp.Augeas.Test/lens/avahi.aug create mode 100644 Sharp.Augeas.Test/lens/backuppchosts.aug create mode 100644 Sharp.Augeas.Test/lens/bbhosts.aug create mode 100644 Sharp.Augeas.Test/lens/bootconf.aug create mode 100644 Sharp.Augeas.Test/lens/build.aug create mode 100644 Sharp.Augeas.Test/lens/cachefilesd.aug create mode 100644 Sharp.Augeas.Test/lens/carbon.aug create mode 100644 Sharp.Augeas.Test/lens/ceph.aug create mode 100644 Sharp.Augeas.Test/lens/cgconfig.aug create mode 100644 Sharp.Augeas.Test/lens/cgrules.aug create mode 100644 Sharp.Augeas.Test/lens/channels.aug create mode 100644 Sharp.Augeas.Test/lens/chrony.aug create mode 100644 Sharp.Augeas.Test/lens/clamav.aug create mode 100644 Sharp.Augeas.Test/lens/cmdline.aug create mode 100644 Sharp.Augeas.Test/lens/cobblermodules.aug create mode 100644 Sharp.Augeas.Test/lens/cobblersettings.aug create mode 100644 Sharp.Augeas.Test/lens/collectd.aug create mode 100644 Sharp.Augeas.Test/lens/cpanel.aug create mode 100644 Sharp.Augeas.Test/lens/cron.aug create mode 100644 Sharp.Augeas.Test/lens/cron_user.aug create mode 100644 Sharp.Augeas.Test/lens/crypttab.aug create mode 100644 Sharp.Augeas.Test/lens/csv.aug create mode 100644 Sharp.Augeas.Test/lens/cups.aug create mode 100644 Sharp.Augeas.Test/lens/cyrus_imapd.aug create mode 100644 Sharp.Augeas.Test/lens/darkice.aug create mode 100644 Sharp.Augeas.Test/lens/debctrl.aug create mode 100644 Sharp.Augeas.Test/lens/desktop.aug create mode 100644 Sharp.Augeas.Test/lens/devfsrules.aug create mode 100644 Sharp.Augeas.Test/lens/device_map.aug create mode 100644 Sharp.Augeas.Test/lens/dhclient.aug create mode 100644 Sharp.Augeas.Test/lens/dhcpd.aug create mode 100644 Sharp.Augeas.Test/lens/dns_zone.aug create mode 100644 Sharp.Augeas.Test/lens/dnsmasq.aug create mode 100644 Sharp.Augeas.Test/lens/dovecot.aug create mode 100644 Sharp.Augeas.Test/lens/dpkg.aug create mode 100644 Sharp.Augeas.Test/lens/dput.aug create mode 100644 Sharp.Augeas.Test/lens/erlang.aug create mode 100644 Sharp.Augeas.Test/lens/ethers.aug create mode 100644 Sharp.Augeas.Test/lens/exports.aug create mode 100644 Sharp.Augeas.Test/lens/fai_diskconfig.aug create mode 100644 Sharp.Augeas.Test/lens/fail2ban.aug create mode 100644 Sharp.Augeas.Test/lens/fonts.aug create mode 100644 Sharp.Augeas.Test/lens/fstab.aug create mode 100644 Sharp.Augeas.Test/lens/fuse.aug create mode 100644 Sharp.Augeas.Test/lens/gdm.aug create mode 100644 Sharp.Augeas.Test/lens/getcap.aug create mode 100644 Sharp.Augeas.Test/lens/group.aug create mode 100644 Sharp.Augeas.Test/lens/grub.aug create mode 100644 Sharp.Augeas.Test/lens/grubenv.aug create mode 100644 Sharp.Augeas.Test/lens/gshadow.aug create mode 100644 Sharp.Augeas.Test/lens/gtkbookmarks.aug create mode 100644 Sharp.Augeas.Test/lens/host_conf.aug create mode 100644 Sharp.Augeas.Test/lens/hostname.aug create mode 100644 Sharp.Augeas.Test/lens/hosts.aug create mode 100644 Sharp.Augeas.Test/lens/hosts_access.aug create mode 100644 Sharp.Augeas.Test/lens/htpasswd.aug create mode 100644 Sharp.Augeas.Test/lens/httpd.aug create mode 100644 Sharp.Augeas.Test/lens/inetd.aug create mode 100644 Sharp.Augeas.Test/lens/inifile.aug create mode 100644 Sharp.Augeas.Test/lens/inittab.aug create mode 100644 Sharp.Augeas.Test/lens/inputrc.aug create mode 100644 Sharp.Augeas.Test/lens/interfaces.aug create mode 100644 Sharp.Augeas.Test/lens/iproute2.aug create mode 100644 Sharp.Augeas.Test/lens/iptables.aug create mode 100644 Sharp.Augeas.Test/lens/iscsid.aug create mode 100644 Sharp.Augeas.Test/lens/jaas.aug create mode 100644 Sharp.Augeas.Test/lens/jettyrealm.aug create mode 100644 Sharp.Augeas.Test/lens/jmxaccess.aug create mode 100644 Sharp.Augeas.Test/lens/jmxpassword.aug create mode 100644 Sharp.Augeas.Test/lens/json.aug create mode 100644 Sharp.Augeas.Test/lens/kdump.aug create mode 100644 Sharp.Augeas.Test/lens/keepalived.aug create mode 100644 Sharp.Augeas.Test/lens/known_hosts.aug create mode 100644 Sharp.Augeas.Test/lens/koji.aug create mode 100644 Sharp.Augeas.Test/lens/krb5.aug create mode 100644 Sharp.Augeas.Test/lens/ldif.aug create mode 100644 Sharp.Augeas.Test/lens/ldso.aug create mode 100644 Sharp.Augeas.Test/lens/lightdm.aug create mode 100644 Sharp.Augeas.Test/lens/limits.aug create mode 100644 Sharp.Augeas.Test/lens/login_defs.aug create mode 100644 Sharp.Augeas.Test/lens/logrotate.aug create mode 100644 Sharp.Augeas.Test/lens/logwatch.aug create mode 100644 Sharp.Augeas.Test/lens/lokkit.aug create mode 100644 Sharp.Augeas.Test/lens/lvm.aug create mode 100644 Sharp.Augeas.Test/lens/mailscanner.aug create mode 100644 Sharp.Augeas.Test/lens/mailscanner_rules.aug create mode 100644 Sharp.Augeas.Test/lens/masterpasswd.aug create mode 100644 Sharp.Augeas.Test/lens/mcollective.aug create mode 100644 Sharp.Augeas.Test/lens/mdadm_conf.aug create mode 100644 Sharp.Augeas.Test/lens/memcached.aug create mode 100644 Sharp.Augeas.Test/lens/mke2fs.aug create mode 100644 Sharp.Augeas.Test/lens/modprobe.aug create mode 100644 Sharp.Augeas.Test/lens/modules.aug create mode 100644 Sharp.Augeas.Test/lens/modules_conf.aug create mode 100644 Sharp.Augeas.Test/lens/mongodbserver.aug create mode 100644 Sharp.Augeas.Test/lens/monit.aug create mode 100644 Sharp.Augeas.Test/lens/multipath.aug create mode 100644 Sharp.Augeas.Test/lens/mysql.aug create mode 100644 Sharp.Augeas.Test/lens/nagioscfg.aug create mode 100644 Sharp.Augeas.Test/lens/nagiosobjects.aug create mode 100644 Sharp.Augeas.Test/lens/netmasks.aug create mode 100644 Sharp.Augeas.Test/lens/networkmanager.aug create mode 100644 Sharp.Augeas.Test/lens/networks.aug create mode 100644 Sharp.Augeas.Test/lens/nginx.aug create mode 100644 Sharp.Augeas.Test/lens/nrpe.aug create mode 100644 Sharp.Augeas.Test/lens/nslcd.aug create mode 100644 Sharp.Augeas.Test/lens/nsswitch.aug create mode 100644 Sharp.Augeas.Test/lens/ntp.aug create mode 100644 Sharp.Augeas.Test/lens/ntpd.aug create mode 100644 Sharp.Augeas.Test/lens/odbc.aug create mode 100644 Sharp.Augeas.Test/lens/opendkim.aug create mode 100644 Sharp.Augeas.Test/lens/openshift_config.aug create mode 100644 Sharp.Augeas.Test/lens/openshift_http.aug create mode 100644 Sharp.Augeas.Test/lens/openshift_quickstarts.aug create mode 100644 Sharp.Augeas.Test/lens/openvpn.aug create mode 100644 Sharp.Augeas.Test/lens/oz.aug create mode 100644 Sharp.Augeas.Test/lens/pagekite.aug create mode 100644 Sharp.Augeas.Test/lens/pam.aug create mode 100644 Sharp.Augeas.Test/lens/pamconf.aug create mode 100644 Sharp.Augeas.Test/lens/passwd.aug create mode 100644 Sharp.Augeas.Test/lens/pbuilder.aug create mode 100644 Sharp.Augeas.Test/lens/pg_hba.aug create mode 100644 Sharp.Augeas.Test/lens/pgbouncer.aug create mode 100644 Sharp.Augeas.Test/lens/php.aug create mode 100644 Sharp.Augeas.Test/lens/phpvars.aug create mode 100644 Sharp.Augeas.Test/lens/postfix_access.aug create mode 100644 Sharp.Augeas.Test/lens/postfix_main.aug create mode 100644 Sharp.Augeas.Test/lens/postfix_master.aug create mode 100644 Sharp.Augeas.Test/lens/postfix_passwordmap.aug create mode 100644 Sharp.Augeas.Test/lens/postfix_sasl_smtpd.aug create mode 100644 Sharp.Augeas.Test/lens/postfix_transport.aug create mode 100644 Sharp.Augeas.Test/lens/postfix_virtual.aug create mode 100644 Sharp.Augeas.Test/lens/postgresql.aug create mode 100644 Sharp.Augeas.Test/lens/properties.aug create mode 100644 Sharp.Augeas.Test/lens/protocols.aug create mode 100644 Sharp.Augeas.Test/lens/puppet.aug create mode 100644 Sharp.Augeas.Test/lens/puppet_auth.aug create mode 100644 Sharp.Augeas.Test/lens/puppetfile.aug create mode 100644 Sharp.Augeas.Test/lens/puppetfileserver.aug create mode 100644 Sharp.Augeas.Test/lens/pylonspaste.aug create mode 100644 Sharp.Augeas.Test/lens/pythonpaste.aug create mode 100644 Sharp.Augeas.Test/lens/qpid.aug create mode 100644 Sharp.Augeas.Test/lens/quote.aug create mode 100644 Sharp.Augeas.Test/lens/rabbitmq.aug create mode 100644 Sharp.Augeas.Test/lens/radicale.aug create mode 100644 Sharp.Augeas.Test/lens/rancid.aug create mode 100644 Sharp.Augeas.Test/lens/redis.aug create mode 100644 Sharp.Augeas.Test/lens/reprepro_uploaders.aug create mode 100644 Sharp.Augeas.Test/lens/resolv.aug create mode 100644 Sharp.Augeas.Test/lens/rhsm.aug create mode 100644 Sharp.Augeas.Test/lens/rmt.aug create mode 100644 Sharp.Augeas.Test/lens/rsyncd.aug create mode 100644 Sharp.Augeas.Test/lens/rsyslog.aug create mode 100644 Sharp.Augeas.Test/lens/rtadvd.aug create mode 100644 Sharp.Augeas.Test/lens/rx.aug create mode 100644 Sharp.Augeas.Test/lens/samba.aug create mode 100644 Sharp.Augeas.Test/lens/schroot.aug create mode 100644 Sharp.Augeas.Test/lens/securetty.aug create mode 100644 Sharp.Augeas.Test/lens/semanage.aug create mode 100644 Sharp.Augeas.Test/lens/sep.aug create mode 100644 Sharp.Augeas.Test/lens/services.aug create mode 100644 Sharp.Augeas.Test/lens/shadow.aug create mode 100644 Sharp.Augeas.Test/lens/shells.aug create mode 100644 Sharp.Augeas.Test/lens/shellvars.aug create mode 100644 Sharp.Augeas.Test/lens/shellvars_list.aug create mode 100644 Sharp.Augeas.Test/lens/simplelines.aug create mode 100644 Sharp.Augeas.Test/lens/simplevars.aug create mode 100644 Sharp.Augeas.Test/lens/sip_conf.aug create mode 100644 Sharp.Augeas.Test/lens/slapd.aug create mode 100644 Sharp.Augeas.Test/lens/smbusers.aug create mode 100644 Sharp.Augeas.Test/lens/solaris_system.aug create mode 100644 Sharp.Augeas.Test/lens/soma.aug create mode 100644 Sharp.Augeas.Test/lens/spacevars.aug create mode 100644 Sharp.Augeas.Test/lens/splunk.aug create mode 100644 Sharp.Augeas.Test/lens/squid.aug create mode 100644 Sharp.Augeas.Test/lens/ssh.aug create mode 100644 Sharp.Augeas.Test/lens/sshd.aug create mode 100644 Sharp.Augeas.Test/lens/sssd.aug create mode 100644 Sharp.Augeas.Test/lens/star.aug create mode 100644 Sharp.Augeas.Test/lens/strongswan.aug create mode 100644 Sharp.Augeas.Test/lens/stunnel.aug create mode 100644 Sharp.Augeas.Test/lens/subversion.aug create mode 100644 Sharp.Augeas.Test/lens/sudoers.aug create mode 100644 Sharp.Augeas.Test/lens/sysconfig.aug create mode 100644 Sharp.Augeas.Test/lens/sysconfig_route.aug create mode 100644 Sharp.Augeas.Test/lens/sysctl.aug create mode 100644 Sharp.Augeas.Test/lens/syslog.aug create mode 100644 Sharp.Augeas.Test/lens/systemd.aug create mode 100644 Sharp.Augeas.Test/lens/termcap.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_access.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_activemq_conf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_activemq_xml.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_afs_cellalias.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_aliases.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_anaconda.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_anacron.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_approx.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_apt_update_manager.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_aptcacherngsecurity.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_aptconf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_aptpreferences.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_aptsources.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_authinfo2.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_authorized_keys.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_authselectpam.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_automaster.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_automounter.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_avahi.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_backuppchosts.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_bbhosts.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_bootconf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_build.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cachefilesd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_carbon.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ceph.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cgconfig.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cgrules.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_channels.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_chrony.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_clamav.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cmdline.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cobblermodules.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cobblersettings.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_collectd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cpanel.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cron.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cron_user.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_crypttab.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_csv.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cups.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_cyrus_imapd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_darkice.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_debctrl.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_desktop.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_devfsrules.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_device_map.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_dhclient.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_dhcpd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_dns_zone.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_dnsmasq.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_dovecot.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_dpkg.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_dput.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_erlang.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ethers.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_exports.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_fai_diskconfig.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_fail2ban.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_fonts.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_fstab.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_fuse.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_gdm.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_getcap.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_group.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_grub.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_grubenv.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_gshadow.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_gtkbookmarks.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_host_conf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_hostname.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_hosts.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_hosts_access.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_htpasswd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_httpd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_inetd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_inifile.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_inittab.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_inputrc.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_interfaces.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_iproute2.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_iptables.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_iscsid.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_jaas.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_jettyrealm.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_jmxaccess.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_jmxpassword.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_json.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_kdump.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_keepalived.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_known_hosts.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_koji.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_krb5.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ldap.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ldif.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ldso.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_lightdm.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_limits.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_login_defs.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_logrotate.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_logwatch.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_lokkit.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_lvm.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_mailscanner.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_mailscanner_rules.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_masterpasswd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_mcollective.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_mdadm_conf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_memcached.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_mke2fs.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_modprobe.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_modules.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_modules_conf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_mongodbserver.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_monit.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_multipath.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_mysql.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_nagioscfg.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_nagiosobjects.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_netmasks.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_networkmanager.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_networks.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_nginx.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_nrpe.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_nslcd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_nsswitch.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ntp.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ntpd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_odbc.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_opendkim.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_openshift_config.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_openshift_http.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_openshift_quickstarts.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_openvpn.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_oz.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pagekite.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pam.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pamconf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_passwd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pbuilder.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pg_hba.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pgbouncer.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_php.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_phpvars.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postfix_access.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postfix_main.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postfix_master.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postfix_passwordmap.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postfix_sasl_smtpd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postfix_transport.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postfix_virtual.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_postgresql.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_properties.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_protocols.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_puppet.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_puppet_auth.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_puppetfile.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_puppetfileserver.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pylonspaste.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_pythonpaste.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_qpid.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_quote.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rabbitmq.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_radicale.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rancid.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_redis.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_reprepro_uploaders.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_resolv.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rhsm.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rmt.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rsyncd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rsyslog.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rtadvd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_rx.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_samba.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_schroot.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_securetty.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_semanage.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_services.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_shadow.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_shells.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_shellvars.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_shellvars_list.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_simplelines.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_simplevars.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_sip_conf.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_slapd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_smbusers.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_solaris_system.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_soma.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_spacevars.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_splunk.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_squid.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_ssh.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_sshd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_sssd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_star.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_strongswan.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_stunnel.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_subversion.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_sudoers.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_sysconfig.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_sysconfig_route.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_sysctl.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_syslog.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_systemd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_termcap.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_thttpd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_tinc.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_tmpfiles.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_toml.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_trapperkeeper.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_tuned.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_up2date.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_updatedb.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_util.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_vfstab.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_vmware_config.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_vsftpd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_webmin.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_wine.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_xendconfsxp.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_xinetd.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_xml.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_xorg.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_xymon.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_xymon_alerting.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_yaml.aug create mode 100644 Sharp.Augeas.Test/lens/tests/test_yum.aug create mode 100644 Sharp.Augeas.Test/lens/thttpd.aug create mode 100644 Sharp.Augeas.Test/lens/tinc.aug create mode 100644 Sharp.Augeas.Test/lens/tmpfiles.aug create mode 100644 Sharp.Augeas.Test/lens/toml.aug create mode 100644 Sharp.Augeas.Test/lens/trapperkeeper.aug create mode 100644 Sharp.Augeas.Test/lens/tuned.aug create mode 100644 Sharp.Augeas.Test/lens/up2date.aug create mode 100644 Sharp.Augeas.Test/lens/updatedb.aug create mode 100644 Sharp.Augeas.Test/lens/util.aug create mode 100644 Sharp.Augeas.Test/lens/vfstab.aug create mode 100644 Sharp.Augeas.Test/lens/vmware_config.aug create mode 100644 Sharp.Augeas.Test/lens/vsftpd.aug create mode 100644 Sharp.Augeas.Test/lens/webmin.aug create mode 100644 Sharp.Augeas.Test/lens/wine.aug create mode 100644 Sharp.Augeas.Test/lens/xendconfsxp.aug create mode 100644 Sharp.Augeas.Test/lens/xinetd.aug create mode 100644 Sharp.Augeas.Test/lens/xml.aug create mode 100644 Sharp.Augeas.Test/lens/xorg.aug create mode 100644 Sharp.Augeas.Test/lens/xymon.aug create mode 100644 Sharp.Augeas.Test/lens/xymon_alerting.aug create mode 100644 Sharp.Augeas.Test/lens/yaml.aug create mode 100644 Sharp.Augeas.Test/lens/yum.aug rename {Sharp.Augeas => Sharp.Augeas.Test}/root/boot/grub/grub.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/boot/grub/menu.lst (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/aliases (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/apache2.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-available/charset.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-available/localized-error-pages.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-available/other-vhosts-access-log.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-available/security.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-available/serve-cgi-bin.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-enabled/charset.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-enabled/localized-error-pages.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-enabled/other-vhosts-access-log.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-enabled/security.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/conf-enabled/serve-cgi-bin.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/envvars (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/magic (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/access_compat.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/actions.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/actions.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/alias.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/alias.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/allowmethods.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/asis.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/auth_basic.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/auth_digest.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/auth_form.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authn_anon.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authn_core.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authn_dbd.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authn_dbm.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authn_file.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authn_socache.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authnz_fcgi.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authnz_ldap.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authz_core.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authz_dbd.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authz_dbm.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authz_groupfile.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authz_host.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authz_owner.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/authz_user.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/autoindex.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/autoindex.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/brotli.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/buffer.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cache.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cache_disk.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cache_disk.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cache_socache.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cern_meta.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cgi.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cgid.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/cgid.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/charset_lite.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/data.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dav.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dav_fs.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dav_fs.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dav_lock.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dbd.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/deflate.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/deflate.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dialup.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dir.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dir.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/dump_io.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/echo.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/env.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/expires.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/ext_filter.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/file_cache.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/filter.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/headers.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/heartbeat.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/heartmonitor.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/http2.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/http2.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/ident.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/imagemap.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/include.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/info.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/info.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/lbmethod_bybusyness.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/lbmethod_byrequests.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/lbmethod_bytraffic.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/lbmethod_heartbeat.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/ldap.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/ldap.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/log_debug.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/log_forensic.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/lua.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/macro.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/md.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mime.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mime.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mime_magic.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mime_magic.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mpm_event.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mpm_event.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mpm_prefork.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mpm_prefork.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mpm_worker.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/mpm_worker.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/negotiation.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/negotiation.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_ajp.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_balancer.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_balancer.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_connect.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_express.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_fcgi.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_fdpass.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_ftp.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_ftp.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_hcheck.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_html.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_html.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_http.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_http2.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_scgi.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_uwsgi.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/proxy_wstunnel.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/ratelimit.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/reflector.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/remoteip.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/reqtimeout.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/reqtimeout.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/request.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/rewrite.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/sed.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/session.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/session_cookie.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/session_crypto.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/session_dbd.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/setenvif.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/setenvif.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/slotmem_plain.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/slotmem_shm.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/socache_dbm.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/socache_memcache.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/socache_redis.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/socache_shmcb.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/speling.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/ssl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/ssl.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/status.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/status.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/substitute.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/suexec.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/unique_id.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/userdir.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/userdir.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/usertrack.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/vhost_alias.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-available/xml2enc.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/access_compat.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/alias.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/alias.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/auth_basic.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/authn_core.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/authn_file.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/authz_core.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/authz_host.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/authz_user.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/autoindex.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/autoindex.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/deflate.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/deflate.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/dir.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/dir.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/env.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/filter.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/headers.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/lbmethod_byrequests.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/mime.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/mime.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/mpm_event.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/mpm_event.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/negotiation.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/negotiation.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_balancer.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_balancer.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_connect.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_ftp.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_ftp.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_html.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_html.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/proxy_http.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/reqtimeout.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/reqtimeout.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/rewrite.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/setenvif.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/setenvif.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/slotmem_shm.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/socache_shmcb.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/ssl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/ssl.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/status.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/status.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/mods-enabled/xml2enc.load (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/ports.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-available/00-ci.codeliturgy.com-le-ssl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-available/00-ci.codeliturgy.com.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-available/000-default.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-available/01-git.codeliturgy.com.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-available/02-codeliturgy.com.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-available/default-ssl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-available/sample_dotnet_apache_config.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-enabled/00-ci.codeliturgy.com-le-ssl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-enabled/01-git.codeliturgy.com.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-enabled/02-codeliturgy.com.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apache2/sites-enabled/default-ssl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apt/apt.conf.d/01autoremove (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apt/apt.conf.d/01autoremove-kernels (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apt/apt.conf.d/50unattended-upgrades (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apt/apt.conf.d/70debconf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apt/apt.conf.d/90cloud-init-pipelining (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/apt/sources.list (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/ceph/ceph.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/crontab (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/default/im-config (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/dput.cf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/exports (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/fstab (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/group (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/grub.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/gshadow (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/hosts (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.d/ssl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/00-base.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/00-dav.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/00-lua.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/00-mpm.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/00-optional.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/00-proxy.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/00-systemd.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/01-cgi.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/10-h2.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/10-mod_dnssd.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/10-proxy_h2.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/httpd/conf.modules.d/README (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/inittab (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/kdump.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/krb5.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/logrotate.d/acpid (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/logrotate.d/rpm (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/modules.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/multipath.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/network/interfaces (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/nginx/nginx.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/nrpe.cfg (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/nslcd.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/ntp.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/pam.d/login (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/pam.d/newrole (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/pam.d/postgresql (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/passwd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/php.ini (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/puppet/puppet.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/resolv.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/samba/smb.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/security/limits.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/selinux/semanage.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/services (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/shadow (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/squid/squid.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/ssh/ssh_config (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/ssh/sshd_config (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sudoers (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/anaconda (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/atd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/authconfig (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/autofs (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/clock (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/cpuspeed (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/crond (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/crontab (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/firstboot (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/grub (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/hsqldb (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/httpd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/hw-uuid (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/hwconf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/i18n (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/init (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/iptables (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/iptables-config (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/irda (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/irqbalance (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/kdump (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/kernel (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/keyboard (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/kudzu (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/libvirtd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/lircd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/lm_sensors (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/nasd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/netconsole (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/netdump_id_dsa.pub (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/network (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/network-scripts/ifcfg-br0 (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/network-scripts/ifcfg-eth0 (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/network-scripts/ifcfg-lo (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/network-scripts/ifcfg-lo.rpmsave (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/network-scripts/ifcfg-weird [!] (used to fail) (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/network-scripts/ifcfg-wlan0 (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/nfs (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/ntpd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/prelink (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/puppet (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/readonly-root (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/rsyslog (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/samba (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/saslauthd (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/smartmontools (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/spamassassin (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/sysstat (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/sysstat.ioconf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/system-config-firewall (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/system-config-securitylevel (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/system-config-users (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/vncservers (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/wpa_supplicant (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/xend (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysconfig/xendomains (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/sysctl.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/syslog.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/vsftpd.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/xinetd.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/xinetd.d/cvs (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/xinetd.d/rsync (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/yum.conf (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/yum.repos.d/fedora-updates.repo (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/yum.repos.d/fedora.repo (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/etc/yum.repos.d/remi.repo (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/pairs.txt (100%) rename {Sharp.Augeas => Sharp.Augeas.Test}/root/var/spool/cron/root (100%) delete mode 100644 Sharp.Augeas/.dockerignore create mode 100644 Sharp.Augeas/Platform/Linux/libclAugeas.so delete mode 100644 Sharp.Augeas/Program.cs create mode 100644 Sharp.Augeas/VirtualHost/ApacheConfigExtensions.cs diff --git a/README.md b/README.md index 2468846..6d03af1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Note: Currently the focus is abstractions with a focus on handling Apache config ## Instructions -### Ccopy Native wrapper library +### Copy Native wrapper library `cd Sharp.Augeas && ./copyLibrary.sh` diff --git a/Sharp.Augeas.Test/AugeasTests.cs b/Sharp.Augeas.Test/AugeasTests.cs new file mode 100644 index 0000000..7e14622 --- /dev/null +++ b/Sharp.Augeas.Test/AugeasTests.cs @@ -0,0 +1,43 @@ +namespace Sharp.Augeas.Test; + +public class AugeasTests +{ + private Augeas _augeas; + + [SetUp] + public void Setup() + { + var rootDir = Environment.CurrentDirectory + "/root"; + var lensDir = Environment.CurrentDirectory + "/lens"; + _augeas = new Augeas(new AugSettings(rootDir, lensDir)); + } + + [Test] + public void NoExceptionThrownWhenPrintingVirtualhostTree() + { + var virtualHostConfig = "/etc/apache2/sites-available/00-ci.codeliturgy.com.conf"; + _augeas.PrintVirtualHostTree(virtualHostConfig); + Assert.Pass(); + } + + + [Test] + public void NoExceptionThrownWhenPrintingPreview() + { + var virtualHostConfig = "/etc/apache2/sites-available/00-ci.codeliturgy.com.conf"; + _augeas.PrintPreview(virtualHostConfig); + Assert.Pass(); + + } + + [Test] + public void GetTreeVirtualHostReturnsDictionaryWithKeys() + { + var virtualHostConfig = "/etc/apache2/sites-available/00-ci.codeliturgy.com.conf"; + var tree = _augeas.GetVirtualHostTree(virtualHostConfig); + Assert.That(tree.Count > 0); + + } + + +} \ No newline at end of file diff --git a/Sharp.Augeas.Test/Platform/Linux/libclAugeas.so b/Sharp.Augeas.Test/Platform/Linux/libclAugeas.so new file mode 100644 index 0000000000000000000000000000000000000000..6903728a71a84b450f82cc63c3e38c903c029f67 GIT binary patch literal 209256 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%0D{Q{3mB){&g`Wfc?9 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 literal 0 HcmV?d00001 diff --git a/Sharp.Augeas.Test/Sharp.Augeas.Test.csproj b/Sharp.Augeas.Test/Sharp.Augeas.Test.csproj new file mode 100644 index 0000000..7e3509a --- /dev/null +++ b/Sharp.Augeas.Test/Sharp.Augeas.Test.csproj @@ -0,0 +1,38 @@ + + + + net6.0 + enable + disable + true + + false + + + + + + + + + + + + + + + + + + PreserveNewest + root\%(RecursiveDir)\%(Filename)%(Extension) + + + + + PreserveNewest + lens\%(RecursiveDir)\%(Filename)%(Extension) + + + + diff --git a/Sharp.Augeas.Test/Usings.cs b/Sharp.Augeas.Test/Usings.cs new file mode 100644 index 0000000..3244567 --- /dev/null +++ b/Sharp.Augeas.Test/Usings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; diff --git a/Sharp.Augeas/copyLibrary.sh b/Sharp.Augeas.Test/copyLibrary.sh similarity index 100% rename from Sharp.Augeas/copyLibrary.sh rename to Sharp.Augeas.Test/copyLibrary.sh diff --git a/Sharp.Augeas.Test/lens/access.aug b/Sharp.Augeas.Test/lens/access.aug new file mode 100644 index 0000000..39920d3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/access.aug @@ -0,0 +1,128 @@ +(* +Module: Access + Parses /etc/security/access.conf + +Author: Lorenzo Dalrio + +About: Reference + Some examples of valid entries can be found in access.conf or "man access.conf" + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Add a rule to permit login of all users from local sources (tty's, X, cron) + > set /files/etc/security/access.conf[0] + + > set /files/etc/security/access.conf[0]/user ALL + > set /files/etc/security/access.conf[0]/origin LOCAL + +About: Configuration files + This lens applies to /etc/security/access.conf. See . + +About: Examples + The file contains various examples and tests. +*) +module Access = + autoload xfm + +(* Group: Comments and empty lines *) +(* Variable: comment *) +let comment = Util.comment +(* Variable: empty *) +let empty = Util.empty + +(* Group: Useful primitives *) +(* Variable: colon + * this is the standard field separator " : " + *) +let colon = del (Rx.opt_space . ":" . Rx.opt_space) " : " + + +(************************************************************************ + * Group: ENTRY LINE + *************************************************************************) +(* View: access + * Allow (+) or deny (-) access + *) +let access = label "access" . store /[+-]/ + +(* Variable: identifier_re + Regex for user/group identifiers *) +let identifier_re = /[A-Za-z0-9_.\\-]+/ + +(* View: user_re + * Regex for user/netgroup fields + *) +let user_re = identifier_re - /[Ee][Xx][Cc][Ee][Pp][Tt]/ + +(* View: user + * user can be a username, username@hostname or a group + *) +let user = [ label "user" + . ( store user_re + | store Rx.word . Util.del_str "@" + . [ label "host" . store Rx.word ] ) ] + +(* View: group + * Format is (GROUP) + *) +let group = [ label "group" + . Util.del_str "(" . store identifier_re . Util.del_str ")" ] + +(* View: netgroup + * Format is @NETGROUP[@@NISDOMAIN] + *) +let netgroup = + [ label "netgroup" . Util.del_str "@" . store user_re + . [ label "nisdomain" . Util.del_str "@@" . store Rx.word ]? ] + +(* View: user_list + * A list of users or netgroups to apply the rule to + *) +let user_list = Build.opt_list (user|group|netgroup) Sep.space + +(* View: origin_list + * origin_list can be a single ipaddr/originname/domain/fqdn or a list of those values + *) +let origin_list = + let origin_re = Rx.no_spaces - /[Ee][Xx][Cc][Ee][Pp][Tt]/ + in Build.opt_list [ label "origin" . store origin_re ] Sep.space + +(* View: except + * The except operator makes it possible to write very compact rules. + *) +let except (lns:lens) = [ label "except" . Sep.space + . del /[Ee][Xx][Cc][Ee][Pp][Tt]/ "EXCEPT" + . Sep.space . lns ] + +(* View: entry + * A valid entry line + * Definition: + * > entry ::= access ':' user ':' origin_list + *) +let entry = [ access . colon + . user_list + . (except user_list)? + . colon + . origin_list + . (except origin_list)? + . Util.eol ] + +(************************************************************************ + * Group: LENS & FILTER + *************************************************************************) +(* View: lns + The access.conf lens, any amount of + * lines + * + * +*) +let lns = (comment|empty|entry) * + +(* Variable: filter *) +let filter = incl "/etc/security/access.conf" + +(* xfm *) +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/activemq_conf.aug b/Sharp.Augeas.Test/lens/activemq_conf.aug new file mode 100644 index 0000000..191d811 --- /dev/null +++ b/Sharp.Augeas.Test/lens/activemq_conf.aug @@ -0,0 +1,61 @@ +(* +Module: ActiveMQ_Conf + ActiveMQ / FuseMQ conf module for Augeas + +Author: Brian Redbeard + +About: Reference + This lens ensures that conf files included in ActiveMQ /FuseMQ are properly + handled by Augeas. + +About: License + This file is licensed under the LGPL License. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get your current setup + > print /files/etc/activemq.conf + ... + + * Change ActiveMQ Home + > set /files/etc/activemq.conf/ACTIVEMQ_HOME /usr/share/activemq + + Saving your file: + + > save + +About: Configuration files + This lens applies to relevant conf files located in /etc/activemq/ and + the file /etc/activemq.conf . See . + +*) + +module ActiveMQ_Conf = + autoload xfm + +(* Variable: blank_val *) +let blank_val = del /^\z/ + +(* View: entry *) +let entry = + Build.key_value_line Rx.word Sep.space_equal Quote.any_opt + +(* View: empty_entry *) +let empty_entry = Build.key_value_line Rx.word Sep.equal Quote.dquote_opt_nil + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry | empty_entry )* + +(* Variable: filter *) +let filter = incl "/etc/activemq.conf" + . incl "/etc/activemq/*" + . excl "/etc/activemq/*.xml" + . excl "/etc/activemq/jmx.*" + . excl "/etc/activemq/jetty-realm.properties" + . excl "/etc/activemq/*.ts" + . excl "/etc/activemq/*.ks" + . excl "/etc/activemq/*.cert" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/activemq_xml.aug b/Sharp.Augeas.Test/lens/activemq_xml.aug new file mode 100644 index 0000000..df2a222 --- /dev/null +++ b/Sharp.Augeas.Test/lens/activemq_xml.aug @@ -0,0 +1,41 @@ +(* +Module: ActiveMQ_XML + ActiveMQ / FuseMQ XML module for Augeas + +Author: Brian Redbeard + +About: Reference + This lens ensures that XML files included in ActiveMQ / FuseMQ are properly + handled by Augeas. + +About: License + This file is licensed under the LGPL License. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get your current setup + > print /files/etc/activemq/activemq.xml + ... + + * Change OpenShift domain + > set /files/etc/openshift/broker.conf/CLOUD_DOMAIN ose.example.com + + Saving your file: + + > save + +About: Configuration files + This lens applies to relevant XML files located in /etc/activemq/ . See . + +*) + +module ActiveMQ_XML = + autoload xfm + +let lns = Xml.lns + +let filter = (incl "/etc/activemq/*.xml") + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/afs_cellalias.aug b/Sharp.Augeas.Test/lens/afs_cellalias.aug new file mode 100644 index 0000000..6b67675 --- /dev/null +++ b/Sharp.Augeas.Test/lens/afs_cellalias.aug @@ -0,0 +1,60 @@ +(* +Module: AFS_cellalias + Parses AFS configuration file CellAlias + +Author: Pat Riehecky + +About: Reference + This lens is targeted at the OpenAFS CellAlias file + +About: Lens Usage + Sample usage of this lens in augtool + + * Add a CellAlias for fnal.gov/files to fnal-files + > set /files/usr/vice/etc/CellAlias/target[99] fnal.gov/files + > set /files/usr/vice/etc/CellAlias/target[99]/linkname fnal-files + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module AFS_cellalias = + autoload xfm + + (************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + (* Group: Comments and empty lines *) + + (* View: eol *) + let eol = Util.eol + (* View: comment *) + let comment = Util.comment + (* View: empty *) + let empty = Util.empty + + (* Group: separators *) + + (* View: space + * Separation between key and value + *) + let space = Util.del_ws_spc + let target = /[^ \t\n#]+/ + let linkname = Rx.word + + (************************************************************************ + * Group: ENTRIES + *************************************************************************) + + (* View: entry *) + let entry = [ label "target" . store target . space . [ label "linkname" . store linkname . eol ] ] + + (* View: lns *) + let lns = (empty | comment | entry)* + + let xfm = transform lns (incl "/usr/vice/etc/CellAlias") + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/aliases.aug b/Sharp.Augeas.Test/lens/aliases.aug new file mode 100644 index 0000000..10c2d66 --- /dev/null +++ b/Sharp.Augeas.Test/lens/aliases.aug @@ -0,0 +1,89 @@ +(* +Module: Aliases + Parses /etc/aliases + +Author: David Lutterkort + +About: Reference + This lens tries to keep as close as possible to `man 5 aliases` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + See . + +About: Configuration files + This lens applies to /etc/aliases. + +About: Examples + The file contains various examples and tests. +*) + +module Aliases = + autoload xfm + + (************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + (* Group: basic tokens *) + + (* Variable: word *) + let word = /[^|", \t\n]+/ + (* Variable: name *) + let name = /([^ \t\n#:|@]+|"[^"|\n]*")/ (* " make emacs calm down *) + + (* Variable: command + * a command can contain spaces, if enclosed in double quotes, the case + * without spaces is taken care with + *) + let command = /(\|([^", \t\n]+|"[^"\n]+"))|("\|[^"\n]+")/ + + (* Group: Comments and empty lines *) + + (* View: eol *) + let eol = Util.eol + (* View: comment *) + let comment = Util.comment + (* View: empty *) + let empty = Util.empty + + (* Group: separators *) + (* View: colon + * Separation between the alias and it's destinations + *) + let colon = del /[ \t]*:[ \t]*/ ":\t" + (* View: comma + * Separation between multiple destinations + *) + let comma = del /[ \t]*,[ \t]*(\n[ \t]+)?/ ", " + + (* Group: alias *) + + (* View: destination + * Can be either a word (no spaces included) or a command with spaces + *) + let destination = ( word | command ) + + (* View: value_list + * List of destinations + *) + let value_list = Build.opt_list ([ label "value" . store destination]) comma + + (* View: alias + * a name with one or more destinations + *) + let alias = [ seq "alias" . + [ label "name" . store name ] . colon . + value_list + ] . eol + + (* View: lns *) + let lns = (comment | empty | alias)* + + let xfm = transform lns (incl "/etc/aliases") + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/anaconda.aug b/Sharp.Augeas.Test/lens/anaconda.aug new file mode 100644 index 0000000..8f618db --- /dev/null +++ b/Sharp.Augeas.Test/lens/anaconda.aug @@ -0,0 +1,30 @@ +(* +Module: Anaconda + Parses Anaconda's user interaction configuration files. + +Author: Pino Toscano + +About: Reference + https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html + +About: Configuration file + This lens applies to /etc/sysconfig/anaconda. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) +module Anaconda = +autoload xfm + +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" + +let entry = IniFile.entry IniFile.entry_re sep comment +let title = IniFile.title IniFile.record_re +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = incl "/etc/sysconfig/anaconda" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/anacron.aug b/Sharp.Augeas.Test/lens/anacron.aug new file mode 100644 index 0000000..e7aa5ca --- /dev/null +++ b/Sharp.Augeas.Test/lens/anacron.aug @@ -0,0 +1,87 @@ +(* +Module: Anacron + Parses /etc/anacrontab + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 anacrontab` where + possible. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + +About: Configuration files + This lens applies to /etc/anacrontab. See . + +About: Examples + The file contains various examples and tests. +*) + +module Anacron = + autoload xfm + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + + +(************************************************************************ + * View: shellvar + * A shell variable in crontab + *************************************************************************) + +let shellvar = Cron.shellvar + + +(* View: period *) +let period = [ label "period" . store Rx.integer ] + +(* Variable: period_name_re + The valid values for . Currently only "monthly" *) +let period_name_re = "monthly" + +(************************************************************************ + * View: period_name + * In the format "@keyword" + *************************************************************************) +let period_name = [ label "period_name" . Util.del_str "@" + . store period_name_re ] + +(************************************************************************ + * View: delay + * The delay for an + *************************************************************************) +let delay = [ label "delay" . store Rx.integer ] + +(************************************************************************ + * View: job_identifier + * The job_identifier for an + *************************************************************************) +let job_identifier = [ label "job-identifier" . store Rx.word ] + +(************************************************************************ + * View: entry + * An anacrontab entry + *************************************************************************) + +let entry = [ label "entry" . Util.indent + . ( period | period_name ) + . Sep.space . delay + . Sep.space . job_identifier + . Sep.space . store Rx.space_in . Util.eol ] + + +(* + * View: lns + * The anacron lens + *) +let lns = ( Util.empty | Util.comment | shellvar | entry )* + + +(* Variable: filter *) +let filter = incl "/etc/anacrontab" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/approx.aug b/Sharp.Augeas.Test/lens/approx.aug new file mode 100644 index 0000000..a482d1a --- /dev/null +++ b/Sharp.Augeas.Test/lens/approx.aug @@ -0,0 +1,59 @@ +(* +Module: Approx + Parses /etc/approx/approx.conf + +Author: David Lutterkort + +About: Reference + This lens tries to keep as close as possible to `man 5 approx.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + See . + +About: Configuration files + This lens applies to /etc/approx/approx.conf. + +About: Examples + The file contains various examples and tests. +*) + +module Approx = + autoload xfm + + (* Variable: eol + An *) + let eol = Util.eol + + (* Variable: indent + An *) + let indent = Util.indent + + (* Variable: key_re *) + let key_re = /\$?[A-Za-z0-9_.-]+/ + + (* Variable: sep *) + let sep = /[ \t]+/ + + (* Variable: value_re *) + let value_re = /[^ \t\n](.*[^ \t\n])?/ + + (* View: comment *) + let comment = [ indent . label "#comment" . del /[#;][ \t]*/ "# " + . store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ . eol ] + + (* View: empty + An *) + let empty = Util.empty + + (* View: kv *) + let kv = [ indent . key key_re . del sep " " . store value_re . eol ] + + (* View: lns *) + let lns = (empty | comment | kv) * + + (* View: filter *) + let filter = incl "/etc/approx/approx.conf" + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/apt_update_manager.aug b/Sharp.Augeas.Test/lens/apt_update_manager.aug new file mode 100644 index 0000000..f1c361d --- /dev/null +++ b/Sharp.Augeas.Test/lens/apt_update_manager.aug @@ -0,0 +1,47 @@ +(* +Module: Apt_Update_Manager + Parses files in /etc/update-manager + +Author: Raphael Pinson + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to files in /etc/update-manager. See . + +About: Examples + The file contains various examples and tests. +*) +module Apt_Update_Manager = + +autoload xfm + +(* View: comment *) +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + +(* View: sep *) +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default + +(* View: title *) +let title = IniFile.title Rx.word + +(* View: entry *) +let entry = IniFile.entry Rx.word sep comment + +(* View: record *) +let record = IniFile.record title entry + +(* View: lns *) +let lns = IniFile.lns record comment + +(* Variable: filter *) +let filter = incl "/etc/update-manager/meta-release" + . incl "/etc/update-manager/release-upgrades" + . incl "/etc/update-manager/release-upgrades.d/*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/aptcacherngsecurity.aug b/Sharp.Augeas.Test/lens/aptcacherngsecurity.aug new file mode 100644 index 0000000..204ea5b --- /dev/null +++ b/Sharp.Augeas.Test/lens/aptcacherngsecurity.aug @@ -0,0 +1,25 @@ +(* Module: AptCacherNGSecurity + + Lens for config files like the one found in + /etc/apt-cacher-ng/security.conf + + + About: License + Copyright 2013 Erik B. Andersen; this file is licenced under the LGPL v2+. +*) +module AptCacherNGSecurity = + autoload xfm + + (* Define a Username/PW pair *) + let authpair = [ key /[^ \t:\/]*/ . del /:/ ":" . store /[^: \t\n]*/ ] + + (* Define a record. So far as I can tell, the only auth level supported is Admin *) + let record = [ key "AdminAuth". del /[ \t]*:[ \t]*/ ": ". authpair . Util.del_str "\n"] + + (* Define the basic lens *) + let lns = ( record | Util.empty | Util.comment )* + + let filter = incl "/etc/apt-cacher-ng/security.conf" + . Util.stdexcl + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/aptconf.aug b/Sharp.Augeas.Test/lens/aptconf.aug new file mode 100644 index 0000000..2131540 --- /dev/null +++ b/Sharp.Augeas.Test/lens/aptconf.aug @@ -0,0 +1,151 @@ +(* +Module: AptConf + Parses /etc/apt/apt.conf and /etc/apt/apt.conf.d/* + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 apt.conf` +where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/apt/apt.conf and /etc/apt/apt.conf.d/*. +See . +*) + + +module AptConf = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: eol + And end of line *) +let eol = Util.eol + +(* View: empty + A C-style empty line *) +let empty = Util.empty_any + +(* View: indent + An indentation *) +let indent = Util.indent + +(* View: comment_simple + A one-line comment, C-style *) +let comment_simple = Util.comment_c_style_or_hash + +(* View: comment_multi + A multiline comment, C-style *) +let comment_multi = Util.comment_multiline + +(* View: comment + A comment, either or *) +let comment = comment_simple | comment_multi + + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +(* View: name_re + Regex for entry names *) +let name_re = /[A-Za-z][A-Za-z-]*/ + +(* View: name_re_colons + Regex for entry names with colons *) +let name_re_colons = /[A-Za-z][A-Za-z:-]*/ + + +(* View: entry + An apt.conf entry, recursive + + WARNING: + This lens exploits a put ambiguity + since apt.conf allows for both + APT { Clean-Installed { "true" } } + and APT::Clean-Installed "true"; + but we're choosing to map them the same way + + The recursive lens doesn't seem + to care and defaults to the first + item in the union. + + This is why the APT { Clean-Installed { "true"; } } + form is listed first, since it supports + all subnodes (which Dpkg::Conf) doesn't. + + Exchanging these two expressions in the union + makes tests fails since the tree cannot + be mapped back. + + This situation results in existing + configuration being modified when the + associated tree is modified. For example, + changing the value of + APT::Clean-Installed "true"; to "false" + results in + APT { Clean-Installed "false"; } + (see unit tests) + *) +let rec entry_noeol = + let value = + Util.del_str "\"" . store /[^"\n]+/ + . del /";?/ "\";" in + let opt_eol = del /[ \t\n]*/ "\n" in + let long_eol = del /[ \t]*\n+/ "\n" in + let list_elem = [ opt_eol . label "@elem" . value ] in + let eol_comment = del /([ \t\n]*\n)?/ "" . comment in + [ key name_re . Sep.space . value ] + | [ key name_re . del /[ \t\n]*\{/ " {" . + ( (opt_eol . entry_noeol) | + list_elem | + eol_comment + )* . + del /[ \t\n]*\};?/ "\n};" ] + | [ key name_re . Util.del_str "::" . entry_noeol ] + +let entry = indent . entry_noeol . eol + + +(* View: include + A file inclusion + /!\ The manpage is not clear on the syntax *) +let include = + [ indent . key "#include" . Sep.space + . store Rx.fspath . eol ] + + +(* View: clear + A list of variables to clear + /!\ The manpage is not clear on the syntax *) +let clear = + let name = [ label "name" . store name_re_colons ] in + [ indent . key "#clear" . Sep.space + . Build.opt_list name Sep.space + . eol ] + + +(************************************************************************ + * Group: LENS AND FILTER + *************************************************************************) + +(* View: lns + The apt.conf lens *) +let lns = (empty|comment|entry|include|clear)* + + +(* View: filter *) +let filter = incl "/etc/apt/apt.conf" + . incl "/etc/apt/apt.conf.d/*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/aptpreferences.aug b/Sharp.Augeas.Test/lens/aptpreferences.aug new file mode 100644 index 0000000..0c3c84c --- /dev/null +++ b/Sharp.Augeas.Test/lens/aptpreferences.aug @@ -0,0 +1,69 @@ +(* +Module: AptPreferences + Apt/preferences module for Augeas + +Author: Raphael Pinson +*) + +module AptPreferences = +autoload xfm + +(************************************************************************ + * Group: Entries + ************************************************************************) + +(* View: colon *) +let colon = del /:[ \t]*/ ": " + +(* View: pin_gen + A generic pin + + Parameters: + lbl:string - the label *) +let pin_gen (lbl:string) = store lbl + . [ label lbl . Sep.space . store Rx.no_spaces ] + +(* View: pin_keys *) +let pin_keys = + let space_in = store /[^, \r\t\n][^,\n]*[^, \r\t\n]|[^, \t\n\r]/ + in Build.key_value /[aclnov]/ Sep.equal space_in + +(* View: pin_options *) +let pin_options = + let comma = Util.delim "," + in store "release" . Sep.space + . Build.opt_list pin_keys comma + +(* View: version_pin *) +let version_pin = pin_gen "version" + +(* View: origin_pin *) +let origin_pin = pin_gen "origin" + +(* View: pin *) +let pin = + let pin_value = pin_options | version_pin | origin_pin + in Build.key_value_line "Pin" colon pin_value + +(* View: entries *) +let entries = Build.key_value_line ("Explanation"|"Package"|"Pin-Priority") + colon (store Rx.space_in) + | pin + | Util.comment + +(* View: record *) +let record = [ seq "record" . entries+ ] + +(************************************************************************ + * Group: Lens + ************************************************************************) + +(* View: lns *) +let lns = Util.empty* . (Build.opt_list record Util.eol+ . Util.empty*)? + +(* View: filter *) +let filter = incl "/etc/apt/preferences" + . incl "/etc/apt/preferences.d/*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/aptsources.aug b/Sharp.Augeas.Test/lens/aptsources.aug new file mode 100644 index 0000000..d7a6b3b --- /dev/null +++ b/Sharp.Augeas.Test/lens/aptsources.aug @@ -0,0 +1,70 @@ +(* +Module: Aptsources + Parsing /etc/apt/sources.list +*) + +module Aptsources = + autoload xfm + +(************************************************************************ + * Group: Utility variables/functions + ************************************************************************) + (* View: sep_ws *) + let sep_ws = Sep.space + + (* View: eol *) + let eol = Util.del_str "\n" + + (* View: comment *) + let comment = Util.comment + (* View: empty *) + let empty = Util.empty + + (* View: word *) + let word = /[^][# \n\t]+/ + + (* View: uri *) + let uri = + let protocol = /[a-z+]+:/ + in let path = /\/[^] \t]*/ + in let path_brack = /\[[^]]+\]\/?/ + in protocol? . path + | protocol . path_brack + +(************************************************************************ + * Group: Keywords + ************************************************************************) + (* View: record *) + let record = + let option_sep = [ label "operation" . store /[+-]/]? . Sep.equal + in let option = Build.key_value /arch|trusted/ option_sep (store Rx.word) + in let options = [ label "options" + . Util.del_str "[" . Sep.opt_space + . Build.opt_list option Sep.space + . Sep.opt_space . Util.del_str "]" + . sep_ws ] + in [ Util.indent . seq "source" + . [ label "type" . store word ] . sep_ws + . options? + . [ label "uri" . store uri ] . sep_ws + . [ label "distribution" . store word ] + . [ label "component" . sep_ws . store word ]* + . del /[ \t]*(#.*)?/ "" + . eol ] + +(************************************************************************ + * Group: Lens + ************************************************************************) + (* View: lns *) + let lns = ( comment | empty | record ) * + + (* View: filter *) + let filter = (incl "/etc/apt/sources.list") + . (incl "/etc/apt/sources.list.d/*") + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/authinfo2.aug b/Sharp.Augeas.Test/lens/authinfo2.aug new file mode 100644 index 0000000..7ef4ba2 --- /dev/null +++ b/Sharp.Augeas.Test/lens/authinfo2.aug @@ -0,0 +1,39 @@ +(* Authinfo2 module for Augeas *) +(* Author: Nicolas Gif *) +(* Heavily based on DPUT module by Raphael Pinson *) +(* *) +(* *) + +module Authinfo2 = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) +let comment = IniFile.comment IniFile.comment_re "#" + +let sep = IniFile.sep IniFile.sep_re ":" + + +(************************************************************************ + * ENTRY + *************************************************************************) +let entry = + IniFile.entry_generic_nocomment (key IniFile.entry_re) sep IniFile.comment_re comment + + +(************************************************************************ + * TITLE & RECORD + *************************************************************************) +let title = IniFile.title IniFile.record_re +let record = IniFile.record title entry + + +(************************************************************************ + * LENS & FILTER + *************************************************************************) +let lns = IniFile.lns record comment + +let filter = (incl (Sys.getenv("HOME") . "/.s3ql/authinfo2")) + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/authorized_keys.aug b/Sharp.Augeas.Test/lens/authorized_keys.aug new file mode 100644 index 0000000..e913d4b --- /dev/null +++ b/Sharp.Augeas.Test/lens/authorized_keys.aug @@ -0,0 +1,72 @@ +(* +Module: Authorized_Keys + Parses SSH authorized_keys + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 authorized_keys` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to SSH authorized_keys. See . + +About: Examples + The file contains various examples and tests. +*) + + +module Authorized_Keys = + +autoload xfm + +(* View: option + A key option *) +let option = + let kv_re = "command" | "environment" | "from" + | "permitopen" | "principals" | "tunnel" + in let flag_re = "cert-authority" | "no-agent-forwarding" + | "no-port-forwarding" | "no-pty" | "no-user-rc" + | "no-X11-forwarding" + in let option_value = Util.del_str "\"" + . store /((\\\\")?[^\\\n"]*)+/ + . Util.del_str "\"" + in Build.key_value kv_re Sep.equal option_value + | Build.flag flag_re + +(* View: key_options + A list of key

+ - allow|deny|cmdallow|cmddeny [all] [] + - log + - broadcast
+ - fallbackdrift + - hwtimestamp + - initstepslew + - local + - mailonchange + - makestep + - maxchange + - ratelimit|cmdratelimit|ntsratelimit + - refclock + - smoothtime + - tempcomp ( | ) + - confdir|sourcedir + *) + + (* View: host_list + Find all NTP sources and their flags/options + *) + let host_list = [ Util.indent . key ntp_source + . space . store address_re + . ( host_flags | host_options )* + . eol ] + + (* View: allowdeny + allow/deny/cmdallow/cmddeny has a specific syntax + *) + let allowdeny = [ Util.indent . key allowdeny_types + . [ space . key "all" ]? + . ( space . store ( no_space - "all" ) )? + . eol ] + + (* View: log_list + log has a specific options list + *) + let log_list = [ Util.indent . key "log" . log_flag_list+ . eol ] + + (* View: bcast + broadcast has specific syntax + *) + let bcast = [ Util.indent . key "broadcast" + . space . [ label "interval" . store integer ] + . space . store_address + . ( space . [ label "port" . store integer ] )? + . eol ] + + (* View: bcast + confdir and sourcedir have specific syntax + *) + let dir_list = [ Util.indent . key /(conf|source)dir/ + . [ label "directory" . space . store no_space ]+ + . eol ] + + (* View: fdrift + fallbackdrift has specific syntax + *) + let fdrift = [ Util.indent . key "fallbackdrift" + . space . [ label "min" . store integer ] + . space . [ label "max" . store integer ] + . eol ] + + (* View: hwtimestamp + hwtimestamp has specific syntax + *) + let hwtimestamp = [ Util.indent . key "hwtimestamp" + . space . [ label "interface" . store no_space ] + . ( space . ( [ key hwtimestamp_flags ] + | [ key hwtimestamp_options . space + . store no_space ] ) + )* + . eol ] + (* View: istepslew + initstepslew has specific syntax + *) + let istepslew = [ Util.indent . key "initstepslew" + . space . [ label "threshold" . store number ] + . ( space . store_address )+ + . eol ] + + (* View: local + local has specific syntax + *) + let local = [ Util.indent . key "local" + . ( space . ( [ key local_flags ] + | [ key local_options . space . store no_space ] ) + )* + . eol ] + + (* View: email + mailonchange has specific syntax + *) + let email = [ Util.indent . key "mailonchange" . space + . [ label "emailaddress" . store email_addr ] + . space + . [ label "threshold" . store number ] + . eol ] + + (* View: makestep + makestep has specific syntax + *) + let makestep = [ Util.indent . key "makestep" + . space + . [ label "threshold" . store number ] + . space + . [ label "limit" . store integer ] + . eol ] + + (* View: maxchange + maxchange has specific syntax + *) + let maxchange = [ Util.indent . key "maxchange" + . space + . [ label "threshold" . store number ] + . space + . [ label "delay" . store integer ] + . space + . [ label "limit" . store integer ] + . eol ] + + (* View: ratelimit + ratelimit/cmdratelimit has specific syntax + *) + let ratelimit = [ Util.indent . key /(cmd|nts)?ratelimit/ + . [ space . key ratelimit_options + . space . store no_space ]* + . eol ] + (* View: refclock + refclock has specific syntax + *) + let refclock = [ Util.indent . key "refclock" + . space + . [ label "driver" . store word ] + . space + . [ label "parameter" . store no_space ] + . ( space . ( [ key refclock_flags ] + | [ key refclock_options . space . store no_space ] ) + )* + . eol ] + + (* View: smoothtime + smoothtime has specific syntax + *) + let smoothtime = [ Util.indent . key "smoothtime" + . space + . [ label "maxfreq" . store number ] + . space + . [ label "maxwander" . store number ] + . ( space . [ key "leaponly" ] )? + . eol ] + + (* View: tempcomp + tempcomp has specific syntax + *) + let tempcomp = [ Util.indent . key "tempcomp" + . space + . [ label "sensorfile" . store path ] + . space + . [ label "interval" . store number ] + . space + . ( [ label "t0" . store number ] . space + . [ label "k0" . store number ] . space + . [ label "k1" . store number ] . space + . [ label "k2" . store number ] + | [ label "pointfile" . store path ] ) + . eol ] + +(************************************************************************ + * Group: Final lense summary + ************************************************************************) +(* View: settings + * All supported chrony settings + *) +let settings = host_list | allowdeny | log_list | bcast | fdrift | istepslew + | local | email | makestep | maxchange | refclock | smoothtime + | dir_list | hwtimestamp | ratelimit | tempcomp | kv | all_flags + +(* + * View: lns + * The crony lens + *) +let lns = ( empty | comment | settings )* + +(* View: filter + * The files parsed by default + *) +let filter = incl "/etc/chrony.conf" + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/clamav.aug b/Sharp.Augeas.Test/lens/clamav.aug new file mode 100644 index 0000000..df5041a --- /dev/null +++ b/Sharp.Augeas.Test/lens/clamav.aug @@ -0,0 +1,55 @@ +(* +Module: ClamAV + Parses ClamAV clamd and freshclam configuration files. + +Author: Andrew Colin Kissa + Baruwa Enterprise Edition http://www.baruwa.com + +About: License + This file is licensed under the LGPL v2+. + +About: Configuration files + This lens applies to /etc/clamd.conf, /etc/freshclam.conf and files in + /etc/clamd.d. See . +*) + +module Clamav = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + ************************************************************************) + +let word = /[A-Za-z][A-Za-z0-9]+/ + +let comment = Util.comment + +let some_value = Sep.space . store Rx.space_in + +(************************************************************************ + * Group: Entry + ************************************************************************) + +let example_entry = [ key "Example" . Util.eol ] + +let clamd_entry = [ key word . some_value . Util.eol ] + +(****************************************************************** + * Group: LENS AND FILTER + ******************************************************************) + +(************************************************************************ + * View: Lns + ************************************************************************) + +let lns = (Util.empty | example_entry | clamd_entry | comment )* + +(* Variable: filter *) +let filter = (incl "/etc/clamd.conf") + . (incl "/etc/freshclam.conf") + . (incl "/etc/clamd.d/*.conf") + . (incl "/etc/clamav/clamd.conf") + . (incl "/etc/clamav/freshclam.conf") + . (incl "/etc/clamav/clamd.d/*.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/cmdline.aug b/Sharp.Augeas.Test/lens/cmdline.aug new file mode 100644 index 0000000..b8b5176 --- /dev/null +++ b/Sharp.Augeas.Test/lens/cmdline.aug @@ -0,0 +1,21 @@ +(* +Module: Cmdline + Parses /proc/cmdline and /etc/kernel/cmdline + +Author: Thomas Weißschuh + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Cmdline = + autoload xfm + +let entry = [ key Rx.word . Util.del_str "=" . store Rx.no_spaces ] | [ key Rx.word ] + +let lns = (Build.opt_list entry Sep.space)? . del /\n?/ "" + +let filter = incl "/etc/kernel/cmdline" + . incl "/proc/cmdline" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/cobblermodules.aug b/Sharp.Augeas.Test/lens/cobblermodules.aug new file mode 100644 index 0000000..21bf6f9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/cobblermodules.aug @@ -0,0 +1,17 @@ + +module CobblerModules = + autoload xfm + +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" + +let entry = IniFile.entry IniFile.entry_re sep comment + +let title = IniFile.indented_title IniFile.record_re +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = (incl "/etc/cobbler/modules.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/cobblersettings.aug b/Sharp.Augeas.Test/lens/cobblersettings.aug new file mode 100644 index 0000000..6017000 --- /dev/null +++ b/Sharp.Augeas.Test/lens/cobblersettings.aug @@ -0,0 +1,72 @@ +(* + Parse the /etc/cobbler/settings file which is in + YAML 1.0 format. + + The lens can handle the following constructs + * key: value + * key: "value" + * key: 'value' + * key: [value1, value2] + * key: + - value1 + - value2 + * key: + key2: value1 + key3: value2 + + Author: Bryan Kearney + + About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) +module CobblerSettings = + autoload xfm + + let kw = /[a-zA-Z0-9_]+/ + (* TODO Would be better if this stripped off the "" and '' characters *) + let kv = /([^]['", \t\n#:@-]+|"[^"\n]*"|'[^'\n]*')/ + + let lbr = del /\[/ "[" + let rbr = del /\]/ "]" + let colon = del /[ \t]*:[ \t]*/ ": " + let dash = del /-[ \t]*/ "- " + (* let comma = del /,[ \t]*(\n[ \t]+)?/ ", " *) + let comma = del /[ \t]*,[ \t]*/ ", " + + let eol_only = del /\n/ "\n" + + (* TODO Would be better to make items a child of a document *) + let docmarker = /-{3}/ + + let eol = Util.eol + let comment = Util.comment + let empty = Util.empty + let indent = del /[ \t]+/ "\t" + let ws = del /[ \t]*/ " " + + let value_list = Build.opt_list [label "item" . store kv] comma + let setting = [key kw . colon . store kv] . eol + let simple_setting_suffix = store kv . eol + let setting_list_suffix = [label "sequence" . lbr . ws . (value_list . ws)? . rbr ] . eol + let indendented_setting_list_suffix = eol_only . (indent . setting)+ + let indented_list_suffix = [label "list" . eol_only . ([ label "value" . indent . dash . store kv] . eol)+] + + (* Break out setting because of a current bug in augeas *) + let nested_setting = [key kw . colon . ( + (* simple_setting_suffix | *) + setting_list_suffix | + indendented_setting_list_suffix | + indented_list_suffix + ) + ] + + let document = [label "---" . store docmarker] . eol + + let lns = (document | comment | empty | setting | nested_setting )* + + let xfm = transform lns (incl "/etc/cobbler/settings") + + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/collectd.aug b/Sharp.Augeas.Test/lens/collectd.aug new file mode 100644 index 0000000..bbd48b9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/collectd.aug @@ -0,0 +1,36 @@ +(* +Module: Collectd + Parses collectd configuration files + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 collectd.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to collectd configuration files. See . + +About: Examples + The file contains various examples and tests. +*) + +module Collectd = + +autoload xfm + +(* View: lns + Collectd is essentially Httpd-compliant configuration files *) +let lns = Httpd.lns + +(* Variable: filter *) +let filter = incl "/etc/collectd.conf" + . incl "/etc/collectd/*.conf" + . incl "/usr/share/doc/collectd/examples/collection3/etc/collection.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/cpanel.aug b/Sharp.Augeas.Test/lens/cpanel.aug new file mode 100644 index 0000000..f311826 --- /dev/null +++ b/Sharp.Augeas.Test/lens/cpanel.aug @@ -0,0 +1,39 @@ +(* +Module: CPanel + Parses cpanel.config + +Author: Raphael Pinson + +About: Reference + This lens parses cpanel.config files + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to cpanel.config files. See . + +About: Examples + The file contains various examples and tests. +*) +module CPanel = + +autoload xfm + +(* View: kv + A key-value pair, supporting flags and empty values *) +let kv = [ key /[A-Za-z0-9:_.-]+/ + . (Sep.equal . store (Rx.space_in?))? + . Util.eol ] + +(* View: lns + The lens *) +let lns = (Util.comment | Util.empty | kv)* + +(* View: filter *) +let filter = incl "/var/cpanel/cpanel.config" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/cron.aug b/Sharp.Augeas.Test/lens/cron.aug new file mode 100644 index 0000000..2e48891 --- /dev/null +++ b/Sharp.Augeas.Test/lens/cron.aug @@ -0,0 +1,155 @@ +(* +Module: Cron + Parses /etc/cron.d/*, /etc/crontab + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 crontab` where + possible. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Get the entry that launches '/usr/bin/ls' + > match '/files/etc/crontab/entry[. = "/usr/bin/ls"]' + +About: Configuration files + This lens applies to /etc/cron.d/* and /etc/crontab. See . +*) + +module Cron = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Generic primitives *) + +(* Variable: eol *) +let eol = Util.eol + +(* Variable: indent *) +let indent = Util.indent + +(* Variable: comment *) +let comment = Util.comment + +(* Variable: empty *) +let empty = Util.empty + +(* Variable: num *) +let num = /[0-9*][0-9\/,*-]*/ + +(* Variable: alpha *) +let alpha = /[A-Za-z]{3}/ + +(* Variable: alphanum *) +let alphanum = (num|alpha) . ("-" . (num|alpha))? + +(* Variable: entry_prefix *) +let entry_prefix = /-/ + +(* Group: Separators *) + +(* Variable: sep_spc *) +let sep_spc = Util.del_ws_spc + +(* Variable: sep_eq *) +let sep_eq = Util.del_str "=" + + + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + + +(************************************************************************ + * View: shellvar + * A shell variable in crontab + *************************************************************************) + +let shellvar = + let key_re = /[A-Za-z1-9_-]+(\[[0-9]+\])?/ - "entry" in + let sto_to_eol = store /[^\n]*[^ \t\n]/ in + [ key key_re . sep_eq . sto_to_eol . eol ] + +(* View: - prefix of an entry *) +let prefix = [ label "prefix" . store entry_prefix ] + +(* View: minute *) +let minute = [ label "minute" . store num ] + +(* View: hour *) +let hour = [ label "hour" . store num ] + +(* View: dayofmonth *) +let dayofmonth = [ label "dayofmonth" . store num ] + +(* View: month *) +let month = [ label "month" . store alphanum ] + +(* View: dayofweek *) +let dayofweek = [ label "dayofweek" . store alphanum ] + + +(* View: user *) +let user = [ label "user" . store Rx.word ] + + +(************************************************************************ + * View: time + * Time in the format "minute hour dayofmonth month dayofweek" + *************************************************************************) +let time = [ label "time" . + minute . sep_spc . hour . sep_spc . dayofmonth + . sep_spc . month . sep_spc . dayofweek ] + +(* Variable: the valid values for schedules *) +let schedule_re = "reboot" | "yearly" | "annually" | "monthly" + | "weekly" | "daily" | "midnight" | "hourly" + +(************************************************************************ + * View: schedule + * Time in the format "@keyword" + *************************************************************************) +let schedule = [ label "schedule" . Util.del_str "@" + . store schedule_re ] + + +(************************************************************************ + * View: entry + * A crontab entry + *************************************************************************) + +let entry = [ label "entry" . indent + . prefix? + . ( time | schedule ) + . sep_spc . user + . sep_spc . store Rx.space_in . eol ] + + +(* + * View: lns + * The cron lens + *) +let lns = ( empty | comment | shellvar | entry )* + + +(* Variable: filter *) +let filter = + incl "/etc/cron.d/*" . + incl "/etc/crontab" . + incl "/etc/crontabs/*" . + excl "/etc/cron.d/at.allow" . + excl "/etc/cron.d/at.deny" . + excl "/etc/cron.d/cron.allow" . + excl "/etc/cron.d/cron.deny" . + Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/cron_user.aug b/Sharp.Augeas.Test/lens/cron_user.aug new file mode 100644 index 0000000..afbfc88 --- /dev/null +++ b/Sharp.Augeas.Test/lens/cron_user.aug @@ -0,0 +1,46 @@ +(* +Module: Cron_User + Parses /var/spool/cron/* + +Author: David Lutterkort + +About: Reference + This lens parses the user crontab files in /var/spool/cron. It produces + almost the same tree as the Cron.lns, except that it never contains a user + field. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Get the entry that launches '/usr/bin/ls' + > match '/files/var/spool/cron/foo/entry[. = "/usr/bin/ls"]' + +About: Configuration files + This lens applies to /var/spool/cron*. See . + *) +module Cron_User = + autoload xfm + +(************************************************************************ + * View: entry + * A crontab entry for a user's crontab + *************************************************************************) +let entry = [ label "entry" . Cron.indent + . Cron.prefix? + . ( Cron.time | Cron.schedule ) + . Cron.sep_spc . store Rx.space_in . Cron.eol ] + +(* + * View: lns + * The cron_user lens. Almost identical to Cron.lns + *) +let lns = ( Cron.empty | Cron.comment | Cron.shellvar | entry )* + +let filter = + incl "/var/spool/cron/*" . + Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/crypttab.aug b/Sharp.Augeas.Test/lens/crypttab.aug new file mode 100644 index 0000000..8c9409b --- /dev/null +++ b/Sharp.Augeas.Test/lens/crypttab.aug @@ -0,0 +1,108 @@ +(* +Module: Crypttab + Parses /etc/crypttab from the cryptsetup package. + +Author: Frédéric Lespez + +About: Reference + This lens tries to keep as close as possible to `man crypttab` where possible. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Create a new entry for an encrypted block devices + > ins 01 after /files/etc/crypttab/*[last()] + > set /files/etc/crypttab/01/target crypt_sda2 + > set /files/etc/crypttab/01/device /dev/sda2 + > set /files/etc/crypttab/01/password /dev/random + > set /files/etc/crypttab/01/opt swap + * Print the entry applying to the "/dev/sda2" device + > print /files/etc/crypttab/01 + * Remove the entry applying to the "/dev/sda2" device + > rm /files/etc/crypttab/*[device="/dev/sda2"] + +About: Configuration files + This lens applies to /etc/crypttab. See . +*) + +module Crypttab = + autoload xfm + + (************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + (* Group: Separators *) + + (* Variable: sep_tab *) + let sep_tab = Sep.tab + + (* Variable: comma *) + let comma = Sep.comma + + (* Group: Generic primitives *) + + (* Variable: eol *) + let eol = Util.eol + + (* Variable: comment *) + let comment = Util.comment + + (* Variable: empty *) + let empty = Util.empty + + (* Variable: word *) + let word = Rx.word + + (* Variable: optval *) + let optval = /[A-Za-z0-9\/_.:-]+/ + + (* Variable: target *) + let target = Rx.device_name + + (* Variable: fspath *) + let fspath = Rx.fspath + + (* Variable: uuid *) + let uuid = /UUID=[0-9a-f-]+/ + + (************************************************************************ + * Group: ENTRIES + *************************************************************************) + + (************************************************************************ + * View: comma_sep_list + * A comma separated list of options (opt=value or opt) + *************************************************************************) + let comma_sep_list (l:string) = + let value = [ label "value" . Util.del_str "=" . store optval ] in + let lns = [ label l . store word . value? ] in + Build.opt_list lns comma + + (************************************************************************ + * View: record + * A crypttab record + *************************************************************************) + + let record = [ seq "entry" . + [ label "target" . store target ] . sep_tab . + [ label "device" . store (fspath|uuid) ] . + (sep_tab . [ label "password" . store fspath ] . + ( sep_tab . comma_sep_list "opt")? )? + . eol ] + + (* + * View: lns + * The crypttab lens + *) + let lns = ( empty | comment | record ) * + + (* Variable: filter *) + let filter = (incl "/etc/crypttab") + + let xfm = transform lns filter + +(* coding: utf-8 *) diff --git a/Sharp.Augeas.Test/lens/csv.aug b/Sharp.Augeas.Test/lens/csv.aug new file mode 100644 index 0000000..028aaf7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/csv.aug @@ -0,0 +1,51 @@ +(* +Module: CSV + Generic CSV lens collection + +Author: Raphael Pinson + +About: Reference + https://tools.ietf.org/html/rfc4180 + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + +About: Examples + The file contains various examples and tests. + +Caveats: + No support for files without an ending CRLF +*) +module CSV = + +(* View: eol *) +let eol = Util.del_str "\n" + +(* View: comment *) +let comment = Util.comment + | [ del /#[ \t]*\r?\n/ "#\n" ] + +(* View: entry + An entry of fields, quoted or not *) +let entry (sep_str:string) = + let field = [ seq "field" . store (/[^"#\r\n]/ - sep_str)* ] + | [ seq "field" . store /("[^"#]*")+/ ] + in let sep = Util.del_str sep_str + in [ seq "entry" . counter "field" . Build.opt_list field sep . eol ] + +(* View: lns + The generic lens, taking the separator as a parameter *) +let lns_generic (sep:string) = (comment | entry sep)* + +(* View: lns + The comma-separated value lens *) +let lns = lns_generic "," + +(* View: lns_semicol + A semicolon-separated value lens *) +let lns_semicol = lns_generic ";" diff --git a/Sharp.Augeas.Test/lens/cups.aug b/Sharp.Augeas.Test/lens/cups.aug new file mode 100644 index 0000000..7a9430d --- /dev/null +++ b/Sharp.Augeas.Test/lens/cups.aug @@ -0,0 +1,27 @@ +(* +Module: Cups + Parses cups configuration files + +Author: Raphael Pinson + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Examples + The file contains various examples and tests. +*) + +module Cups = + +autoload xfm + +(* View: lns *) +let lns = Httpd.lns + +(* Variable: filter *) +let filter = incl "/etc/cups/*.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/cyrus_imapd.aug b/Sharp.Augeas.Test/lens/cyrus_imapd.aug new file mode 100644 index 0000000..6df1311 --- /dev/null +++ b/Sharp.Augeas.Test/lens/cyrus_imapd.aug @@ -0,0 +1,49 @@ +(* +Cyrus_Imapd module for Augeas + +Author: Free Ekanayaka +*) + +module Cyrus_Imapd = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let indent = del /[ \t]*(\n[ \t]+)?/ " " +let comment = Util.comment +let empty = Util.empty +let eq = del /[ \t]*:/ ":" +let word = /[A-Za-z0-9_.-]+/ + +(* The value of a parameter, after the '=' sign. Postfix allows that + * lines are continued by starting continuation lines with spaces. + * The definition needs to make sure we don't add indented comment lines + * into values *) +let value = + let chr = /[^# \t\n]/ in + let any = /.*/ in + let line = (chr . any* . chr | chr) in + let lines = line . (/\n[ \t]+/ . line)* in + store lines + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let entry = [ key word . eq . (indent . value)? . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter = (incl "/etc/imapd.conf") + . (incl "/etc/imap/*.conf") + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/darkice.aug b/Sharp.Augeas.Test/lens/darkice.aug new file mode 100644 index 0000000..a41a948 --- /dev/null +++ b/Sharp.Augeas.Test/lens/darkice.aug @@ -0,0 +1,29 @@ +(* Darkice module for Augeas + Author: Free Ekanayaka + + Reference: man 5 darkice.cfg +*) + + +module Darkice = + autoload xfm + + +(************************************************************************ + * INI File settings + *************************************************************************) +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default + +let entry_re = ( /[A-Za-z0-9][A-Za-z0-9._-]*/ ) +let entry = IniFile.entry entry_re sep comment + +let title = IniFile.title_label "target" IniFile.record_label_re +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = (incl "/etc/darkice.cfg") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/debctrl.aug b/Sharp.Augeas.Test/lens/debctrl.aug new file mode 100644 index 0000000..02a1aab --- /dev/null +++ b/Sharp.Augeas.Test/lens/debctrl.aug @@ -0,0 +1,131 @@ +(* +Module: debctrl + Parses ./debian/control + +Author: + Dominique Dumont domi.dumont@free.fr or dominique.dumont@hp.com + +About: Reference + http://augeas.net/page/Create_a_lens_from_bottom_to_top + http://www.debian.org/doc/debian-policy/ch-controlfields.html + +About: License + This file is licensed under the LGPL v2+. + +About: Lens Usage + Since control file is not a system configuration file, you will have + to use augtool -r option to point to 'debian' directory. + + Run augtool: + $ augtool -r debian + + Sample usage of this lens in augtool: + + * Get the value stored in control file + > print /files/control + ... + + Saving your file: + + > save + + +*) + +module Debctrl = + autoload xfm + +let eol = Util.eol +let del_ws_spc = del /[\t ]*/ " " +let hardeol = del /\n/ "\n" +let del_opt_ws = del /[\t ]*/ "" +let colon = del /:[ \t]*/ ": " + +let simple_entry (k:regexp) = + let value = store /[^ \t][^\n]+/ in + [ key k . colon . value . hardeol ] + +let cont_line = del /\n[ \t]+/ "\n " +let comma = del /,[ \t]*/ ", " + +let sep_comma_with_nl = del /[ \t\n]*,[ \t\n]*/ ",\n " + (*= del_opt_ws . cont_line* . comma . cont_line**) + +let email = store ( /([A-Za-z]+ )+<[^\n>]+>/ | /[^\n,\t<> ]+/ ) + +let multi_line_array_entry (k:regexp) (v:lens) = + [ key k . colon . [ counter "array" . seq "array" . v ] . + [ seq "array" . sep_comma_with_nl . v ]* . hardeol ] + +(* dependency stuff *) + +let version_depends = + [ label "version" + . [ del / *\( */ " ( " . label "relation" . store /[<>=]+/ ] + . [ del_ws_spc . label "number" + . store ( /[a-zA-Z0-9_.-]+/ | /\$\{[a-zA-Z0-9:]+\}/ ) + . del / *\)/ " )" ] + ] + +let arch_depends = + [ label "arch" + . [ del / *\[ */ " [ " . label "prefix" . store /!?/ ] + . [ label "name" . store /[a-zA-Z0-9_.-]+/ . del / *\]/ " ]" ] ] + + +let package_depends + = [ key ( /[a-zA-Z0-9_-]+/ | /\$\{[a-zA-Z0-9:]+\}/ ) + . ( version_depends | arch_depends ) * ] + + +let dependency = [ label "or" . package_depends ] + . [ label "or" . del / *\| */ " | " + . package_depends ] * + +let dependency_list (field:regexp) = + [ key field . colon . [ label "and" . dependency ] + . [ label "and" . sep_comma_with_nl . dependency ]* + . eol ] + +(* source package *) +let uploaders = + multi_line_array_entry /Uploaders/ email + +let simple_src_keyword = "Source" | "Section" | "Priority" + | "Standards\-Version" | "Homepage" | /Vcs\-Svn/ | /Vcs\-Browser/ + | "Maintainer" | "DM-Upload-Allowed" | /XS?-Python-Version/ +let depend_src_keywords = /Build\-Depends/ | /Build\-Depends\-Indep/ + +let src_entries = ( simple_entry simple_src_keyword + | uploaders + | dependency_list depend_src_keywords ) * + + +(* package paragraph *) +let multi_line_entry (k:string) = + let line = /.*[^ \t\n].*/ in + [ label k . del / / " " . store line . hardeol ] * + + +let description + = [ key "Description" . colon + . [ label "summary" . store /[a-zA-Z][^\n]+/ . hardeol ] + . multi_line_entry "text" ] + + +(* binary package *) +let simple_bin_keywords = "Package" | "Architecture" | "Section" + | "Priority" | "Essential" | "Homepage" | "XB-Python-Version" +let depend_bin_keywords = "Depends" | "Recommends" | "Suggests" | "Provides" + +let bin_entries = ( simple_entry simple_bin_keywords + | dependency_list depend_bin_keywords + ) + . description + +(* The whole stuff *) +let lns = [ label "srcpkg" . src_entries ] + . [ label "binpkg" . hardeol+ . bin_entries ]+ + . eol* + +(* lens must be used with AUG_ROOT set to debian package source directory *) +let xfm = transform lns (incl "/control") diff --git a/Sharp.Augeas.Test/lens/desktop.aug b/Sharp.Augeas.Test/lens/desktop.aug new file mode 100644 index 0000000..b020f8e --- /dev/null +++ b/Sharp.Augeas.Test/lens/desktop.aug @@ -0,0 +1,53 @@ +(* +Module: Desktop + Desktop module for Augeas (.desktop files) + +Author: Raphael Pinson + +About: Lens Usage + This lens is made to provide a lens for .desktop files for augeas + +Reference: Freedesktop.org + http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. +*) + + +module Desktop = +(* We don't load this lens by default + Since a lot of desktop files contain unicode characters + which we can't parse *) +(* autoload xfm *) + +(* Comments can be only of # type *) +let comment = IniFile.comment "#" "#" + + +(* TITLE +* These represents sections of a desktop file +* Example : [DesktopEntry] +*) + +let title = IniFile.title IniFile.record_re + +let sep = IniFile.sep "=" "=" + +let setting = /[A-Za-z0-9_.-]+([][@A-Za-z0-9_.-]+)?/ + +(* Variable: sto_to_comment +Store until comment *) +let sto_to_comment = Sep.opt_space . store /[^# \t\r\n][^#\r\n]*[^# \t\r\n]|[^# \t\r\n]/ + +(* Entries can have comments at their end and so they are modified to represent as such *) +let entry = [ key setting . sep . sto_to_comment? . (comment|IniFile.eol) ] | comment + +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = ( incl "/usr/share/applications/*.desktop" + . incl "/usr/share/applications/screensavers/*.desktop" ) + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/devfsrules.aug b/Sharp.Augeas.Test/lens/devfsrules.aug new file mode 100644 index 0000000..155be76 --- /dev/null +++ b/Sharp.Augeas.Test/lens/devfsrules.aug @@ -0,0 +1,24 @@ +module DevfsRules = + + autoload xfm + + let comment = IniFile.comment IniFile.comment_re "#" + + let eol = Util.eol + + let line_re = /[^][#; \t\n][^#;\n]*[^#; \t\n]/ + let entry = [ seq "entry" . store line_re . (eol | comment) ] + + let title = Util.del_str "[" + . key Rx.word . [ label "id" . Sep.equal . store Rx.integer ] + . Util.del_str "]" . eol + . counter "entry" + + let record = IniFile.record title (entry | comment) + + let lns = IniFile.lns record comment + + let filter = incl "/etc/defaults/devfs.rules" + . incl "/etc/devfs.rules" + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/device_map.aug b/Sharp.Augeas.Test/lens/device_map.aug new file mode 100644 index 0000000..bd1825d --- /dev/null +++ b/Sharp.Augeas.Test/lens/device_map.aug @@ -0,0 +1,28 @@ +(* Parsing grub's device.map *) + +module Device_map = + autoload xfm + + let sep_tab = Sep.tab + let eol = Util.eol + let fspath = Rx.fspath + let del_str = Util.del_str + + let comment = Util.comment + let empty = Util.empty + + let dev_name = /(h|f|c)d[0-9]+(,[0-9a-zA-Z]+){0,2}/ + let dev_hex = Rx.hex + let dev_dec = /[0-9]+/ + + let device = del_str "(" . key ( dev_name | dev_hex | dev_dec ) . del_str ")" + + let map = [ device . sep_tab . store fspath . eol ] + + let lns = ( empty | comment | map ) * + + let xfm = transform lns (incl "/boot/*/device.map") + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/dhclient.aug b/Sharp.Augeas.Test/lens/dhclient.aug new file mode 100644 index 0000000..19e924c --- /dev/null +++ b/Sharp.Augeas.Test/lens/dhclient.aug @@ -0,0 +1,184 @@ +(* Intefraces module for Augeas + Author: Free Ekanayaka + + Reference: man dhclient.conf + The only difference with the reference syntax is that this lens assumes + that statements end with a new line, while the reference syntax allows + new statements to be started right after the trailing ";" of the + previous statement. This should not be a problem in real-life + configuration files as statements get usually split across several + lines, rather than merged in a single one. + +*) + +module Dhclient = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let comment = Util.comment +let comment_or_eol = Util.comment_or_eol +let empty = Util.empty + +(* Define separators *) +let sep_spc = del /[ \t\n]+/ " " +let sep_scl = del /[ \t]*;/ ";" +let sep_obr = del /[ \t\n]*\{\n]*/ " {\n" +let sep_cbr = del /[ \t\n]*\}/ " }" +let sep_com = del /[ \t\n]*,[ \t\n]*/ "," +let sep_slh = del "\/" "/" +let sep_col = del ":" ":" +let sep_eq = del /[ \t]*=[ \t]*/ "=" + +(* Define basic types *) +let word = /[A-Za-z0-9_.-]+(\[[0-9]+\])?/ + +(* Define fields *) + +(* TODO: there could be a " " in the middle of a value ... *) +let sto_to_spc = store /[^\\#,;{}" \t\n]+|"[^\\#"\n]+"/ +let sto_to_spc_noeval = store /[^=\\#,;{}" \t\n]|[^=\\#,;{}" \t\n][^\\#,;{}" \t\n]*|"[^\\#"\n]+"/ +let sto_to_scl = store /[^ \t\n][^;\n]+[^ \t]|[^ \t;\n]+/ +let rfc_code = [ key "code" . sep_spc . store word ] + . sep_eq + . [ label "value" . sto_to_scl ] +let eval = [ label "#eval" . Sep.equal . sep_spc . sto_to_scl ] +let sto_number = store /[0-9][0-9]*/ + +(************************************************************************ + * SIMPLE STATEMENTS + *************************************************************************) + +let stmt_simple_re = "timeout" + | "retry" + | "select-timeout" + | "reboot" + | "backoff-cutoff" + | "initial-interval" + | "do-forward-updates" + | "reject" + +let stmt_simple = [ key stmt_simple_re + . sep_spc + . sto_to_spc + . sep_scl + . comment_or_eol ] + + +(************************************************************************ + * ARRAY STATEMENTS + *************************************************************************) + +(* TODO: the array could also be empty, like in the request statement *) +let stmt_array_re = "media" + | "request" + | "require" + +let stmt_array = [ key stmt_array_re + . sep_spc + . counter "stmt_array" + . [ seq "stmt_array" . sto_to_spc ] + . [ sep_com . seq "stmt_array" . sto_to_spc ]* + . sep_scl . comment_or_eol ] + +(************************************************************************ + * HASH STATEMENTS + *************************************************************************) + + +let stmt_hash_re = "send" + | "option" + +let stmt_args = ( [ key word . sep_spc . sto_to_spc_noeval ] + | [ key word . sep_spc . (rfc_code|eval) ] ) + . sep_scl + . comment_or_eol + +let stmt_hash = [ key stmt_hash_re + . sep_spc + . stmt_args ] + +let stmt_opt_mod_re = "append" + | "prepend" + | "default" + | "supersede" + +let stmt_opt_mod = [ key stmt_opt_mod_re + . sep_spc + . stmt_args ] + +(************************************************************************ + * BLOCK STATEMENTS + *************************************************************************) + +let stmt_block_re = "interface" + | "lease" + | "alias" + +let stmt_block_opt_re = "interface" + | "script" + | "bootp" + | "fixed-address" + | "filename" + | "server-name" + | "medium" + | "vendor option space" + +(* TODO: some options could take no argument like bootp *) +let stmt_block_opt = [ key stmt_block_opt_re + . sep_spc + . sto_to_spc + . sep_scl + . comment_or_eol ] + +let stmt_block_date_re + = "renew" + | "rebind" + | "expire" + +let stmt_block_date = [ key stmt_block_date_re + . [ sep_spc . label "weekday" . sto_number ] + . [ sep_spc . label "year" . sto_number ] + . [ sep_slh . label "month" . sto_number ] + . [ sep_slh . label "day" . sto_number ] + . [ sep_spc . label "hour" . sto_number ] + . [ sep_col . label "minute" . sto_number ] + . [ sep_col . label "second" . sto_number ] + . sep_scl + . comment_or_eol ] + +let stmt_block_arg = sep_spc . sto_to_spc + +let stmt_block_entry = sep_spc + . ( stmt_array + | stmt_hash + | stmt_opt_mod + | stmt_block_opt + | stmt_block_date ) + +let stmt_block = [ key stmt_block_re + . stmt_block_arg? + . sep_obr + . stmt_block_entry+ + . sep_cbr + . comment_or_eol ] + +(************************************************************************ + * LENS & FILTER + *************************************************************************) + +let statement = (stmt_simple|stmt_opt_mod|stmt_array|stmt_hash|stmt_block) + +let lns = ( empty + | comment + | statement )* + +let filter = incl "/etc/dhcp3/dhclient.conf" + . incl "/etc/dhcp/dhclient.conf" + . incl "/etc/dhclient.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/dhcpd.aug b/Sharp.Augeas.Test/lens/dhcpd.aug new file mode 100644 index 0000000..f84a409 --- /dev/null +++ b/Sharp.Augeas.Test/lens/dhcpd.aug @@ -0,0 +1,518 @@ +(* +Module: Dhcpd + BIND dhcp 3 server configuration module for Augeas + +Author: Francis Giraldeau + +About: Reference + Reference: manual of dhcpd.conf and dhcp-eval + Follow dhclient module for tree structure + +About: License + This file is licensed under the GPL. + +About: Lens Usage + Sample usage of this lens in augtool + + Directive without argument. + Set this dhcpd server authoritative on the domain. + > clear /files/etc/dhcp3/dhcpd.conf/authoritative + + Directives with integer or string argument. + Set max-lease-time to one hour: + > set /files/etc/dhcp3/dhcpd.conf/max-lease-time 3600 + + Options are declared as a list, even for single values. + Set the domain of the network: + > set /files/etc/dhcp3/dhcpd.conf/option/domain-name/arg example.org + Set two name server: + > set /files/etc/dhcp3/dhcpd.conf/option/domain-name-servers/arg[1] foo.example.org + > set /files/etc/dhcp3/dhcpd.conf/option/domain-name-servers/arg[2] bar.example.org + + Create the subnet 172.16.0.1 with 10 addresses: + > clear /files/etc/dhcp3/dhcpd.conf/subnet[last() + 1] + > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/network 172.16.0.0 + > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/netmask 255.255.255.0 + > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/range/from 172.16.0.10 + > set /files/etc/dhcp3/dhcpd.conf/subnet[last()]/range/to 172.16.0.20 + + Create a new group "foo" with one static host. Nodes type and address are ordered. + > ins group after /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/*[last()] + > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[last()]/host foo + > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[host='foo']/host/hardware/type "ethernet" + > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[host='foo']/host/hardware/address "00:00:00:aa:bb:cc" + > set /files/etc/dhcp3/dhcpd.conf/subnet[network='172.16.0.0']/group[host='foo']/host/fixed-address 172.16.0.100 + +About: Configuration files + This lens applies to /etc/dhcpd3/dhcpd.conf. See . +*) + +module Dhcpd = + +autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) +let dels (s:string) = del s s +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty +let indent = Util.indent +let eos = comment? + +(* Define separators *) +let sep_spc = del /[ \t]+/ " " +let sep_osp = del /[ \t]*/ "" +let sep_scl = del /[ \t]*;([ \t]*\n)*/ ";\n" +let sep_obr = del /[ \t\n]*\{([ \t]*\n)*/ " {\n" +let sep_cbr = del /[ \t]*\}([ \t]*\n)*/ "}\n" +let sep_com = del /[ \t\n]*,[ \t\n]*/ ", " +let sep_slh = del "\/" "/" +let sep_col = del ":" ":" +let sep_eq = del /[ \t\n]*=[ \t\n]*/ "=" +let scl = del ";" ";" + +(* Define basic types *) +let word = /[A-Za-z0-9_.-]+(\[[0-9]+\])?/ +let ip = Rx.ipv4 + +(* Define fields *) + +(* adapted from sysconfig.aug *) + (* Chars allowed in a bare string *) + let bchar = /[^ \t\n"'\\{}#,()\/]|\\\\./ + let qchar = /["']/ (* " *) + + (* We split the handling of right hand sides into a few cases: + * bare - strings that contain no spaces, optionally enclosed in + * single or double quotes + * dquot - strings that contain at least one space, apostrophe or slash + * which must be enclosed in double quotes + * squot - strings that contain an unescaped double quote + *) + let bare = del qchar? "" . store (bchar+) . del qchar? "" + let quote = Quote.do_quote (store (bchar* . /[ \t'\/]/ . bchar*)+) + let dquote = Quote.do_dquote (store (bchar+)) + (* these two are for special cases. bare_to_scl is for any bareword that is + * space or semicolon terminated. dquote_any allows almost any character in + * between the quotes. *) + let bare_to_scl = Quote.do_dquote_opt (store /[^" \t\n;]+/) + let dquote_any = Quote.do_dquote (store /[^"\n]*[ \t]+[^"\n]*/) + +let sto_to_spc = store /[^\\#,;\{\}" \t\n]+|"[^\\#"\n]+"/ +let sto_to_scl = store /[^ \t;][^;\n=]+[^ \t;]|[^ \t;=]+/ + +let sto_number = store /[0-9][0-9]*/ + +(************************************************************************ + * NO ARG STATEMENTS + *************************************************************************) + +let stmt_noarg_re = "authoritative" + | "primary" + | "secondary" + +let stmt_noarg = [ indent + . key stmt_noarg_re + . sep_scl + . eos ] + +(************************************************************************ + * INT ARG STATEMENTS + *************************************************************************) + +let stmt_integer_re = "default-lease-time" + | "max-lease-time" + | "min-lease-time" + | /lease[ ]+limit/ + | "port" + | /peer[ ]+port/ + | "max-response-delay" + | "max-unacked-updates" + | "mclt" + | "split" + | /load[ ]+balance[ ]+max[ ]+seconds/ + | "max-lease-misbalance" + | "max-lease-ownership" + | "min-balance" + | "max-balance" + | "adaptive-lease-time-threshold" + | "dynamic-bootp-lease-length" + | "local-port" + | "min-sec" + | "omapi-port" + | "ping-timeout" + | "remote-port" + +let stmt_integer = [ indent + . key stmt_integer_re + . sep_spc + . sto_number + . sep_scl + . eos ] + +(************************************************************************ + * STRING ARG STATEMENTS + *************************************************************************) + +let stmt_string_re = "ddns-update-style" + | "ddns-updates" + | "ddns-hostname" + | "ddns-domainname" + | "ddns-rev-domainname" + | "log-facility" + | "server-name" + | "fixed-address" + | /failover[ ]+peer/ + | "use-host-decl-names" + | "next-server" + | "address" + | /peer[ ]+address/ + | "type" + | "file" + | "algorithm" + | "secret" + | "key" + | "include" + | "hba" + | "boot-unknown-clients" + | "db-time-format" + | "do-forward-updates" + | "dynamic-bootp-lease-cutoff" + | "get-lease-hostnames" + | "infinite-is-reserved" + | "lease-file-name" + | "local-address" + | "one-lease-per-client" + | "pid-file-name" + | "ping-check" + | "server-identifier" + | "site-option-space" + | "stash-agent-options" + | "update-conflict-detection" + | "update-optimization" + | "update-static-leases" + | "use-host-decl-names" + | "use-lease-addr-for-default-route" + | "vendor-option-space" + | "primary" + | "omapi-key" + +let stmt_string_tpl (kw:regexp) (l:lens) = [ indent + . key kw + . sep_spc + . l + . sep_scl + . eos ] + +let stmt_string = stmt_string_tpl stmt_string_re bare + | stmt_string_tpl stmt_string_re quote + | stmt_string_tpl "filename" dquote + +(************************************************************************ + * RANGE STATEMENTS + *************************************************************************) + +let stmt_range = [ indent + . key "range" + . sep_spc + . [ label "flag" . store /dynamic-bootp/ . sep_spc ]? + . [ label "from" . store ip . sep_spc ]? + . [ label "to" . store ip ] + . sep_scl + . eos ] + +(************************************************************************ + * HARDWARE STATEMENTS + *************************************************************************) + +let stmt_hardware = [ indent + . key "hardware" + . sep_spc + . [ label "type" . store /ethernet|tokenring|fddi/ ] + . sep_spc + . [ label "address" . store /[a-fA-F0-9:-]+/ ] + . sep_scl + . eos ] + +(************************************************************************ + * SET STATEMENTS + *************************************************************************) +let stmt_set = [ indent + . key "set" + . sep_spc + . store word + . sep_spc + . Sep.equal + . sep_spc + . [ label "value" . sto_to_scl ] + . sep_scl + . eos ] + +(************************************************************************ + * OPTION STATEMENTS + *************************************************************************) +(* The general case is considering options as a list *) + + +let stmt_option_value = /((array of[ \t]+)?(((un)?signed[ \t]+)?integer (8|16|32)|string|ip6?-address|boolean|domain-list|text)|encapsulate [A-Za-z0-9_.-]+)/ + +let stmt_option_list = ([ label "arg" . bare ] | [ label "arg" . quote ]) + . ( sep_com . ([ label "arg" . bare ] | [ label "arg" . quote ]))* + +let del_trail_spc = del /[ \t\n]*/ "" + +let stmt_record = counter "record" . Util.del_str "{" + . sep_spc + . ([seq "record" . store stmt_option_value . sep_com]* + . [seq "record" . store stmt_option_value . del_trail_spc])? + . Util.del_str "}" + +let stmt_option_code = [ label "label" . store word . sep_spc ] + . [ key "code" . sep_spc . store word ] + . sep_eq + . ([ label "type" . store stmt_option_value ] + |[ label "record" . stmt_record ]) + +let stmt_option_basic = [ key word . sep_spc . stmt_option_list ] +let stmt_option_extra = [ key word . sep_spc . store /true|false/ . sep_spc . stmt_option_list ] + +let stmt_option_body = stmt_option_basic | stmt_option_extra + +let stmt_option1 = [ indent + . key "option" + . sep_spc + . stmt_option_body + . sep_scl + . eos ] + +let stmt_option2 = [ indent + . dels "option" . label "rfc-code" + . sep_spc + . stmt_option_code + . sep_scl + . eos ] + +let stmt_option = stmt_option1 | stmt_option2 + +(************************************************************************ + * SUBCLASS STATEMENTS + *************************************************************************) +(* this statement is not well documented in the manual dhcpd.conf + we support basic use case *) + +let stmt_subclass = [ indent . key "subclass" . sep_spc + . ( [ label "name" . bare_to_scl ]|[ label "name" . dquote_any ] ) + . sep_spc + . ( [ label "value" . bare_to_scl ]|[ label "value" . dquote_any ] ) + . sep_scl + . eos ] + + +(************************************************************************ + * ALLOW/DENY STATEMENTS + *************************************************************************) +(* We have to use special key for allow/deny members of + to avoid ambiguity in the put direction *) + +let allow_deny_re = /unknown(-|[ ]+)clients/ + | /known(-|[ ]+)clients/ + | /all[ ]+clients/ + | /dynamic[ ]+bootp[ ]+clients/ + | /authenticated[ ]+clients/ + | /unauthenticated[ ]+clients/ + | "bootp" + | "booting" + | "duplicates" + | "declines" + | "client-updates" + | "leasequery" + +let stmt_secu_re = "allow" + | "deny" + +let del_allow = del /allow[ ]+members[ ]+of/ "allow members of" +let del_deny = del /deny[ \t]+members[ \t]+of/ "deny members of" + +(* bare is anything but whitespace, quote marks or semicolon. + * technically this should be locked down to mostly alphanumerics, but the + * idea right now is just to make things work. Also ideally I would use + * dquote_space but I had a whale of a time with it. It doesn't like + * semicolon termination and my attempts to fix that led me to 3 hours of + * frustration and back to this :) + *) +let stmt_secu_tpl (l:lens) (s:string) = + [ indent . l . sep_spc . label s . bare_to_scl . sep_scl . eos ] | + [ indent . l . sep_spc . label s . dquote_any . sep_scl . eos ] + + +let stmt_secu = [ indent . key stmt_secu_re . sep_spc . + store allow_deny_re . sep_scl . eos ] | + stmt_secu_tpl del_allow "allow-members-of" | + stmt_secu_tpl del_deny "deny-members-of" + +(************************************************************************ + * MATCH STATEMENTS + *************************************************************************) + +let sto_com = /[^ \t\n,\(\)][^,\(\)]*[^ \t\n,\(\)]|[^ \t\n,\(\)]+/ | word . /[ \t]*\([^)]*\)/ +(* this is already the most complicated part of this module and it's about to + * get worse. match statements can be way more complicated than this + * + * examples: + * using or: + * match if ((option vendor-class-identifier="Banana Bready") or (option vendor-class-identifier="Cherry Sunfire")); + * unneeded parenthesis: + * match if (option vendor-class-identifier="Hello"); + * + * and of course the fact that the above two rules used one of infinately + * many potential options instead of a builtin function. + *) +(* sto_com doesn't support quoted strings as arguments. It also doesn't + support single arguments (needs to match a comma) It will need to be + updated for lcase, ucase and log to be workable. + + it also doesn't support no arguments, so gethostbyname() doesn't work. + + option and config-option are considered operators. They should be matched + in stmt_entry but also available under "match if" and "if" conditionals + leased-address, host-decl-name, both take no args and return a value. We + might need to treat them as variable names in the parser. + + things like this may be near-impossible to parse even with recursion + because we have no way of knowing when or if a subfunction takes arguments + set ClientMac = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)); + + even if we could parse it, they could get arbitrarily complicated like: + binary-to-ascii(16, 8, ":", substring(hardware, 1, 6) and substring(hardware, 2, 3)); + + so at some point we may need to programmatically knock it off and tell + people to put weird stuff in an include file that augeas doesn't parse. + + the other option is to change the API to not parse the if statement at all, + just pull in the conditional as a string. + *) + +let fct_re = "substring" | "binary-to-ascii" | "suffix" | "lcase" | "ucase" + | "gethostbyname" | "packet" + | "concat" | "reverse" | "encode-int" + | "extract-int" | "lease-time" | "client-state" | "exists" | "known" | "static" + | "pick-first-value" | "log" | "execute" + +(* not needs to be different because it's a negation of whatever happens next *) +let op_re = "~="|"="|"~~"|"and"|"or" + +let fct_args = [ label "args" . dels "(" . sep_osp . + ([ label "arg" . store sto_com ] . [ label "arg" . sep_com . store sto_com ]+) . + sep_osp . dels ")" ] + +let stmt_match_ifopt = [ dels "if" . sep_spc . key "option" . sep_spc . store word . + sep_eq . ([ label "value" . bare_to_scl ]|[ label "value" . dquote_any ]) ] + +let stmt_match_func = [ store fct_re . sep_osp . label "function" . fct_args ] . + sep_eq . ([ label "value" . bare_to_scl ]|[ label "value" . dquote_any ]) + +let stmt_match_pfv = [ label "function" . store "pick-first-value" . sep_spc . + dels "(" . sep_osp . + [ label "args" . + [ label "arg" . store sto_com ] . + [ sep_com . label "arg" . store sto_com ]+ ] . + dels ")" ] + +let stmt_match_tpl (l:lens) = [ indent . key "match" . sep_spc . l . sep_scl . eos ] + +let stmt_match = stmt_match_tpl (dels "if" . sep_spc . stmt_match_func | stmt_match_pfv | stmt_match_ifopt) + +(************************************************************************ + * BLOCK STATEMENTS + *************************************************************************) +(* Blocks doesn't support comments at the end of the closing bracket *) + +let stmt_entry = stmt_secu + | stmt_option + | stmt_hardware + | stmt_range + | stmt_string + | stmt_integer + | stmt_noarg + | stmt_match + | stmt_subclass + | stmt_set + | empty + | comment + +let stmt_block_noarg_re = "pool" | "group" + +let stmt_block_noarg (body:lens) + = [ indent + . key stmt_block_noarg_re + . sep_obr + . body* + . sep_cbr ] + +let stmt_block_arg_re = "host" + | "class" + | "shared-network" + | /failover[ ]+peer/ + | "zone" + | "group" + | "on" + +let stmt_block_arg (body:lens) + = ([ indent . key stmt_block_arg_re . sep_spc . dquote_any . sep_obr . body* . sep_cbr ] + |[ indent . key stmt_block_arg_re . sep_spc . bare_to_scl . sep_obr . body* . sep_cbr ] + |[ indent . del /key/ "key" . label "key_block" . sep_spc . dquote_any . sep_obr . body* . sep_cbr . del /(;([ \t]*\n)*)?/ "" ] + |[ indent . del /key/ "key" . label "key_block" . sep_spc . bare_to_scl . sep_obr . body* . sep_cbr . del /(;([ \t]*\n)*)?/ "" ]) + +let stmt_block_subnet (body:lens) + = [ indent + . key "subnet" + . sep_spc + . [ label "network" . store ip ] + . sep_spc + . [ key "netmask" . sep_spc . store ip ] + . sep_obr + . body* + . sep_cbr ] + +let conditional (body:lens) = + let condition = /[^{ \r\t\n][^{\n]*[^{ \r\t\n]|[^{ \t\n\r]/ + in let elsif = [ indent + . Build.xchgs "elsif" "@elsif" + . sep_spc + . store condition + . sep_obr + . body* + . sep_cbr ] + in let else = [ indent + . Build.xchgs "else" "@else" + . sep_obr + . body* + . sep_cbr ] + in [ indent + . Build.xchgs "if" "@if" + . sep_spc + . store condition + . sep_obr + . body* + . sep_cbr + . elsif* + . else? ] + + +let all_block (body:lens) = + let lns1 = stmt_block_subnet body in + let lns2 = stmt_block_arg body in + let lns3 = stmt_block_noarg body in + let lns4 = conditional body in + (lns1 | lns2 | lns3 | lns4 | stmt_entry) + +let rec lns_staging = stmt_entry|all_block lns_staging +let lns = (lns_staging)* + +let filter = incl "/etc/dhcp3/dhcpd.conf" + . incl "/etc/dhcp/dhcpd.conf" + . incl "/etc/dhcpd.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/dns_zone.aug b/Sharp.Augeas.Test/lens/dns_zone.aug new file mode 100644 index 0000000..4db194c --- /dev/null +++ b/Sharp.Augeas.Test/lens/dns_zone.aug @@ -0,0 +1,113 @@ +(* +Module: Dns_Zone + Lens for parsing DNS zone files + +Authors: + Kaarle Ritvanen + +About: Reference + RFC 1035, RFC 2782, RFC 3403 + +About: License + This file is licensed under the LGPL v2+ +*) + +module Dns_Zone = + +autoload xfm + +let eol = del /([ \t\n]*(;[^\n]*)?\n)+/ "\n" +let opt_eol = del /([ \t\n]*(;[^\n]*)?\n)*/ "" + +let ws = del /[ \t]+|(([ \t\n]*;[^\n]*)?\n)+[ \t]*/ " " +let opt_ws = del /(([ \t\n]*;[^\n]*)?\n)*[ \t]*/ "" + +let token = /([^ \t\n";()\\]|\\\\.)+|"([^"\\]|\\\\.)*"/ + + +let control = [ key /\$[^ \t\n\/]+/ + . Util.del_ws_tab + . store token + . eol ] + + +let labeled_token (lbl:string) (re:regexp) (sep:lens) = + [ label lbl . store re . sep ] + +let regexp_token (lbl:string) (re:regexp) = + labeled_token lbl re Util.del_ws_tab + +let type_token (re:regexp) = regexp_token "type" re + +let simple_token (lbl:string) = regexp_token lbl token + +let enclosed_token (lbl:string) = labeled_token lbl token ws + +let last_token (lbl:string) = labeled_token lbl token eol + + +let class_re = /IN/ + +let ttl = regexp_token "ttl" /[0-9]+[DHMWdhmw]?/ +let class = regexp_token "class" class_re + +let rr = + let simple_type = /[A-Z]+/ - class_re - /MX|NAPTR|SOA|SRV/ + in type_token simple_type . last_token "rdata" + + +let mx = type_token "MX" + . simple_token "priority" + . last_token "exchange" + +let naptr = type_token "NAPTR" + . simple_token "order" + . simple_token "preference" + . simple_token "flags" + . simple_token "service" + . simple_token "regexp" + . last_token "replacement" + +let soa = type_token "SOA" + . simple_token "mname" + . simple_token "rname" + . Util.del_str "(" + . opt_ws + . enclosed_token "serial" + . enclosed_token "refresh" + . enclosed_token "retry" + . enclosed_token "expiry" + . labeled_token "minimum" token opt_ws + . Util.del_str ")" + . eol + +let srv = type_token "SRV" + . simple_token "priority" + . simple_token "weight" + . simple_token "port" + . last_token "target" + + +let record = seq "owner" + . ((ttl? . class?) | (class . ttl)) + . (rr|mx|naptr|soa|srv) +let ws_record = [ Util.del_ws_tab . record ] +let records (k:regexp) = [ key k . counter "owner" . ws_record+ ] + +let any_record_block = records /[^ \t\n;\/$][^ \t\n;\/]*/ +let non_root_records = records /@[^ \t\n;\/]+|[^ \t\n;\/$@][^ \t\n;\/]*/ + +let root_records = [ del /@?/ "@" + . Util.del_ws_tab + . label "@" + . counter "owner" + . [ record ] + . ws_record* ] + +let lns = opt_eol + . control* + . ( (root_records|non_root_records) + . (control|any_record_block)* )? + +let filter = incl "/var/bind/pri/*.zone" +let xfm = transform Dns_Zone.lns filter diff --git a/Sharp.Augeas.Test/lens/dnsmasq.aug b/Sharp.Augeas.Test/lens/dnsmasq.aug new file mode 100644 index 0000000..f7ef907 --- /dev/null +++ b/Sharp.Augeas.Test/lens/dnsmasq.aug @@ -0,0 +1,62 @@ +(* Dnsmasq module for Augeas + Author: Free Ekanayaka + + Reference: man dnsmasq (8) + + "Format is one option per line, legal options are the same + as the long options legal on the command line. See + "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details." + +*) + +module Dnsmasq = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let spc = Util.del_ws_spc +let comment = Util.comment +let empty = Util.empty + +let sep_eq = Sep.equal +let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + +let slash = Util.del_str "/" +let sto_no_slash = store /([^\/ \t\n]+)/ +let domains = slash . [ label "domain" . sto_no_slash . slash ]+ + +(************************************************************************ + * SIMPLE ENTRIES + *************************************************************************) + +let entry_re = Rx.word - /(address|server)/ +let entry = [ key entry_re . (sep_eq . sto_to_eol)? . eol ] + +(************************************************************************ + * STRUCTURED ENTRIES + *************************************************************************) + +let address = [ key "address" . sep_eq . domains . sto_no_slash . eol ] + +let server = + let port = [ Build.xchgs "#" "port" . store Rx.integer ] + in let source = [ Build.xchgs "@" "source" . store /[^#\/ \t\n]+/ . port? ] + in let srv_spec = store /(#|([^#@\/ \t\n]+))/ . port? . source? + in [ key "server" . sep_eq . domains? . srv_spec? . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|address|server|entry) * + +let filter = incl "/etc/dnsmasq.conf" + . incl "/etc/dnsmasq.d/*" + . excl ".*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/dovecot.aug b/Sharp.Augeas.Test/lens/dovecot.aug new file mode 100644 index 0000000..4a25a83 --- /dev/null +++ b/Sharp.Augeas.Test/lens/dovecot.aug @@ -0,0 +1,135 @@ +(* +Module: Dovecot + Parses dovecot configuration files. + +Author: Serge Smetana + Acunote http://www.acunote.com + Pluron, Inc. http://pluron.com + +About: License + This file is licensed under the LGPL v2+. + +About: Configuration files + This lens applies to /etc/dovecot/dovecot.conf and files in + /etc/dovecot/conf.d/. See . + +About: Examples + The file contains various examples and tests. + +About: TODO + Support for multiline values like queries in dict-sql.conf +*) + +module Dovecot = + + autoload xfm + +(****************************************************************** + * Group: USEFUL PRIMITIVES + ******************************************************************) + +(* View: indent *) +let indent = Util.indent + +(* View: eol *) +let eol = Util.eol + +(* View: empty +Map empty lines. *) +let empty = Util.empty + +(* View: comment +Map comments in "#comment" nodes. *) +let comment = Util.comment + +(* View: eq *) +let eq = del /[ \t]*=/ " =" + +(* Variable: any *) +let any = Rx.no_spaces + +(* Variable: value +Match any value after " =". +Should not start and end with spaces. May contain spaces inside *) +let value = any . (Rx.space . any)* + +(* View: command_start *) +let command_start = Util.del_str "!" + + +(****************************************************************** + * Group: ENTRIES + ******************************************************************) + +(* Variable: commands *) +let commands = /include|include_try/ + +(* Variable: block_names *) +let block_names = /dict|userdb|passdb|protocol|service|plugin|namespace|map|fields|unix_listener|fifo_listener|inet_listener/ + +(* Variable: keys +Match any possible key except commands and block names. *) +let keys = Rx.word - (commands | block_names) + +(* View: entry +Map simple "key = value" entries including "key =" entries with empty value. *) +let entry = [ indent . key keys. eq . (Sep.opt_space . store value)? . eol ] + +(* View: command +Map commands started with "!". *) +let command = [ command_start . key commands . Sep.space . store Rx.fspath . eol ] + +(* +View: dquote_spaces + Make double quotes mandatory if value contains spaces, + and optional if value doesn't contain spaces. + +Based off Quote.dquote_spaces + +Parameters: + lns1:lens - the lens before + lns2:lens - the lens after +*) +let dquote_spaces (lns1:lens) (lns2:lens) = + (* bare has no spaces, and is optionally quoted *) + let bare = Quote.do_dquote_opt (store /[^" \t\n]+/) + (* quoted has at least one space, and must be quoted *) + in let quoted = Quote.do_dquote (store /[^"\n]*[ \t]+[^"\n]*/) + in [ lns1 . bare . lns2 ] | [ lns1 . quoted . lns2 ] + +let mailbox = indent + . dquote_spaces + (key /mailbox/ . Sep.space) + (Build.block_newlines_spc entry comment . eol) + +let block_ldelim_newlines_re = /[ \t]+\{([ \t\n]*\n)?/ + +let block_newlines (entry:lens) (comment:lens) = + let indent = del Rx.opt_space "\t" + in del block_ldelim_newlines_re Build.block_ldelim_default + . ((entry | comment) . (Util.empty | entry | comment)*)? + . del Build.block_rdelim_newlines_re Build.block_rdelim_newlines_default + +(* View: block +Map block enclosed in brackets recursively. +Block may be indented and have optional argument. +Block body may have entries, comments, empty lines, and nested blocks recursively. *) +let rec block = [ indent . key block_names . (Sep.space . Quote.do_dquote_opt (store /!?[\/A-Za-z0-9_-]+/))? . block_newlines (entry|block|mailbox) comment . eol ] + + +(****************************************************************** + * Group: LENS AND FILTER + ******************************************************************) + +(* View: lns +The Dovecot lens *) +let lns = (comment|empty|entry|command|block)* + +(* Variable: filter *) +let filter = incl "/etc/dovecot/dovecot.conf" + . (incl "/etc/dovecot/conf.d/*.conf") + . incl "/usr/local/etc/dovecot/dovecot.conf" + . (incl "/usr/local/etc/dovecot/conf.d/*.conf") + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/dpkg.aug b/Sharp.Augeas.Test/lens/dpkg.aug new file mode 100644 index 0000000..15cbe04 --- /dev/null +++ b/Sharp.Augeas.Test/lens/dpkg.aug @@ -0,0 +1,91 @@ +(* +Module: Dpkg + Parses /etc/dpkg/dpkg.cfg + +Author: Robin Lee Powell + +About: License + This file, and the attendant test_dpgk.aug, are explicitly + placed in the public domain. + +About: Description + dpkg.cfg is a simple list of options, the same ones as the + command line options, with or without a value. + + The tree is a list of either comments or option/value pairs by + name. Use "set" to set an option with a value, and "clear" for a + bare option. + +About: Usage Example + +(start code) + $ augtool -n + augtool> ls /files/etc/dpkg/dpkg.cfg + #comment[1] = dpkg configuration file + #comment[2] = This file can contain default options for dpkg. All command-line + #comment[3] = options are allowed. Values can be specified by putting them after + #comment[4] = the option, separated by whitespace and/or an `=' sign. + #comment[5] = Do not enable debsig-verify by default; since the distribution is not using + #comment[6] = embedded signatures, debsig-verify would reject all packages. + no-debsig = (none) + #comment[7] = Log status changes and actions to a file. + log = /var/log/dpkg.log + augtool> get /files/etc/dpkg/dpkg.cfg/no-debsig + /files/etc/dpkg/dpkg.cfg/no-debsig (none) + augtool> get /files/etc/dpkg/dpkg.cfg/log + /files/etc/dpkg/dpkg.cfg/log = /var/log/dpkg.log + augtool> clear /files/etc/dpkg/dpkg.cfg/testopt + augtool> set /files/etc/dpkg/dpkg.cfg/testopt2 test + augtool> save + Saved 1 file(s) + augtool> + $ cat /etc/dpkg/dpkg.cfg.augnew + # dpkg configuration file + # + # This file can contain default options for dpkg. All command-line + # options are allowed. Values can be specified by putting them after + # the option, separated by whitespace and/or an `=' sign. + # + + # Do not enable debsig-verify by default; since the distribution is not using + # embedded signatures, debsig-verify would reject all packages. + no-debsig + + # Log status changes and actions to a file. + log /var/log/dpkg.log + testopt + testopt2 test +(end code) + +*) + +module Dpkg = + autoload xfm + + let sep_tab = Util.del_ws_tab + let sep_spc = Util.del_ws_spc + let eol = del /[ \t]*\n/ "\n" + + let comment = Util.comment + let empty = Util.empty + + let word = /[^,# \n\t]+/ + let keyword = /[^,# \n\t\/]+/ + + (* View: record + Keyword, followed by optional whitespace and value, followed + by EOL. + + The actual file specification doesn't require EOL, but the + likelihood of the file not having one is pretty slim, and + this way things we add have EOL. + *) + + let record = [ key keyword . (sep_spc . store word)? . eol ] + + (* View: lns + Any number of empty lines, comments, and records. + *) + let lns = ( empty | comment | record ) * + + let xfm = transform lns (incl "/etc/dpkg/dpkg.cfg") diff --git a/Sharp.Augeas.Test/lens/dput.aug b/Sharp.Augeas.Test/lens/dput.aug new file mode 100644 index 0000000..a0867cc --- /dev/null +++ b/Sharp.Augeas.Test/lens/dput.aug @@ -0,0 +1,68 @@ +(* Dput module for Augeas + Author: Raphael Pinson + + + Reference: dput uses Python's ConfigParser: + http://docs.python.org/lib/module-ConfigParser.html +*) + + +module Dput = + autoload xfm + + +(************************************************************************ + * INI File settings + *************************************************************************) +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default + + +let setting = "allow_dcut" + | "allow_non-us_software" + | "allow_unsigned_uploads" + | "check_version" + | "default_host_main" + | "default_host_non-us" + | "fqdn" + | "hash" + | "incoming" + | "login" + | "method" + | "passive_ftp" + | "post_upload_command" + | "pre_upload_command" + | "progress_indicator" + | "run_dinstall" + | "run_lintian" + | "scp_compress" + | "ssh_config_options" + | "allowed_distributions" + +(************************************************************************ + * "name: value" entries, with continuations in the style of RFC 822; + * "name=value" is also accepted + * leading whitespace is removed from values + *************************************************************************) +let entry = IniFile.entry setting sep comment + + +(************************************************************************ + * sections, led by a "[section]" header + * We can't use titles as node names here since they could contain "/" + * We remove #comment from possible keys + * since it is used as label for comments + * We also remove / as first character + * because augeas doesn't like '/' keys (although it is legal in INI Files) + *************************************************************************) +let title = IniFile.title_label "target" IniFile.record_label_re +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = (incl "/etc/dput.cf") + . (incl (Sys.getenv("HOME") . "/.dput.cf")) + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/erlang.aug b/Sharp.Augeas.Test/lens/erlang.aug new file mode 100644 index 0000000..d219f50 --- /dev/null +++ b/Sharp.Augeas.Test/lens/erlang.aug @@ -0,0 +1,196 @@ +(* +Module: Erlang + Parses Erlang configuration files + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `http://www.erlang.org/doc/man/config.html` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to Erlang configuration files. See . + +About: Examples + The file contains various examples and tests. +*) +module Erlang = + + +(* Group: Spacing Functions *) + +(* View: space *) +let space = del /[ \t\n]*/ "" + +(* View: lspace + Add spaces to the left of char *) +let lspace (char:string) = del (/[ \t\n]*/ . char) char + +(* View: rspace + Add spaces to the right of char *) +let rspace (char:string) = del (char . /[ \t\n]*/ ) char + +(* View: lrspace + Add spaces to the left or right of char *) +let lrspace (char:string) = del (/[ \t\n]*/ . char . /[ \t\n]*/ ) char + + +(* Group: Separators *) + +(* Variable: lbrace + Left square bracket *) +let lbrace = "{" + +(* Variable: rbrace + Right square bracket *) +let rbrace = "}" + +(* Variable: lbrack + Left curly brackets *) +let lbrack = "[" + +(* Variable: rbrack + Right curly brackets *) +let rbrack = "]" + +(* Variable: lglob + Left glob separator *) +let lglob = "<<\"" + +(* Variable: rglob + Right glob separator *) +let rglob = "\">>" + +(* Variable: comma *) +let comma = "," + + +(* Group: Value types *) + +(* View: opt_list + An optional list of elements, in square brackets *) +let opt_list (lns:lens) = rspace lbrack + . (Build.opt_list lns (lrspace comma) . space)? + . Util.del_str rbrack + +(* View: integer + Store a *) +let integer = store Rx.integer + +(* View: decimal + Store a decimal value *) +let decimal = store /[0-9]+(.[0-9]+)?/ + +(* View: quoted + Store a quoted value *) +let quoted = Quote.do_quote (store /[^,\n}{]+/) + +(* View: bare + Store a bare *) +let bare = store Rx.word + +(* View: boolean + Store a boolean value *) +let boolean = store /true|false/ + +(* View: path + Store a path () *) +let path = quoted + +(* View: glob + Store a glob *) +let glob = Util.del_str lglob . store /[^\n"]+/ . Util.del_str rglob + +(* View: make_value + Make a "value" subnode for arrays/tuples *) +let make_value (lns:lens) = [ label "value" . lns ] + + +(* Group: Store types *) + +(* View: value + A single value *) +let value (kw:regexp) (sto:lens) = + [ rspace lbrace + . key kw + . lrspace comma + . sto + . lspace rbrace ] + +(* View: tuple + A tuple of values *) +let tuple (one:lens) (two:lens) = + [ rspace lbrace + . label "tuple" + . [ label "value" . one ] + . lrspace comma + . [ label "value" . two ] + . lspace rbrace ] + +(* View: tuple3 + A tuple of 3 values *) +let tuple3 (one:lens) (two:lens) (three:lens) = + [ rspace lbrace + . label "tuple" + . [ label "value" . one ] + . lrspace comma + . [ label "value" . two ] + . lrspace comma + . [ label "value" . three ] + . lspace rbrace ] + +(* View: list + A list of lenses *) +let list (kw:regexp) (lns:lens) = + [ rspace lbrace + . key kw + . lrspace comma + . opt_list lns + . lspace rbrace ] + +(* View: value_list + A of seq entries *) +let value_list (kw:regexp) (sto:lens) = + list kw (make_value sto) + +(* View: application *) +let application (name:regexp) (parameter:lens) = + list name parameter + +(* View: kernel_parameters + Config parameters accepted for kernel app *) +let kernel_parameters = + value "browser_cmd" path + | value "dist_auto_connect" (store /never|once/) + | value "error_logger" (store /tty|false|silent/) + | value "net_setuptime" integer + | value "net_ticktime" integer + | value "shutdown_timeout" integer + | value "sync_nodes_timeout" integer + | value "start_dist_ac" boolean + | value "start_boot_server" boolean + | value "start_disk_log" boolean + | value "start_pg2" boolean + | value "start_timer" boolean + +(* View: kernel + Core Erlang kernel app configuration *) +let kernel = application "kernel" kernel_parameters + +(* View: comment *) +let comment = Util.comment_generic /%[ \t]*/ "% " + +(* View: config + A top-level config *) +let config (app:lens) = + (Util.empty | comment)* + . rspace lbrack + . Build.opt_list (kernel | app) (lrspace comma) + . lrspace rbrack + . Util.del_str "." . Util.eol + . (Util.empty | comment)* diff --git a/Sharp.Augeas.Test/lens/ethers.aug b/Sharp.Augeas.Test/lens/ethers.aug new file mode 100644 index 0000000..9cb633b --- /dev/null +++ b/Sharp.Augeas.Test/lens/ethers.aug @@ -0,0 +1,25 @@ +(* Parsing /etc/ethers *) + +module Ethers = + autoload xfm + + let sep_tab = Util.del_ws_tab + + let eol = del /[ \t]*\n/ "\n" + let indent = del /[ \t]*/ "" + + let comment = Util.comment + let empty = [ del /[ \t]*#?[ \t]*\n/ "\n" ] + + let word = /[^# \n\t]+/ + let address = + let hex = /[0-9a-fA-F][0-9a-fA-F]?/ in + hex . ":" . hex . ":" . hex . ":" . hex . ":" . hex . ":" . hex + + let record = [ seq "ether" . indent . + [ label "mac" . store address ] . sep_tab . + [ label "ip" . store word ] . eol ] + + let lns = ( empty | comment | record ) * + + let xfm = transform lns (incl "/etc/ethers") diff --git a/Sharp.Augeas.Test/lens/exports.aug b/Sharp.Augeas.Test/lens/exports.aug new file mode 100644 index 0000000..3841480 --- /dev/null +++ b/Sharp.Augeas.Test/lens/exports.aug @@ -0,0 +1,98 @@ +(* Lens for Linux syntax of NFS exports(5) *) + +(* +Module: Exports + Parses /etc/exports + +Author: David Lutterkort + +About: Description + /etc/exports contains lines associating a directory with one or + more hosts, and NFS options for each host. + +About: Usage Example + +(start code) + + $ augtool + augtool> ls /files/etc/exports/ + comment[1] = /etc/exports: the access control list for filesystems which may be exported + comment[2] = to NFS clients. See exports(5). + comment[3] = sample /etc/exports file + dir[1]/ = / + dir[2]/ = /projects + dir[3]/ = /usr + dir[4]/ = /home/joe + + + augtool> ls /files/etc/exports/dir[1] + client[1]/ = master + client[2]/ = trusty +(end code) + +The corresponding line in the file is: + +(start code) + / master(rw) trusty(rw,no_root_squash) +(end code) + + Digging further: + +(start code) + augtool> ls /files/etc/exports/dir[1]/client[1] + option = rw + + To add a new entry, you'd do something like this: +(end code) + +(start code) + augtool> set /files/etc/exports/dir[10000] /foo + augtool> set /files/etc/exports/dir[last()]/client[1] weeble + augtool> set /files/etc/exports/dir[last()]/client[1]/option[1] ro + augtool> set /files/etc/exports/dir[last()]/client[1]/option[2] all_squash + augtool> save + Saved 1 file(s) +(end code) + + Which creates the line: + +(start code) + /foo weeble(ro,all_squash) +(end code) + +About: Limitations + This lens cannot handle options without a host, as with the last + example line in "man 5 exports": + + /pub (ro,insecure,all_squash) + + In this case, though, you can just do: + + /pub *(ro,insecure,all_squash) + + It also can't handle whitespace before the directory name. +*) + +module Exports = + autoload xfm + + let client_re = /[][a-zA-Z0-9.@*?\/:-]+/ + + let eol = Util.eol + let lbracket = Util.del_str "(" + let rbracket = Util.del_str ")" + let sep_com = Sep.comma + let sep_spc = Sep.space + + let option = [ label "option" . store /[^,)]*/ ] + + let client = [ label "client" . store client_re . + ( Build.brackets lbracket rbracket + ( Build.opt_list option sep_com ) )? ] + + let entry = [ label "dir" . store /[^ \t\n#]*/ + . sep_spc . Build.opt_list client sep_spc . eol ] + + let lns = (Util.empty | Util.comment | entry)* + + let xfm = transform lns (incl "/etc/exports") diff --git a/Sharp.Augeas.Test/lens/fai_diskconfig.aug b/Sharp.Augeas.Test/lens/fai_diskconfig.aug new file mode 100644 index 0000000..a87de30 --- /dev/null +++ b/Sharp.Augeas.Test/lens/fai_diskconfig.aug @@ -0,0 +1,286 @@ +(* +Module: FAI_DiskConfig + Parses disk_config files for FAI + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to the FAI wiki where possible: + http://wiki.fai-project.org/wiki/Setup-storage#New_configuration_file_syntax + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Examples + The file contains various examples and tests. +*) + +module FAI_DiskConfig = + +(* autoload xfm *) + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Generic primitives *) +(* Variable: eol *) +let eol = Util.eol + +(* Variable: space *) +let space = Sep.space + +(* Variable: empty *) +let empty = Util.empty + +(* Variable: comment *) +let comment = Util.comment + +(* Variable: tag + A generic tag beginning with a colon *) +let tag (re:regexp) = [ Util.del_str ":" . key re ] + +(* Variable: generic_opt + A generic key/value option *) +let generic_opt (type:string) (kw:regexp) = + [ key type . Util.del_str ":" . store kw ] + +(* Variable: generic_opt_list + A generic key/list option *) +let generic_opt_list (type:string) (kw:regexp) = + [ key type . Util.del_str ":" . counter "locallist" + . Build.opt_list [seq "locallist" . store kw] Sep.comma ] + + +(************************************************************************ + * Group: RECORDS + *************************************************************************) + + +(* Group: volume *) + +(* Variable: mountpoint_kw *) +let mountpoint_kw = "-" (* do not mount *) + | "swap" (* swap space *) + (* fully qualified path; if :encrypt is given, the partition + * will be encrypted, the key is generated automatically *) + | /\/[^: \t\n]*/ + +(* Variable: encrypt + encrypt tag *) +let encrypt = tag "encrypt" + +(* Variable: mountpoint *) +let mountpoint = [ label "mountpoint" . store mountpoint_kw + (* encrypt is only for the fspath, but we parse it anyway *) + . encrypt?] + +(* Variable: resize + resize tag *) +let resize = tag "resize" + +(* Variable: size_kw + Regexps for size *) +let size_kw = /[0-9]+[kMGTP%]?(-([0-9]+[kMGTP%]?)?)?/ + | /-[0-9]+[kMGTP%]?/ + +(* Variable: size *) +let size = [ label "size" . store size_kw . resize? ] + +(* Variable: filesystem_kw + Regexps for filesystem *) +let filesystem_kw = "-" + | "swap" + (* NOTE: Restraining this regexp would improve perfs *) + | (Rx.no_spaces - ("-" | "swap")) (* mkfs.xxx must exist *) + +(* Variable: filesystem *) +let filesystem = [ label "filesystem" . store filesystem_kw ] + + +(* Variable: mount_option_value *) +let mount_option_value = [ label "value" . Util.del_str "=" + . store /[^,= \t\n]+/ ] + +(* Variable: mount_option + Counting options *) +let mount_option = [ seq "mount_option" + . store /[^,= \t\n]+/ + . mount_option_value? ] + +(* Variable: mount_options + An array of s *) +let mount_options = [ label "mount_options" + . counter "mount_option" + . Build.opt_list mount_option Sep.comma ] + +(* Variable: fs_option *) +let fs_option = + [ key /createopts|tuneopts/ + . Util.del_str "=\"" . store /[^"\n]*/ . Util.del_str "\"" ] + +(* Variable: fs_options + An array of s *) +let fs_options = + (* options to append to mkfs.xxx and to the filesystem-specific + * tuning tool *) + [ label "fs_options" . Build.opt_list fs_option Sep.space ] + +(* Variable: volume_full *) +let volume_full (type:lens) (third_field:lens) = + [ type . space + . mountpoint .space + (* The third field changes depending on types *) + . third_field . space + . filesystem . space + . mount_options + . (space . fs_options)? + . eol ] + +(* Variable: name + LVM volume group name *) +let name = [ label "name" . store /[^\/ \t\n]+/ ] + +(* Variable: partition + An optional partition number for *) +let partition = [ label "partition" . Util.del_str "." . store /[0-9]+/ ] + +(* Variable: disk *) +let disk = [ label "disk" . store /[^., \t\n]+/ . partition? ] + +(* Variable: vg_option + An option for *) +let vg_option = + [ key "pvcreateopts" + . Util.del_str "=\"" . store /[^"\n]*/ . Util.del_str "\"" ] + +(* Variable: volume_vg *) +let volume_vg = [ key "vg" + . space . name + . space . disk + . (space . vg_option)? + . eol ] + +(* Variable: spare_missing *) +let spare_missing = tag /spare|missing/ + +(* Variable: disk_with_opt + A with a spare/missing option for raids *) +let disk_with_opt = [ label "disk" . store /[^:., \t\n]+/ . partition? + . spare_missing* ] + +(* Variable: disk_list + A list of s *) +let disk_list = Build.opt_list disk_with_opt Sep.comma + +(* Variable: type_label_lv *) +let type_label_lv = label "lv" + . [ label "vg" . store (/[^# \t\n-]+/ - "raw") ] + . Util.del_str "-" + . [ label "name" . store /[^ \t\n]+/ ] + +(* Variable: volume_tmpfs *) +let volume_tmpfs = + [ key "tmpfs" . space + . mountpoint .space + . size . space + . mount_options + . (space . fs_options)? + . eol ] + +(* Variable: volume_lvm *) +let volume_lvm = volume_full type_label_lv size (* lvm logical volume: vg name and lv name *) + | volume_vg + +(* Variable: volume_raid *) +let volume_raid = volume_full (key /raid[0156]/) disk_list (* raid level *) + +(* Variable: device *) +let device = [ label "device" . store Rx.fspath ] + +(* Variable: volume_cryptsetup *) +let volume_cryptsetup = volume_full (key ("swap"|"tmp"|"luks")) device + +(* Variable: volume *) +let volume = volume_full (key "primary") size (* for physical disks only *) + | volume_full (key "logical") size (* for physical disks only *) + | volume_full (key "raw-disk") size + +(* Variable: volume_or_comment + A succesion of s and s *) +let volume_or_comment (vol:lens) = + (vol|empty|comment)* . vol + +(* Variable: disk_config_entry *) +let disk_config_entry (kw:regexp) (opt:lens) (vol:lens) = + [ key "disk_config" . space . store kw + . (space . opt)* . eol + . (volume_or_comment vol)? ] + +(* Variable: lvmoption *) +let lvmoption = + (* preserve partitions -- always *) + generic_opt "preserve_always" /[^\/, \t\n-]+-[^\/, \t\n-]+(,[^\/, \t\n-]+-[^\/, \t\n-]+)*/ + (* preserve partitions -- unless the system is installed + * for the first time *) + | generic_opt "preserve_reinstall" /[^\/, \t\n-]+-[^\/, \t\n-]+(,[^\/, \t\n-]+-[^\/, \t\n-]+)*/ + (* attempt to resize partitions *) + | generic_opt "resize" /[^\/, \t\n-]+-[^\/, \t\n-]+(,[^\/, \t\n-]+-[^\/, \t\n-]+)*/ + (* when creating the fstab, the key used for defining the device + * may be the device (/dev/xxx), a label given using -L, or the uuid *) + | generic_opt "fstabkey" /device|label|uuid/ + +(* Variable: raidoption *) +let raidoption = + (* preserve partitions -- always *) + generic_opt_list "preserve_always" (Rx.integer | "all") + (* preserve partitions -- unless the system is installed + * for the first time *) + | generic_opt_list "preserve_reinstall" Rx.integer + (* when creating the fstab, the key used for defining the device + * may be the device (/dev/xxx), a label given using -L, or the uuid *) + | generic_opt "fstabkey" /device|label|uuid/ + +(* Variable: option *) +let option = + (* preserve partitions -- always *) + generic_opt_list "preserve_always" (Rx.integer | "all") + (* preserve partitions -- unless the system is installed + for the first time *) + | generic_opt_list "preserve_reinstall" Rx.integer + (* attempt to resize partitions *) + | generic_opt_list "resize" Rx.integer + (* write a disklabel - default is msdos *) + | generic_opt "disklabel" /msdos|gpt/ + (* mark a partition bootable, default is / *) + | generic_opt "bootable" Rx.integer + (* do not assume the disk to be a physical device, use with xen *) + | [ key "virtual" ] + (* when creating the fstab, the key used for defining the device + * may be the device (/dev/xxx), a label given using -L, or the uuid *) + | generic_opt "fstabkey" /device|label|uuid/ + | generic_opt_list "always_format" Rx.integer + | generic_opt "sameas" Rx.fspath + +let cryptoption = + [ key "randinit" ] + +(* Variable: disk_config *) +let disk_config = + let excludes = "lvm" | "raid" | "end" | /disk[0-9]+/ + | "cryptsetup" | "tmpfs" in + let other_label = Rx.fspath - excludes in + disk_config_entry "lvm" lvmoption volume_lvm + | disk_config_entry "raid" raidoption volume_raid + | disk_config_entry "tmpfs" option volume_tmpfs + | disk_config_entry "end" option volume (* there shouldn't be an option here *) + | disk_config_entry /disk[0-9]+/ option volume + | disk_config_entry "cryptsetup" cryptoption volume_cryptsetup + | disk_config_entry other_label option volume + +(* Variable: lns + The disk_config lens *) +let lns = (disk_config|comment|empty)* + + +(* let xfm = transform lns Util.stdexcl *) diff --git a/Sharp.Augeas.Test/lens/fail2ban.aug b/Sharp.Augeas.Test/lens/fail2ban.aug new file mode 100644 index 0000000..02af4da --- /dev/null +++ b/Sharp.Augeas.Test/lens/fail2ban.aug @@ -0,0 +1,47 @@ +(* Fail2ban module for Augeas *) +(* Author: Nicolas Gif *) +(* Heavily based on DPUT module by Raphael Pinson *) +(* *) +(* *) + +module Fail2ban = + autoload xfm + + +(************************************************************************ + * INI File settings + *************************************************************************) +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default + + +(************************************************************************ + * "name: value" entries, with continuations in the style of RFC 822; + * "name=value" is also accepted + * leading whitespace is removed from values + *************************************************************************) +let entry = IniFile.entry IniFile.entry_re sep comment + + +(************************************************************************ + * sections, led by a "[section]" header + * We can't use titles as node names here since they could contain "/" + * We remove #comment from possible keys + * since it is used as label for comments + * We also remove / as first character + * because augeas doesn't like '/' keys (although it is legal in INI Files) + *************************************************************************) +let title = IniFile.title IniFile.record_re +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = (incl "/etc/fail2ban/fail2ban.conf") + . (incl "/etc/fail2ban/jail.conf") + . (incl "/etc/fail2ban/jail.local") + . (incl "/etc/fail2ban/fail2ban.d/*.conf") + . (incl "/etc/fail2ban/jail.d/*.conf") + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/fonts.aug b/Sharp.Augeas.Test/lens/fonts.aug new file mode 100644 index 0000000..17d7a09 --- /dev/null +++ b/Sharp.Augeas.Test/lens/fonts.aug @@ -0,0 +1,37 @@ +(* +Module: Fonts + Parses the /etc/fonts directory + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 fonts-conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to files in the /etc/fonts directory. See . + +About: Examples + The file contains various examples and tests. +*) + +module Fonts = + +autoload xfm + +(* View: lns *) +let lns = Xml.lns + +(* Variable: filter *) +let filter = incl "/etc/fonts/fonts.conf" + . incl "/etc/fonts/conf.avail/*" + . incl "/etc/fonts/conf.d/*" + . excl "/etc/fonts/*/README" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/fstab.aug b/Sharp.Augeas.Test/lens/fstab.aug new file mode 100644 index 0000000..2e54955 --- /dev/null +++ b/Sharp.Augeas.Test/lens/fstab.aug @@ -0,0 +1,43 @@ +(* Parsing /etc/fstab *) + +module Fstab = + autoload xfm + + let sep_tab = Sep.tab + let sep_spc = Sep.space + let comma = Sep.comma + let eol = Util.eol + + let comment = Util.comment + let empty = Util.empty + + let file = /[^# \t\n]+/ + + (* An option label can't contain comma, comment, equals, or space *) + let optlabel = /[^,#= \n\t]+/ + let spec = /[^,# \n\t][^ \n\t]*/ + + let comma_sep_list (l:string) = + let value = [ label "value" . Util.del_str "=" . ( store Rx.neg1 )? ] in + let lns = [ label l . store optlabel . value? ] in + Build.opt_list lns comma + + let record = [ seq "mntent" . + Util.indent . + [ label "spec" . store spec ] . sep_tab . + [ label "file" . store file ] . sep_tab . + comma_sep_list "vfstype" . + (sep_tab . comma_sep_list "opt" . + (sep_tab . [ label "dump" . store /[0-9]+/ ] . + ( sep_spc . [ label "passno" . store /[0-9]+/ ])? )? )? + . Util.comment_or_eol ] + + let lns = ( empty | comment | record ) * + let filter = incl "/etc/fstab" + . incl "/etc/mtab" + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/fuse.aug b/Sharp.Augeas.Test/lens/fuse.aug new file mode 100644 index 0000000..cf08154 --- /dev/null +++ b/Sharp.Augeas.Test/lens/fuse.aug @@ -0,0 +1,45 @@ +(* +Module: Fuse + Parses /etc/fuse.conf + +Author: Raphael Pinson + +About: Reference + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/fuse.conf. See . + +About: Examples + The file contains various examples and tests. +*) + + +module Fuse = +autoload xfm + +(* Variable: equal *) +let equal = del /[ \t]*=[ \t]*/ " = " + +(* View: mount_max *) +let mount_max = Build.key_value_line "mount_max" equal (store Rx.integer) + +(* View: user_allow_other *) +let user_allow_other = Build.flag_line "user_allow_other" + + +(* View: lns + The fuse.conf lens +*) +let lns = ( Util.empty | Util.comment | mount_max | user_allow_other )* + +(* Variable: filter *) +let filter = incl "/etc/fuse.conf" + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/gdm.aug b/Sharp.Augeas.Test/lens/gdm.aug new file mode 100644 index 0000000..e94fde1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/gdm.aug @@ -0,0 +1,48 @@ +(* Gdm module for Augeas *) +(* Author: Free Ekanayaka *) +(* *) + +module Gdm = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) + +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default +let empty = IniFile.empty + + +(************************************************************************ + * ENTRY + * Entry keywords can be bare digits as well (the [server] section) + *************************************************************************) +let entry_re = ( /[A-Za-z0-9][A-Za-z0-9._-]*/ ) +let entry = IniFile.entry entry_re sep comment + + +(************************************************************************ + * TITLE + * + * We use IniFile.title_label because there can be entries + * outside of sections whose labels would conflict with section names + *************************************************************************) +let title = IniFile.title ( IniFile.record_re - ".anon" ) +let record = IniFile.record title entry + +let record_anon = [ label ".anon" . ( entry | empty )+ ] + + +(************************************************************************ + * LENS & FILTER + * There can be entries before any section + * IniFile.entry includes comment management, so we just pass entry to lns + *************************************************************************) +let lns = record_anon? . record* + +let filter = (incl "/etc/gdm/gdm.conf*") + . (incl "/etc/gdm/custom.conf") + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/getcap.aug b/Sharp.Augeas.Test/lens/getcap.aug new file mode 100644 index 0000000..a685fe9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/getcap.aug @@ -0,0 +1,49 @@ +(* +Module: Getcap + Parses generic termcap-style capability databases + +Author: Matt Dainty + +About: Reference + - man 3 getcap + - man 5 login.conf + - man 5 printcap + +Each line represents a record consisting of a number of ':'-separated fields +the first of which is the name or identifier for the record. The name can +optionally be split by '|' and each subsequent value is considered an alias +of the first. Records can be split across multiple lines with '\'. + +See also the Rtadvd and Termcap modules which contain slightly more specific +grammars. + +*) + +module Getcap = + autoload xfm + + (* Comments cannot have any leading characters *) + let comment = Util.comment_generic /#[ \t]*/ "# " + + let nfield = /[^#:\\\\\t\n|][^:\\\\\t\n|]*/ + + (* field must not contain ':' *) + let cfield = /[a-zA-Z0-9-]+([%^$#\\]?@|[%^$#\\=]([^:\\\\^]|\\\\[0-7]{1,3}|\\\\[bBcCeEfFnNrRtT\\^]|\^.)*)?/ + + let csep = del /:([ \t]*\\\\\n[ \t]*:)?/ ":\\\n\t:" + let nsep = Util.del_str "|" + let name = [ label "name" . store nfield ] + let capability (re:regexp) = [ label "capability" . store re ] + let record (re:regexp) = [ label "record" . name . ( nsep . name )* . ( csep . capability re )* . Sep.colon . Util.eol ] + + let lns = ( Util.empty | comment | record cfield )* + + let filter = incl "/etc/login.conf" + . incl "/etc/printcap" + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/group.aug b/Sharp.Augeas.Test/lens/group.aug new file mode 100644 index 0000000..be16892 --- /dev/null +++ b/Sharp.Augeas.Test/lens/group.aug @@ -0,0 +1,59 @@ +(* Group module for Augeas + Author: Free Ekanayaka + + Reference: man 5 group + +*) + +module Group = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty +let dels = Util.del_str + +let colon = Sep.colon +let comma = Sep.comma + +let sto_to_spc = store Rx.space_in +let sto_to_col = Passwd.sto_to_col + +let word = Rx.word +let password = /[A-Za-z0-9_.!*-]*/ +let integer = Rx.integer + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let user = [ label "user" . store word ] +let user_list = Build.opt_list user comma +let params = [ label "password" . store password . colon ] + . [ label "gid" . store integer . colon ] + . user_list? +let entry = Build.key_value_line word colon params + +let nisdefault = + let overrides = + colon + . [ label "password" . store password? . colon ] + . [ label "gid" . store integer? . colon ] + . user_list? in + [ dels "+" . label "@nisdefault" . overrides? . eol ] + + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry|nisdefault) * + +let filter = incl "/etc/group" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/grub.aug b/Sharp.Augeas.Test/lens/grub.aug new file mode 100644 index 0000000..82c1c37 --- /dev/null +++ b/Sharp.Augeas.Test/lens/grub.aug @@ -0,0 +1,337 @@ +(* +Module: Grub + Parses grub configuration + +Author: David Lutterkort + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented +*) + +module Grub = + autoload xfm + + (* This only covers the most basic grub directives. Needs to be *) + (* expanded to cover more (and more esoteric) directives *) + (* It is good enough to handle the grub.conf on my Fedora 8 box *) + + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + (* View: value_to_eol *) + let value_to_eol = store /[^= \t\n][^\n]*[^= \t\n]|[^= \t\n]/ + + (* View: eol *) + let eol = Util.eol + + (* View: spc *) + let spc = Util.del_ws_spc + + (* View: opt_ws *) + let opt_ws = Util.del_opt_ws "" + + (* View: dels *) + let dels (s:string) = Util.del_str s + + (* View: eq *) + let eq = dels "=" + + (* View: switch *) + let switch (n:regexp) = dels "--" . key n + + (* View: switch_arg *) + let switch_arg (n:regexp) = switch n . eq . store Rx.no_spaces + + (* View: value_sep *) + let value_sep (dflt:string) = del /[ \t]*[ \t=][ \t]*/ dflt + + (* View: comment_re *) + let comment_re = /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + - /# ## (Start|End) Default Options ##/ + + (* View: comment *) + let comment = + [ Util.indent . label "#comment" . del /#[ \t]*/ "# " + . store comment_re . eol ] + + (* View: empty *) + let empty = Util.empty + +(************************************************************************ + * Group: USEFUL FUNCTIONS + *************************************************************************) + + (* View: command *) + let command (kw:regexp) (indent:string) = + Util.del_opt_ws indent . key kw + + (* View: kw_arg *) + let kw_arg (kw:regexp) (indent:string) (dflt_sep:string) = + [ command kw indent . value_sep dflt_sep . value_to_eol . eol ] + + (* View: kw_boot_arg *) + let kw_boot_arg (kw:regexp) = kw_arg kw "\t" " " + + (* View: kw_menu_arg *) + let kw_menu_arg (kw:regexp) = kw_arg kw "" " " + + (* View: password_arg *) + let password_arg = [ command "password" "" . + (spc . [ switch "md5" ])? . + (spc . [ switch "encrypted" ])? . + spc . store (/[^ \t\n]+/ - /--[^ \t\n]+/) . + (spc . [ label "file" . store /[^ \t\n]+/ ])? . + eol ] + + (* View: kw_pres *) + let kw_pres (kw:string) = [ opt_ws . key kw . eol ] + + (* View: error + * Parse a line that looks almost like a valid setting, but isn't, + * into an '#error' node. Any line that starts with letters, but not + * anything matching kw, is considered an error line. + * + * Parameters: + * kw:regexp - the valid keywords that are _not_ considered an + * error + *) + let error (kw:regexp) = + let not_kw = /[a-zA-Z]+/ - kw in + [ label "#error" . Util.del_opt_ws "\t" + . store (not_kw . /([^a-zA-Z\n].*[^ \t\n])?/) . eol ] + + +(************************************************************************ + * Group: BOOT ENTRIES + *************************************************************************) + + (* View: device + * This is a shell-only directive in upstream grub; the grub versions + * in at least Fedora/RHEL use this to find devices for UEFI boot *) + let device = + [ command "device" "" . Sep.space . store /\([A-Za-z0-9_.-]+\)/ . spc . + [ label "file" . value_to_eol ] . Util.eol ] + + (* View: color *) + let color = + (* Should we nail it down to exactly the color names that *) + (* grub supports ? *) + let color_name = store /[A-Za-z-]+/ in + let color_spec = + [ label "foreground" . color_name] . + dels "/" . + [ label "background" . color_name ] in + [ opt_ws . key "color" . + spc . [ label "normal" . color_spec ] . + (spc . [ label "highlight" . color_spec ])? . + eol ] + + (* View: serial *) + let serial = + [ command "serial" "" . + [ spc . switch_arg /unit|port|speed|word|parity|stop|device/ ]* . + eol ] + + (* View: terminal *) + let terminal = + [ command "terminal" "" . + ([ spc . switch /dumb|no-echo|no-edit|silent/ ] + |[ spc . switch_arg /timeout|lines/ ])* . + [ spc . key /console|serial|hercules/ ]* . eol ] + + (* View: setkey *) + let setkey = [ command "setkey" "" . + ( spc . [ label "to" . store Rx.no_spaces ] . + spc . [ label "from" . store Rx.no_spaces ] )? . + eol ] + + (* View: menu_entry *) + let menu_entry = kw_menu_arg "default" + | kw_menu_arg "fallback" + | kw_pres "hiddenmenu" + | kw_menu_arg "timeout" + | kw_menu_arg "splashimage" + | kw_menu_arg "gfxmenu" + | kw_menu_arg "foreground" + | kw_menu_arg "background" + | kw_menu_arg "verbose" + | kw_menu_arg "boot" (* only for CLI, ignored in conf *) + | serial + | terminal + | password_arg + | color + | device + | setkey + + (* View: menu_error + * Accept lines not matching menu_entry and stuff them into + * '#error' nodes + *) + let menu_error = + let kw = /default|fallback|hiddenmenu|timeout|splashimage|gfxmenu/ + |/foreground|background|verbose|boot|password|title/ + |/serial|setkey|terminal|color|device/ in + error kw + + (* View: menu_setting + * a valid menu setting or a line that looks like one but is an #error + *) + let menu_setting = menu_entry | menu_error + + (* View: title *) + let title = del /title[ \t=]+/ "title " . value_to_eol . eol + + (* View: multiboot_arg + * Permits a second form for Solaris multiboot kernels that + * take a path (with a slash) as their first arg, e.g. + * /boot/multiboot kernel/unix another=arg *) + let multiboot_arg = [ label "@path" . + store (Rx.word . "/" . Rx.no_spaces) ] + + (* View: kernel_args + Parse the file name and args on a kernel or module line. *) + let kernel_args = + let arg = /[A-Za-z0-9_.$\+-]+/ - /type|no-mem-option/ in + store /(\([a-z0-9,]+\))?\/[^ \t\n]*/ . + (spc . multiboot_arg)? . + (spc . [ key arg . (eq. store /([^ \t\n])*/)?])* . eol + + (* View: module_line + Solaris extension adds module$ and kernel$ for variable interpolation *) + let module_line = + [ command /module\$?/ "\t" . spc . kernel_args ] + + (* View: map_line *) + let map_line = + [ command "map" "\t" . spc . + [ label "from" . store /[()A-za-z0-9]+/ ] . spc . + [ label "to" . store /[()A-za-z0-9]+/ ] . eol ] + + (* View: kernel *) + let kernel = + [ command /kernel\$?/ "\t" . + (spc . + ([switch "type" . eq . store /[a-z]+/] + |[switch "no-mem-option"]))* . + spc . kernel_args ] + + (* View: chainloader *) + let chainloader = + [ command "chainloader" "\t" . + [ spc . switch "force" ]? . spc . store Rx.no_spaces . eol ] + + (* View: savedefault *) + let savedefault = + [ command "savedefault" "\t" . (spc . store Rx.integer)? . eol ] + + (* View: configfile *) + let configfile = + [ command "configfile" "\t" . spc . store Rx.no_spaces . eol ] + + (* View: boot_entry + entries *) + let boot_entry = + let boot_arg_re = "root" | "initrd" | "rootnoverify" | "uuid" + | "findroot" | "bootfs" (* Solaris extensions *) + in kw_boot_arg boot_arg_re + | kernel + | chainloader + | kw_pres "quiet" (* Seems to be a Ubuntu extension *) + | savedefault + | configfile + | module_line + | map_line + | kw_pres "lock" + | kw_pres "makeactive" + | password_arg + + (* View: boot_error + * Accept lines not matching boot_entry and stuff them into + * '#error' nodes + *) + let boot_error = + let kw = /lock|uuid|password|root|initrd|rootnoverify|findroot|bootfs/ + |/configfile|chainloader|title|boot|quiet|kernel|module/ + |/makeactive|savedefault|map/ in + error kw + + (* View: boot_setting + * a valid boot setting or a line that looks like one but is an #error + *) + let boot_setting = boot_entry | boot_error + + (* View: boot *) + let boot = + let line = ((boot_setting|comment)* . boot_setting)? in + [ label "title" . title . line ] + +(************************************************************************ + * Group: DEBIAN-SPECIFIC SECTIONS + *************************************************************************) + + (* View: debian_header + Header for a -specific section *) + let debian_header = "## ## Start Default Options ##\n" + + (* View: debian_footer + Footer for a -specific section *) + let debian_footer = "## ## End Default Options ##\n" + + (* View: debian_comment_re *) + let debian_comment_re = /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + - "## End Default Options ##" + + (* View: debian_comment + A comment entry inside a -specific section *) + let debian_comment = + [ Util.indent . label "#comment" . del /##[ \t]*/ "## " + . store debian_comment_re . eol ] + + (* View: debian_setting_re *) + let debian_setting_re = "kopt" + | "groot" + | "alternative" + | "lockalternative" + | "defoptions" + | "lockold" + | "xenhopt" + | "xenkopt" + | "altoptions" + | "howmany" + | "memtest86" + | "updatedefaultentry" + | "savedefault" + | "indomU" + + (* View: debian_entry *) + let debian_entry = [ Util.del_str "#" . Util.indent + . key debian_setting_re . del /[ \t]*=/ "=" + . value_to_eol? . eol ] + + (* View: debian + A debian-specific section, made of lines *) + let debian = [ label "debian" + . del debian_header debian_header + . (debian_comment|empty|debian_entry)* + . del debian_footer debian_footer ] + +(************************************************************************ + * Group: LENS AND FILTER + *************************************************************************) + + (* View: lns *) + let lns = (comment | empty | menu_setting | debian)* + . (boot . (comment | empty | boot)*)? + + (* View: filter *) + let filter = incl "/boot/grub/grub.conf" + . incl "/boot/grub/menu.lst" + . incl "/etc/grub.conf" + . incl "/boot/efi/EFI/*/grub.conf" + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/grubenv.aug b/Sharp.Augeas.Test/lens/grubenv.aug new file mode 100644 index 0000000..5a3878a --- /dev/null +++ b/Sharp.Augeas.Test/lens/grubenv.aug @@ -0,0 +1,19 @@ +(* Parsing /boot/grub/grubenv *) + +module GrubEnv = + autoload xfm + + let eol = Util.del_str "\n" + + let comment = Util.comment + let eq = Util.del_str "=" + let value = /[^\\\n]*(\\\\(\\\\|\n)[^\\\n]*)*/ + + let word = /[A-Za-z_][A-Za-z0-9_]*/ + let record = [ seq "target" . + [ label "name" . store word ] . eq . + [ label "value" . store value ] . eol ] + + let lns = ( comment | record ) * + + let xfm = transform lns (incl "/boot/grub/grubenv" . incl "/boot/grub2/grubenv") diff --git a/Sharp.Augeas.Test/lens/gshadow.aug b/Sharp.Augeas.Test/lens/gshadow.aug new file mode 100644 index 0000000..c5e8947 --- /dev/null +++ b/Sharp.Augeas.Test/lens/gshadow.aug @@ -0,0 +1,80 @@ +(* + Module: Gshadow + Parses /etc/gshadow + + Author: Lorenzo M. Catucci + + Original Author: Free Ekanayaka + + About: Reference + - man 5 gshadow + + About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + + About: + + Each line in the gshadow files represents the additional shadow-defined + attributes for the corresponding group, as defined in the group file. + +*) + +module Gshadow = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty + +let colon = Sep.colon +let comma = Sep.comma + +let sto_to_spc = store Rx.space_in + +let word = Rx.word +let password = /[A-Za-z0-9_.!*-]*/ +let integer = Rx.integer + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +(* View: member *) +let member = [ label "member" . store word ] +(* View: member_list + the member list is a comma separated list of + users allowed to chgrp to the group without + being prompted for the group's password *) +let member_list = Build.opt_list member comma + +(* View: admin *) +let admin = [ label "admin" . store word ] +(* View: admin_list + the admin_list is a comma separated list of + users allowed to change the group's password + and the member_list *) +let admin_list = Build.opt_list admin comma + +(* View: params *) +let params = [ label "password" . store password . colon ] + . admin_list? . colon + . member_list? + +let entry = Build.key_value_line word colon params + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter + = incl "/etc/gshadow" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/gtkbookmarks.aug b/Sharp.Augeas.Test/lens/gtkbookmarks.aug new file mode 100644 index 0000000..9421b4c --- /dev/null +++ b/Sharp.Augeas.Test/lens/gtkbookmarks.aug @@ -0,0 +1,36 @@ +(* +Module: GtkBookmarks + Parses $HOME/.gtk-bookmarks + +Author: Raphael Pinson + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to $HOME/.gtk-bookmarks. See . + +About: Examples + The file contains various examples and tests. +*) +module GtkBookmarks = + +autoload xfm + +(* View: empty + Comment are not allowed, even empty comments *) +let empty = Util.empty_generic Rx.opt_space + +(* View: entry *) +let entry = [ label "bookmark" . store Rx.no_spaces + . (Sep.space . [ label "label" . store Rx.space_in ])? + . Util.eol ] + +(* View: lns *) +let lns = (empty | entry)* + +(* View: xfm *) +let xfm = transform lns (incl (Sys.getenv("HOME") . "/.gtk-bookmarks")) diff --git a/Sharp.Augeas.Test/lens/host_conf.aug b/Sharp.Augeas.Test/lens/host_conf.aug new file mode 100644 index 0000000..294975b --- /dev/null +++ b/Sharp.Augeas.Test/lens/host_conf.aug @@ -0,0 +1,71 @@ +(* +Module: Host_Conf + Parses /etc/host.conf + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 host.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/host.conf. See . +*) + +module Host_Conf = + +autoload xfm + +(************************************************************************ + * Group: ENTRY TYPES + *************************************************************************) + +(* View: sto_bool + Store a boolean value *) +let sto_bool = store ("on"|"off") + +(* View: sto_bool_warn + Store a boolean value *) +let sto_bool_warn = store ("on"|"off"|"warn"|"nowarn") + +(* View: bool + A boolean switch *) +let bool (kw:regexp) = Build.key_value_line kw Sep.space sto_bool + +(* View: bool_warn + A boolean switch with extended values *) +let bool_warn (kw:regexp) = Build.key_value_line kw Sep.space sto_bool_warn + +(* View: list + A list of items *) +let list (kw:regexp) (elem:string) = + let list_elems = Build.opt_list [seq elem . store Rx.word] (Sep.comma . Sep.opt_space) in + Build.key_value_line kw Sep.space list_elems + +(* View: trim *) +let trim = + let trim_list = Build.opt_list [seq "trim" . store Rx.word] (del /[:;,]/ ":") in + Build.key_value_line "trim" Sep.space trim_list + +(* View: entry *) +let entry = bool ("multi"|"nospoof"|"spoofalert"|"reorder") + | bool_warn "spoof" + | list "order" "order" + | trim + +(************************************************************************ + * Group: LENS AND FILTER + *************************************************************************) + +(* View: lns *) +let lns = ( Util.empty | Util.comment | entry )* + +(* View: filter *) +let filter = incl "/etc/host.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/hostname.aug b/Sharp.Augeas.Test/lens/hostname.aug new file mode 100644 index 0000000..61cf90b --- /dev/null +++ b/Sharp.Augeas.Test/lens/hostname.aug @@ -0,0 +1,22 @@ +(* +Module: Hostname + Parses /etc/hostname and /etc/mailname + +Author: Raphael Pinson + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. +*) + + +module Hostname = +autoload xfm + +(* View: lns *) +let lns = [ label "hostname" . store Rx.word . Util.eol ] | Util.empty + +(* View: filter *) +let filter = incl "/etc/hostname" + . incl "/etc/mailname" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/hosts.aug b/Sharp.Augeas.Test/lens/hosts.aug new file mode 100644 index 0000000..6c01367 --- /dev/null +++ b/Sharp.Augeas.Test/lens/hosts.aug @@ -0,0 +1,15 @@ +(* Parsing /etc/hosts *) + +module Hosts = + autoload xfm + + let word = /[^# \n\t]+/ + let record = [ seq "host" . Util.indent . + [ label "ipaddr" . store word ] . Sep.tab . + [ label "canonical" . store word ] . + [ label "alias" . Sep.space . store word ]* + . Util.comment_or_eol ] + + let lns = ( Util.empty | Util.comment | record ) * + + let xfm = transform lns (incl "/etc/hosts") diff --git a/Sharp.Augeas.Test/lens/hosts_access.aug b/Sharp.Augeas.Test/lens/hosts_access.aug new file mode 100644 index 0000000..2ae450a --- /dev/null +++ b/Sharp.Augeas.Test/lens/hosts_access.aug @@ -0,0 +1,152 @@ +(* +Module: Hosts_Access + Parses /etc/hosts.{allow,deny} + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 hosts_access` and `man 5 hosts_options` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/hosts.{allow,deny}. See . +*) + +module Hosts_Access = + +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: colon *) +let colon = del /[ \t]*(\\\\[ \t]*\n[ \t]+)?:[ \t]*(\\\\[ \t]*\n[ \t]+)?/ ": " + +(* Variable: comma_sep *) +let comma_sep = /([ \t]|(\\\\\n))*,([ \t]|(\\\\\n))*/ + +(* Variable: ws_sep *) +let ws_sep = / +/ + +(* View: list_sep *) +let list_sep = del ( comma_sep | ws_sep ) ", " + +(* View: list_item *) +let list_item = store ( Rx.word - /EXCEPT/i ) + +(* View: client_host_item + Allows @ for netgroups, supports [ipv6] syntax *) +let client_host_item = + let client_hostname_rx = /[A-Za-z0-9_.@?*-][A-Za-z0-9_.?*-]*/ in + let client_ipv6_rx = "[" . /[A-Za-z0-9:?*%]+/ . "]" in + let client_host_rx = client_hostname_rx | client_ipv6_rx in + let netmask = [ Util.del_str "/" . label "netmask" . store Rx.word ] in + store ( client_host_rx - /EXCEPT/i ) . netmask? + +(* View: client_file_item *) +let client_file_item = + let client_file_rx = /\/[^ \t\n,:]+/ in + store ( client_file_rx - /EXCEPT/i ) + +(* Variable: option_kw + Since either an option or a shell command can be given, use an explicit list + of known options to avoid misinterpreting a command as an option *) +let option_kw = "severity" + | "spawn" + | "twist" + | "keepalive" + | "linger" + | "rfc931" + | "banners" + | "nice" + | "setenv" + | "umask" + | "user" + | /allow/i + | /deny/i + +(* Variable: shell_command_rx *) +let shell_command_rx = /[^ \t\n:][^\n]*[^ \t\n]|[^ \t\n:\\\\]/ + - ( option_kw . /.*/ ) + +(* View: sto_to_colon + Allows escaped colon sequences *) +let sto_to_colon = store /[^ \t\n:=][^\n:]*((\\\\:|\\\\[ \t]*\n[ \t]+)[^\n:]*)*[^ \\\t\n:]|[^ \t\n:\\\\]/ + +(* View: except + * The except operator makes it possible to write very compact rules. + *) +let except (lns:lens) = [ label "except" . Sep.space + . del /except/i "EXCEPT" + . Sep.space . lns ] + +(************************************************************************ + * Group: ENTRY TYPES + *************************************************************************) + +(* View: daemon *) +let daemon = + let host = [ label "host" + . Util.del_str "@" + . list_item ] in + [ label "process" + . list_item + . host? ] + +(* View: daemon_list + A list of s *) +let daemon_list = Build.opt_list daemon list_sep + +(* View: client *) +let client = + let user = [ label "user" + . list_item + . Util.del_str "@" ] in + [ label "client" + . user? + . client_host_item ] + +(* View: client_file *) +let client_file = [ label "file" . client_file_item ] + +(* View: client_list + A list of s *) +let client_list = Build.opt_list ( client | client_file ) list_sep + +(* View: option + Optional extensions defined in hosts_options(5) *) +let option = [ key option_kw + . ( del /([ \t]*=[ \t]*|[ \t]+)/ " " . sto_to_colon )? ] + +(* View: shell_command *) +let shell_command = [ label "shell_command" + . store shell_command_rx ] + +(* View: entry *) +let entry = [ seq "line" + . daemon_list + . (except daemon_list)? + . colon + . client_list + . (except client_list)? + . ( (colon . option)+ | (colon . shell_command)? ) + . Util.eol ] + +(************************************************************************ + * Group: LENS AND FILTER + *************************************************************************) + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry)* + +(* View: filter *) +let filter = incl "/etc/hosts.allow" + . incl "/etc/hosts.deny" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/htpasswd.aug b/Sharp.Augeas.Test/lens/htpasswd.aug new file mode 100644 index 0000000..6e51745 --- /dev/null +++ b/Sharp.Augeas.Test/lens/htpasswd.aug @@ -0,0 +1,41 @@ +(* +Module: Htpasswd + Parses htpasswd and rsyncd.secrets files + +Author: Marc Fournier + +About: Reference + This lens is based on examples in htpasswd(1) and rsyncd.conf(5) + +About: Usage Example +(start code) + augtool> set /augeas/load/Htpasswd/lens "Htpasswd.lns" + augtool> set /augeas/load/Htpasswd/incl "/var/www/.htpasswd" + augtool> load + + augtool> get /files/var/www/.htpasswd/foo + /files/var/www/.htpasswd/foo = $apr1$e2WS6ARQ$lYhqy9CLmwlxR/07TLR46. + + augtool> set /files/var/www/.htpasswd/foo bar + augtool> save + Saved 1 file(s) + + $ cat /var/www/.htpasswd + foo:bar +(end code) + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Htpasswd = +autoload xfm + +let entry = Build.key_value_line Rx.word Sep.colon (store Rx.space_in) +let lns = (Util.empty | Util.comment | entry)* + +let filter = incl "/etc/httpd/htpasswd" + . incl "/etc/apache2/htpasswd" + . incl "/etc/rsyncd.secrets" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/httpd.aug b/Sharp.Augeas.Test/lens/httpd.aug new file mode 100644 index 0000000..5600088 --- /dev/null +++ b/Sharp.Augeas.Test/lens/httpd.aug @@ -0,0 +1,206 @@ +(* Apache HTTPD lens for Augeas + +Authors: + David Lutterkort + Francis Giraldeau + Raphael Pinson + +About: Reference + Online Apache configuration manual: http://httpd.apache.org/docs/trunk/ + +About: License + This file is licensed under the LGPL v2+. + +About: Lens Usage + Sample usage of this lens in augtool + + Apache configuration is represented by two main structures, nested sections + and directives. Sections are used as labels, while directives are kept as a + value. Sections and directives can have positional arguments inside values + of "arg" nodes. Arguments of sections must be the firsts child of the + section node. + + This lens doesn't support automatic string quoting. Hence, the string must + be quoted when containing a space. + + Create a new VirtualHost section with one directive: + > clear /files/etc/apache2/sites-available/foo/VirtualHost + > set /files/etc/apache2/sites-available/foo/VirtualHost/arg "172.16.0.1:80" + > set /files/etc/apache2/sites-available/foo/VirtualHost/directive "ServerAdmin" + > set /files/etc/apache2/sites-available/foo/VirtualHost/*[self::directive="ServerAdmin"]/arg "admin@example.com" + +About: Configuration files + This lens applies to files in /etc/httpd and /etc/apache2. See . + +*) + + +module Httpd = + +autoload xfm + +(****************************************************************** + * Utilities lens + *****************************************************************) +let dels (s:string) = del s s + +(* The continuation sequence that indicates that we should consider the + * next line part of the current line *) +let cont = /\\\\\r?\n/ + +(* Whitespace within a line: space, tab, and the continuation sequence *) +let ws = /[ \t]/ | cont + +(* Any possible character - '.' does not match \n *) +let any = /(.|\n)/ + +(* Any character preceded by a backslash *) +let esc_any = /\\\\(.|\n)/ + +(* Newline sequence - both for Unix and DOS newlines *) +let nl = /\r?\n/ + +(* Whitespace at the end of a line *) +let eol = del (ws* . nl) "\n" + +(* deal with continuation lines *) +let sep_spc = del ws+ " " +let sep_osp = del ws* "" +let sep_eq = del (ws* . "=" . ws*) "=" + +let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/ +let word = /[a-z][a-z0-9._-]*/i + +(* A complete line that is either just whitespace or a comment that only + * contains whitespace *) +let empty = [ del (ws* . /#?/ . ws* . nl) "\n" ] + +let indent = Util.indent + +(* A comment that is not just whitespace. We define it in terms of the + * things that are not allowed as part of such a comment: + * 1) Starts with whitespace + * 2) Ends with whitespace, a backslash or \r + * 3) Unescaped newlines + *) +let comment = + let comment_start = del (ws* . "#" . ws* ) "# " in + let unesc_eol = /[^\]?/ . nl in + let w = /[^\t\n\r \\]/ in + let r = /[\r\\]/ in + let s = /[\t\r ]/ in + (* + * we'd like to write + * let b = /\\\\/ in + * let t = /[\t\n\r ]/ in + * let x = b . (t? . (s|w)* ) in + * but the definition of b depends on commit 244c0edd in 1.9.0 and + * would make the lens unusable with versions before 1.9.0. So we write + * x out which works in older versions, too + *) + let x = /\\\\[\t\n\r ]?[^\n\\]*/ in + let line = ((r . s* . w|w|r) . (s|w)* . x*|(r.s* )?).w.(s*.w)* in + [ label "#comment" . comment_start . store line . eol ] + +(* borrowed from shellvars.aug *) +let char_arg_sec = /([^\\ '"\t\r\n>]|[^ '"\t\r\n>]+[^\\ \t\r\n>])|\\\\"|\\\\'|\\\\ / +let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/ + +let dquot = + let no_dquot = /[^"\\\r\n]/ + in /"/ . (no_dquot|esc_any)* . /"/ +let dquot_msg = + let no_dquot = /([^ \t"\\\r\n]|[^"\\\r\n]+[^ \t"\\\r\n])/ + in /"/ . (no_dquot|esc_any)* . no_dquot + +let squot = + let no_squot = /[^'\\\r\n]/ + in /'/ . (no_squot|esc_any)* . /'/ +let comp = /[<>=]?=/ + +(****************************************************************** + * Attributes + *****************************************************************) + +(* The arguments for a directive come in two flavors: quoted with single or + * double quotes, or bare. Bare arguments may not start with a single or + * double quote; since we also treat "word lists" special, i.e. lists + * enclosed in curly braces, bare arguments may not start with those, + * either. + * + * Bare arguments may not contain unescaped spaces, but we allow escaping + * with '\\'. Quoted arguments can contain anything, though the quote must + * be escaped with '\\'. + *) +let bare = /([^{"' \t\n\r]|\\\\.)([^ \t\n\r]|\\\\.)*[^ \t\n\r\\]|[^{"' \t\n\r\\]/ + +let arg_quoted = [ label "arg" . store (dquot|squot) ] +let arg_bare = [ label "arg" . store bare ] + +(* message argument starts with " but ends at EOL *) +let arg_dir_msg = [ label "arg" . store dquot_msg ] +let arg_wl = [ label "arg" . store (char_arg_wl+|dquot|squot) ] + +(* comma-separated wordlist as permitted in the SSLRequire directive *) +let arg_wordlist = + let wl_start = dels "{" in + let wl_end = dels "}" in + let wl_sep = del /[ \t]*,[ \t]*/ ", " + in [ label "wordlist" . wl_start . arg_wl . (wl_sep . arg_wl)* . wl_end ] + +let argv (l:lens) = l . (sep_spc . l)* + +(* the arguments of a directive. We use this once we have parsed the name + * of the directive, and the space right after it. When dir_args is used, + * we also know that we have at least one argument. We need to be careful + * with the spacing between arguments: quoted arguments and word lists do + * not need to have space between them, but bare arguments do. + * + * Apache apparently is also happy if the last argument starts with a double + * quote, but has no corresponding closing duoble quote, which is what + * arg_dir_msg handles + *) +let dir_args = + let arg_nospc = arg_quoted|arg_wordlist in + (arg_bare . sep_spc | arg_nospc . sep_osp)* . (arg_bare|arg_nospc|arg_dir_msg) + +let directive = + [ indent . label "directive" . store word . (sep_spc . dir_args)? . eol ] + +let arg_sec = [ label "arg" . store (char_arg_sec+|comp|dquot|squot) ] + +let section (body:lens) = + (* opt_eol includes empty lines *) + let opt_eol = del /([ \t]*#?[ \t]*\r?\n)*/ "\n" in + let inner = (sep_spc . argv arg_sec)? . sep_osp . + dels ">" . opt_eol . ((body|comment) . (body|empty|comment)*)? . + indent . dels "[ \t\n\r]*/ ">\n" ] + +let perl_section = [ indent . label "Perl" . del //i "" + . store /[^<]*/ + . del /<\/perl>/i "" . eol ] + + +let rec content = section (content|directive) + | perl_section + +let lns = (content|directive|comment|empty)* + +let filter = (incl "/etc/apache2/apache2.conf") . + (incl "/etc/apache2/httpd.conf") . + (incl "/etc/apache2/ports.conf") . + (incl "/etc/apache2/conf.d/*") . + (incl "/etc/apache2/conf-available/*.conf") . + (incl "/etc/apache2/mods-available/*") . + (incl "/etc/apache2/sites-available/*") . + (incl "/etc/apache2/vhosts.d/*.conf") . + (incl "/etc/httpd/conf.d/*.conf") . + (incl "/etc/httpd/httpd.conf") . + (incl "/etc/httpd/conf/httpd.conf") . + (incl "/etc/httpd/conf.modules.d/*.conf") . + Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/inetd.aug b/Sharp.Augeas.Test/lens/inetd.aug new file mode 100644 index 0000000..edfc23a --- /dev/null +++ b/Sharp.Augeas.Test/lens/inetd.aug @@ -0,0 +1,185 @@ +(* inetd.conf lens definition for Augeas + Auther: Matt Palmer + + Copyright (C) 2009 Matt Palmer, All Rights Reserved + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License version 2.1 as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see . + +This lens parses /etc/inetd.conf. The current format is based on the +syntax documented in the inetd manpage shipped with Debian's openbsd-inetd +package version 0.20080125-2. Apologies if your inetd.conf doesn't follow +the same format. + +Each top-level entry will have a key being that of the service name (the +first column in the service definition, which is the name or number of the +port that the service should listen on). The attributes for the service all +sit under that. In regular Augeas style, the order of the attributes +matter, and attempts to set things in a different order will fail miserably. +The defined attribute names (and the order in which they must appear) are as +follows (with mandatory parameters indicated by [*]): + +address -- a sequence of IP addresses or hostnames on which this service + should listen. + +socket[*] -- The type of the socket that will be created (either stream or + dgram, although the lens doesn't constrain the possibilities here) + +protocol[*] -- The socket protocol. I believe that the usual possibilities + are "tcp", "udp", or "unix", but no restriction is made on what you + can actually put here. + +sndbuf -- Specify a non-default size for the send buffer of the connection. + +rcvbuf -- Specify a non-default size for the receive buffer of the connection. + +wait[*] -- Whether to wait for new connections ("wait"), or just terminate + immediately ("nowait"). + +max -- The maximum number of times that a service can be invoked in one minute. + +user[*] -- The user to run the service as. + +group -- A group to set the running service to, rather than the primary + group of the previously specified user. + +command[*] -- What program to run. + +arguments -- A sequence of arguments to pass to the command. + +In addition to this straightforward tree, inetd has the ability to set +"default" listen addresses; this is a little used feature which nonetheless +comes in handy sometimes. The key for entries of this type is "address" +, and the subtree should be a sequence of addresses. "*" can +always be used to return the default behaviour of listening on INADDR_ANY. + +*) + +module Inetd = + autoload xfm + + (*************************** + * PRIMITIVES + ***************************) + + (* Store whitespace *) + let wsp = del /[ \t]+/ " " + let sep = del /[ \t]+/ " " + let owsp(t:string) = del /[ \t]*/ t + + (* It's the end of the line as we know it... doo, doo, dooooo *) + let eol = Util.eol + + (* In the beginning, the earth was without form, and void *) + let empty = Util.empty + + let comment = Util.comment + + let del_str = Util.del_str + + let address = [ seq "addrseq" . store /([a-zA-Z0-9.-]+|\[[A-Za-z0-9:?*%]+\]|\*)/ ] + let address_list = ( counter "addrseq" . (address . del_str ",")* . address ) + + let argument = [ seq "argseq" . store /[^ \t\n]+/ ] + let argument_list = ( counter "argseq" . [ label "arguments" . (argument . wsp)* . argument ] ) + + (*************************** + * ELEMENTS + ***************************) + + let service (l:string) = ( label l . [label "address" . address_list . del_str ":" ]? . store /[^ \t\n\/:#]+/ ) + + let socket = [ label "socket" . store /[^ \t\n#]+/ ] + + let protocol = ( [ label "protocol" . store /[^ \t\n,#]+/ ] + . [ del_str "," . key /sndbuf/ . del_str "=" . store /[^ \t\n,]+/ ]? + . [ del_str "," . key /rcvbuf/ . del_str "=" . store /[^ \t\n,]+/ ]? + ) + + let wait = ( [ label "wait" . store /(wait|nowait)/ ] + . [ del_str "." . label "max" . store /[0-9]+/ ]? + ) + + let usergroup = ( [ label "user" . store /[^ \t\n:.]+/ ] + . [ del /[:.]/ ":" . label "group" . store /[^ \t\n:.]+/ ]? + ) + + let command = ( [ label "command" . store /[^ \t\n]+/ ] + . (wsp . argument_list)? + ) + + (*************************** + * SERVICE LINES + ***************************) + + let service_line = [ service "service" + . sep + . socket + . sep + . protocol + . sep + . wait + . sep + . usergroup + . sep + . command + . eol + ] + + + (*************************** + * RPC LINES + ***************************) + + let rpc_service = service "rpc_service" . Util.del_str "/" + . [ label "version" . store Rx.integer ] + + let rpc_endpoint = [ label "endpoint-type" . store Rx.word ] + let rpc_protocol = Util.del_str "rpc/" + . (Build.opt_list + [label "protocol" . store /[^ \t\n,#]+/ ] + Sep.comma) + + let rpc_line = [ rpc_service + . sep + . rpc_endpoint + . sep + . rpc_protocol + . sep + . wait + . sep + . usergroup + . sep + . command + . eol + ] + + + (*************************** + * DEFAULT LISTEN ADDRESSES + ***************************) + + let default_listen_address = [ label "address" + . address_list + . del_str ":" + . eol + ] + + (*********************** + * LENS / FILTER + ***********************) + + let lns = (comment|empty|service_line|rpc_line|default_listen_address)* + + let filter = incl "/etc/inetd.conf" + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/inifile.aug b/Sharp.Augeas.Test/lens/inifile.aug new file mode 100644 index 0000000..d01dcfd --- /dev/null +++ b/Sharp.Augeas.Test/lens/inifile.aug @@ -0,0 +1,555 @@ +(* +Module: IniFile + Generic module to create INI files lenses + +Author: Raphael Pinson + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: TODO + Things to add in the future + - Support double quotes in value + +About: Lens usage + This lens is made to provide generic primitives to construct INI File lenses. + See , , or for examples of real life lenses using it. + +About: Examples + The file contains various examples and tests. +*) + +module IniFile = + + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Internal primitives *) + +(* +Variable: eol + End of line, inherited from +*) +let eol = Util.doseol + + +(* Group: Separators *) + + + +(* +Variable: sep + Generic separator + + Parameters: + pat:regexp - the pattern to delete + default:string - the default string to use +*) +let sep (pat:regexp) (default:string) + = Sep.opt_space . del pat default + +(* +Variable: sep_noindent + Generic separator, no indentation + + Parameters: + pat:regexp - the pattern to delete + default:string - the default string to use +*) +let sep_noindent (pat:regexp) (default:string) + = del pat default + +(* +Variable: sep_re + The default regexp for a separator +*) + +let sep_re = /[=:]/ + +(* +Variable: sep_default + The default separator value +*) +let sep_default = "=" + + +(* Group: Stores *) + + +(* +Variable: sto_to_eol + Store until end of line +*) +let sto_to_eol = Sep.opt_space . store Rx.space_in + +(* +Variable: to_comment_re + Regex until comment +*) +let to_comment_re = /[^";# \t\n][^";#\n]*[^";# \t\n]|[^";# \t\n]/ + +(* +Variable: sto_to_comment + Store until comment +*) +let sto_to_comment = Sep.opt_space . store to_comment_re + +(* +Variable: sto_multiline + Store multiline values +*) +let sto_multiline = Sep.opt_space + . store (to_comment_re + . (/[ \t]*\n/ . Rx.space . to_comment_re)*) + +(* +Variable: sto_multiline_nocomment + Store multiline values without an end-of-line comment +*) +let sto_multiline_nocomment = Sep.opt_space + . store (Rx.space_in . (/[ \t]*\n/ . Rx.space . Rx.space_in)*) + + +(* Group: Define comment and defaults *) + +(* +View: comment_noindent + Map comments into "#comment" nodes, + no indentation allowed + + Parameters: + pat:regexp - pattern to delete before commented data + default:string - default pattern before commented data + + Sample Usage: + (start code) + let comment = IniFile.comment_noindent "#" "#" + let comment = IniFile.comment_noindent IniFile.comment_re IniFile.comment_default + (end code) +*) +let comment_noindent (pat:regexp) (default:string) = + Util.comment_generic_seteol (pat . Rx.opt_space) default eol + +(* +View: comment + Map comments into "#comment" nodes + + Parameters: + pat:regexp - pattern to delete before commented data + default:string - default pattern before commented data + + Sample Usage: + (start code) + let comment = IniFile.comment "#" "#" + let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + (end code) +*) +let comment (pat:regexp) (default:string) = + Util.comment_generic_seteol (Rx.opt_space . pat . Rx.opt_space) default eol + +(* +Variable: comment_re + Default regexp for pattern +*) + +let comment_re = /[;#]/ + +(* +Variable: comment_default + Default value for pattern +*) +let comment_default = ";" + +(* +View: empty_generic + Empty line, including empty comments + + Parameters: + indent:regexp - the indentation regexp + comment_re:regexp - the comment separator regexp +*) +let empty_generic (indent:regexp) (comment_re:regexp) = + Util.empty_generic_dos (indent . comment_re? . Rx.opt_space) + +(* +View: empty + Empty line +*) +let empty = empty_generic Rx.opt_space comment_re + +(* +View: empty_noindent + Empty line, without indentation +*) +let empty_noindent = empty_generic "" comment_re + + +(************************************************************************ + * Group: ENTRY + *************************************************************************) + +(* Group: entry includes comments *) + +(* +View: entry_generic_nocomment + A very generic INI File entry, not including comments + It allows to set the key lens (to set indentation + or subnodes linked to the key) as well as the comment + separator regexp, used to tune the store regexps. + + Parameters: + kw:lens - lens to match the key, including optional indentation + sep:lens - lens to use as key/value separator + comment_re:regexp - comment separator regexp + comment:lens - lens to use as comment + + Sample Usage: + > let entry = IniFile.entry_generic (key "setting") sep IniFile.comment_re comment +*) +let entry_generic_nocomment (kw:lens) (sep:lens) + (comment_re:regexp) (comment:lens) = + let bare_re_noquot = (/[^" \t\r\n]/ - comment_re) + in let bare_re = (/[^\r\n]/ - comment_re)+ + in let no_quot = /[^"\r\n]*/ + in let bare = Quote.do_dquote_opt_nil (store (bare_re_noquot . (bare_re* . bare_re_noquot)?)) + in let quoted = Quote.do_dquote (store (no_quot . comment_re+ . no_quot)) + in [ kw . sep . (Sep.opt_space . bare)? . (comment|eol) ] + | [ kw . sep . Sep.opt_space . quoted . (comment|eol) ] + +(* +View: entry_generic + A very generic INI File entry + It allows to set the key lens (to set indentation + or subnodes linked to the key) as well as the comment + separator regexp, used to tune the store regexps. + + Parameters: + kw:lens - lens to match the key, including optional indentation + sep:lens - lens to use as key/value separator + comment_re:regexp - comment separator regexp + comment:lens - lens to use as comment + + Sample Usage: + > let entry = IniFile.entry_generic (key "setting") sep IniFile.comment_re comment +*) +let entry_generic (kw:lens) (sep:lens) (comment_re:regexp) (comment:lens) = + entry_generic_nocomment kw sep comment_re comment | comment + +(* +View: entry + Generic INI File entry + + Parameters: + kw:regexp - keyword regexp for the label + sep:lens - lens to use as key/value separator + comment:lens - lens to use as comment + + Sample Usage: + > let entry = IniFile.entry setting sep comment +*) +let entry (kw:regexp) (sep:lens) (comment:lens) = + entry_generic (key kw) sep comment_re comment + +(* +View: indented_entry + Generic INI File entry that might be indented with an arbitrary + amount of whitespace + + Parameters: + kw:regexp - keyword regexp for the label + sep:lens - lens to use as key/value separator + comment:lens - lens to use as comment + + Sample Usage: + > let entry = IniFile.indented_entry setting sep comment +*) +let indented_entry (kw:regexp) (sep:lens) (comment:lens) = + entry_generic (Util.indent . key kw) sep comment_re comment + +(* +View: entry_multiline_generic + A very generic multiline INI File entry + It allows to set the key lens (to set indentation + or subnodes linked to the key) as well as the comment + separator regexp, used to tune the store regexps. + + Parameters: + kw:lens - lens to match the key, including optional indentation + sep:lens - lens to use as key/value separator + comment_re:regexp - comment separator regexp + comment:lens - lens to use as comment + eol:lens - lens for end of line + + Sample Usage: + > let entry = IniFile.entry_generic (key "setting") sep IniFile.comment_re comment comment_or_eol +*) +let entry_multiline_generic (kw:lens) (sep:lens) (comment_re:regexp) + (comment:lens) (eol:lens) = + let newline = /\r?\n[ \t]+/ + in let bare = + let word_re_noquot = (/[^" \t\r\n]/ - comment_re)+ + in let word_re = (/[^\r\n]/ - comment_re)+ + in let base_re = (word_re_noquot . (word_re* . word_re_noquot)?) + in let sto_re = base_re . (newline . base_re)* + | (newline . base_re)+ + in Quote.do_dquote_opt_nil (store sto_re) + in let quoted = + let no_quot = /[^"\r\n]*/ + in let base_re = (no_quot . comment_re+ . no_quot) + in let sto_re = base_re . (newline . base_re)* + | (newline . base_re)+ + in Quote.do_dquote (store sto_re) + in [ kw . sep . (Sep.opt_space . bare)? . eol ] + | [ kw . sep . Sep.opt_space . quoted . eol ] + | comment + + +(* +View: entry_multiline + Generic multiline INI File entry + + Parameters: + kw:regexp - keyword regexp for the label + sep:lens - lens to use as key/value separator + comment:lens - lens to use as comment +*) +let entry_multiline (kw:regexp) (sep:lens) (comment:lens) = + entry_multiline_generic (key kw) sep comment_re comment (comment|eol) + +(* +View: entry_multiline_nocomment + Generic multiline INI File entry without an end-of-line comment + + Parameters: + kw:regexp - keyword regexp for the label + sep:lens - lens to use as key/value separator + comment:lens - lens to use as comment +*) +let entry_multiline_nocomment (kw:regexp) (sep:lens) (comment:lens) = + entry_multiline_generic (key kw) sep comment_re comment eol + +(* +View: entry_list + Generic INI File list entry + + Parameters: + kw:regexp - keyword regexp for the label + sep:lens - lens to use as key/value separator + sto:regexp - store regexp for the values + list_sep:lens - lens to use as list separator + comment:lens - lens to use as comment +*) +let entry_list (kw:regexp) (sep:lens) (sto:regexp) (list_sep:lens) (comment:lens) = + let list = counter "elem" + . Build.opt_list [ seq "elem" . store sto ] list_sep + in Build.key_value_line_comment kw sep (Sep.opt_space . list) comment + +(* +View: entry_list_nocomment + Generic INI File list entry without an end-of-line comment + + Parameters: + kw:regexp - keyword regexp for the label + sep:lens - lens to use as key/value separator + sto:regexp - store regexp for the values + list_sep:lens - lens to use as list separator +*) +let entry_list_nocomment (kw:regexp) (sep:lens) (sto:regexp) (list_sep:lens) = + let list = counter "elem" + . Build.opt_list [ seq "elem" . store sto ] list_sep + in Build.key_value_line kw sep (Sep.opt_space . list) + +(* +Variable: entry_re + Default regexp for keyword +*) +let entry_re = ( /[A-Za-z][A-Za-z0-9._-]*/ ) + + +(************************************************************************ + * Group: RECORD + *************************************************************************) + +(* Group: Title definition *) + +(* +View: title + Title for . This maps the title of a record as a node in the abstract tree. + + Parameters: + kw:regexp - keyword regexp for the label + + Sample Usage: + > let title = IniFile.title IniFile.record_re +*) +let title (kw:regexp) + = Util.del_str "[" . key kw + . Util.del_str "]". eol + +(* +View: indented_title + Title for . This maps the title of a record as a node in the abstract tree. The title may be indented with arbitrary amounts of whitespace + + Parameters: + kw:regexp - keyword regexp for the label + + Sample Usage: + > let title = IniFile.title IniFile.record_re +*) +let indented_title (kw:regexp) + = Util.indent . title kw + +(* +View: title_label + Title for . This maps the title of a record as a value in the abstract tree. + + Parameters: + name:string - name for the title label + kw:regexp - keyword regexp for the label + + Sample Usage: + > let title = IniFile.title_label "target" IniFile.record_label_re +*) +let title_label (name:string) (kw:regexp) + = label name + . Util.del_str "[" . store kw + . Util.del_str "]". eol + +(* +View: indented_title_label + Title for . This maps the title of a record as a value in the abstract tree. The title may be indented with arbitrary amounts of whitespace + + Parameters: + name:string - name for the title label + kw:regexp - keyword regexp for the label + + Sample Usage: + > let title = IniFile.title_label "target" IniFile.record_label_re +*) +let indented_title_label (name:string) (kw:regexp) + = Util.indent . title_label name kw + + +(* +Variable: record_re + Default regexp for keyword pattern +*) +let record_re = ( /[^]\r\n\/]+/ - /#comment/ ) + +(* +Variable: record_label_re + Default regexp for <title_label> keyword pattern +*) +let record_label_re = /[^]\r\n]+/ + + +(* Group: Record definition *) + +(* +View: record_noempty + INI File Record with no empty lines allowed. + + Parameters: + title:lens - lens to use for title. Use either <title> or <title_label>. + entry:lens - lens to use for entries in the record. See <entry>. +*) +let record_noempty (title:lens) (entry:lens) + = [ title + . entry* ] + +(* +View: record + Generic INI File record + + Parameters: + title:lens - lens to use for title. Use either <title> or <title_label>. + entry:lens - lens to use for entries in the record. See <entry>. + + Sample Usage: + > let record = IniFile.record title entry +*) +let record (title:lens) (entry:lens) + = record_noempty title ( entry | empty ) + + +(************************************************************************ + * Group: GENERIC LENSES + *************************************************************************) + + +(* + +Group: Lens definition + +View: lns_noempty + Generic INI File lens with no empty lines + + Parameters: + record:lens - record lens to use. See <record_noempty>. + comment:lens - comment lens to use. See <comment>. + + Sample Usage: + > let lns = IniFile.lns_noempty record comment +*) +let lns_noempty (record:lens) (comment:lens) + = comment* . record* + +(* +View: lns + Generic INI File lens + + Parameters: + record:lens - record lens to use. See <record>. + comment:lens - comment lens to use. See <comment>. + + Sample Usage: + > let lns = IniFile.lns record comment +*) +let lns (record:lens) (comment:lens) + = lns_noempty record (comment|empty) + + +(************************************************************************ + * Group: READY-TO-USE LENSES + *************************************************************************) + +let record_anon (entry:lens) = [ label "section" . value ".anon" . ( entry | empty )+ ] + +(* +View: lns_loose + A loose, ready-to-use lens, featuring: + - sections as values (to allow '/' in names) + - support empty lines and comments + - support for [#;] as comment, defaulting to ";" + - .anon sections + - don't allow multiline values + - allow indented titles + - allow indented entries +*) +let lns_loose = + let l_comment = comment comment_re comment_default + in let l_sep = sep sep_re sep_default + in let l_entry = indented_entry entry_re l_sep l_comment + in let l_title = indented_title_label "section" (record_label_re - ".anon") + in let l_record = record l_title l_entry + in (record_anon l_entry)? . l_record* + +(* +View: lns_loose_multiline + A loose, ready-to-use lens, featuring: + - sections as values (to allow '/' in names) + - support empty lines and comments + - support for [#;] as comment, defaulting to ";" + - .anon sections + - allow multiline values +*) +let lns_loose_multiline = + let l_comment = comment comment_re comment_default + in let l_sep = sep sep_re sep_default + in let l_entry = entry_multiline entry_re l_sep l_comment + in let l_title = title_label "section" (record_label_re - ".anon") + in let l_record = record l_title l_entry + in (record_anon l_entry)? . l_record* + diff --git a/Sharp.Augeas.Test/lens/inittab.aug b/Sharp.Augeas.Test/lens/inittab.aug new file mode 100644 index 0000000..68593ec --- /dev/null +++ b/Sharp.Augeas.Test/lens/inittab.aug @@ -0,0 +1,31 @@ +(* Parsing /etc/inittab *) +module Inittab = + autoload xfm + + let sep = Util.del_str ":" + let eol = Util.del_str "\n" + + let id = /[^\/#:\n]{1,4}/ + let value = /[^#:\n]*/ + + let comment = Util.comment|Util.empty + + let record = + let field (name:string) = [ label name . store value ] in + let process = [ label "process" . store /[^#\n]*/ ] in + let eolcomment = + [ label "#comment" . del /#[ \t]*/ "# " + . store /([^ \t\n].*[^ \t\n]|[^ \t\n]?)/ ] in + [ key id . sep . + field "runlevels" . sep . + field "action" . sep . + process . eolcomment? . eol ] + + let lns = ( comment | record ) * + + let xfm = transform lns (incl "/etc/inittab") + + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/inputrc.aug b/Sharp.Augeas.Test/lens/inputrc.aug new file mode 100644 index 0000000..3902528 --- /dev/null +++ b/Sharp.Augeas.Test/lens/inputrc.aug @@ -0,0 +1,59 @@ +(* +Module: Inputrc + Parses /etc/inputrc + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 3 readline` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/inputrc. See <filter>. + +About: Examples + The <Test_Inputrc> file contains various examples and tests. +*) + +module Inputrc = + +autoload xfm + +(* View: entry + An inputrc mapping entry *) +let entry = + let mapping = [ label "mapping" . store /[A-Za-z0-9_."\*\/+\,\\-]+/ ] + in [ label "entry" + . Util.del_str "\"" . store /[^" \t\n]+/ + . Util.del_str "\":" . Sep.space + . mapping + . Util.eol ] + +(* View: variable + An inputrc variable declaration *) +let variable = [ Util.del_str "set" . Sep.space + . key (Rx.word - "entry") . Sep.space + . store Rx.word . Util.eol ] + +(* View: condition + An "if" declaration, recursive *) +let rec condition = [ Util.del_str "$if" . label "@if" + . Sep.space . store Rx.space_in . Util.eol + . (Util.empty | Util.comment | condition | variable | entry)* + . [ Util.del_str "$else" . label "@else" . Util.eol + . (Util.empty | Util.comment | condition | variable | entry)* ] ? + . Util.del_str "$endif" . Util.eol ] + +(* View: lns + The inputrc lens *) +let lns = (Util.empty | Util.comment | condition | variable | entry)* + +(* Variable: filter *) +let filter = incl "/etc/inputrc" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/interfaces.aug b/Sharp.Augeas.Test/lens/interfaces.aug new file mode 100644 index 0000000..fed982e --- /dev/null +++ b/Sharp.Augeas.Test/lens/interfaces.aug @@ -0,0 +1,131 @@ +(* Interfaces module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: man interfaces + +*) + +module Interfaces = + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol + +(* Define separators *) + +(* a line can be extended across multiple lines by making the last *) +(* character a backslash *) +let sep_spc = del /([ \t]+|[ \t]*\\\\\n[ \t]*)/ " " + +(* Define fields *) +let sto_to_eol = store /([^\\ \t\n].*[^\\ \t\n]|[^\\ \t\n])/ . eol +let sto_to_spc = store /[^\\ \t\n]+/ + +(* Define comments and empty lines *) + +(* note that the comment definition from Util does not support *) +(* splitting lines with a backlash *) +let comment = Util.comment + +let empty = Util.empty + +(* Define tree stanza_ids *) +let stanza_id (t:string) = key t . sep_spc . sto_to_spc +let stanza_param (l:string) = [ sep_spc . label l . sto_to_spc ] + +(* Define reserved words and multi-value options *) +let stanza_word = + /(source(-directory)?|iface|auto|allow-[a-z-]+|mapping|bond-slaves|bridge-ports)/ + +(* Define stanza option indentation *) +let stanza_indent = del /[ \t]*/ " " + +(* Define additional lines for multi-line stanzas *) +let stanza_option = [ stanza_indent + . key ( /[a-z0-9_-]+/ - stanza_word ) + . sep_spc + . sto_to_eol ] + +(* Define space-separated array *) +let array (r:regexp) (t:string) = del r t . label t . counter t + . [ sep_spc . seq t . sto_to_spc ]+ + +(************************************************************************ + * AUTO + *************************************************************************) + +let auto = [ array /(allow-)?auto/ "auto" . eol ] + +(************************************************************************ + * GENERIC ALLOW + *************************************************************************) + +let allow = [ key ( /allow-[a-z-]+/ - "allow-auto" ) + . counter "allow_seq" + . [ sep_spc . seq "allow_seq" . sto_to_spc ]+ + . eol ] + +(************************************************************************ + * MAPPING + *************************************************************************) + +let mapping = [ stanza_id "mapping" + . eol + . (stanza_option|comment|empty)+ ] + +(************************************************************************ + * IFACE + *************************************************************************) + +let multi_option (t:string) = [ stanza_indent . array t t . eol ] + +let iface = [ Util.indent + . stanza_id "iface" + . stanza_param "family" + . stanza_param "method" + . eol + . ( stanza_option + | multi_option "bond-slaves" + | multi_option "bridge-ports" + | comment + | empty )* ] + +(************************************************************************ + * SOURCE + *************************************************************************) + +let source = [ key "source" . sep_spc . sto_to_eol ] + +(************************************************************************ + * SOURCE-DIRECTORY + *************************************************************************) + +let source_directory = [ key "source-directory" . sep_spc . sto_to_eol ] + +(************************************************************************ + * STANZAS + *************************************************************************) + +(* The auto and hotplug stanzas always consist of one line only, while + iface and mapping can spand along more lines. Comment nodes are + inserted in the tree as direct children of the root node only when they + come after an auto or hotplug stanza, otherwise they are considered part + of an iface or mapping block *) + +let stanza_single = (auto|allow|source|source_directory) . (comment|empty)* +let stanza_multi = iface|mapping + +(************************************************************************ + * LENS & FILTER + *************************************************************************) + + let lns = (comment|empty)* . (stanza_multi | stanza_single)* + + let filter = (incl "/etc/network/interfaces") + . (incl "/etc/network/interfaces.d/*") + . Util.stdexcl + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/iproute2.aug b/Sharp.Augeas.Test/lens/iproute2.aug new file mode 100644 index 0000000..fa3dcb7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/iproute2.aug @@ -0,0 +1,10 @@ +module IPRoute2 = + autoload xfm + + let empty = [ del /[ \t]*#?[ \t]*\n/ "\n" ] + let id = Rx.hex | Rx.integer + let record = [ key id . del /[ \t]+/ "\t" . store /[a-zA-Z0-9\/-]+/ . Util.comment_or_eol ] + + let lns = ( empty | Util.comment | record ) * + + let xfm = transform lns (incl "/etc/iproute2/*" . Util.stdexcl) diff --git a/Sharp.Augeas.Test/lens/iptables.aug b/Sharp.Augeas.Test/lens/iptables.aug new file mode 100644 index 0000000..8ad2aef --- /dev/null +++ b/Sharp.Augeas.Test/lens/iptables.aug @@ -0,0 +1,87 @@ +module Iptables = + autoload xfm + +(* +Module: Iptables + Parse the iptables file format as produced by iptables-save. The + resulting tree is fairly simple; in particular a rule is simply + a long list of options/switches and their values (if any) + + This lens should be considered experimental +*) + +let comment = Util.comment +let empty = Util.empty +let eol = Util.eol +let spc = Util.del_ws_spc +let dels = Util.del_str + +let chain_name = store /[A-Za-z0-9_-]+/ +let chain = + let policy = [ label "policy" . store /ACCEPT|DROP|REJECT|-/ ] in + let counters_eol = del /[ \t]*(\[[0-9:]+\])?[ \t]*\n/ "\n" in + [ label "chain" . + dels ":" . chain_name . spc . policy . counters_eol ] + +let param (long:string) (short:string) = + [ label long . + spc . del (/--/ . long | /-/ . short) ("-" . short) . spc . + store /(![ \t]*)?[^ \t\n!-][^ \t\n]*/ ] + +(* A negatable parameter, which can either be FTW + ! --param arg + or + --param ! arg +*) +let neg_param (long:string) (short:string) = + [ label long . + [ spc . dels "!" . label "not" ]? . + spc . del (/--/ . long | /-/ . short) ("-" . short) . spc . + store /(![ \t]*)?[^ \t\n!-][^ \t\n]*/ ] + +let tcp_flags = + let flags = /SYN|ACK|FIN|RST|URG|PSH|ALL|NONE/ in + let flag_list (name:string) = + Build.opt_list [label name . store flags] (dels ",") in + [ label "tcp-flags" . + spc . dels "--tcp-flags" . + spc . flag_list "mask" . spc . flag_list "set" ] + +(* misses --set-counters *) +let ipt_match = + let any_key = /[a-zA-Z-][a-zA-Z0-9-]+/ - + /protocol|source|destination|jump|goto|in-interface|out-interface|fragment|match|tcp-flags/ in + let any_val = /([^" \t\n!-][^ \t\n]*)|"([^"\\\n]|\\\\.)*"/ in + let any_param = + [ [ spc . dels "!" . label "not" ]? . + spc . dels "--" . key any_key . (spc . store any_val)? ] in + (neg_param "protocol" "p" + |neg_param "source" "s" + |neg_param "destination" "d" + |param "jump" "j" + |param "goto" "g" + |neg_param "in-interface" "i" + |neg_param "out-interface" "o" + |neg_param "fragment" "f" + |param "match" "m" + |tcp_flags + |any_param)* + +let chain_action (n:string) (o:string) = + [ label n . + del (/--/ . n | o) o . + spc . chain_name . ipt_match . eol ] + +let table_rule = chain_action "append" "-A" + | chain_action "insert" "-I" + | empty + + +let table = [ del /\*/ "*" . label "table" . store /[a-z]+/ . eol . + (chain|comment|table_rule)* . + dels "COMMIT" . eol ] + +let lns = (comment|empty|table)* +let xfm = transform lns (incl "/etc/sysconfig/iptables" + . incl "/etc/sysconfig/iptables.save" + . incl "/etc/iptables-save") diff --git a/Sharp.Augeas.Test/lens/iscsid.aug b/Sharp.Augeas.Test/lens/iscsid.aug new file mode 100644 index 0000000..0f373da --- /dev/null +++ b/Sharp.Augeas.Test/lens/iscsid.aug @@ -0,0 +1,28 @@ +(* +Module: Iscsid +Parses iscsid configuration file +Author: Joey Boggs <jboggs@redhat.com> +About: Reference +This lens is targeted at /etc/iscsi/iscsid.conf +*) +module Iscsid = + autoload xfm + + let filter = incl "/etc/iscsi/iscsid.conf" + + let eol = Util.eol + let indent = Util.indent + let key_re = /[][A-Za-z0-9_.-]+/ + let eq = del /[ \t]*=[ \t]*/ " = " + let value_re = /[^ \t\n](.*[^ \t\n])?/ + + let comment = [ indent . label "#comment" . del /[#;][ \t]*/ "# " + . store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ . eol ] + + let empty = Util.empty + + let kv = [ indent . key key_re . eq . store value_re . eol ] + + let lns = (empty | comment | kv) * + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/jaas.aug b/Sharp.Augeas.Test/lens/jaas.aug new file mode 100644 index 0000000..4f06bad --- /dev/null +++ b/Sharp.Augeas.Test/lens/jaas.aug @@ -0,0 +1,36 @@ +(* Module Jaas *) +(* Original Author: Simon Vocella <voxsim@gmail.com> *) +(* Updated by: Steve Shipway <steve@steveshipway.org> *) +(* Changes: allow comments within Modules, allow optionless flags, *) +(* allow options without linebreaks, allow naked true/false options *) +(* Trailing ';' terminator should not be included in option value *) +(* Note: requires latest Util.aug for multiline comments to work *) + +module Jaas = + +autoload xfm + +let space_equal = del (/[ \t]*/ . "=" . /[ \t]*/) (" = ") +let lbrace = del (/[ \t\n]*\{[ \t]*\n/) " {\n" +let rbrace = del (/[ \t]*}[ \t]*;/) " };" +let word = /[A-Za-z0-9_.-]+/ +let wsnl = del (/[ \t\n]+/) ("\n") +let endflag = del ( /[ \t]*;/ ) ( ";" ) + +let value_re = + let value_squote = /'[^\n']*'/ + in let value_dquote = /"[^\n"]*"/ + in let value_tf = /(true|false)/ + in value_squote | value_dquote | value_tf + +let moduleOption = [ wsnl . key word . space_equal . (store value_re) ] +let moduleSuffix = ( moduleOption | Util.eol . Util.comment_c_style | Util.comment_multiline ) +let flag = [ Util.del_ws_spc . label "flag" . (store word) . moduleSuffix* . endflag ] +let loginModuleClass = [( Util.del_opt_ws "" . label "loginModuleClass" . (store word) . flag ) ] + +let content = (Util.empty | Util.comment_c_style | Util.comment_multiline | loginModuleClass)* +let loginModule = [Util.del_opt_ws "" . label "login" . (store word . lbrace) . (content . rbrace)] + +let lns = (Util.empty | Util.comment_c_style | Util.comment_multiline | loginModule)* +let filter = incl "/opt/shibboleth-idp/conf/login.config" +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/jettyrealm.aug b/Sharp.Augeas.Test/lens/jettyrealm.aug new file mode 100644 index 0000000..a3fca03 --- /dev/null +++ b/Sharp.Augeas.Test/lens/jettyrealm.aug @@ -0,0 +1,56 @@ +(* +Module: JettyRealm + JettyRealm Properties for Augeas + +Author: Brian Redbeard <redbeard@dead-city.org> + +About: Reference + This lens ensures that properties files for JettyRealms are properly + handled by Augeas. + +About: License + This file is licensed under the LGPL License. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Create a new user + > ins user after /files/etc/activemq/jetty-realm.properties/user + > set /files/etc/activemq/jetty-realm.properties/user[last()]/username redbeard + > set /files/etc/activemq/jetty-realm.properties/user[last()]/password testing + > set /files/etc/activemq/jetty-realm.properties/user[last()]/realm admin + ... + + * Delete the user named sample_user + > rm /files/etc/activemq/jetty-realm.properties/user[*][username = "sample_user"] + + Saving your file: + + > save + +About: Configuration files + This lens applies to jetty-realm.properties files. See <filter>. +*) + +module JettyRealm = + autoload xfm + + +(* View: comma_sep *) +let comma_sep = del /,[ \t]*/ ", " + +(* View: realm_entry *) +let realm_entry = [ label "user" . + [ label "username" . store Rx.word ] . del /[ \t]*:[ \t]*/ ": " . + [ label "password" . store Rx.word ] . + [ label "realm" . comma_sep . store Rx.word ]* . + Util.eol ] + +(* View: lns *) +let lns = ( Util.comment | Util.empty | realm_entry )* + + +(* Variable: filter *) +let filter = incl "/etc/activemq/jetty-realm.properties" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/jmxaccess.aug b/Sharp.Augeas.Test/lens/jmxaccess.aug new file mode 100644 index 0000000..c41c892 --- /dev/null +++ b/Sharp.Augeas.Test/lens/jmxaccess.aug @@ -0,0 +1,58 @@ +(* +Module: JMXAccess + JMXAccess module for Augeas + +Author: Brian Redbeard <redbeard@dead-city.org> + + +About: Reference + This lens ensures that files included in JMXAccess are properly + handled by Augeas. + +About: License + This file is licensed under the LGPL License. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Create a new user + > ins user after /files/etc/activemq/jmx.access + > set /files/etc/activemq/jmx.password/user[last()]/username redbeard + > set /files/etc/activemq/jmx.password/user[last()]/access readonly + ... + + * Delete the user named sample_user + > rm /files/etc/activemq/jmx.password/user[*][username = "sample_user"] + + Saving your file: + + > save + +About: Configuration files + This lens applies to relevant conf files located in /etc/activemq/ + The following views correspond to the related files: + * access_entry: + /etc/activemq/jmx.access + See <filter>. + + +*) + +module JMXAccess = + autoload xfm + +(* View: access_entry *) +let access_entry = [ label "user" . + [ label "username" . store Rx.word ] . Sep.space . + [ label "access" . store /(readonly|readwrite)/i ] . Util.eol ] + + + +(* View: lns *) +let lns = ( Util.comment | Util.empty | access_entry )* + + +(* Variable: filter *) +let filter = incl "/etc/activemq/jmx.access" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/jmxpassword.aug b/Sharp.Augeas.Test/lens/jmxpassword.aug new file mode 100644 index 0000000..369ec1d --- /dev/null +++ b/Sharp.Augeas.Test/lens/jmxpassword.aug @@ -0,0 +1,56 @@ +(* +Module: JMXPassword + JMXPassword for Augeas + +Author: Brian Redbeard <redbeard@dead-city.org> + + +About: Reference + This lens ensures that files included in JMXPassword are properly + handled by Augeas. + +About: License + This file is licensed under the LGPL License. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Create a new user + > ins user after /files/etc/activemq/jmx.password + > set /files/etc/activemq/jmx.password/user[last()]/username redbeard + > set /files/etc/activemq/jmx.password/user[last()]/password testing + ... + + * Delete the user named sample_user + > rm /files/etc/activemq/jmx.password/user[*][username = "sample_user"] + + Saving your file: + + > save + +About: Configuration files + This lens applies to relevant conf files located in /etc/activemq/ + The following views correspond to the related files: + * pass_entry: + /etc/activemq/jmx.password + See <filter>. + + +*) + +module JMXPassword = + autoload xfm + +(* View: pass_entry *) +let pass_entry = [ label "user" . + [ label "username" . store Rx.word ] . Sep.space . + [ label "password" . store Rx.no_spaces ] . Util.eol ] + +(* View: lns *) +let lns = ( Util.comment | Util.empty | pass_entry )* + + +(* Variable: filter *) +let filter = incl "/etc/activemq/jmx.password" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/json.aug b/Sharp.Augeas.Test/lens/json.aug new file mode 100644 index 0000000..c17f514 --- /dev/null +++ b/Sharp.Augeas.Test/lens/json.aug @@ -0,0 +1,50 @@ +module Json = + +(* A generic lens for Json files *) +(* Based on the following grammar from http://www.json.org/ *) +(* Object ::= '{'Members ? '}' *) +(* Members ::= Pair+ *) +(* Pair ::= String ':' Value *) +(* Array ::= '[' Elements ']' *) +(* Elements ::= Value ( "," Value )* *) +(* Value ::= String | Number | Object | Array | "true" | "false" | "null" *) +(* String ::= "\"" Char* "\"" *) +(* Number ::= /-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/ *) + + +let ws = del /[ \t\n]*/ "" +let comment = Util.empty_c_style | Util.comment_c_style | Util.comment_multiline +let comments = comment* . Sep.opt_space + +let comma = Util.del_str "," . comments +let colon = Util.del_str ":" . comments +let lbrace = Util.del_str "{" . comments +let rbrace = Util.del_str "}" +let lbrack = Util.del_str "[" . comments +let rbrack = Util.del_str "]" + +(* This follows the definition of 'string' at https://www.json.org/ + It's a little wider than what's allowed there as it would accept + nonsensical \u escapes *) +let str_store = Quote.dquote . store /([^\\"]|\\\\["\/bfnrtu\\])*/ . Quote.dquote + +let number = [ label "number" . store /-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/ + . comments ] +let str = [ label "string" . str_store . comments ] + +let const (r:regexp) = [ label "const" . store r . comments ] + +let fix_value (value:lens) = + let array = [ label "array" . lbrack + . ( ( Build.opt_list value comma . rbrack . comments ) + | (rbrack . ws) ) ] + in let pair = [ label "entry" . str_store . ws . colon . value ] + in let obj = [ label "dict" . lbrace + . ( ( Build.opt_list pair comma. rbrace . comments ) + | (rbrace . ws ) ) ] + in (str | number | obj | array | const /true|false|null/) + +(* Process arbitrarily deeply nested JSON objects *) +let rec rlns = fix_value rlns + +let lns = comments . rlns diff --git a/Sharp.Augeas.Test/lens/kdump.aug b/Sharp.Augeas.Test/lens/kdump.aug new file mode 100644 index 0000000..ddf50ed --- /dev/null +++ b/Sharp.Augeas.Test/lens/kdump.aug @@ -0,0 +1,83 @@ +(* +Module: Kdump + Parses /etc/kdump.conf + +Author: Roman Rakus <rrakus@redhat.com> + +About: References + manual page kdump.conf(5) + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to /etc/kdump.conf. See <filter>. +*) + +module Kdump = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +let empty = Util.empty +let comment = Util.comment +let value_to_eol = store /[^ \t\n#][^\n#]*[^ \t\n#]|[^ \t\n#]/ +let int_to_eol = store Rx.integer +let delimiter = Util.del_ws_spc +let eol = Util.eol +let value_to_spc = store Rx.neg1 +let key_to_space = key /[A-Za-z0-9_.\$-]+/ +let eq = Sep.equal + +(************************************************************************ + * Group: ENTRY TYPES + *************************************************************************) + +let list (kw:string) = counter kw + . Build.key_value_line_comment kw delimiter + (Build.opt_list [ seq kw . value_to_spc ] delimiter) + comment + +let mdl_key_value = [ delimiter . key_to_space . ( eq . value_to_spc)? ] +let mdl_options = [ key_to_space . mdl_key_value+ ] +let mod_options = [ key "options" . delimiter . mdl_options . (comment|eol) ] + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +(* Got from mount(8) *) +let fs_types = "adfs" | "affs" | "autofs" | "cifs" | "coda" | "coherent" + | "cramfs" | "debugfs" | "devpts" | "efs" | "ext" | "ext2" + | "ext3" | "ext4" | "hfs" | "hfsplus" | "hpfs" | "iso9660" + | "jfs" | "minix" | "msdos" | "ncpfs" | "nfs" | "nfs4" | "ntfs" + | "proc" | "qnx4" | "ramfs" | "reiserfs" | "romfs" | "squashfs" + | "smbfs" | "sysv" | "tmpfs" | "ubifs" | "udf" | "ufs" | "umsdos" + | "usbfs" | "vfat" | "xenix" | "xfs" | "xiafs" + +let simple_kws = "raw" | "net" | "path" | "core_collector" | "kdump_post" + | "kdump_pre" | "default" | "ssh" | "sshkey" | "dracut_args" + | "fence_kdump_args" + +let int_kws = "force_rebuild" | "override_resettable" | "debug_mem_level" + | "link_delay" | "disk_timeout" + +let option = Build.key_value_line_comment ( simple_kws | fs_types ) + delimiter value_to_eol comment + | Build.key_value_line_comment int_kws delimiter int_to_eol comment + | list "extra_bins" + | list "extra_modules" + | list "blacklist" + | list "fence_kdump_nodes" + | mod_options + +(* View: lns + The options lens +*) +let lns = ( empty | comment | option )* + +let filter = incl "/etc/kdump.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/keepalived.aug b/Sharp.Augeas.Test/lens/keepalived.aug new file mode 100644 index 0000000..abe65dd --- /dev/null +++ b/Sharp.Augeas.Test/lens/keepalived.aug @@ -0,0 +1,348 @@ +(* +Module: Keepalived + Parses /etc/keepalived/keepalived.conf + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 keepalived.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/keepalived/keepalived.conf. See <filter>. + +About: Examples + The <Test_Keepalived> file contains various examples and tests. +*) + + +module Keepalived = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Comments and empty lines *) + +(* View: indent *) +let indent = Util.indent + +(* View: eol *) +let eol = Util.eol + +(* View: opt_eol *) +let opt_eol = del /[ \t]*\n?/ " " + +(* View: sep_spc *) +let sep_spc = Sep.space + +(* View: comment +Map comments in "#comment" nodes *) +let comment = Util.comment_generic /[ \t]*[#!][ \t]*/ "# " + +(* View: comment_eol +Map comments at eol *) +let comment_eol = Util.comment_generic /[ \t]*[#!][ \t]*/ " # " + +(* View: comment_or_eol +A <comment_eol> or <eol> *) +let comment_or_eol = comment_eol | (del /[ \t]*[#!]?\n/ "\n") + +(* View: empty +Map empty lines *) +let empty = Util.empty + +(* View: sto_email_addr *) +let sto_email_addr = store Rx.email_addr + +(* Variable: word *) +let word = Rx.word + +(* Variable: word_slash *) +let word_slash = word | "/" + +(* View: sto_word *) +let sto_word = store word + +(* View: sto_num *) +let sto_num = store Rx.relinteger + +(* View: sto_ipv6 *) +let sto_ipv6 = store Rx.ipv6 + +(* View: sto_to_eol *) +let sto_to_eol = store /[^#! \t\n][^#!\n]*[^#! \t\n]|[^#! \t\n]/ + +(* View: field *) +let field (kw:regexp) (sto:lens) = indent . Build.key_value_line_comment kw sep_spc sto comment_eol + +(* View: flag +A single word *) +let flag (kw:regexp) = [ indent . key kw . comment_or_eol ] + +(* View: ip_port + An IP <space> port pair *) +let ip_port = [ label "ip" . sto_word ] . sep_spc . [ label "port" . sto_num ] + +(* View: lens_block +A generic block with a title lens. +The definition is very similar to Build.block_newlines +but uses a different type of <comment>. *) +let lens_block (title:lens) (sto:lens) = + [ indent . title + . Build.block_newlines sto comment . eol ] + +(* View: block +A simple block with just a block title *) +let block (kw:regexp) (sto:lens) = lens_block (key kw) sto + +(* View: named_block +A block with a block title and name *) +let named_block (kw:string) (sto:lens) = lens_block (key kw . sep_spc . sto_word) sto + +(* View: named_block_arg_title +A title lens for named_block_arg *) +let named_block_arg_title (kw:string) (name:string) (arg:string) = + key kw . sep_spc + . [ label name . sto_word ] + . sep_spc + . [ label arg . sto_word ] + +(* View: named_block_arg +A block with a block title, a name and an argument *) +let named_block_arg (kw:string) (name:string) (arg:string) (sto:lens) = + lens_block (named_block_arg_title kw name arg) sto + + +(************************************************************************ + * Group: GLOBAL CONFIGURATION + *************************************************************************) + +(* View: email +A simple email address entry *) +let email = [ indent . label "email" . sto_email_addr . comment_or_eol ] + +(* View: global_defs_field +Possible fields in the global_defs block *) +let global_defs_field = + let word_re = "smtp_server"|"lvs_id"|"router_id"|"vrrp_mcast_group4" + in let ipv6_re = "vrrp_mcast_group6" + in let num_re = "smtp_connect_timeout" + in block "notification_email" email + | field "notification_email_from" sto_email_addr + | field word_re sto_word + | field num_re sto_num + | field ipv6_re sto_ipv6 + +(* View: global_defs +A global_defs block *) +let global_defs = block "global_defs" global_defs_field + +(* View: prefixlen +A prefix for IP addresses *) +let prefixlen = [ label "prefixlen" . Util.del_str "/" . sto_num ] + +(* View: ipaddr +An IP address or range with an optional mask *) +let ipaddr = label "ipaddr" . store /[0-9.-]+/ . prefixlen? + +(* View: ipdev +A device for IP addresses *) +let ipdev = [ key "dev" . sep_spc . sto_word ] + +(* View: static_ipaddress_field +The whole string is fed to ip addr add. +You can truncate the string anywhere you like and let ip addr add use defaults for the rest of the string. +To be refined with fields according to `ip addr help`. +*) +let static_ipaddress_field = [ indent . ipaddr + . (sep_spc . ipdev)? + . comment_or_eol ] + +(* View: static_routes_field +src $SRC_IP to $DST_IP dev $SRC_DEVICE +*) +let static_routes_field = [ indent . label "route" + . [ key "src" . sto_word ] . sep_spc + . [ key "to" . sto_word ] . sep_spc + . [ key "dev" . sto_word ] . comment_or_eol ] + +(* View: static_routes *) +let static_routes = block "static_ipaddress" static_ipaddress_field + | block "static_routes" static_routes_field + + +(* View: global_conf +A global configuration entry *) +let global_conf = global_defs | static_routes + + +(************************************************************************ + * Group: VRRP CONFIGURATION + *************************************************************************) + +(*View: vrrp_sync_group_field *) +let vrrp_sync_group_field = + let to_eol_re = /notify(_master|_backup|_fault)?/ + in let flag_re = "smtp_alert" + in field to_eol_re sto_to_eol + | flag flag_re + | block "group" [ indent . key word . comment_or_eol ] + +(* View: vrrp_sync_group *) +let vrrp_sync_group = named_block "vrrp_sync_group" vrrp_sync_group_field + +(* View: vrrp_instance_field *) +let vrrp_instance_field = + let word_re = "state" | "interface" | "lvs_sync_daemon_interface" + in let num_re = "virtual_router_id" | "priority" | "advert_int" | /garp_master_(delay|repeat|refresh|refresh_repeat)/ + in let to_eol_re = /notify(_master|_backup|_fault)?/ | /(mcast|unicast)_src_ip/ + in let flag_re = "smtp_alert" | "nopreempt" | "ha_suspend" | "debug" | "use_vmac" | "vmac_xmit_base" | "native_ipv6" | "dont_track_primary" | "preempt_delay" + in field word_re sto_word + | field num_re sto_num + | field to_eol_re sto_to_eol + | flag flag_re + | block "authentication" ( + field /auth_(type|pass)/ sto_word + ) + | block "virtual_ipaddress" static_ipaddress_field + | block /track_(interface|script)/ ( flag word ) + | block "unicast_peer" static_ipaddress_field + +(* View: vrrp_instance *) +let vrrp_instance = named_block "vrrp_instance" vrrp_instance_field + +(* View: vrrp_script_field *) +let vrrp_script_field = + let num_re = "interval" | "weight" | "fall" | "raise" + in let to_eol_re = "script" + in field to_eol_re sto_to_eol + | field num_re sto_num + +(* View: vrrp_script *) +let vrrp_script = named_block "vrrp_script" vrrp_script_field + + +(* View: vrrpd_conf +contains subblocks of VRRP synchronization group(s) and VRRP instance(s) *) +let vrrpd_conf = vrrp_sync_group | vrrp_instance | vrrp_script + + +(************************************************************************ + * Group: REAL SERVER CHECKS CONFIGURATION + *************************************************************************) + +(* View: tcp_check_field *) +let tcp_check_field = + let word_re = "bindto" + in let num_re = /connect_(timeout|port)/ + in field word_re sto_word + | field num_re sto_num + +(* View: misc_check_field *) +let misc_check_field = + let flag_re = "misc_dynamic" + in let num_re = "misc_timeout" + in let to_eol_re = "misc_path" + in field num_re sto_num + | flag flag_re + | field to_eol_re sto_to_eol + +(* View: smtp_host_check_field *) +let smtp_host_check_field = + let word_re = "connect_ip" | "bindto" + in let num_re = "connect_port" + in field word_re sto_word + | field num_re sto_num + +(* View: smtp_check_field *) +let smtp_check_field = + let word_re = "connect_ip" | "bindto" + in let num_re = "connect_timeout" | "retry" | "delay_before_retry" + in let to_eol_re = "helo_name" + in field word_re sto_word + | field num_re sto_num + | field to_eol_re sto_to_eol + | block "host" smtp_host_check_field + +(* View: http_url_check_field *) +let http_url_check_field = + let word_re = "digest" + in let num_re = "status_code" + in let to_eol_re = "path" + in field word_re sto_word + | field num_re sto_num + | field to_eol_re sto_to_eol + +(* View: http_check_field *) +let http_check_field = + let num_re = /connect_(timeout|port)/ | "nb_get_retry" | "delay_before_retry" + in field num_re sto_num + | block "url" http_url_check_field + +(* View: real_server_field *) +let real_server_field = + let num_re = "weight" + in let flag_re = "inhibit_on_failure" + in let to_eol_re = /notify_(up|down)/ + in field num_re sto_num + | flag flag_re + | field to_eol_re sto_to_eol + | block "TCP_CHECK" tcp_check_field + | block "MISC_CHECK" misc_check_field + | block "SMTP_CHECK" smtp_check_field + | block /(HTTP|SSL)_GET/ http_check_field + +(************************************************************************ + * Group: LVS CONFIGURATION + *************************************************************************) + +(* View: virtual_server_field *) +let virtual_server_field = + let num_re = "delay_loop" | "persistence_timeout" | "quorum" | "hysteresis" + in let word_re = /lb_(algo|kind)/ | "nat_mask" | "protocol" | "persistence_granularity" + | "virtualhost" + in let flag_re = "ops" | "ha_suspend" | "alpha" | "omega" + in let to_eol_re = /quorum_(up|down)/ + in let ip_port_re = "sorry_server" + in field num_re sto_num + | field word_re sto_word + | flag flag_re + | field to_eol_re sto_to_eol + | field ip_port_re ip_port + | named_block_arg "real_server" "ip" "port" real_server_field + +(* View: virtual_server *) +let virtual_server = named_block_arg "virtual_server" "ip" "port" virtual_server_field + +(* View: virtual_server_group_field *) +let virtual_server_group_field = [ indent . label "vip" + . [ ipaddr ] + . sep_spc + . [ label "port" . sto_num ] + . comment_or_eol ] + +(* View: virtual_server_group *) +let virtual_server_group = named_block "virtual_server_group" virtual_server_group_field + +(* View: lvs_conf +contains subblocks of Virtual server group(s) and Virtual server(s) *) +let lvs_conf = virtual_server | virtual_server_group + + +(* View: lns + The keepalived lens +*) +let lns = ( empty | comment | global_conf | vrrpd_conf | lvs_conf )* + +(* Variable: filter *) +let filter = incl "/etc/keepalived/keepalived.conf" + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/known_hosts.aug b/Sharp.Augeas.Test/lens/known_hosts.aug new file mode 100644 index 0000000..6d027d6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/known_hosts.aug @@ -0,0 +1,70 @@ +(* +Module: Known_Hosts + Parses SSH known_hosts files + +Author: Raphaël Pinson <raphink@gmail.com> + +About: Reference + This lens manages OpenSSH's known_hosts files. See `man 8 sshd` for reference. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get a key by name from ssh_known_hosts + > print /files/etc/ssh_known_hosts/*[.="foo.example.com"] + ... + + * Change a host's key + > set /files/etc/ssh_known_hosts/*[.="foo.example.com"]/key "newkey" + +About: Configuration files + This lens applies to SSH known_hosts files. See <filter>. + +*) + +module Known_Hosts = + +autoload xfm + + +(* View: marker + The marker is optional, but if it is present then it must be one of + “@cert-authority”, to indicate that the line contains a certification + authority (CA) key, or “@revoked”, to indicate that the key contained + on the line is revoked and must not ever be accepted. + Only one marker should be used on a key line. +*) +let marker = [ key /@(revoked|cert-authority)/ . Sep.space ] + + +(* View: type + Bits, exponent, and modulus are taken directly from the RSA host key; + they can be obtained, for example, from /etc/ssh/ssh_host_key.pub. + The optional comment field continues to the end of the line, and is not used. +*) +let type = [ label "type" . store Rx.neg1 ] + + +(* View: entry + A known_hosts entry *) +let entry = + let alias = [ label "alias" . store Rx.neg1 ] + in let key = [ label "key" . store Rx.neg1 ] + in [ Util.indent . seq "entry" . marker? + . store Rx.neg1 + . (Sep.comma . Build.opt_list alias Sep.comma)? + . Sep.space . type . Sep.space . key + . Util.comment_or_eol ] + +(* View: lns + The known_hosts lens *) +let lns = (Util.empty | Util.comment | entry)* + +(* Variable: filter *) +let filter = incl "/etc/ssh/ssh_known_hosts" + . incl (Sys.getenv("HOME") . "/.ssh/known_hosts") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/koji.aug b/Sharp.Augeas.Test/lens/koji.aug new file mode 100644 index 0000000..8acd516 --- /dev/null +++ b/Sharp.Augeas.Test/lens/koji.aug @@ -0,0 +1,40 @@ +(* +Module: Koji + Parses koji config files + +Author: Pat Riehecky <riehecky@fnal.gov> + +About: Reference + This lens tries to keep as close as possible to koji config syntax + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to: + /etc/koji.conf + /etc/kojid/kojid.conf + /etc/koji-hub/hub.conf + /etc/kojira/kojira.conf + /etc/kojiweb/web.conf + /etc/koji-shadow/koji-shadow.conf + + See <filter>. +*) + +module Koji = + autoload xfm + +let lns = IniFile.lns_loose_multiline + +let filter = incl "/etc/koji.conf" + . incl "/etc/kojid/kojid.conf" + . incl "/etc/koji-hub/hub.conf" + . incl "/etc/kojira/kojira.conf" + . incl "/etc/kojiweb/web.conf" + . incl "/etc/koji-shadow/koji-shadow.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/krb5.aug b/Sharp.Augeas.Test/lens/krb5.aug new file mode 100644 index 0000000..0470888 --- /dev/null +++ b/Sharp.Augeas.Test/lens/krb5.aug @@ -0,0 +1,182 @@ +module Krb5 = + +autoload xfm + +let comment = Inifile.comment IniFile.comment_re "#" +let empty = Inifile.empty +let eol = Inifile.eol +let dels = Util.del_str + +let indent = del /[ \t]*/ "" +let comma_or_space_sep = del /[ \t,]{1,}/ " " +let eq = del /[ \t]*=[ \t]*/ " = " +let eq_openbr = del /[ \t]*=[ \t\n]*\{[ \t]*\n/ " = {\n" +let closebr = del /[ \t]*\}/ "}" + +(* These two regexps for realms and apps are not entirely true + - strictly speaking, there's no requirement that a realm is all upper case + and an application only uses lowercase. But it's what's used in practice. + + Without that distinction we couldn't distinguish between applications + and realms in the [appdefaults] section. +*) + +let include_re = /include(dir)?/ +let realm_re = /[A-Z0-9][.a-zA-Z0-9-]*/ +let realm_anycase_re = /[A-Za-z0-9][.a-zA-Z0-9-]*/ +let app_re = /[a-z][a-zA-Z0-9_]*/ +let name_re = /[.a-zA-Z0-9_-]+/ - include_re + +let value_br = store /[^;# \t\r\n{}]+/ +let value = store /[^;# \t\r\n]+/ +let entry (kw:regexp) (sep:lens) (value:lens) (comment:lens) + = [ indent . key kw . sep . value . (comment|eol) ] | comment + +let subsec_entry (kw:regexp) (sep:lens) (comment:lens) + = ( entry kw sep value_br comment ) | empty + +let simple_section (n:string) (k:regexp) = + let title = Inifile.indented_title n in + let entry = entry k eq value comment in + Inifile.record title entry + +let record (t:string) (e:lens) = + let title = Inifile.indented_title t in + Inifile.record title e + +let v4_name_convert (subsec:lens) = [ indent . key "v4_name_convert" . + eq_openbr . subsec* . closebr . eol ] + +(* + For the enctypes this appears to be a list of the valid entries: + c4-hmac arcfour-hmac aes128-cts rc4-hmac + arcfour-hmac-md5 des3-cbc-sha1 des-cbc-md5 des-cbc-crc +*) +let enctype_re = /[a-zA-Z0-9-]{3,}/ +let enctypes = /permitted_enctypes|default_tgs_enctypes|default_tkt_enctypes/i + +(* An #eol label prevents ambiguity between "k = v1 v2" and "k = v1\n k = v2" *) +let enctype_list (nr:regexp) (ns:string) = + indent . del nr ns . eq + . Build.opt_list [ label ns . store enctype_re ] comma_or_space_sep + . (comment|eol) . [ label "#eol" ] + +let libdefaults = + let option = entry (name_re - ("v4_name_convert" |enctypes)) eq value comment in + let enctype_lists = enctype_list /permitted_enctypes/i "permitted_enctypes" + | enctype_list /default_tgs_enctypes/i "default_tgs_enctypes" + | enctype_list /default_tkt_enctypes/i "default_tkt_enctypes" in + let subsec = [ indent . key /host|plain/ . eq_openbr . + (subsec_entry name_re eq comment)* . closebr . eol ] in + record "libdefaults" (option|enctype_lists|v4_name_convert subsec) + +let login = + let keys = /krb[45]_get_tickets|krb4_convert|krb_run_aklog/ + |/aklog_path|accept_passwd/ in + simple_section "login" keys + +let appdefaults = + let option = entry (name_re - ("realm" | "application")) eq value_br comment in + let realm = [ indent . label "realm" . store realm_re . + eq_openbr . (option|empty)* . closebr . eol ] in + let app = [ indent . label "application" . store app_re . + eq_openbr . (realm|option|empty)* . closebr . eol] in + record "appdefaults" (option|realm|app) + +let realms = + let simple_option = /kdc|admin_server|database_module|default_domain/ + |/v4_realm|auth_to_local(_names)?|master_kdc|kpasswd_server/ + |/admin_server|ticket_lifetime|pkinit_(anchors|identities|identity|pool)/ + |/krb524_server/ in + let subsec_option = /v4_instance_convert/ in + let option = subsec_entry simple_option eq comment in + let subsec = [ indent . key subsec_option . eq_openbr . + (subsec_entry name_re eq comment)* . closebr . eol ] in + let v4subsec = [ indent . key /host|plain/ . eq_openbr . + (subsec_entry name_re eq comment)* . closebr . eol ] in + let realm = [ indent . label "realm" . store realm_anycase_re . + eq_openbr . (option|subsec|(v4_name_convert v4subsec))* . + closebr . eol ] in + record "realms" (realm|comment) + +let domain_realm = + simple_section "domain_realm" name_re + +let logging = + let keys = /kdc|admin_server|default/ in + let xchg (m:regexp) (d:string) (l:string) = + del m d . label l in + let xchgs (m:string) (l:string) = xchg m m l in + let dest = + [ xchg /FILE[=:]/ "FILE=" "file" . value ] + |[ xchgs "STDERR" "stderr" ] + |[ xchgs "CONSOLE" "console" ] + |[ xchgs "DEVICE=" "device" . value ] + |[ xchgs "SYSLOG" "syslog" . + ([ xchgs ":" "severity" . store /[A-Za-z0-9]+/ ]. + [ xchgs ":" "facility" . store /[A-Za-z0-9]+/ ]?)? ] in + let entry = [ indent . key keys . eq . dest . (comment|eol) ] | comment in + record "logging" entry + +let capaths = + let realm = [ indent . key realm_re . + eq_openbr . + (entry realm_re eq value_br comment)* . closebr . eol ] in + record "capaths" (realm|comment) + +let dbdefaults = + let keys = /database_module|ldap_kerberos_container_dn|ldap_kdc_dn/ + |/ldap_kadmind_dn|ldap_service_password_file|ldap_servers/ + |/ldap_conns_per_server/ in + simple_section "dbdefaults" keys + +let dbmodules = + let subsec_key = /database_name|db_library|disable_last_success/ + |/disable_lockout|ldap_conns_per_server|ldap_(kdc|kadmind)_dn/ + |/ldap_(kdc|kadmind)_sasl_mech|ldap_(kdc|kadmind)_sasl_authcid/ + |/ldap_(kdc|kadmind)_sasl_authzid|ldap_(kdc|kadmind)_sasl_realm/ + |/ldap_kerberos_container_dn|ldap_servers/ + |/ldap_service_password_file|mapsize|max_readers|nosync/ + |/unlockiter/ in + let subsec_option = subsec_entry subsec_key eq comment in + let key = /db_module_dir/ in + let option = entry key eq value comment in + let realm = [ indent . label "realm" . store realm_re . + eq_openbr . (subsec_option)* . closebr . eol ] in + record "dbmodules" (option|realm) + +(* This section is not documented in the krb5.conf manpage, + but the Fermi example uses it. *) +let instance_mapping = + let value = dels "\"" . store /[^;# \t\r\n{}]*/ . dels "\"" in + let map_node = label "mapping" . store /[a-zA-Z0-9\/*]+/ in + let mapping = [ indent . map_node . eq . + [ label "value" . value ] . (comment|eol) ] in + let instance = [ indent . key name_re . + eq_openbr . (mapping|comment)* . closebr . eol ] in + record "instancemapping" instance + +let kdc = + simple_section "kdc" /profile/ + +let pam = + simple_section "pam" name_re + +let plugins = + let interface_option = subsec_entry name_re eq comment in + let interface = [ indent . key name_re . + eq_openbr . (interface_option)* . closebr . eol ] in + record "plugins" (interface|comment) + +let includes = Build.key_value_line include_re Sep.space (store Rx.fspath) +let include_lines = includes . (comment|empty)* + +let lns = (comment|empty)* . + (libdefaults|login|appdefaults|realms|domain_realm + |logging|capaths|dbdefaults|dbmodules|instance_mapping|kdc|pam|include_lines + |plugins)* + +let filter = (incl "/etc/krb5.conf.d/*.conf") + . (incl "/etc/krb5.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/ldif.aug b/Sharp.Augeas.Test/lens/ldif.aug new file mode 100644 index 0000000..e8751c0 --- /dev/null +++ b/Sharp.Augeas.Test/lens/ldif.aug @@ -0,0 +1,227 @@ +(* +Module: Ldif + Parses the LDAP Data Interchange Format (LDIF) + +Author: Dominic Cleal <dcleal@redhat.com> + +About: Reference + This lens tries to keep as close as possible to RFC2849 + <http://tools.ietf.org/html/rfc2849> + and OpenLDAP's ldif(5) + +About: Licence + This file is licensed under the LGPLv2+, like the rest of Augeas. +*) + +module Ldif = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + ************************************************************************) + +(* View: comment *) +let comment = Util.comment_generic /#[ \t]*/ "# " + +(* View: empty + Map empty lines, including empty comments *) +let empty = [ del /#?[ \t]*\n/ "\n" ] + +(* View: eol + Only eol, don't include whitespace *) +let eol = Util.del_str "\n" + +(* View: sep_colon + The separator for attributes and values *) +let sep_colon = del /:[ \t]*/ ": " + +(* View: sep_base64 + The separator for attributes and base64 encoded values *) +let sep_base64 = del /::[ \t]*/ ":: " + +(* View: sep_url + The separator for attributes and URL-sourced values *) +let sep_url = del /:<[ \t]*/ ":< " + +(* Variable: ldapoid_re + Format of an LDAP OID from RFC 2251 *) +let ldapoid_re = /[0-9][0-9\.]*/ + +(* View: sep_modspec + Separator between modify operations *) +let sep_modspec = Util.del_str "-" . eol + +(************************************************************************ + * Group: BASIC ATTRIBUTES + ************************************************************************) + +(* Different types of values, all permitting continuation where the next line + begins with whitespace *) +let attr_safe_string = + let line = /[^ \t\n:<][^\n]*/ + in let lines = line . (/\n[ \t]+[^ \t\n][^\n]*/)* + in sep_colon . store lines + +let attr_base64_string = + let line = /[a-zA-Z0-9=+]+/ + in let lines = line . (/\n[ \t]+/ . line)* + in sep_base64 . [ label "@base64" . store lines ] + +let attr_url_string = + let line = /[^ \t\n][^\n]*/ + in let lines = line . (/\n[ \t]+/ . line)* + in sep_url . [ label "@url" . store lines ] + +let attr_intflag = sep_colon . store /0|1/ + +(* View: attr_version + version-spec = "version:" FILL version-number *) +let attr_version = Build.key_value_line "version" sep_colon (store /[0-9]+/) + +(* View: attr_dn + dn-spec = "dn:" (FILL distinguishedName / + ":" FILL base64-distinguishedName) *) +let attr_dn = del /dn/i "dn" + . ( attr_safe_string | attr_base64_string ) + . eol + +(* View: attr_type + AttributeType = ldap-oid / (ALPHA *(attr-type-chars)) *) +let attr_type = ldapoid_re | /[a-zA-Z][a-zA-Z0-9-]*/ + - /dn/i + - /changeType/i + - /include/i + +(* View: attr_option + options = option / (option ";" options) *) +let attr_option = Util.del_str ";" + . [ label "@option" . store /[a-zA-Z0-9-]+/ ] + +(* View: attr_description + Attribute name, possibly with options *) +let attr_description = key attr_type . attr_option* + +(* View: attr_val_spec + Generic attribute with a value *) +let attr_val_spec = [ attr_description + . ( attr_safe_string + | attr_base64_string + | attr_url_string ) + . eol ] + +(* View: attr_changetype + Parameters: + t:regexp - value of changeType *) +let attr_changetype (t:regexp) = + key /changeType/i . sep_colon . store t . eol + +(* View: attr_modspec *) +let attr_modspec = key /add|delete|replace/ . sep_colon . store attr_type + . attr_option* . eol + +(* View: attr_dn_value + Parses an attribute line with a DN on the RHS + Parameters: + k:regexp - match attribute name as key *) +let attr_dn_value (k:regexp) = + [ key k . ( attr_safe_string | attr_base64_string ) . eol ] + +(* View: sep_line *) +let sep_line = empty | comment + +(* View: attr_include + OpenLDAP extension, must be separated by blank lines *) +let attr_include = eol . [ key "include" . sep_colon + . store /[^ \t\n][^\n]*/ . eol . comment* . eol ] + +(* View: sep_record *) +let sep_record = ( sep_line | attr_include )* + +(************************************************************************ + * Group: LDIF CONTENT RECORDS + ************************************************************************) + +(* View: ldif_attrval_record + ldif-attrval-record = dn-spec SEP 1*attrval-spec *) +let ldif_attrval_record = [ seq "record" + . attr_dn + . ( sep_line* . attr_val_spec )+ ] + +(* View: ldif_content + ldif-content = version-spec 1*(1*SEP ldif-attrval-record) *) +let ldif_content = [ label "@content" + . ( sep_record . attr_version )? + . ( sep_record . ldif_attrval_record )+ + . sep_record ] + +(************************************************************************ + * Group: LDIF CHANGE RECORDS + ************************************************************************) + +(* View: change_add + change-add = "add" SEP 1*attrval-spec *) +let change_add = [ attr_changetype "add" ] . ( sep_line* . attr_val_spec )+ + +(* View: change_delete + change-delete = "add" SEP 1*attrval-spec *) +let change_delete = [ attr_changetype "delete" ] + +(* View: change_modspec + change-modspec = add/delete/replace: AttributeDesc SEP *attrval-spec "-" *) +let change_modspec = attr_modspec . ( sep_line* . attr_val_spec )* + +(* View: change_modify + change-modify = "modify" SEP *mod-spec *) +let change_modify = [ attr_changetype "modify" ] + . ( sep_line* . [ change_modspec + . sep_line* . sep_modspec ] )+ + +(* View: change_modrdn + ("modrdn" / "moddn") SEP newrdn/newsuperior/deleteoldrdn *) +let change_modrdn = + let attr_deleteoldrdn = [ key "deleteoldrdn" . attr_intflag . eol ] + in let attrs_modrdn = attr_dn_value "newrdn" + | attr_dn_value "newsuperior" + | attr_deleteoldrdn + in [ attr_changetype /modr?dn/ ] + . ( sep_line | attrs_modrdn )* . attrs_modrdn + +(* View: change_record + changerecord = "changetype:" FILL (changeadd/delete/modify/moddn) *) +let change_record = ( change_add | change_delete | change_modify + | change_modrdn) + +(* View: change_control + "control:" FILL ldap-oid 0*1(1*SPACE ("true" / "false")) 0*1(value-spec) *) +let change_control = + let attr_criticality = [ Util.del_ws_spc . label "criticality" + . store /true|false/ ] + in let attr_ctrlvalue = [ label "value" . (attr_safe_string + | attr_base64_string + | attr_url_string ) ] + in [ key "control" . sep_colon . store ldapoid_re + . attr_criticality? . attr_ctrlvalue? . eol ] + +(* View: ldif_change_record + ldif-change-record = dn-spec SEP *control changerecord *) +let ldif_change_record = [ seq "record" . attr_dn + . ( ( sep_line | change_control )* . change_control )? + . sep_line* . change_record ] + +(* View: ldif_changes + ldif-changes = version-spec 1*(1*SEP ldif-change-record) *) +let ldif_changes = [ label "@changes" + . ( sep_record . attr_version )? + . ( sep_record . ldif_change_record )+ + . sep_record ] + +(************************************************************************ + * Group: LENS + ************************************************************************) + +(* View: lns *) +let lns = sep_record | ldif_content | ldif_changes + +let filter = incl "/etc/openldap/schema/*.ldif" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/ldso.aug b/Sharp.Augeas.Test/lens/ldso.aug new file mode 100644 index 0000000..d362573 --- /dev/null +++ b/Sharp.Augeas.Test/lens/ldso.aug @@ -0,0 +1,44 @@ +(* +Module: Keepalived + Parses /etc/ld.so.conf and /etc/ld.so.conf.d/* + +Author: Raphael Pinson <raphink@gmail.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/ld.so.conf and /etc/ld.so.conf.d/*. See <filter>. + +About: Examples + The <Test_Ldso> file contains various examples and tests. +*) + +module LdSo = + +autoload xfm + +(* View: path *) +let path = [ label "path" . store /[^# \t\n][^ \t\n]*/ . Util.eol ] + +(* View: include *) +let include = Build.key_value_line "include" Sep.space (store Rx.fspath) + +(* View: hwcap *) +let hwcap = + let hwcap_val = [ label "bit" . store Rx.integer ] . Sep.space . + [ label "name" . store Rx.word ] + in Build.key_value_line "hwcap" Sep.space hwcap_val + +(* View: lns *) +let lns = (Util.empty | Util.comment | path | include | hwcap)* + +(* Variable: filter *) +let filter = incl "/etc/ld.so.conf" + . incl "/etc/ld.so.conf.d/*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/lightdm.aug b/Sharp.Augeas.Test/lens/lightdm.aug new file mode 100644 index 0000000..4a24935 --- /dev/null +++ b/Sharp.Augeas.Test/lens/lightdm.aug @@ -0,0 +1,56 @@ +(* +Module: Lightdm + Lightdm module for Augeas for which parses /etc/lightdm/*.conf files which + are standard INI file format. + +Author: David Salmen <dsalmen@dsalmen.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/lightdm/*.conf. See <filter>. + +About: Tests + The tests/test_lightdm.aug file contains unit tests. +*) + +module Lightdm = + autoload xfm + +(************************************************************************ + * INI File settings + * + * lightdm.conf only supports "# as commentary and "=" as separator + *************************************************************************) +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" + + +(************************************************************************ + * ENTRY + * lightdm.conf uses standard INI File entries + *************************************************************************) +let entry = IniFile.indented_entry IniFile.entry_re sep comment + + +(************************************************************************ + * RECORD + * lightdm.conf uses standard INI File records + *************************************************************************) +let title = IniFile.indented_title IniFile.record_re +let record = IniFile.record title entry + + +(************************************************************************ + * LENS & FILTER + * lightdm.conf uses standard INI File records + *************************************************************************) +let lns = IniFile.lns record comment + +let filter = (incl "/etc/lightdm/*.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/limits.aug b/Sharp.Augeas.Test/lens/limits.aug new file mode 100644 index 0000000..3553da8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/limits.aug @@ -0,0 +1,71 @@ +(* Limits module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: /etc/security/limits.conf + +*) + +module Limits = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let comment_or_eol = Util.comment_or_eol +let spc = Util.del_ws_spc +let comment = Util.comment +let empty = Util.empty + +let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let domain = label "domain" . store /[%@]?[A-Za-z0-9_.:-]+|\*/ + +let type_re = "soft" + | "hard" + | "-" +let type = [ label "type" . store type_re ] + +let item_re = "core" + | "data" + | "fsize" + | "memlock" + | "nofile" + | "rss" + | "stack" + | "cpu" + | "nproc" + | "as" + | "maxlogins" + | "maxsyslogins" + | "priority" + | "locks" + | "sigpending" + | "msgqueue" + | "nice" + | "rtprio" + | "chroot" +let item = [ label "item" . store item_re ] + +let value = [ label "value" . store /[A-Za-z0-9_.\/-]+/ ] +let entry = [ domain . spc + . type . spc + . item . spc + . value . comment_or_eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter = incl "/etc/security/limits.conf" + . incl "/etc/security/limits.d/*.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/login_defs.aug b/Sharp.Augeas.Test/lens/login_defs.aug new file mode 100644 index 0000000..29b8a6e --- /dev/null +++ b/Sharp.Augeas.Test/lens/login_defs.aug @@ -0,0 +1,29 @@ +(* +Module: Login_defs + Lense for login.defs + +Author: Erinn Looney-Triggs + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to /etc/login.defs. See <filter>. +*) +module Login_defs = +autoload xfm + +(* View: record + A login.defs record *) +let record = + let value = store /[^ \t\n]+([ \t]+[^ \t\n]+)*/ in + [ key Rx.word . Sep.space . value . Util.eol ] + +(* View: lns + The login.defs lens *) +let lns = (record | Util.comment | Util.empty) * + +(* View: filter *) +let filter = incl "/etc/login.defs" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/logrotate.aug b/Sharp.Augeas.Test/lens/logrotate.aug new file mode 100644 index 0000000..2142774 --- /dev/null +++ b/Sharp.Augeas.Test/lens/logrotate.aug @@ -0,0 +1,126 @@ +(* Logrotate module for Augeas *) +(* Author: Raphael Pinson <raphink@gmail.com> *) +(* Patches from: *) +(* Sean Millichamp <sean@bruenor.org> *) +(* *) +(* Supported : *) +(* - defaults *) +(* - rules *) +(* - (pre|post)rotate entries *) +(* *) +(* Todo : *) +(* *) + +module Logrotate = + autoload xfm + + let sep_spc = Sep.space + let sep_val = del /[ \t]*=[ \t]*|[ \t]+/ " " + let eol = Util.eol + let num = Rx.relinteger + let word = /[^,#= \n\t{}]+/ + let filename = Quote.do_quote_opt (store /\/[^"',#= \n\t{}]+/) + let size = num . /[kMG]?/ + + let indent = del Rx.opt_space "\t" + + (* define omments and empty lines *) + let comment = Util.comment + let empty = Util.empty + + + (* Useful functions *) + + let list_item = [ sep_spc . key /[^\/+,# \n\t{}]+/ ] + let select_to_eol (kw:string) (select:regexp) = [ label kw . store select ] + let value_to_eol (kw:string) (value:regexp) = Build.key_value kw sep_val (store value) + let flag_to_eol (kw:string) = Build.flag kw + let list_to_eol (kw:string) = [ key kw . list_item+ ] + + + (* Defaults *) + + let create = + let mode = sep_spc . [ label "mode" . store num ] in + let owner = sep_spc . [ label "owner" . store word ] in + let group = sep_spc . [ label "group" . store word ] in + [ key "create" . + ( mode | mode . owner | mode . owner . group )? ] + + let su = + let owner = sep_spc . [ label "owner" . store word ] in + let group = sep_spc . [ label "group" . store word ] in + [ key "su" . + ( owner | owner . group )? ] + + let tabooext = [ key "tabooext" . ( sep_spc . store /\+/ )? . list_item+ ] + + let attrs = select_to_eol "schedule" /(hourly|daily|weekly|monthly|yearly)/ + | value_to_eol "rotate" num + | create + | flag_to_eol "nocreate" + | su + | value_to_eol "include" word + | select_to_eol "missingok" /(no)?missingok/ + | select_to_eol "compress" /(no)?compress/ + | select_to_eol "delaycompress" /(no)?delaycompress/ + | select_to_eol "ifempty" /(not)?ifempty/ + | select_to_eol "sharedscripts" /(no)?sharedscripts/ + | value_to_eol "size" size + | tabooext + | value_to_eol "olddir" word + | flag_to_eol "noolddir" + | value_to_eol "mail" word + | flag_to_eol "mailfirst" + | flag_to_eol "maillast" + | flag_to_eol "nomail" + | value_to_eol "errors" word + | value_to_eol "extension" word + | select_to_eol "dateext" /(no)?dateext/ + | value_to_eol "dateformat" word + | flag_to_eol "dateyesterday" + | value_to_eol "compresscmd" word + | value_to_eol "uncompresscmd" word + | value_to_eol "compressext" word + | list_to_eol "compressoptions" + | select_to_eol "copy" /(no)?copy/ + | select_to_eol "copytruncate" /(no)?copytruncate/ + | value_to_eol "maxage" num + | value_to_eol "minsize" size + | value_to_eol "maxsize" size + | select_to_eol "shred" /(no)?shred/ + | value_to_eol "shredcycles" num + | value_to_eol "start" num + + (* Define hooks *) + + + let hook_lines = + let line_re = /.*/ - /[ \t]*endscript[ \t]*/ in + store ( line_re . ("\n" . line_re)* )? . Util.del_str "\n" + + let hooks = + let hook_names = /(pre|post)rotate|(first|last)action/ in + [ key hook_names . eol . + hook_lines? . + del /[ \t]*endscript/ "\tendscript" ] + + (* Define rule *) + + let body = Build.block_newlines + (indent . (attrs | hooks) . eol) + Util.comment + + let rule = + let filename_entry = [ label "file" . filename ] in + let filename_sep = del /[ \t\n]+/ " " in + let filenames = Build.opt_list filename_entry filename_sep in + [ label "rule" . Util.indent . filenames . body . eol ] + + let lns = ( comment | empty | (attrs . eol) | rule )* + + let filter = incl "/etc/logrotate.d/*" + . incl "/etc/logrotate.conf" + . Util.stdexcl + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/logwatch.aug b/Sharp.Augeas.Test/lens/logwatch.aug new file mode 100644 index 0000000..9acf9a2 --- /dev/null +++ b/Sharp.Augeas.Test/lens/logwatch.aug @@ -0,0 +1,46 @@ +(* Logwatch module for Augeas + Author: Francois Lebel <francois@flebel.com> + Based on the dnsmasq lens written by Free Ekanayaka. + + Reference: man logwatch (8) + + "Format is one option per line, legal options are the same + as the long options legal on the command line. See + "logwatch.pl --help" or "man 8 logwatch" for details." + +*) + +module Logwatch = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let spc = Util.del_ws_spc +let comment = Util.comment +let empty = Util.empty + +let sep_eq = del / = / " = " +let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let entry_re = /[A-Za-z0-9._-]+/ +let entry = [ key entry_re . sep_eq . sto_to_eol . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter = incl "/etc/logwatch/conf/logwatch.conf" + . excl ".*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/lokkit.aug b/Sharp.Augeas.Test/lens/lokkit.aug new file mode 100644 index 0000000..830f956 --- /dev/null +++ b/Sharp.Augeas.Test/lens/lokkit.aug @@ -0,0 +1,84 @@ +module Lokkit = + autoload xfm + +(* Module: Lokkit + Parse the config file for lokkit from system-config-firewall +*) + +let comment = Util.comment +let empty = Util.empty +let eol = Util.eol +let spc = Util.del_ws_spc +let dels = Util.del_str + +let eq = del /[ \t=]+/ "=" +let token = store /[a-zA-Z0-9][a-zA-Z0-9-]*/ + +let long_opt (n:regexp) = + [ dels "--" . key n . eq . token . eol ] + +let flag (n:regexp) = + [ dels "--" . key n . eol ] + +let option (l:string) (s:string) = + del ("--" . l | "-" . s) ("--" . l) . label l . eq + +let opt (l:string) (s:string) = + [ option l s . token . eol ] + +(* trust directive + -t <interface>, --trust=<interface> +*) +let trust = + [ option "trust" "t" . store Rx.device_name . eol ] + +(* port directive + -p <port>[-<port>]:<protocol>, --port=<port>[-<port>]:<protocol> +*) +let port = + let portnum = store /[0-9]+/ in + [ option "port" "p" . + [ label "start" . portnum ] . + (dels "-" . [ label "end" . portnum])? . + dels ":" . [ label "protocol" . token ] . eol ] + +(* custom_rules directive + --custom-rules=[<type>:][<table>:]<filename> +*) +let custom_rules = + let types = store /ipv4|ipv6/ in + let tables = store /mangle|nat|filter/ in + let filename = store /[^ \t\n:=][^ \t\n:]*/ in + [ dels "--custom-rules" . label "custom-rules" . eq . + [ label "type" . types . dels ":" ]? . + [ label "table" . tables . dels ":"]? . + filename . eol ] + +(* forward_port directive + --forward-port=if=<interface>:port=<port>:proto=<protocol>[:toport=<destination port>][:toaddr=<destination address>] +*) +let forward_port = + let elem (n:string) (v:lens) = + [ key n . eq . v ] in + let ipaddr = store /[0-9.]+/ in + let colon = dels ":" in + [ dels "--forward-port" . label "forward-port" . eq . + elem "if" token . colon . + elem "port" token . colon . + elem "proto" token . + (colon . elem "toport" token)? . + (colon . elem "toaddr" ipaddr)? . eol ] + +let entry = + long_opt /selinux|selinuxtype|addmodule|removemodule|block-icmp/ + |flag /enabled|disabled/ + |opt "service" "s" + |port + |trust + |opt "masq" "m" + |custom_rules + |forward_port + +let lns = (comment|empty|entry)* + +let xfm = transform lns (incl "/etc/sysconfig/system-config-firewall") diff --git a/Sharp.Augeas.Test/lens/lvm.aug b/Sharp.Augeas.Test/lens/lvm.aug new file mode 100644 index 0000000..40cdc6a --- /dev/null +++ b/Sharp.Augeas.Test/lens/lvm.aug @@ -0,0 +1,75 @@ +(* +Module: LVM + Parses LVM metadata. + +Author: Gabriel de Perthuis <g2p.code+augeas@gmail.com> + +About: License + This file is licensed under the LGPL v2+. + +About: Configuration files + This lens applies to files in /etc/lvm/backup and /etc/lvm/archive. + +About: Examples + The <Test_LVM> file contains various examples and tests. +*) + +module LVM = + autoload xfm + + (* See lvm2/libdm/libdm-config.c for tokenisation; + * libdm uses a blacklist but I prefer the safer whitelist approach. *) + (* View: identifier + * The left hand side of a definition *) + let identifier = /[a-zA-Z0-9_-]+/ + + (* strings can contain backslash-escaped dquotes, but I don't know + * how to get the message across to augeas *) + let str = [label "str". Quote.do_dquote (store /([^\"]|\\\\.)*/)] + let int = [label "int". store Rx.relinteger] + (* View: flat_literal + * A literal without structure *) + let flat_literal = int|str + + (* allow multiline and mixed int/str, used for raids and stripes *) + (* View: list + * A list containing flat literals *) + let list = [ + label "list" . counter "list" + . del /\[[ \t\n]*/ "[" + .([seq "list". flat_literal . del /,[ \t\n]*/ ", "]* + . [seq "list". flat_literal . del /[ \t\n]*/ ""])? + . Util.del_str "]"] + + (* View: val + * Any value that appears on the right hand side of an assignment *) + let val = flat_literal | list + + (* View: nondef + * A line that doesn't contain a statement *) + let nondef = + Util.empty + | Util.comment + + (* Build.block couldn't be reused, because of recursion and + * a different philosophy of whitespace handling. *) + (* View: def + * An assignment, or a block containing definitions *) + let rec def = [ + Util.indent . key identifier . ( + del /[ \t]*\{\n/ " {\n" + .[label "dict".(nondef | def)*] + . Util.indent . Util.del_str "}\n" + |Sep.space_equal . val . Util.comment_or_eol)] + + (* View: lns + * The main lens *) + let lns = (nondef | def)* + + let filter = + incl "/etc/lvm/archive/*.vg" + . incl "/etc/lvm/backup/*" + . incl "/etc/lvm/lvm.conf" + . Util.stdexcl + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/mailscanner.aug b/Sharp.Augeas.Test/lens/mailscanner.aug new file mode 100644 index 0000000..972ae4a --- /dev/null +++ b/Sharp.Augeas.Test/lens/mailscanner.aug @@ -0,0 +1,65 @@ +(* +Module: Mailscanner + Parses MailScanner configuration files. + +Author: Andrew Colin Kissa <andrew@topdog.za.net> + Baruwa Enterprise Edition http://www.baruwa.com + +About: License + This file is licensed under the LGPL v2+. + +About: Configuration files + This lens applies to /etc/MailScanner/MailScanner.conf and files in + /etc/MailScanner/conf.d/. See <filter>. +*) + +module Mailscanner = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) +let comment = Util.comment + +let empty = Util.empty + +let space = Sep.space + +let eol = Util.eol + +let non_eq = /[^ =\t\r\n]+/ + +let non_space = /[^# \t\n]/ + +let any = /.*/ + +let word = /[A-Za-z%][ :<>%A-Za-z0-9_.-]+[A-Za-z%2]/ + +let include_kw = /include/ + +let keys = word - include_kw + +let eq = del /[ \t]*=/ " =" + +let indent = del /[ \t]*(\n[ \t]+)?/ " " + +let line_value = store (non_space . any . non_space | non_space) + +(************************************************************************ + * Group: Entries + *************************************************************************) + +let include_line = Build.key_value_line include_kw space (store non_eq) + +let normal_line = [ key keys . eq . (indent . line_value)? . eol ] + +(************************************************************************ + * Group: Lns and Filter + *************************************************************************) + +let lns = (empty|include_line|normal_line|comment) * + +let filter = (incl "/etc/MailScanner/MailScanner.conf") + . (incl "/etc/MailScanner/conf.d/*.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/mailscanner_rules.aug b/Sharp.Augeas.Test/lens/mailscanner_rules.aug new file mode 100644 index 0000000..87ba227 --- /dev/null +++ b/Sharp.Augeas.Test/lens/mailscanner_rules.aug @@ -0,0 +1,75 @@ +(* +Module: Mailscanner_rules + Parses MailScanner rules files. + +Author: Andrew Colin Kissa <andrew@topdog.za.net> + Baruwa Enterprise Edition http://www.baruwa.com + +About: License + This file is licensed under the LGPL v2+. + +About: Configuration files + This lens applies to MailScanner rules files + The format is described below: + + # NOTE: Fields are separated by TAB characters --- Important! + # + # Syntax is allow/deny/deny+delete/rename/rename to replacement-text/email-addresses, + # then regular expression, + # then log text, + # then user report text. + # The "email-addresses" can be a space or comma-separated list of email + # addresses. If the rule hits, the message will be sent to these address(es) + # instead of the original recipients. + + # If a rule is a "rename" rule, then the attachment filename will be renamed + # according to the "Default Rename Pattern" setting in MailScanner.conf. + # If a rule is a "rename" rule and the "to replacement-text" is supplied, then + # the text matched by the regular expression in the 2nd field of the line + # will be replaced with the "replacement-text" string. + # For example, the rule + # rename to .ppt \.pps$ Renamed .pps to .ppt Renamed .pps to .ppt + # will find all filenames ending in ".pps" and rename them so they end in + # ".ppt" instead. +*) + +module Mailscanner_Rules = +autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = del /\n/ "\n" +let ws = del /[\t]+/ "\t" +let comment = Util.comment +let empty = Util.empty +let action = /allow|deny|deny\+delete|rename|rename[ ]+to[ ]+[^# \t\n]+|([A-Za-z0-9_+.-]+@[A-Za-z0-9_.-]+[, ]?)+/ +let non_space = /[^# \t\n]+/ +let non_tab = /[^\t\n]+/ + +let field (l:string) (r:regexp) + = [ label l . store r ] + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let entry = [ seq "rule" . field "action" action + . ws . field "regex" non_tab + . ws . field "log-text" non_tab + . ws . field "user-report" non_tab + . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry)* + +let filter = (incl "/etc/MailScanner/filename.rules.conf") + . (incl "/etc/MailScanner/filetype.rules.conf") + . (incl "/etc/MailScanner/archives.filename.rules.conf") + . (incl "/etc/MailScanner/archives.filetype.rules.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/masterpasswd.aug b/Sharp.Augeas.Test/lens/masterpasswd.aug new file mode 100644 index 0000000..06e4e0f --- /dev/null +++ b/Sharp.Augeas.Test/lens/masterpasswd.aug @@ -0,0 +1,148 @@ +(* + Module: MasterPasswd + Parses /etc/master.passwd + + Author: Matt Dainty <matt@bodgit-n-scarper.com> + + About: Reference + - man 5 master.passwd + + Each line in the master.passwd file represents a single user record, whose + colon-separated attributes correspond to the members of the passwd struct + +*) + +module MasterPasswd = + + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Comments and empty lines *) + +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty +let dels = Util.del_str + +let word = Rx.word +let integer = Rx.integer + +let colon = Sep.colon + +let sto_to_eol = Passwd.sto_to_eol +let sto_to_col = Passwd.sto_to_col +(* Store an empty string if nothing matches *) +let sto_to_col_or_empty = Passwd.sto_to_col_or_empty + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +let username = /[_.A-Za-z0-9][-_.A-Za-z0-9]*\$?/ + +(* View: password + pw_passwd *) +let password = [ label "password" . sto_to_col? . colon ] + +(* View: uid + pw_uid *) +let uid = [ label "uid" . store integer . colon ] + +(* View: gid + pw_gid *) +let gid = [ label "gid" . store integer . colon ] + +(* View: class + pw_class *) +let class = [ label "class" . sto_to_col? . colon ] + +(* View: change + pw_change *) +let change_date = [ label "change_date" . store integer? . colon ] + +(* View: expire + pw_expire *) +let expire_date = [ label "expire_date" . store integer? . colon ] + +(* View: name + pw_gecos; the user's full name *) +let name = [ label "name" . sto_to_col? . colon ] + +(* View: home + pw_dir *) +let home = [ label "home" . sto_to_col? . colon ] + +(* View: shell + pw_shell *) +let shell = [ label "shell" . sto_to_eol? ] + +(* View: entry + struct passwd *) +let entry = [ key username + . colon + . password + . uid + . gid + . class + . change_date + . expire_date + . name + . home + . shell + . eol ] + +(* NIS entries *) +let niscommon = [ label "password" . sto_to_col ]? . colon + . [ label "uid" . store integer ]? . colon + . [ label "gid" . store integer ]? . colon + . [ label "class" . sto_to_col ]? . colon + . [ label "change_date" . store integer ]? . colon + . [ label "expire_date" . store integer ]? . colon + . [ label "name" . sto_to_col ]? . colon + . [ label "home" . sto_to_col ]? . colon + . [ label "shell" . sto_to_eol ]? + +let nisentry = + let overrides = + colon + . niscommon in + [ dels "+@" . label "@nis" . store username . overrides . eol ] + +let nisuserplus = + let overrides = + colon + . niscommon in + [ dels "+" . label "@+nisuser" . store username . overrides . eol ] + +let nisuserminus = + let overrides = + colon + . niscommon in + [ dels "-" . label "@-nisuser" . store username . overrides . eol ] + +let nisdefault = + let overrides = + colon + . [ label "password" . sto_to_col_or_empty . colon ] + . [ label "uid" . store integer? . colon ] + . [ label "gid" . store integer? . colon ] + . [ label "class" . sto_to_col? . colon ] + . [ label "change_date" . store integer? . colon ] + . [ label "expire_date" . store integer? . colon ] + . [ label "name" . sto_to_col? . colon ] + . [ label "home" . sto_to_col? . colon ] + . [ label "shell" . sto_to_eol? ] in + [ dels "+" . label "@nisdefault" . overrides? . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry|nisentry|nisdefault|nisuserplus|nisuserminus) * + +let filter = incl "/etc/master.passwd" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/mcollective.aug b/Sharp.Augeas.Test/lens/mcollective.aug new file mode 100644 index 0000000..e23b372 --- /dev/null +++ b/Sharp.Augeas.Test/lens/mcollective.aug @@ -0,0 +1,41 @@ +(* +Module: MCollective + Parses MCollective's configuration files + +Author: Marc Fournier <marc.fournier@camptocamp.com> + +About: Reference + This lens is based on MCollective's default client.cfg and server.cfg. + +About: Usage Example +(start code) + augtool> get /files/etc/mcollective/client.cfg/plugin.psk + /files/etc/mcollective/client.cfg/plugin.psk = unset + + augtool> ls /files/etc/mcollective/client.cfg/ + topicprefix = /topic/ + main_collective = mcollective + collectives = mcollective + [...] + + augtool> set /files/etc/mcollective/client.cfg/plugin.stomp.password example123 + augtool> save + Saved 1 file(s) +(end code) + The <Test_MCollective> file also contains various examples. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module MCollective = +autoload xfm + +let lns = Simplevars.lns + +let filter = incl "/etc/mcollective/client.cfg" + . incl "/etc/mcollective/server.cfg" + . incl "/etc/puppetlabs/mcollective/client.cfg" + . incl "/etc/puppetlabs/mcollective/server.cfg" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/mdadm_conf.aug b/Sharp.Augeas.Test/lens/mdadm_conf.aug new file mode 100644 index 0000000..3bf5887 --- /dev/null +++ b/Sharp.Augeas.Test/lens/mdadm_conf.aug @@ -0,0 +1,279 @@ +(****************************************************************************** +Mdadm_conf module for Augeas + +Author: Matthew Booth <mbooth@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 LGPL v2+. + +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 = /dev(i(ce?)?)?/i + +let dev_containers_re = /containers/i +let dev_partitions_re = /partitions/i + +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 = /arr(ay?)?/i + +let arr_auto_re = /auto/i +let arr_bitmap_re = /bitmap/i +let arr_container_re = /container/i +let arr_devices_re = /devices/i +let arr_disks_re = /disks/i (* Undocumented *) +let arr_level_re = /level/i +let arr_member_re = /member/i +let arr_metadata_re = /metadata/i +let arr_name_re = /name/i +let arr_num_devices_re = /num-devices/i +let arr_spare_group_re = /spare-group/i +let arr_spares_re = /spares/i +let arr_super_minor_re = /super-minor/i +let arr_uuid_re = /uuid/i + +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 = /mai(l(a(d(dr?)?)?)?)?/i + +(* We intentionally 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 = /mailf(r(om?)?)?/i + +let mailfrom = [ del mailfrom_re "MAILFROM" . label "mailfrom" + . ( value_sep . [ label "value" . store value ] )* . eol ] + + +(****************************************************************************** + * PROGRAM + ******************************************************************************) + +let program_re = /pro(g(r(am?)?)?)?/i + +let program = simplevalue program_re "program" "PROGRAM" + + +(****************************************************************************** + * CREATE + ******************************************************************************) + +let create_re = /cre(a(te?)?)?/i + +let cre_auto_re = /auto/i +let cre_owner_re = /owner/i +let cre_group_re = /group/i +let cre_mode_re = /mode/i +let cre_metadata_re = /metadata/i +let cre_symlinks_re = /symlinks/i + +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 = /hom(e(h(o(st?)?)?)?)?/i + +let homehost = simplevalue homehost_re "homehost" "HOMEHOST" + + +(****************************************************************************** + * AUTO + ******************************************************************************) + +let auto_re = /auto?/i + +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 = /pol(i(cy?)?)?/i +let part_policy_re = /par(t(-(p(o(l(i(cy?)?)?)?)?)?)?)?/i + +(* 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" + . incl "/etc/mdadm/mdadm.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/memcached.aug b/Sharp.Augeas.Test/lens/memcached.aug new file mode 100644 index 0000000..4688ce9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/memcached.aug @@ -0,0 +1,47 @@ +(* +Module: Memcached + Parses Memcached's configuration files + +Author: Marc Fournier <marc.fournier@camptocamp.com> + +About: Reference + This lens is based on Memcached's default memcached.conf file. + +About: Usage Example +(start code) + augtool> get /files/etc/memcached.conf/u + /files/etc/memcached.conf/u = nobody + + augtool> set /files/etc/memcached.conf/m 128 + augtool> save + Saved 1 file(s) +(end code) + The <Test_Memcached> file also contains various examples. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Memcached = +autoload xfm + +let comment = Util.comment +let comment_eol = Util.comment_generic /[#][ \t]*/ "# " +let option = /[a-zA-Z]/ +let val = /[^# \n\t]+/ +let empty = Util.empty +let eol = Util.del_str "\n" + +let entry = [ Util.del_str "-" . key option + . ( Util.del_ws_spc . (store val) )? + . del /[ \t]*/ "" . (eol|comment_eol) ] + +let logfile = Build.key_value_line_comment + "logfile" Sep.space (store val) comment + +let lns = ( entry | logfile | comment | empty )* + +let filter = incl "/etc/memcached.conf" + . incl "/etc/memcachedb.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/mke2fs.aug b/Sharp.Augeas.Test/lens/mke2fs.aug new file mode 100644 index 0000000..46a7136 --- /dev/null +++ b/Sharp.Augeas.Test/lens/mke2fs.aug @@ -0,0 +1,194 @@ +(* +Module: Mke2fs + Parses /etc/mke2fs.conf + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 mke2fs.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/mke2fs.conf. See <filter>. +*) + + +module Mke2fs = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: comment *) +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + +(* View: sep *) +let sep = IniFile.sep /=[ \t]*/ "=" + +(* View: empty *) +let empty = IniFile.empty + +(* View: boolean + The configuration parser of e2fsprogs recognizes different values + for booleans, so list all the recognized values *) +let boolean = ("y"|"yes"|"true"|"t"|"1"|"on"|"n"|"no"|"false"|"nil"|"0"|"off") + +(* View: fspath *) +let fspath = /[^ \t\n"]+/ + + +(************************************************************************ + * Group: RECORD TYPES + *************************************************************************) + + +(* View: entry + A generic entry for lens lns *) +let entry (kw:regexp) (lns:lens) = Build.key_value_line kw sep lns + + +(* View: list_sto + A list of values with given lens *) +let list_sto (kw:regexp) (lns:lens) = + entry kw (Quote.do_dquote_opt_nil (Build.opt_list [lns] Sep.comma)) + +(* View: entry_sto + Store a regexp as entry value *) +let entry_sto (kw:regexp) (val:regexp) = + entry kw (Quote.do_dquote_opt_nil (store val)) + | entry kw (Util.del_str "\"\"") + + +(************************************************************************ + * Group: COMMON ENTRIES + *************************************************************************) + +(* View: common_entries_list + Entries with a list value *) +let common_entries_list = ("base_features"|"default_features"|"default_mntopts") + +(* View: common_entries_int + Entries with an integer value *) +let common_entries_int = ("cluster_size"|"flex_bg_size"|"force_undo" + |"inode_ratio"|"inode_size"|"num_backup_sb") + +(* View: common_entries_bool + Entries with a boolean value *) +let common_entries_bool = ("auto_64-bit_support"|"discard" + |"enable_periodic_fsck"|"lazy_itable_init" + |"lazy_journal_init"|"packed_meta_blocks") + +(* View: common_entries_string + Entries with a string value *) +let common_entries_string = ("encoding"|"journal_location") + +(* View: common_entries_double + Entries with a double value *) +let common_entries_double = ("reserved_ratio") + +(* View: common_entry + Entries shared between <defaults> and <fs_types> sections *) +let common_entry = list_sto common_entries_list (key Rx.word) + | entry_sto common_entries_int Rx.integer + | entry_sto common_entries_bool boolean + | entry_sto common_entries_string Rx.word + | entry_sto common_entries_double Rx.decimal + | entry_sto "blocksize" ("-"? . Rx.integer) + | entry_sto "hash_alg" ("legacy"|"half_md4"|"tea") + | entry_sto "errors" ("continue"|"remount-ro"|"panic") + | list_sto "features" + ([del /\^/ "^" . label "disable"]? + . key Rx.word) + | list_sto "options" + (key Rx.word . Util.del_str "=" + . store Rx.word) + +(************************************************************************ + * Group: DEFAULTS SECTION + *************************************************************************) + +(* View: defaults_entry + Possible entries under the <defaults> section *) +let defaults_entry = entry_sto "fs_type" Rx.word + | entry_sto "undo_dir" fspath + +(* View: defaults_title + Title for the <defaults> section *) +let defaults_title = IniFile.title "defaults" + +(* View: defaults + A defaults section *) +let defaults = IniFile.record defaults_title + ((Util.indent . (defaults_entry|common_entry)) | comment) + + +(************************************************************************ + * Group: FS_TYPES SECTION + *************************************************************************) + +(* View: fs_types_record + Fs group records under the <fs_types> section *) +let fs_types_record = [ label "filesystem" + . Util.indent . store Rx.word + . del /[ \t]*=[ \t]*\{[ \t]*\n/ " = {\n" + . ((Util.indent . common_entry) | empty | comment)* + . del /[ \t]*\}[ \t]*\n/ " }\n" ] + +(* View: fs_types_title + Title for the <fs_types> section *) +let fs_types_title = IniFile.title "fs_types" + +(* View: fs_types + A fs_types section *) +let fs_types = IniFile.record fs_types_title + (fs_types_record | comment) + + +(************************************************************************ + * Group: OPTIONS SECTION + *************************************************************************) + +(* View: options_entries_int + Entries with an integer value *) +let options_entries_int = ("proceed_delay"|"sync_kludge") + +(* View: options_entries_bool + Entries with a boolean value *) +let options_entries_bool = ("old_bitmaps") + +(* View: options_entry + Possible entries under the <options> section *) +let options_entry = entry_sto options_entries_int Rx.integer + | entry_sto options_entries_bool boolean + +(* View: defaults_title + Title for the <options> section *) +let options_title = IniFile.title "options" + +(* View: options + A options section *) +let options = IniFile.record options_title + ((Util.indent . options_entry) | comment) + + +(************************************************************************ + * Group: LENS AND FILTER + *************************************************************************) + +(* View: lns + The mke2fs lens +*) +let lns = (empty|comment)* . (defaults|fs_types|options)* + +(* Variable: filter *) +let filter = incl "/etc/mke2fs.conf" + +let xfm = transform lns filter + + diff --git a/Sharp.Augeas.Test/lens/modprobe.aug b/Sharp.Augeas.Test/lens/modprobe.aug new file mode 100644 index 0000000..bd897b9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/modprobe.aug @@ -0,0 +1,111 @@ +(* +Module: Modprobe + Parses /etc/modprobe.conf and /etc/modprobe.d/* + +Original Author: David Lutterkort <lutter@redhat.com> + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 modprobe.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/modprobe.conf and /etc/modprobe.d/*. See <filter>. +*) + +module Modprobe = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: comment *) +let comment = Util.comment + +(* View: empty *) +let empty = Util.empty + +(* View: sep_space *) +let sep_space = del /([ \t]|(\\\\\n))+/ " " + +(* View: sto_no_spaces *) +let sto_no_spaces = store /[^# \t\n\\\\]+/ + +(* View: sto_no_colons *) +let sto_no_colons = store /[^:# \t\n\\\\]+/ + +(* View: sto_to_eol *) +let sto_to_eol = store /(([^# \t\n\\\\][^#\n\\\\]*[ \t]*\\\\[ \t]*\n[ \t]*)*([^# \t\n\\\\][^#\n\\\\]*[^# \t\n\\\\]|[^# \t\n\\\\])|[^# \t\n\\\\])/ + +(* View: alias *) +let alias = + let modulename = [ label "modulename" . sto_no_spaces ] in + Build.key_value_line_comment "alias" sep_space + (sto_no_spaces . sep_space . modulename) + comment + +(************************************************************************ + * Group: ENTRY TYPES + *************************************************************************) + +(* View: options *) +let options = + let opt_value = /[^#" \t\n\\\\]+|"[^#"\n\\\\]*"/ in + let option = [ key Rx.word . (del /[ \t]*=[ \t]*/ "=" . store opt_value)? ] in + [ key "options" . sep_space . sto_no_spaces + . (sep_space . option)* . Util.comment_or_eol ] + +(* View: install_remove *) +let kv_line_command (kw:regexp) = + let command = [ label "command" . sto_to_eol ] in + [ key kw . sep_space . sto_no_spaces + . sep_space . command . Util.comment_or_eol ] + +(* View: blacklist *) +let blacklist = Build.key_value_line_comment "blacklist" sep_space + sto_no_spaces + comment + +(* View: config *) +let config = Build.key_value_line_comment "config" sep_space + (store /binary_indexes|yes|no/) + comment + +(* View: softdep *) +let softdep = + let premod = [ label "pre" . sep_space . sto_no_colons ] in + let pre = sep_space . Util.del_str "pre:" . premod+ in + let postmod = [ label "post" . sep_space . sto_no_colons ] in + let post = sep_space . Util.del_str "post:" . postmod+ in + [ key "softdep" . sep_space . sto_no_colons . pre? . post? + . Util.comment_or_eol ] + +(* View: entry *) +let entry = alias + | options + | kv_line_command /install|remove/ + | blacklist + | config + | softdep + +(************************************************************************ + * Group: LENS AND FILTER + *************************************************************************) + +(* View: lns *) +let lns = (comment|empty|entry)* + +(* View: filter *) +let filter = (incl "/etc/modprobe.conf") . + (incl "/etc/modprobe.d/*"). + (incl "/etc/modprobe.conf.local"). + Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/modules.aug b/Sharp.Augeas.Test/lens/modules.aug new file mode 100644 index 0000000..ce598fe --- /dev/null +++ b/Sharp.Augeas.Test/lens/modules.aug @@ -0,0 +1,35 @@ +(* +Module: Modules + Parses /etc/modules + +About: Reference + This lens tries to keep as close as possible to `man 5 modules` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/modules. See <filter>. +*) +module Modules = +autoload xfm + +(* View: word *) +let word = /[^#, \n\t\/]+/ + +(* View: sto_line *) +let sto_line = store /[^# \t\n].*[^ \t\n]|[^# \t\n]/ + +(* View: record *) +let record = [ key word . (Util.del_ws_tab . sto_line)? . Util.eol ] + +(* View: lns *) +let lns = ( Util.empty | Util.comment | record ) * + +(* View: filter *) +let filter = incl "/etc/modules" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/modules_conf.aug b/Sharp.Augeas.Test/lens/modules_conf.aug new file mode 100644 index 0000000..e9ab7c1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/modules_conf.aug @@ -0,0 +1,42 @@ +(* +Module: Modules_conf + Parses /etc/modules.conf and /etc/conf.modules + + Based on the similar Modprobe lens + + Not all directives currently listed in modules.conf(5) are currently + supported. +*) +module Modules_conf = +autoload xfm + +let comment = Util.comment +let empty = Util.empty +let eol = Util.eol | Util.comment + +(* Basic file structure is the same as modprobe.conf *) +let sto_to_eol = Modprobe.sto_to_eol +let sep_space = Modprobe.sep_space + +let path = [ key "path" . Util.del_str "=" . sto_to_eol . eol ] +let keep = [ key "keep" . eol ] +let probeall = Build.key_value_line_comment "probeall" sep_space + sto_to_eol + comment + +let entry = + Modprobe.alias + | Modprobe.options + | Modprobe.kv_line_command /install|pre-install|post-install/ + | Modprobe.kv_line_command /remove|pre-remove|post-remove/ + | keep + | path + | probeall + + +let lns = (comment|empty|entry)* + +let filter = (incl "/etc/modules.conf") . + (incl "/etc/conf.modules") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/mongodbserver.aug b/Sharp.Augeas.Test/lens/mongodbserver.aug new file mode 100644 index 0000000..77d1aa4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/mongodbserver.aug @@ -0,0 +1,53 @@ +(* +Module: MongoDBServer + Parses /etc/mongodb.conf + +Author: Brian Redbeard <redbeard@dead-city.org> + +About: Reference + For information on configuration options available to mongod reference one + of the following resources: + * The Mongo DB Manual - <http://docs.mongodb.org/manual/> + * The current options available for your operating system via: + > man mongos + +About: License + This file is licenced under the LGPL v2+, conforming to the other components + of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get your current setup + > print /files/etc/mongodb.conf + ... + + * Change MongoDB port + > set /files/etc/mongodb.conf/port 27117 + + Saving your file: + + > save + +About: Configuration files + This lens applies to /etc/mongodb.conf. See <filter>. + +About: Examples + The <Test_MongoDBServer> file contains various examples and tests. +*) +module MongoDBServer = + +autoload xfm + +(* View: entry *) +let entry = + Build.key_value_line Rx.word Sep.space_equal (store Rx.space_in) + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry)* + + +(* Variable: filter *) +let filter = incl "/etc/mongodb.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/monit.aug b/Sharp.Augeas.Test/lens/monit.aug new file mode 100644 index 0000000..f2f1e9e --- /dev/null +++ b/Sharp.Augeas.Test/lens/monit.aug @@ -0,0 +1,70 @@ +(* Monit module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: man monit (1), section "HOW TO MONITOR" + + "A monit control file consists of a series of service entries and + global option statements in a free-format, token-oriented syntax. + + Comments begin with a # and extend through the end of the line. There + are three kinds of tokens in the control file: grammar keywords, numbers + and strings. On a semantic level, the control file consists of three + types of statements: + + 1. Global set-statements + A global set-statement starts with the keyword set and the item to + configure. + + 2. Global include-statement + The include statement consists of the keyword include and a glob + string. + + 3. One or more service entry statements. + A service entry starts with the keyword check followed by the + service type" + +*) + +module Monit = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let spc = Sep.space +let comment = Util.comment +let empty = Util.empty + +let sto_to_spc = store Rx.space_in +let sto_no_spc = store Rx.no_spaces + +let word = Rx.word +let value = Build.key_value_line word spc sto_to_spc + +(************************************************************************ + * ENTRIES + *************************************************************************) + +(* set statement *) +let set = Build.key_value "set" spc value + +(* include statement *) +let include = Build.key_value_line "include" spc sto_to_spc + +(* service statement *) +let service = Build.key_value "check" spc (Build.list value spc) + +let entry = (set|include|service) + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter = incl "/etc/monit/monitrc" + . incl "/etc/monitrc" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/multipath.aug b/Sharp.Augeas.Test/lens/multipath.aug new file mode 100644 index 0000000..9db27d0 --- /dev/null +++ b/Sharp.Augeas.Test/lens/multipath.aug @@ -0,0 +1,136 @@ +(* Process /etc/multipath.conf *) +(* The lens is based on the multipath.conf(5) man page *) +module Multipath = + +autoload xfm + +let comment = Util.comment +let empty = Util.empty +let dels = Util.del_str +let eol = Util.eol + +let ws = del /[ \t]+/ " " +let indent = del /[ \t]*/ "" +(* We require that braces are always followed by a newline *) +let obr = del /\{([ \t]*)\n/ "{\n" +let cbr = del /[ \t]*}[ \t]*\n/ "}\n" + +(* Like Rx.fspath, but we disallow quotes at the beginning or end *) +let fspath = /[^" \t\n]|[^" \t\n][^ \t\n]*[^" \t\n]/ + +let ikey (k:regexp) = indent . key k + +let section (n:regexp) (b:lens) = + [ ikey n . ws . obr . (b|empty|comment)* . cbr ] + +let kv (k:regexp) (v:regexp) = + [ ikey k . ws . del /"?/ "" . store v . del /"?/ "" . eol ] + +(* FIXME: it would be much more concise to write *) +(* [ key k . ws . (bare | quoted) ] *) +(* but the typechecker trips over that *) +let qstr (k:regexp) = + let delq = del /['"]/ "\"" in + let bare = del /["']?/ "" . store /[^"' \t\n]+/ . del /["']?/ "" in + let quoted = delq . store /.*[ \t].*/ . delq in + [ ikey k . ws . bare . eol ] + |[ ikey k . ws . quoted . eol ] + +(* Settings that can be changed in various places *) +let common_setting = + qstr "path_selector" + |kv "path_grouping_policy" /failover|multibus|group_by_(serial|prio|node_name)/ + |kv "path_checker" /tur|emc_clariion|hp_sw|rdac|directio|rdb|readsector0/ + |kv "prio" /const|emc|alua|ontap|rdac|hp_sw|hds|random|weightedpath/ + |qstr "prio_args" + |kv "failback" (Rx.integer | /immediate|manual|followover/) + |kv "rr_weight" /priorities|uniform/ + |kv "flush_on_last_del" /yes|no/ + |kv "user_friendly_names" /yes|no/ + |kv "no_path_retry" (Rx.integer | /fail|queue/) + |kv /rr_min_io(_q)?/ Rx.integer + |qstr "features" + |kv "reservation_key" Rx.word + |kv "deferred_remove" /yes|no/ + |kv "delay_watch_checks" (Rx.integer | "no") + |kv "delay_wait_checks" (Rx.integer | "no") + |kv "skip_kpartx" /yes|no/ + (* Deprecated settings for backwards compatibility *) + |qstr /(getuid|prio)_callout/ + (* Settings not documented in `man multipath.conf` *) + |kv /rr_min_io_rq/ Rx.integer + |kv "udev_dir" fspath + |qstr "selector" + |kv "async_timeout" Rx.integer + |kv "pg_timeout" Rx.word + |kv "h_on_last_deleassign_maps" /yes|no/ + |qstr "uid_attribute" + |kv "hwtable_regex_match" /yes|no|on|off/ + |kv "reload_readwrite" /yes|no/ + +let default_setting = + common_setting + |kv "polling_interval" Rx.integer + |kv "max_polling_interval" Rx.integer + |kv "multipath_dir" fspath + |kv "find_multipaths" /yes|no/ + |kv "verbosity" /[0-6]/ + |kv "reassign_maps" /yes|no/ + |kv "uid_attrribute" Rx.word + |kv "max_fds" (Rx.integer|"max") + |kv "checker_timeout" Rx.integer + |kv "fast_io_fail_tmo" (Rx.integer|"off") + |kv "dev_loss_tmo" (Rx.integer|"infinity") + |kv "queue_without_daemon" /yes|no/ + |kv "bindings_file" fspath + |kv "wwids_file" fspath + |kv "log_checker_err" /once|always/ + |kv "retain_attached_hw_handler" /yes|no/ + |kv "detect_prio" /yes|no/ + |kv "hw_str_match" /yes|no/ + |kv "force_sync" /yes|no/ + |kv "config_dir" fspath + |kv "missing_uev_wait_timeout" Rx.integer + |kv "ignore_new_boot_devs" /yes|no/ + |kv "retrigger_tries" Rx.integer + |kv "retrigger_delay" Rx.integer + |kv "new_bindings_in_boot" /yes|no/ + +(* A device subsection *) +let device = + let setting = + qstr /vendor|product|product_blacklist|hardware_handler|alias_prefix/ + |default_setting in + section "device" setting + +(* The defaults section *) +let defaults = + section "defaults" default_setting + +(* The blacklist and blacklist_exceptions sections *) +let blacklist = + let setting = + qstr /devnode|wwid|property/ + |device in + section /blacklist(_exceptions)?/ setting + +(* A multipath subsection *) +let multipath = + let setting = + kv "wwid" (Rx.word|"*") + |qstr "alias" + |common_setting in + section "multipath" setting + +(* The multipaths section *) +let multipaths = + section "multipaths" multipath + +(* The devices section *) +let devices = + section "devices" device + +let lns = (comment|empty|defaults|blacklist|devices|multipaths)* + +let xfm = transform lns (incl "/etc/multipath.conf" . + incl "/etc/multipath/conf.d/*.conf") diff --git a/Sharp.Augeas.Test/lens/mysql.aug b/Sharp.Augeas.Test/lens/mysql.aug new file mode 100644 index 0000000..1b8c315 --- /dev/null +++ b/Sharp.Augeas.Test/lens/mysql.aug @@ -0,0 +1,47 @@ +(* MySQL module for Augeas *) +(* Author: Tim Stoop <tim@kumina.nl> *) +(* Heavily based on php.aug by Raphael Pinson *) +(* <raphink@gmail.com> *) +(* *) + +module MySQL = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) +let comment = IniFile.comment IniFile.comment_re "#" + +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default + +let entry = + let bare = Quote.do_dquote_opt_nil (store /[^#;" \t\r\n]+([ \t]+[^#;" \t\r\n]+)*/) + in let quoted = Quote.do_dquote (store /[^"\r\n]*[#;]+[^"\r\n]*/) + in [ Util.indent . key IniFile.entry_re . sep . Sep.opt_space . bare . (comment|IniFile.eol) ] + | [ Util.indent . key IniFile.entry_re . sep . Sep.opt_space . quoted . (comment|IniFile.eol) ] + | [ Util.indent . key IniFile.entry_re . store // . (comment|IniFile.eol) ] + | comment + +(************************************************************************ + * sections, led by a "[section]" header + * We can't use titles as node names here since they could contain "/" + * We remove #comment from possible keys + * since it is used as label for comments + * We also remove / as first character + * because augeas doesn't like '/' keys (although it is legal in INI Files) + *************************************************************************) +let title = IniFile.indented_title_label "target" IniFile.record_label_re +let record = IniFile.record title entry + +let includedir = Build.key_value_line /!include(dir)?/ Sep.space (store Rx.fspath) + . (comment|IniFile.empty)* + +let lns = (comment|IniFile.empty)* . (record|includedir)* + +let filter = (incl "/etc/mysql/my.cnf") + . (incl "/etc/mysql/conf.d/*.cnf") + . (incl "/etc/my.cnf") + . (incl "/etc/my.cnf.d/*.cnf") + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/nagioscfg.aug b/Sharp.Augeas.Test/lens/nagioscfg.aug new file mode 100644 index 0000000..c760875 --- /dev/null +++ b/Sharp.Augeas.Test/lens/nagioscfg.aug @@ -0,0 +1,74 @@ +(* +Module: NagiosConfig + Parses /etc/{nagios{3,},icinga}/*.cfg + +Authors: Sebastien Aperghis-Tramoni <sebastien@aperghis.net> + Raphaël Pinson <raphink@gmail.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/{nagios{3,},icinga}/*.cfg. See <filter>. +*) + +module NagiosCfg = +autoload xfm + +(************************************************************************ + * Group: Utility variables/functions + ************************************************************************) +(* View: param_def + define a field *) +let param_def = + let space_in = /[^ \t\n][^\n=]*[^ \t\n]|[^ \t\n]/ + in key /[A-Za-z0-9_]+/ + . Sep.opt_space . Sep.equal . Sep.opt_space + . store space_in + +(* View: macro_def + Macro line, as used in resource.cfg *) +let macro_def = + let macro = /\$[A-Za-z0-9]+\$/ + in let macro_decl = Rx.word | Rx.fspath + in key macro . Sep.space_equal . store macro_decl + +(************************************************************************ + * Group: Entries + ************************************************************************) +(* View: param + Params can have sub params *) +let param = + [ Util.indent . param_def + . [ Sep.space . param_def ]* + . Util.eol ] + +(* View: macro *) +let macro = [ Util.indent . macro_def . Util.eol ] + +(************************************************************************ + * Group: Lens + ************************************************************************) +(* View: entry + Define the accepted entries, such as param for regular configuration + files, and macro for resources.cfg .*) +let entry = param + | macro + +(* View: lns + main structure *) +let lns = ( Util.empty | Util.comment | entry )* + +(* View: filter *) +let filter = incl "/etc/nagios3/*.cfg" + . incl "/etc/nagios/*.cfg" + . incl "/etc/icinga/*.cfg" + . excl "/etc/nagios3/commands.cfg" + . excl "/etc/nagios/commands.cfg" + . excl "/etc/nagios/nrpe.cfg" + . incl "/etc/icinga/commands.cfg" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/nagiosobjects.aug b/Sharp.Augeas.Test/lens/nagiosobjects.aug new file mode 100644 index 0000000..db4e181 --- /dev/null +++ b/Sharp.Augeas.Test/lens/nagiosobjects.aug @@ -0,0 +1,62 @@ +(* +Module: NagiosObjects + Parses /etc/{nagios{3,},icinga}/objects/*.cfg + +Authors: Sebastien Aperghis-Tramoni <sebastien@aperghis.net> + Raphaël Pinson <raphink@gmail.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + + This lens applies to /etc/{nagios{3,},icinga}/objects/*.cfg. See <filter>. +*) + +module NagiosObjects = + autoload xfm + + (* basic atoms *) + let eol = Util.eol + let ws = Sep.space + + let keyword = key /[A-Za-z0-9_]+/ + + (* optional, but preferred, whitespace *) + let opt_ws = del Rx.opt_space " " + + (* define an empty line *) + let empty = Util.empty + + (* define a comment *) + let comment = Util.comment_generic /[ \t]*[#;][ \t]*/ "# " + + (* define a field *) + let object_field = + let field_name = keyword in + let field_value = store Rx.space_in in + [ Util.indent . field_name . ws + . field_value . eol ] + + (* define an object *) + let object_def = + let object_type = keyword in + [ Util.indent + . Util.del_str "define" . ws + . object_type . opt_ws + . Util.del_str "{" . eol + . ( empty | comment | object_field )* + . Util.indent . Util.del_str "}" . eol ] + + (* main structure *) + let lns = ( empty | comment | object_def )* + + let filter = incl "/etc/nagios3/objects/*.cfg" + . incl "/etc/nagios/objects/*.cfg" + . incl "/etc/icinga/objects/*.cfg" + + let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/netmasks.aug b/Sharp.Augeas.Test/lens/netmasks.aug new file mode 100644 index 0000000..45ea879 --- /dev/null +++ b/Sharp.Augeas.Test/lens/netmasks.aug @@ -0,0 +1,65 @@ +(* +Module: Netmasks + Parses /etc/inet/netmasks on Solaris + +Author: Dominic Cleal <dcleal@redhat.com> + +About: Reference + This lens tries to keep as close as possible to `man 4 netmasks` where possible. + +About: Licence + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + +About: Configuration files + This lens applies to /etc/netmasks and /etc/inet/netmasks. See <filter>. +*) + +module Netmasks = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + ************************************************************************) + +(* View: comment *) +let comment = Util.comment + +(* View: comment_or_eol *) +let comment_or_eol = Util.comment_or_eol + +(* View: indent *) +let indent = Util.indent + +(* View: empty *) +let empty = Util.empty + +(* View: sep + The separator for network/mask entries *) +let sep = Util.del_ws_tab + +(************************************************************************ + * Group: ENTRIES + ************************************************************************) + +(* View: entry + Network / netmask line *) +let entry = [ seq "network" . indent . + [ label "network" . store Rx.ipv4 ] . sep . + [ label "netmask" . store Rx.ipv4 ] . comment_or_eol ] + +(************************************************************************ + * Group: LENS + ************************************************************************) + +(* View: lns *) +let lns = ( empty + | comment + | entry )* + +(* Variable: filter *) +let filter = (incl "/etc/netmasks" + . incl "/etc/inet/netmasks") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/networkmanager.aug b/Sharp.Augeas.Test/lens/networkmanager.aug new file mode 100644 index 0000000..8649168 --- /dev/null +++ b/Sharp.Augeas.Test/lens/networkmanager.aug @@ -0,0 +1,67 @@ +(* +Module: NetworkManager + Parses /etc/NetworkManager/system-connections/* files which are GLib + key-value setting files. + +Author: Raphael Pinson <raphael.pinson@camptocamp.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/NetworkManager/system-connections/*. See <filter>. + +About: Examples + The <Test_NetworkManager> file contains various examples and tests. +*) + +module NetworkManager = +autoload xfm + +(************************************************************************ + * INI File settings + * + * GLib only supports "# as commentary and "=" as separator + *************************************************************************) +let comment = IniFile.comment "#" "#" +let sep = Sep.equal +let eol = Util.eol + +(************************************************************************ + * ENTRY + * GLib entries can contain semicolons, entry names can contain spaces and + * brackets + * + * At least entry for WPA-PSK definition can contain all printable ASCII + * characters including '#', ' ' and others. Comments following the entry + * are no option for this reason. + *************************************************************************) +(* Variable: entry_re *) +let entry_re = /[A-Za-z][A-Za-z0-9:._\(\) \t-]+/ + +(* Lens: entry *) +let entry = [ key entry_re . sep + . IniFile.sto_to_eol? . eol ] + | comment + +(************************************************************************ + * RECORD + * GLib uses standard INI File records + *************************************************************************) +let title = IniFile.indented_title IniFile.record_re +let record = IniFile.record title entry + + +(************************************************************************ + * LENS & FILTER + * GLib uses standard INI File records + *************************************************************************) +let lns = IniFile.lns record comment + +(* Variable: filter *) +let filter = incl "/etc/NetworkManager/system-connections/*" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/networks.aug b/Sharp.Augeas.Test/lens/networks.aug new file mode 100644 index 0000000..db09022 --- /dev/null +++ b/Sharp.Augeas.Test/lens/networks.aug @@ -0,0 +1,46 @@ +(* +Module: Networks + Parses /etc/networks + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 networks` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/networks. See <filter>. +*) + +module Networks = + +autoload xfm + +(* View: ipv4 + A network IP, trailing .0 may be omitted *) +let ipv4 = + let dot = "." in + let digits = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/ in + digits . (dot . digits . (dot . digits . (dot . digits)?)?)? + +(*View: entry *) +let entry = + let alias = [ seq "alias" . store Rx.word ] in + [ seq "network" . counter "alias" + . [ label "name" . store Rx.word ] + . [ Sep.space . label "number" . store ipv4 ] + . [ Sep.space . label "aliases" . Build.opt_list alias Sep.space ]? + . (Util.eol|Util.comment) ] + +(* View: lns *) +let lns = ( Util.empty | Util.comment | entry )* + +(* View: filter *) +let filter = incl "/etc/networks" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/nginx.aug b/Sharp.Augeas.Test/lens/nginx.aug new file mode 100644 index 0000000..06989c8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/nginx.aug @@ -0,0 +1,134 @@ +(* Module: Nginx + Nginx module for Augeas + +Authors: Ian Berry <iberry@barracuda.com> + Raphael Pinson <raphael.pinson@camptocamp.com> + +About: Reference + + This module was built to support a limited subset of nginx + configuration syntax. It works fine with simple blocks and + field/value lines. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/nginx/nginx.conf. See <filter>. + +About: Examples + The <Test_Nginx> file contains various examples and tests. + +About: TODO + * Convert statement keyworks for a regex + * Support more advanced block syntax (location) +*) + +module Nginx = + +autoload xfm + +(* Variable: word *) +let word = /[A-Za-z0-9_.:-]+/ + +(* Variable: block_re + The keywords reserved for block entries *) +let block_re = "http" | "events" | "server" | "mail" | "stream" + +(* All block keywords, including the ones we treat specially *) +let block_re_all = block_re | "if" | "location" | "geo" | "map" + | "split_clients" | "upstream" + +(* View: simple + A simple entry *) +let simple = + let kw = word - block_re_all + in let mask = [ label "mask" . Util.del_str "/" . store Rx.integer ] + in let sto = store /[^ \t\n;#]([^";#]|"[^"]*\")*/ + in [ Util.indent . + key kw . mask? . + (Sep.space . sto)? . Sep.semicolon . + (Util.eol|Util.comment_eol) ] + +(* View: server + A simple server entry *) +let server = + let address = /[A-Za-z0-9_.:\/-]+/ + in [ Util.indent . label "@server" . Util.del_str "server" + . [ Sep.space . label "@address" . store address ] + . [ Sep.space . key word . (Sep.equal . store word)? ]* + . Sep.semicolon + . (Util.eol|Util.comment_eol) ] + +let arg (name:string) (rx:regexp) = + [ label name . Sep.space . store rx ] + +(* Match any argument (as much as possible) *) +let any_rx = + let bare_rx = /[^" \t\n{][^ \t\n{]*/ in + let dquote_rx = /"([^\"]|\\.)*"/ in + bare_rx | dquote_rx + +let any_arg (name:string) = arg name any_rx + +(* 'if' conditions are enclosed in matching parens which we can't match + precisely with a regular expression. Instead, we gobble up anything that + doesn't contain an opening brace. That can of course lead to trouble if + a condition actually contains an opening brace *) +let block_if = key "if" + . arg "#cond" /\(([^ \t\n{]|[ \t\n][^{])*\)/ + +let block_location = key "location" + . (arg "#comp" /=|~|~\*|\^~/)? + . any_arg "#uri" + +let block_geo = key "geo" + . (any_arg "#address")? + . any_arg "#geo" + +let block_map = key "map" + . any_arg "#source" + . any_arg "#variable" + +let block_split_clients = key "split_clients" + . any_arg "#string" + . any_arg "#variable" + +let block_upstream = key "upstream" + . any_arg "#name" + +let block_head = key block_re + | block_if + | block_location + | block_geo + | block_map + | block_split_clients + | block_upstream + +(* View: block + A block containing <simple> entries *) +let block (entry : lens) = + [ Util.indent . block_head + . Build.block_newlines entry Util.comment + . Util.eol ] + +let rec directive = simple | server | block directive + +(* View: lns *) +let lns = ( Util.comment | Util.empty | directive )* + +(* Variable: filter *) +let filter = incl "/etc/nginx/nginx.conf" + . incl "/etc/nginx/conf.d/*.conf" + . incl "/etc/nginx/sites-available/*" + . incl "/etc/nginx/sites-enabled/*" + . incl "/usr/portage/www-servers/nginx/files/nginx.conf" + . incl "/usr/local/etc/nginx/nginx.conf" + . incl "/usr/local/etc/nginx/conf.d/*.conf" + . incl "/usr/local/etc/nginx/sites-available/*" + . incl "/usr/local/etc/nginx/sites-enabled/*" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/nrpe.aug b/Sharp.Augeas.Test/lens/nrpe.aug new file mode 100644 index 0000000..dedacea --- /dev/null +++ b/Sharp.Augeas.Test/lens/nrpe.aug @@ -0,0 +1,85 @@ +(* +Module: Nrpe + Parses nagios-nrpe configuration files. + +Author: Marc Fournier <marc.fournier@camptocamp.com> + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Nrpe = + autoload xfm + + +let eol = Util.eol +let eq = Sep.equal + +(* View: word *) +let word = /[^=\n\t ]+/ + +let words = word . ( / +/ . word )* + +(* View: item_re *) +let item_re = /[^#=\n\t\/ ]+/ - (/command\[[^]\/\n]+\]/ | "include" | "include_dir") + +(* View: command + nrpe.cfg usually has many entries defining commands to run + + > command[check_foo]=/path/to/nagios/plugin -w 123 -c 456 + > command[check_bar]=/path/to/another/nagios/plugin --option +*) +let command = + let obrkt = del /\[/ "[" in + let cbrkt = del /\]/ "]" in + [ key "command" . + [ obrkt . key /[^]\/\n]+/ . cbrkt . eq + . store /[^\n]+/ . del /\n/ "\n" ] + ] + + +(* View: item + regular entries + + > allow_bash_command_substitution=0 +*) +let item = [ key item_re . eq . store words . eol ] + +(* View: include + An include entry. + + nrpe.cfg can include more than one file or directory of files + + > include=/path/to/file1.cfg + > include=/path/to/file2.cfg +*) +let include = [ key "include" . + [ label "file" . eq . store word . eol ] +] + +(* View: include_dir + > include_dir=/path/to/dir/ +*) +let include_dir = [ key "include_dir" . + [ label "dir" . eq . store word . eol ] +] + + +(* View: comment + Nrpe comments must start at beginning of line *) +let comment = Util.comment_generic /#[ \t]*/ "# " + +(* blank lines and empty comments *) +let empty = Util.empty + +(* View: lns + The Nrpe lens *) +let lns = ( command | include | include_dir | item | comment | empty ) * + +(* View: filter + File filter *) +let filter = incl "/etc/nrpe.cfg" . + incl "/etc/nagios/nrpe.cfg" + +let xfm = transform lns (filter) + diff --git a/Sharp.Augeas.Test/lens/nslcd.aug b/Sharp.Augeas.Test/lens/nslcd.aug new file mode 100644 index 0000000..5e85913 --- /dev/null +++ b/Sharp.Augeas.Test/lens/nslcd.aug @@ -0,0 +1,263 @@ +(* +Module: Nslcd + Parses /etc/nslcd.conf + +Author: Jose Plana <jplana@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 nslcd.conf` where + possible. + +License + This file is licenced under the LGPL v2+, like the rest of Augeas. + + +About: Lens Usage + + Sample usage of this lens in augtool: + + * get uid + > get /files/etc/nslcd.conf/threads + + * set ldap URI + > set /files/etc/nslcd.conf/uri "ldaps://x.y.z" + + * get cache values + > get /files/etc/nslcd.conf/cache + + * change syslog level to debug + > set /files/etc/nslcd.conf/log "syslog debug" + + * add/change filter for the passwd map + > set /files/etc/nslcd.conf/filter/passwd "(objectClass=posixGroup)" + + * change the default search scope + > set /files/etc/nslcd.conf/scope[count( * )] "subtree" + + * get the default search scope + > get /files/etc/nslcd.conf/scope[count( * )] "subtree" + + * add/set a scope search value for a specific (host) map + > set /files/etc/nslcd.conf/scope[host]/host "subtree" + + * get all default base search + > match /files/etc/nslcd.conf/base[count( * ) = 0] + + * get the 3rd base search default value + > get /files/etc/nslcd.conf/base[3] + + * add a new base search default value + > set /files/etc/nslcd.conf/base[last()+1] "dc=example,dc=com" + + * change a base search default value to a new base value + > set /files/etc/nslcd.conf/base[self::* = "dc=example,dc=com"] "dc=test,dc=com" + + * add/change a base search for a specific map (hosts) + > set /files/etc/nslcd.conf/base[hosts]/hosts "dc=hosts,dc=example,dc=com" + + * add a base search for a specific map (passwd) + > set /files/etc/nslcd.conf/base[last()+1]/passwd "dc=users,dc=example,dc=com" + + * remove all base search value for a map (rpc) + > rm /files/etc/nslcd.conf/base/rpc + + * remove a specific search base value for a map (passwd) + > rm /files/etc/nslcd.conf/base/passwd[self::* = "dc=users,dc=example,dc=com"] + + * get an attribute mapping value for a map + > get /files/etc/nslcd.conf/map/passwd/homeDirectory + + * get all attribute values for a map + > match /files/etc/nslcd.conf/map/passwd/* + + * set a specific attribute for a map + > set /files/etc/nslcd.conf/map/passwd/homeDirectory "\"${homeDirectory:-/home/$uid}\"" + + * add/change a specific attribute for a map (a map that might not be defined before) + > set /files/etc/nslcd.conf/map[shadow/userPassword]/shadow/userPassword "*" + + * remove an attribute for a specific map + > rm /files/etc/nslcd.conf/map/shadow/userPassword + + * remove all attributes for a specific map + > rm /files/etc/nslcd.conf/map/passwd/* + +About: Configuration files + This lens applies to /etc/nslcd.conf. See <filter>. + +About: Examples + The <Test_Nslcd> file contains various examples and tests. +*) + +module Nslcd = +autoload xfm + + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + +(* Group: Comments and empty lines *) + +(* View: eol *) +let eol = Util.eol +(* View: empty *) +let empty = Util.empty +(* View: spc *) +let spc = Util.del_ws_spc +(* View: comma *) +let comma = Sep.comma +(* View: comment *) +let comment = Util.comment +(* View: do_dquote *) +let do_dquote = Quote.do_dquote +(* View: opt_list *) +let opt_list = Build.opt_list + +(* Group: Ldap related values +Values that need to be parsed. +*) + +(* Variable: ldap_rdn *) +let ldap_rdn = /[A-Za-z][A-Za-z]+=[A-Za-z0-9_.-]+/ +(* Variable: ldap_dn *) +let ldap_dn = ldap_rdn . (/(,)?/ . ldap_rdn)* +(* Variable: ldap_filter *) +let ldap_filter = /\(.*\)/ +(* Variable: ldap_scope *) +let ldap_scope = /sub(tree)?|one(level)?|base/ +(* Variable: map_names *) +let map_names = /alias(es)?/ + | /ether(s)?/ + | /group/ + | /host(s)?/ + | /netgroup/ + | /network(s)?/ + | /passwd/ + | /protocol(s)?/ + | /rpc/ + | /service(s)?/ + | /shadow/ +(* Variable: key_name *) +let key_name = /[^ #\n\t\/][^ #\n\t\/]+/ + + +(************************************************************************ + * Group: CONFIGURATION ENTRIES + *************************************************************************) + +(* Group: Generic definitions *) + +(* View: simple_entry +The simplest configuration option a key spc value. As in `gid id` +*) +let simple_entry (kw:string) = Build.key_ws_value kw + +(* View: simple_entry_quoted_value +Simple entry with quoted value +*) +let simple_entry_quoted_value (kw:string) = Build.key_value_line kw spc (do_dquote (store /.*/)) + +(* View simple_entry_opt_list_comma_value +Simple entry that contains a optional list separated by commas +*) +let simple_entry_opt_list_value (kw:string) (lsep:lens) = Build.key_value_line kw spc (opt_list [ seq kw . store /[^, \t\n\r]+/ ] (lsep)) +(* View: key_value_line_regexp +A simple configuration option but specifying the regex for the value. +*) +let key_value_line_regexp (kw:string) (sto:regexp) = Build.key_value_line kw spc (store sto) + +(* View: mapped_entry +A mapped configuration as in `filter MAP option`. +*) +let mapped_entry (kw:string) (sto:regexp) = [ key kw . spc + . Build.key_value_line map_names spc (store sto) + ] +(* View: key_value_line_regexp_opt_map +A mapped configuration but the MAP value is optional as in scope [MAP] value`. +*) +let key_value_line_regexp_opt_map (kw:string) (sto:regexp) = + ( key_value_line_regexp kw sto | mapped_entry kw sto ) + +(* View: map_entry +A map entry as in `map MAP ATTRIBUTE NEWATTRIBUTE`. +*) +let map_entry = [ key "map" . spc + . [ key map_names . spc + . [ key key_name . spc . store Rx.no_spaces ] + ] .eol + ] + +(* Group: Option definitions *) + +(* View: Base entry *) +let base_entry = key_value_line_regexp_opt_map "base" ldap_dn + +(* View: Scope entry *) +let scope_entry = key_value_line_regexp_opt_map "scope" ldap_scope + +(* View: Filter entry *) +let filter_entry = mapped_entry "filter" ldap_filter + +(* View: entries +All the combined entries. +*) +let entries = map_entry + | base_entry + | scope_entry + | filter_entry + | simple_entry "threads" + | simple_entry "uid" + | simple_entry "gid" + | simple_entry_opt_list_value "uri" spc + | simple_entry "ldap_version" + | simple_entry "binddn" + | simple_entry "bindpw" + | simple_entry "rootpwmoddn" + | simple_entry "rootpwmodpw" + | simple_entry "sasl_mech" + | simple_entry "sasl_realm" + | simple_entry "sasl_authcid" + | simple_entry "sasl_authzid" + | simple_entry "sasl_secprops" + | simple_entry "sasl_canonicalize" + | simple_entry "krb5_ccname" + | simple_entry "deref" + | simple_entry "referrals" + | simple_entry "bind_timelimit" + | simple_entry "timelimit" + | simple_entry "idle_timelimit" + | simple_entry "reconnect_sleeptime" + | simple_entry "reconnect_retrytime" + | simple_entry "ssl" + | simple_entry "tls_reqcert" + | simple_entry "tls_cacertdir" + | simple_entry "tls_cacertfile" + | simple_entry "tls_randfile" + | simple_entry "tls_ciphers" + | simple_entry "tls_cert" + | simple_entry "tls_key" + | simple_entry "pagesize" + | simple_entry_opt_list_value "nss_initgroups_ignoreusers" comma + | simple_entry "nss_min_uid" + | simple_entry "nss_nested_groups" + | simple_entry "nss_getgrent_skipmembers" + | simple_entry "nss_disable_enumeration" + | simple_entry "validnames" + | simple_entry "ignorecase" + | simple_entry "pam_authz_search" + | simple_entry_quoted_value "pam_password_prohibit_message" + | simple_entry "reconnect_invalidate" + | simple_entry "cache" + | simple_entry "log" + | simple_entry "pam_authc_ppolicy" + +(* View: lens *) +let lns = (entries|empty|comment)+ + +(* View: filter *) +let filter = incl "/etc/nslcd.conf" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/nsswitch.aug b/Sharp.Augeas.Test/lens/nsswitch.aug new file mode 100644 index 0000000..ed134b3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/nsswitch.aug @@ -0,0 +1,81 @@ +(* +Module: Nsswitch + Parses /etc/nsswitch.conf + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man nsswitch.conf` where possible. + +About: Licence + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + +About: Configuration files + This lens applies to /etc/nsswitch.conf. See <filter>. +*) + +module Nsswitch = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: comment *) +let comment = Util.comment + +(* View: empty *) +let empty = Util.empty + +(* View: sep_colon + The separator for database entries *) +let sep_colon = del /:[ \t]*/ ": " + +(* View: database_kw + The database specification like `passwd', `shadow', or `hosts' *) +let database_kw = Rx.word + +(* View: service + The service specification like `files', `db', or `nis' *) +let service = [ label "service" . store Rx.word ] + +(* View: reaction + The reaction on lookup result like `[NOTFOUND=return]' + TODO: Use case-insensitive regexps when ticket #147 is fixed. +*) +let reaction = + let status_kw = /[Ss][Uu][Cc][Cc][Ee][Ss][Ss]/ + | /[Nn][Oo][Tt][Ff][Oo][Uu][Nn][Dd]/ + | /[Uu][Nn][Aa][Vv][Aa][Ii][Ll]/ + | /[Tt][Rr][Yy][Aa][Gg][Aa][Ii][Nn]/ + in let action_kw = /[Rr][Ee][Tt][Uu][Rr][Nn]/ + | /[Cc][Oo][Nn][Tt][Ii][Nn][Uu][Ee]/ + | /[Mm][Ee][Rr][Gg][Ee]/ + in let negate = [ Util.del_str "!" . label "negate" ] + in let reaction_entry = [ label "status" . negate? + . store status_kw + . Util.del_str "=" + . [ label "action" . store action_kw ] ] + in Util.del_str "[" + . [ label "reaction" + . (Build.opt_list reaction_entry Sep.space) ] + . Util.del_str "]" + +(* View: database *) +let database = + [ label "database" . store database_kw + . sep_colon + . (Build.opt_list + (service|reaction) + Sep.space) + . Util.comment_or_eol ] + +(* View: lns *) +let lns = ( empty | comment | database )* + +(* Variable: filter *) +let filter = (incl "/etc/nsswitch.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/ntp.aug b/Sharp.Augeas.Test/lens/ntp.aug new file mode 100644 index 0000000..5a52119 --- /dev/null +++ b/Sharp.Augeas.Test/lens/ntp.aug @@ -0,0 +1,139 @@ +(* NTP module for Augeas *) +(* Author: Raphael Pinson <raphink@gmail.com> *) +(* *) +(* Status: basic settings supported *) + +module Ntp = + autoload xfm + + + (* Define useful shortcuts *) + + let eol = del /[ \t]*/ "" . [ label "#comment" . store /#.*/]? + . Util.del_str "\n" + let sep_spc = Util.del_ws_spc + let word = /[^,# \n\t]+/ + let num = /[0-9]+/ + + + (* define comments and empty lines *) + let comment = [ label "#comment" . del /#[ \t]*/ "#" . + store /([^ \t\n][^\n]*)?/ . del "\n" "\n" ] + let empty = [ del /[ \t]*\n/ "\n" ] + + + let kv (k:regexp) (v:regexp) = + [ key k . sep_spc. store v . eol ] + + (* Define generic record *) + let record (kw:regexp) (value:lens) = + [ key kw . sep_spc . store word . value . eol ] + + (* Define a command record; see confopt.html#cfg in the ntp docs *) + let command_record = + let opt = [ sep_spc . key /minpoll|maxpoll|ttl|version|key/ . + sep_spc . store word ] + | [ sep_spc . key (/autokey|burst|iburst|noselect|preempt/ | + /prefer|true|dynamic/) ] in + let cmd = /pool|server|peer|broadcast|manycastclient/ + | /multicastclient|manycastserver/ in + record cmd opt* + + let broadcastclient = + [ key "broadcastclient" . [ sep_spc . key "novolley" ]? . eol ] + + (* Define a fudge record *) + let fudge_opt_re = "refid" | "stratum" + let fudge_opt = [ sep_spc . key fudge_opt_re . sep_spc . store word ] + let fudge_record = record "fudge" fudge_opt? + + (* Define simple settings, see miscopt.html in ntp docs *) + let flags = + let flags_re = /auth|bclient|calibrate|kernel|monitor|ntp|pps|stats/ in + let flag = [ label "flag" . store flags_re ] in + [ key /enable|disable/ . (sep_spc . flag)* . eol ] + + let simple_setting (k:regexp) = kv k word + + (* Still incomplete, misses logconfig, phone, setvar, tos, + trap, ttl *) + let simple_settings = + kv "broadcastdelay" Rx.decimal + | flags + | simple_setting /driftfile|leapfile|logfile|includefile/ + | simple_setting "statsdir" + | simple_setting "ntpsigndsocket" + + (* Misc commands, see miscopt.html in ntp docs *) + + (* Define restrict *) + let restrict_record = + let ip6_restrict = [ label "ipv6" . sep_spc . Util.del_str "-6" ] in + let ip4_restrict = [ label "ipv4" . sep_spc . Util.del_str "-4" ] in + let action = [ label "action" . sep_spc . store /[^,# \n\t-][^,# \n\t]*/ ] in + [ key "restrict" . (ip6_restrict | ip4_restrict)? . sep_spc . store /[^,# \n\t-][^,# \n\t]*/ . action* . eol ] + + (* Define statistics *) + let statistics_flag (kw:string) = [ sep_spc . key kw ] + + let statistics_opts = statistics_flag "loopstats" + | statistics_flag "peerstats" + | statistics_flag "clockstats" + | statistics_flag "rawstats" + + let statistics_record = [ key "statistics" . statistics_opts* . eol ] + + + (* Define filegen *) + let filegen = del /filegen[ \t]+/ "filegen " . store word + let filegen_opt (kw:string) = [ sep_spc . key kw . sep_spc . store word ] + (* let filegen_flag (kw:string) = [ label kw . sep_spc . store word ] *) + let filegen_select (kw:string) (select:regexp) = [ label kw . sep_spc . store select ] + + let filegen_opts = filegen_opt "file" + | filegen_opt "type" + | filegen_select "enable" /(en|dis)able/ + | filegen_select "link" /(no)?link/ + + let filegen_record = [ label "filegen" . filegen . filegen_opts* . eol ] + + (* Authentication commands, see authopt.html#cmd; incomplete *) + let auth_command = + [ key /controlkey|keys|keysdir|requestkey|authenticate/ . + sep_spc . store word . eol ] + | [ key /autokey|revoke/ . [sep_spc . store word]? . eol ] + | [ key /trustedkey/ . [ sep_spc . label "key" . store word ]+ . eol ] + + (* tinker [step step | panic panic | dispersion dispersion | + stepout stepout | minpoll minpoll | allan allan | huffpuff huffpuff] *) + let tinker = + let arg_names = /step|panic|dispersion|stepout|minpoll|allan|huffpuff/ in + let arg = [ key arg_names . sep_spc . store Rx.decimal ] in + [ key "tinker" . (sep_spc . arg)* . eol ] + + (* tos [beacon beacon | ceiling ceiling | cohort {0 | 1} | + floor floor | maxclock maxclock | maxdist maxdist | + minclock minclock | mindist mindist | minsane minsane | + orphan stratum | orphanwait delay] *) + + let tos = + let arg_names = /beacon|ceiling|cohort|floor|maxclock|maxdist| + minclock|mindist|minsane|orphan|orphanwait/ in + let arg = [ key arg_names . sep_spc . store Rx.decimal ] in + [ key "tos" . (sep_spc . arg)* . eol ] + + let interface = + let action = [ label "action" . store /listen|ignore|drop/ ] + in let addresses = [ label "addresses" . store Rx.word ] + in [ key "interface" . sep_spc . action . sep_spc . addresses . eol ] + + (* Define lens *) + + let lns = ( comment | empty | command_record | fudge_record + | restrict_record | simple_settings | statistics_record + | filegen_record | broadcastclient + | auth_command | tinker | tos | interface)* + + let filter = (incl "/etc/ntp.conf") + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/ntpd.aug b/Sharp.Augeas.Test/lens/ntpd.aug new file mode 100644 index 0000000..68b5905 --- /dev/null +++ b/Sharp.Augeas.Test/lens/ntpd.aug @@ -0,0 +1,157 @@ +(* +Module: Ntpd + Parses OpenNTPD's ntpd.conf + +Author: Jasper Lievisse Adriaanse <jasper@jasper.la> + +About: Reference + This lens is used to parse OpenNTPD's configuration file, ntpd.conf. + http://openntpd.org/ + +About: Usage Example + To be documented + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to /etc/ntpd.conf. +See <filter>. +*) + +module Ntpd = +autoload xfm + +(************************************************************************ + * Group: Utility variables/functions + ************************************************************************) + +(* View: comment *) +let comment = Util.comment +(* View: empty *) +let empty = Util.empty +(* View: eol *) +let eol = Util.eol +(* View: space *) +let space = Sep.space +(* View: word *) +let word = Rx.word +(* View: device_re *) +let device_re = Rx.device_name | /\*/ + +(* View: address_re *) +let address_re = Rx.ip | /\*/ | Rx.hostname + +(* View: stratum_re + value between 1 and 15 *) +let stratum_re = /1[0-5]|[1-9]/ + +(* View: refid_re + string with length < 5 *) +let refid_re = /[A-Za-z0-9_.-]{1,5}/ + +(* View: weight_re + value between 1 and 10 *) +let weight_re = /10|[1-9]/ + +(* View: rtable_re + 0 - RT_TABLE_MAX *) +let rtable_re = Rx.byte + +(* View: correction_re + should actually only match between -127000000 and 127000000 *) +let correction_re = Rx.relinteger_noplus + +(************************************************************************ + * View: key_opt_rtable_line + * A subnode with a keyword, an optional routing table id and an end + * of line. + * + * Parameters: + * kw:regexp - the pattern to match as key + * sto:lens - the storing lens + ************************************************************************) +let key_opt_rtable_line (kw:regexp) (sto:lens) = + let rtable = [ Util.del_str "rtable" . space . label "rtable" + . store rtable_re ] + in [ key kw . space . sto . (space . rtable)? . eol ] + +(************************************************************************ + * View: key_opt_weight_rtable_line + * A subnode with a keyword, an optional routing table id, an optional + * weight-value and an end of line. + * of line. + * + * Parameters: + * kw:regexp - the pattern to match as key + * sto:lens - the storing lens + ************************************************************************) +let key_opt_weight_rtable_line (kw:regexp) (sto:lens) = + let rtable = [ Util.del_str "rtable" . space . label "rtable" . store rtable_re ] + in let weight = [ Util.del_str "weight" . space . label "weight" + . store weight_re ] + in [ key kw . space . sto . (space . weight)? . (space . rtable)? . eol ] + +(************************************************************************ + * View: opt_value + * A subnode for optional values. + * + * Parameters: + * s:string - the option name and subtree label + * r:regexp - the pattern to match as store + ************************************************************************) +let opt_value (s:string) (r:regexp) = + Build.key_value s space (store r) + +(************************************************************************ + * Group: Keywords + ************************************************************************) + +(* View: listen + listen on address [rtable table-id] *) +let listen = + let addr = [ label "address" . store address_re ] + in key_opt_rtable_line "listen on" addr + +(* View: server + server address [weight weight-value] [rtable table-id] *) +let server = + let addr = [ label "address" . store address_re ] + in key_opt_weight_rtable_line "server" addr + +(* View: servers + servers address [weight weight-value] [rtable table-id] *) +let servers = + let addr = [ label "address" . store address_re ] + in key_opt_weight_rtable_line "servers" addr + +(* View: sensor + sensor device [correction microseconds] [weight weight-value] [refid + string] [stratum stratum-value] *) +let sensor = + let device = [ label "device" . store device_re ] + in let correction = opt_value "correction" correction_re + in let weight = opt_value "weight" weight_re + in let refid = opt_value "refid" refid_re + in let stratum = opt_value "stratum" stratum_re + in [ key "sensor" . space . device + . (space . correction)? + . (space . weight)? + . (space . refid)? + . (space . stratum)? + . eol ] + +(************************************************************************ + * Group: Lens + ************************************************************************) + +(* View: keyword *) +let keyword = listen | server | servers | sensor + +(* View: lns *) +let lns = ( empty | comment | keyword )* + +(* View: filter *) +let filter = (incl "/etc/ntpd.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/odbc.aug b/Sharp.Augeas.Test/lens/odbc.aug new file mode 100644 index 0000000..633891d --- /dev/null +++ b/Sharp.Augeas.Test/lens/odbc.aug @@ -0,0 +1,43 @@ +(* + ODBC lens for Augeas + Author: Marc Fournier <marc.fournier@camptocamp.com> + + odbc.ini and odbcinst.ini are standard INI files. +*) + + +module Odbc = + autoload xfm + +(************************************************************************ + * INI File settings + * odbc.ini only supports "# as commentary and "=" as separator + ************************************************************************) +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" + + +(************************************************************************ + * ENTRY + * odbc.ini uses standard INI File entries + ************************************************************************) +let entry = IniFile.indented_entry IniFile.entry_re sep comment + + +(************************************************************************ + * RECORD + * odbc.ini uses standard INI File records + ************************************************************************) +let title = IniFile.indented_title IniFile.record_re +let record = IniFile.record title entry + + +(************************************************************************ + * LENS & FILTER + ************************************************************************) +let lns = IniFile.lns record comment + +let filter = incl "/etc/odbc.ini" + . incl "/etc/odbcinst.ini" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/opendkim.aug b/Sharp.Augeas.Test/lens/opendkim.aug new file mode 100644 index 0000000..10fb445 --- /dev/null +++ b/Sharp.Augeas.Test/lens/opendkim.aug @@ -0,0 +1,60 @@ +module Opendkim = + autoload xfm + + (* Inifile.comment is saner than Util.comment regarding spacing after the # *) + let comment = Inifile.comment "#" "#" + let eol = Util.eol + let empty = Util.empty + + (* + The Dataset spec is so broad as to encompass any string (particularly the + degenerate 'single literal string' case of a comma separated list with + only one item). So treat them as 'String' types, and it's up to the user to + format them correctly. Given that many of the variants include file paths + etc, it's impossible to validate for 'correctness' anyway + *) + let stringkv_rx = /ADSPAction|AuthservID|AutoRestartRate|BaseDirectory/ + | /BogusKey|BogusPolicy|Canonicalization|ChangeRootDirectory/ + | /DiagnosticDirectory|FinalPolicyScript|IdentityHeader|Include|KeyFile/ + | /LDAPAuthMechanism|LDAPAuthName|LDAPAuthRealm|LDAPAuthUser/ + | /LDAPBindPassword|LDAPBindUser|Minimum|Mode|MTACommand|Nameservers/ + | /On-BadSignature|On-Default|On-DNSError|On-InternalError|On-KeyNotFound/ + | /On-NoSignature|On-PolicyError|On-Security|On-SignatureError|PidFile/ + | /ReplaceRules|ReportAddress|ReportBccAddress|ResolverConfiguration/ + | /ScreenPolicyScript|SelectCanonicalizationHeader|Selector|SelectorHeader/ + | /SenderMacro|SetupPolicyScript|SignatureAlgorithm|SMTPURI|Socket/ + | /StatisticsName|StatisticsPrefix|SyslogFacility|TemporaryDirectory/ + | /TestPublicKeys|TrustAnchorFile|UnprotectedKey|UnprotectedPolicy|UserID/ + | /VBR-Certifiers|VBR-PurgeFields|VBR-TrustedCertifiers|VBR-Type/ + | /BodyLengthDB|Domain|DontSignMailTo|ExemptDomains|ExternalIgnoreList/ + | /InternalHosts|KeyTable|LocalADSP|MacroList|MTA|MustBeSigned|OmitHeaders/ + | /OversignHeaders|PeerList|POPDBFile|RemoveARFrom|ResignMailTo/ + | /SenderHeaders|SignHeaders|SigningTable|TrustSignaturesFrom/ + let stringkv = key stringkv_rx . + del /[ \t]+/ " " . store /[0-9a-zA-Z\/][^ \t\n#]+/ . eol + + let integerkv_rx = /AutoRestartCount|ClockDrift|DNSTimeout/ + | /LDAPKeepaliveIdle|LDAPKeepaliveInterval|LDAPKeepaliveProbes|LDAPTimeout/ + | /MaximumHeaders|MaximumSignaturesToVerify|MaximumSignedBytes|MilterDebug/ + | /MinimumKeyBits|SignatureTTL|UMask/ + let integerkv = key integerkv_rx . + del /[ \t]+/ " " . store /[0-9]+/ . eol + + let booleankv_rx = /AddAllSignatureResults|ADSPNoSuchDomain/ + | /AllowSHA1Only|AlwaysAddARHeader|AuthservIDWithJobID|AutoRestart/ + | /Background|CaptureUnknownErrors|Diagnostics|DisableADSP/ + | /DisableCryptoInit|DNSConnect|FixCRLF|IdentityHeaderRemove/ + | /LDAPDisableCache|LDAPSoftStart|LDAPUseTLS|MultipleSignatures|NoHeaderB/ + | /Quarantine|QueryCache|RemoveARAll|RemoveOldSignatures|ResolverTracing/ + | /SelectorHeaderRemove|SendADSPReports|SendReports|SoftwareHeader/ + | /StrictHeaders|StrictTestMode|SubDomains|Syslog|SyslogSuccess/ + | /VBR-TrustedCertifiersOnly|WeakSyntaxChecks|LogWhy/ + let booleankv = key booleankv_rx . + del /[ \t]+/ " " . store /([Tt]rue|[Ff]alse|[Yy]es|[Nn]o|1|0)/ . eol + + let entry = [ integerkv ] | [ booleankv ] | [ stringkv ] + + let lns = (comment | empty | entry)* + + let xfm = transform lns (incl "/etc/opendkim.conf") + diff --git a/Sharp.Augeas.Test/lens/openshift_config.aug b/Sharp.Augeas.Test/lens/openshift_config.aug new file mode 100644 index 0000000..416451f --- /dev/null +++ b/Sharp.Augeas.Test/lens/openshift_config.aug @@ -0,0 +1,75 @@ +(* +Module: OpenShift_Config + Parses + - /etc/openshift/broker.conf + - /etc/openshift/broker-dev.conf + - /etc/openshift/console.conf + - /etc/openshift/console-dev.conf + - /etc/openshift/node.conf + - /etc/openshift/plugins.d/*.conf + +Author: Brian Redbeard <redbeard@dead-city.org> + +About: License + This file is licenced under the LGPL v2+, conforming to the other components + of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get your current setup + > print /files/etc/openshift + ... + + * Change OpenShift domain + > set /files/etc/openshift/broker.conf/CLOUD_DOMAIN ose.example.com + + Saving your file: + + > save + +About: Configuration files + /etc/openshift/broker.conf - Configuration file for an OpenShift Broker + running in production mode. + /etc/openshift/broker-dev.conf - Configuration file for an OpenShift + Broker running in development mode. + /etc/openshift/console.conf - Configuration file for an OpenShift + console running in production mode. + /etc/openshift/console-dev.conf - Configuration file for an OpenShift + console running in development mode. + /etc/openshift/node.conf - Configuration file for an OpenShift node + /etc/openshift/plugins.d/*.conf - Configuration files for OpenShift + plugins (i.e. mcollective configuration, remote auth, dns updates) + +About: Examples + The <Test_OpenShift_Config> file contains various examples and tests. +*) +module OpenShift_Config = + autoload xfm + +(* Variable: blank_val *) +let blank_val = del /["']{2}/ "\"\"" + +(* View: primary_entry *) +let primary_entry = Build.key_value_line Rx.word Sep.equal Quote.any_opt + +(* View: empty_entry *) +let empty_entry = Build.key_value_line Rx.word Sep.equal blank_val + +(* View: lns *) +let lns = (Util.empty | Util.comment | primary_entry | empty_entry )* + +(* Variable: filter *) +let filter = incl "/etc/openshift/broker.conf" + . incl "/etc/openshift/broker-dev.conf" + . incl "/etc/openshift/console.conf" + . incl "/etc/openshift/resource_limits.conf" + . incl "/etc/openshift/console-dev.conf" + . incl "/etc/openshift/node.conf" + . incl "/etc/openshift/plugins.d/*.conf" + . incl "/var/www/openshift/broker/conf/broker.conf" + . incl "/var/www/openshift/broker/conf/plugins.d/*.conf" + . Util.stdexcl + +let xfm = transform lns filter +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/openshift_http.aug b/Sharp.Augeas.Test/lens/openshift_http.aug new file mode 100644 index 0000000..7c54d4a --- /dev/null +++ b/Sharp.Augeas.Test/lens/openshift_http.aug @@ -0,0 +1,36 @@ +(* +Module: OpenShift_Http + Parses HTTPD related files specific to openshift + +Author: Brian Redbeard <redbeard@dead-city.org> + +About: License + This file is licenced under the LGPL v2+, conforming to the other components + of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get your current setup + > print /files/var/www/openshift + +About: Examples + The <Test_OpenShift_Http> file contains various examples and tests. +*) +module OpenShift_Http = + autoload xfm + +(* Variable: filter *) +let filter = incl "/var/www/openshift/console/httpd/httpd.conf" + . incl "/var/www/openshift/console/httpd/conf.d/*.conf" + . incl "/var/www/openshift/broker/httpd/conf.d/*.conf" + . incl "/var/www/openshift/broker/httpd/httpd.conf" + . incl "/var/www/openshift/console/httpd/console.conf" + . incl "/var/www/openshift/broker/httpd/broker.conf" + . Util.stdexcl + +(* View: lns *) +let lns = Httpd.lns + +let xfm = transform lns filter +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/openshift_quickstarts.aug b/Sharp.Augeas.Test/lens/openshift_quickstarts.aug new file mode 100644 index 0000000..da248d5 --- /dev/null +++ b/Sharp.Augeas.Test/lens/openshift_quickstarts.aug @@ -0,0 +1,43 @@ +(* +Module: OpenShift_Quickstarts + Parses + - /etc/openshift/quickstarts.json + +Author: Brian Redbeard <redbeard@dead-city.org> + +About: License + This file is licenced under the LGPL v2+, conforming to the other components + of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get your current setup + > print /files/etc/openshift/quickstarts.json + ... + + * Delete the quickstart named WordPress + > rm /files/etc/openshift/quickstarts.json/array/dict[*]/entry/dict/entry[*][string = 'WordPress']/../../../ + + Saving your file: + + > save + +About: Configuration files + /etc/openshift/quickstarts.json - Quickstarts available via the + OpenShift Console. + +About: Examples + The <Test_OpenShift_Quickstarts> file contains various examples and tests. +*) +module OpenShift_Quickstarts = + autoload xfm + +(* View: lns *) +let lns = Json.lns + +(* Variable: filter *) +let filter = incl "/etc/openshift/quickstarts.json" + +let xfm = transform lns filter +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/openvpn.aug b/Sharp.Augeas.Test/lens/openvpn.aug new file mode 100644 index 0000000..607e1d6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/openvpn.aug @@ -0,0 +1,655 @@ +(* OpenVPN module for Augeas + Author: Raphael Pinson <raphink@gmail.com> + Author: Justin Akers <dafugg@gmail.com> + + Reference: http://openvpn.net/index.php/documentation/howto.html + Reference: https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage + + TODO: Inline file support +*) + + +module OpenVPN = + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let indent = Util.indent + +(* Define separators *) +let sep = Util.del_ws_spc + +(* Define value regexps. + Custom simplified ipv6 used instead of Rx.ipv6 as the augeas Travis instances + are limited to 2GB of memory. Using 'ipv6_re = Rx.ipv6' consumes an extra + 2GB of memory and thus the test is OOM-killed. +*) +let ipv6_re = /[0-9A-Fa-f:]+/ +let ipv4_re = Rx.ipv4 +let ip_re = ipv4_re|ipv6_re +let num_re = Rx.integer +let fn_re = /[^#; \t\n][^#;\n]*[^#; \t\n]|[^#; \t\n]/ +let fn_safe_re = /[^#; \t\r\n]+/ +let an_re = /[a-z][a-z0-9_-]*/ +let hn_re = Rx.hostname +let port_re = /[0-9]+/ +let host_re = ip_re|hn_re +let proto_re = /(tcp|udp)/ +let proto_ext_re = /(udp|tcp-client|tcp-server)/ +let alg_re = /(none|[A-Za-z][A-Za-z0-9-]+)/ +let ipv6_bits_re = ipv6_re . /\/[0-9]+/ + +(* Define store aliases *) +let ip = store ip_re +let num = store num_re +let filename = store fn_re +let filename_safe = store fn_safe_re +let hostname = store hn_re +let sto_to_dquote = store /[^"\n]+/ (* " Emacs, relax *) +let port = store port_re +let host = store host_re +let proto = store proto_re +let proto_ext = store proto_ext_re + +(* define comments and empty lines *) +let comment = Util.comment_generic /[ \t]*[;#][ \t]*/ "# " +let comment_or_eol = eol | Util.comment_generic /[ \t]*[;#][ \t]*/ " # " + +let empty = Util.empty + + +(************************************************************************ + * SINGLE VALUES + * + * - local => IP|hostname + * - port => num + * - proto => udp|tcp-client|tcp-server + * - proto-force => udp|tcp + * - mode => p2p|server + * - dev => (tun|tap)\d* + * - dev-node => filename + * - ca => filename + * - config => filename + * - cert => filename + * - key => filename + * - dh => filename + * - ifconfig-pool-persist => filename + * - learn-address => filename + * - cipher => [A-Z0-9-]+ + * - max-clients => num + * - user => alphanum + * - group => alphanum + * - status => filename + * - log => filename + * - log-append => filename + * - client-config-dir => filename + * - verb => num + * - mute => num + * - fragment => num + * - mssfix => num + * - connect-retry num + * - connect-retry-max num + * - connect-timeout num + * - http-proxy-timeout num + * - max-routes num + * - ns-cert-type => "server" + * - resolv-retry => "infinite" + * - script-security => [0-3] (execve|system)? + * - ipchange => command + * - topology => type + *************************************************************************) + +let single_host = "local" | "tls-remote" +let single_ip = "lladdr" +let single_ipv6_bits = "iroute-ipv6" + | "server-ipv6" + | "ifconfig-ipv6-pool" +let single_num = "port" + | "max-clients" + | "verb" + | "mute" + | "fragment" + | "mssfix" + | "connect-retry" + | "connect-retry-max" + | "connect-timeout" + | "http-proxy-timeout" + | "resolv-retry" + | "lport" + | "rport" + | "max-routes" + | "max-routes-per-client" + | "route-metric" + | "tun-mtu" + | "tun-mtu-extra" + | "shaper" + | "ping" + | "ping-exit" + | "ping-restart" + | "sndbuf" + | "rcvbuf" + | "txqueuelen" + | "link-mtu" + | "nice" + | "management-log-cache" + | "bcast-buffers" + | "tcp-queue-limit" + | "server-poll-timeout" + | "keysize" + | "pkcs11-pin-cache" + | "tls-timeout" + | "reneg-bytes" + | "reneg-pkts" + | "reneg-sec" + | "hand-window" + | "tran-window" +let single_fn = "ca" + | "cert" + | "extra-certs" + | "config" + | "key" + | "dh" + | "log" + | "log-append" + | "client-config-dir" + | "dev-node" + | "cd" + | "chroot" + | "writepid" + | "client-config-dir" + | "tmp-dir" + | "replay-persist" + | "ca" + | "capath" + | "pkcs12" + | "pkcs11-id" + | "askpass" + | "tls-export-cert" + | "x509-track" +let single_an = "user" + | "group" + | "management-client-user" + | "management-client-group" +let single_cmd = "ipchange" + | "iproute" + | "route-up" + | "route-pre-down" + | "mark" + | "up" + | "down" + | "setcon" + | "echo" + | "client-connect" + | "client-disconnect" + | "learn-address" + | "tls-verify" + +let single_entry (kw:regexp) (re:regexp) + = [ key kw . sep . store re . comment_or_eol ] + +let single_opt_entry (kw:regexp) (re:regexp) + = [ key kw . (sep . store re)? .comment_or_eol ] + +let single = single_entry single_num num_re + | single_entry single_fn fn_re + | single_entry single_an an_re + | single_entry single_host host_re + | single_entry single_ip ip_re + | single_entry single_ipv6_bits ipv6_bits_re + | single_entry single_cmd fn_re + | single_entry "proto" proto_ext_re + | single_entry "proto-force" proto_re + | single_entry "mode" /(p2p|server)/ + | single_entry "dev" /(tun|tap)[0-9]*|null/ + | single_entry "dev-type" /(tun|tap)/ + | single_entry "topology" /(net30|p2p|subnet)/ + | single_entry "cipher" alg_re + | single_entry "auth" alg_re + | single_entry "resolv-retry" "infinite" + | single_entry "script-security" /[0-3]( execve| system)?/ + | single_entry "route-gateway" (host_re|/dhcp/) + | single_entry "mtu-disc" /(no|maybe|yes)/ + | single_entry "remap-usr1" /SIG(HUP|TERM)/ + | single_entry "socket-flags" /(TCP_NODELAY)/ + | single_entry "auth-retry" /(none|nointeract|interact)/ + | single_entry "tls-version-max" Rx.decimal + | single_entry "verify-hash" /([A-Za-z0-9]{2}:)+[A-Za-z0-9]{2}/ + | single_entry "pkcs11-cert-private" /[01]/ + | single_entry "pkcs11-protected-authentication" /[01]/ + | single_entry "pkcs11-private-mode" /[A-Za-z0-9]+/ + | single_entry "key-method" /[12]/ + | single_entry "ns-cert-type" /(client|server)/ + | single_entry "remote-cert-tls" /(client|server)/ + +let single_opt = single_opt_entry "comp-lzo" /(yes|no|adaptive)/ + | single_opt_entry "syslog" fn_re + | single_opt_entry "daemon" fn_re + | single_opt_entry "auth-user-pass" fn_re + | single_opt_entry "explicit-exit-notify" num_re + | single_opt_entry "engine" fn_re + +(************************************************************************ + * DOUBLE VALUES + *************************************************************************) + +let double_entry (kw:regexp) (a:string) (aval:regexp) (b:string) (bval:regexp) + = [ key kw + . sep . [ label a . store aval ] + . sep . [ label b . store bval ] + . comment_or_eol + ] + +let double_secopt_entry (kw:regexp) (a:string) (aval:regexp) (b:string) (bval:regexp) + = [ key kw + . sep . [ label a . store aval ] + . (sep . [ label b . store bval ])? + . comment_or_eol + ] + + +let double = double_entry "keepalive" "ping" num_re "timeout" num_re + | double_entry "hash-size" "real" num_re "virtual" num_re + | double_entry "ifconfig" "local" ip_re "remote" ip_re + | double_entry "connect-freq" "num" num_re "sec" num_re + | double_entry "verify-x509-name" "name" hn_re "type" + /(subject|name|name-prefix)/ + | double_entry "ifconfig-ipv6" "address" ipv6_bits_re "remote" ipv6_re + | double_entry "ifconfig-ipv6-push" "address" ipv6_bits_re "remote" ipv6_re + | double_secopt_entry "iroute" "local" ip_re "netmask" ip_re + | double_secopt_entry "stale-routes-check" "age" num_re "interval" num_re + | double_secopt_entry "ifconfig-pool-persist" + "file" fn_safe_re "seconds" num_re + | double_secopt_entry "secret" "file" fn_safe_re "direction" /[01]/ + | double_secopt_entry "prng" "algorithm" alg_re "nsl" num_re + | double_secopt_entry "replay-window" "window-size" num_re "seconds" num_re + + +(************************************************************************ + * FLAGS + *************************************************************************) + +let flag_words = "client-to-client" + | "duplicate-cn" + | "persist-key" + | "persist-tun" + | "client" + | "remote-random" + | "nobind" + | "mute-replay-warnings" + | "http-proxy-retry" + | "socks-proxy-retry" + | "remote-random-hostname" + | "show-proxy-settings" + | "float" + | "bind" + | "nobind" + | "tun-ipv6" + | "ifconfig-noexec" + | "ifconfig-nowarn" + | "route-noexec" + | "route-nopull" + | "allow-pull-fqdn" + | "mtu-test" + | "ping-timer-rem" + | "persist-tun" + | "persist-local-ip" + | "persist-remote-ip" + | "mlock" + | "up-delay" + | "down-pre" + | "up-restart" + | "disable-occ" + | "errors-to-stderr" + | "passtos" + | "suppress-timestamps" + | "fast-io" + | "multihome" + | "comp-noadapt" + | "management-client" + | "management-query-passwords" + | "management-query-proxy" + | "management-query-remote" + | "management-forget-disconnect" + | "management-hold" + | "management-signal" + | "management-up-down" + | "management-client-auth" + | "management-client-pf" + | "push-reset" + | "push-peer-info" + | "disable" + | "ifconfig-pool-linear" + | "client-to-client" + | "duplicate-cn" + | "ccd-exclusive" + | "tcp-nodelay" + | "opt-verify" + | "auth-user-pass-optional" + | "client-cert-not-required" + | "username-as-common-name" + | "pull" + | "key-direction" + | "no-replay" + | "mute-replay-warnings" + | "no-iv" + | "use-prediction-resistance" + | "test-crypto" + | "tls-server" + | "tls-client" + | "pkcs11-id-management" + | "single-session" + | "tls-exit" + | "auth-nocache" + | "show-ciphers" + | "show-digests" + | "show-tls" + | "show-engines" + | "genkey" + | "mktun" + | "rmtun" + + +let flag_entry (kw:regexp) + = [ key kw . comment_or_eol ] + +let flag = flag_entry flag_words + + +(************************************************************************ + * OTHER FIELDS + * + * - server => IP IP [nopool] + * - server-bridge => IP IP IP IP + * - route => host host [host [num]] + * - push => "string" + * - tls-auth => filename [01] + * - remote => hostname/IP [num] [(tcp|udp)] + * - management => IP num filename + * - http-proxy => host port [filename|keyword] [method] + * - http-proxy-option => (VERSION decimal|AGENT string) + * ... + * and many others + * + *************************************************************************) + +let server = [ key "server" + . sep . [ label "address" . ip ] + . sep . [ label "netmask" . ip ] + . (sep . [ key "nopool" ]) ? + . comment_or_eol + ] + +let server_bridge = + let ip_params = [ label "address" . ip ] . sep + . [ label "netmask" . ip ] . sep + . [ label "start" . ip ] . sep + . [ label "end" . ip ] in + [ key "server-bridge" + . sep . (ip_params|store /(nogw)/) + . comment_or_eol + ] + +let route = + let route_net_kw = store (/(vpn_gateway|net_gateway|remote_host)/|host_re) in + [ key "route" . sep + . [ label "address" . route_net_kw ] + . (sep . [ label "netmask" . store (ip_re|/default/) ] + . (sep . [ label "gateway" . route_net_kw ] + . (sep . [ label "metric" . store (/default/|num_re)] )? + )? + )? + . comment_or_eol + ] + +let route_ipv6 = + let route_net_re = /(vpn_gateway|net_gateway|remote_host)/ in + [ key "route-ipv6" . sep + . [ label "network" . store (route_net_re|ipv6_bits_re) ] + . (sep . [ label "gateway" . store (route_net_re|ipv6_re) ] + . (sep . [ label "metric" . store (/default/|num_re)] )? + )? + . comment_or_eol + ] + +let push = [ key "push" . sep + . Quote.do_dquote sto_to_dquote + . comment_or_eol + ] + +let tls_auth = [ key "tls-auth" . sep + . [ label "key" . filename ] . sep + . [ label "is_client" . store /[01]/ ] . comment_or_eol + ] + +let remote = [ key "remote" . sep + . [ label "server" . host ] + . (sep . [label "port" . port] + . (sep . [label "proto" . proto]) ? ) ? + . comment_or_eol + ] + +let http_proxy = + let auth_method_re = /(none|basic|ntlm)/ in + let auth_method = store auth_method_re in + [ key "http-proxy" + . sep . [ label "server" . host ] + . sep . [ label "port" . port ] + . (sep . [ label "auth" . filename_safe ] + . (sep . [ label "auth-method" . auth_method ]) ? )? + . comment_or_eol + ] + +let http_proxy_option = [ key "http-proxy-option" + . sep . [ label "option" . store /(VERSION|AGENT)/ ] + . sep . [ label "value" . filename ] + . comment_or_eol + ] + +let socks_proxy = [ key "socks-proxy" + . sep . [ label "server" . host ] + . (sep . [ label "port" . port ] + . (sep . [ label "auth" . filename_safe ])? )? + . comment_or_eol + ] + +let port_share = [ key "port-share" + . sep . [ label "host" . host ] + . sep . [ label "port" . port ] + . (sep . [ label "dir" . filename ])? + . comment_or_eol + ] + +let route_delay = [ key "route-delay" + . (sep . [ label "seconds" . num ] + . (sep . [ label "win-seconds" . num ] ) ? + )? + . comment_or_eol + ] + +let inetd = [ key "inetd" + . (sep . [label "mode" . store /(wait|nowait)/ ] + . (sep . [ label "progname" . filename ] ) ? + )? + . comment_or_eol + ] + +let inactive = [ key "inactive" + . sep . [ label "seconds" . num ] + . (sep . [ label "bytes" . num ] ) ? + . comment_or_eol + ] + +let client_nat = [ key "client-nat" + . sep . [ label "type" . store /(snat|dnat)/ ] + . sep . [ label "network" . ip ] + . sep . [ label "netmask" . ip ] + . sep . [ label "alias" . ip ] + . comment_or_eol + ] + +let status = [ key "status" + . sep . [ label "file" . filename_safe ] + . (sep . [ label "repeat-seconds" . num ]) ? + . comment_or_eol + ] + +let plugin = [ key "plugin" + . sep . [ label "file" . filename_safe ] + . (sep . [ label "init-string" . filename ]) ? + . comment_or_eol + ] + +let management = [ key "management" . sep + . [ label "server" . ip ] + . sep . [ label "port" . port ] + . (sep . [ label "pwfile" . filename ] ) ? + . comment_or_eol + ] + +let auth_user_pass_verify = [ key "auth-user-pass-verify" + . sep . [ Quote.quote_spaces (label "command") ] + . sep . [ label "method" . store /via-(env|file)/ ] + . comment_or_eol + ] + +let static_challenge = [ key "static-challenge" + . sep . [ Quote.quote_spaces (label "text") ] + . sep . [ label "echo" . store /[01]/ ] + . comment_or_eol + ] + +let cryptoapicert = [ key "cryptoapicert" . sep . Quote.dquote + . [ key /[A-Z]+/ . Sep.colon . store /[A-Za-z _-]+/ ] + . Quote.dquote . comment_or_eol + ] + +let setenv = + let envvar = /[^#;\/ \t\n][A-Za-z0-9_-]+/ in + [ key ("setenv"|"setenv-safe") + . sep . [ key envvar . sep . store fn_re ] + . comment_or_eol + ] + +let redirect = + let redirect_flag = /(local|autolocal|def1|bypass-dhcp|bypass-dns|block-local)/ in + let redirect_key = "redirect-gateway" | "redirect-private" in + [ key redirect_key + . (sep . [ label "flag" . store redirect_flag ] ) + + . comment_or_eol + ] + +let tls_cipher = + let ciphername = /[A-Za-z0-9!_-]+/ in + [ key "tls-cipher" . sep + . [label "cipher" . store ciphername] + . (Sep.colon . [label "cipher" . store ciphername])* + . comment_or_eol + ] + +let remote_cert_ku = + let usage = [label "usage" . store /[A-Za-z0-9]{1,2}/] in + [ key "remote-cert-ku" . sep . usage . (sep . usage)* . comment_or_eol ] + +(* FIXME: Surely there's a nicer way to do this *) +let remote_cert_eku = + let oid = [label "oid" . store /[0-9]+\.([0-9]+\.)*[0-9]+/] in + let symbolic = [Quote.do_quote_opt + (label "symbol" . store /[A-Za-z0-9][A-Za-z0-9 _-]*[A-Za-z0-9]/)] in + [ key "remote-cert-eku" . sep . (oid|symbolic) . comment_or_eol ] + +let status_version = [ key "status-version" + . (sep . num) ? + . comment_or_eol + ] + +let ifconfig_pool = [ key "ifconfig-pool" + . sep . [ label "start" . ip ] + . sep . [ label "end" . ip ] + . (sep . [ label "netmask" . ip ])? + . comment_or_eol + ] + +let ifconfig_push = [ key "ifconfig-push" + . sep . [ label "local" . ip ] + . sep . [ label "remote-netmask" . ip ] + . (sep . [ label "alias" . store /[A-Za-z0-9_-]+/ ] )? + . comment_or_eol + ] + +let ignore_unknown_option = [ key "ignore-unknown-option" + . (sep . [ label "opt" . store /[A-Za-z0-9_-]+/ ] ) + + . comment_or_eol + ] + +let tls_version_min = [ key "tls-version-min" + . sep . store Rx.decimal + . (sep . [ key "or-highest" ]) ? + . comment_or_eol + ] + +let crl_verify = [ key "crl-verify" + . sep . filename_safe + . (sep . [ key "dir" ]) ? + . comment_or_eol + ] + +let x509_username_field = + let fieldname = /[A-Za-z0-9_-]+/ in + let extfield = ([key /ext/ . Sep.colon . store fieldname]) in + let subjfield = ([label "subj" . store fieldname]) in + [ key "x509-username-field" + . sep . (extfield|subjfield) + . comment_or_eol + ] + +let other = server + | server_bridge + | route + | push + | tls_auth + | remote + | http_proxy + | http_proxy_option + | socks_proxy + | management + | route_delay + | client_nat + | redirect + | inactive + | setenv + | inetd + | status + | status_version + | plugin + | ifconfig_pool + | ifconfig_push + | ignore_unknown_option + | auth_user_pass_verify + | port_share + | static_challenge + | tls_version_min + | tls_cipher + | cryptoapicert + | x509_username_field + | remote_cert_ku + | remote_cert_eku + | crl_verify + | route_ipv6 + + +(************************************************************************ + * LENS & FILTER + *************************************************************************) + +let lns = ( comment | empty | single | single_opt | double | flag | other )* + +let filter = (incl "/etc/openvpn/client.conf") + . (incl "/etc/openvpn/server.conf") + +let xfm = transform lns filter + + + diff --git a/Sharp.Augeas.Test/lens/oz.aug b/Sharp.Augeas.Test/lens/oz.aug new file mode 100644 index 0000000..befacf6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/oz.aug @@ -0,0 +1,45 @@ +(* +Module: Oz + Oz module for Augeas + + Author: Pat Riehecky <riehecky@fnal.gov> + + oz.cfg is a standard INI File. +*) + +module Oz = + autoload xfm + +(************************************************************************ + * Group: INI File settings + * avahi-daemon.conf only supports "# as commentary and "=" as separator + *************************************************************************) +(* View: comment *) +let comment = IniFile.comment "#" "#" +(* View: sep *) +let sep = IniFile.sep "=" "=" + +(************************************************************************ + * Group: Entry + *************************************************************************) +(* View: entry *) +let entry = IniFile.indented_entry IniFile.entry_re sep comment + +(************************************************************************ + * Group: Record + *************************************************************************) +(* View: title *) +let title = IniFile.indented_title IniFile.record_re +(* View: record *) +let record = IniFile.record title entry + +(************************************************************************ + * Group: Lens and filter + *************************************************************************) +(* View: lns *) +let lns = IniFile.lns record comment + +(* View: filter *) +let filter = (incl "/etc/oz/oz.cfg") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/pagekite.aug b/Sharp.Augeas.Test/lens/pagekite.aug new file mode 100644 index 0000000..83ced80 --- /dev/null +++ b/Sharp.Augeas.Test/lens/pagekite.aug @@ -0,0 +1,79 @@ +(* +Module: Pagekite + Parses /etc/pagekite.d/ + +Author: Michael Pimmer <blubb@fonfon.at> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. +*) + +module Pagekite = +autoload xfm + +(* View: lns *) + +(* Variables *) +let equals = del /[ \t]*=[ \t]*/ "=" +let neg2 = /[^# \n\t]+/ +let neg3 = /[^# \:\n\t]+/ +let eol = del /\n/ "\n" +(* Match everything from here to eol, cropping whitespace at both ends *) +let to_eol = /[^ \t\n](.*[^ \t\n])?/ + +(* A key followed by comma-separated values + k: name of the key + key_sep: separator between key and values + value_sep: separator between values + sto: store for values +*) +let key_csv_line (k:string) (key_sep:lens) (value_sep:lens) (sto:lens) = + [ key k . key_sep . [ seq k . sto ] . + [ seq k . value_sep . sto ]* . Util.eol ] + +(* entries for pagekite.d/10_account.rc *) +let domain = [ key "domain" . equals . store neg2 . Util.comment_or_eol ] +let frontend = Build.key_value_line ("frontend" | "frontends") + equals (store Rx.neg1) +let host = Build.key_value_line "host" equals (store Rx.ip) +let ports = key_csv_line "ports" equals Sep.comma (store Rx.integer) +let protos = key_csv_line "protos" equals Sep.comma (store Rx.word) + +(* entries for pagekite.d/20_frontends.rc *) +let kitesecret = Build.key_value_line "kitesecret" equals (store Rx.space_in) +let kv_frontend = Build.key_value_line ( "kitename" | "fe_certname" | + "ca_certs" | "tls_endpoint" ) + equals (store Rx.neg1) + +(* entries for services like 80_httpd.rc *) +let service_colon = del /[ \t]*:[ \t]*/ " : " +let service_on = [ key "service_on" . [ seq "service_on" . equals . + [ label "protocol" . store neg3 ] . service_colon . + [ label "kitename" . (store neg3) ] . service_colon . + [ label "backend_host" . (store neg3) ] . service_colon . + [ label "backend_port" . (store neg3) ] . service_colon . ( + [ label "secret" . (store Rx.no_spaces) . Util.eol ] | eol + ) ] ] + +let service_cfg = [ key "service_cfg" . equals . store to_eol . eol ] + +let flags = ( "defaults" | "isfrontend" | "abort_not_configured" | "insecure" ) + +let entries = Build.flag_line flags + | domain + | frontend + | host + | ports + | protos + | kv_frontend + | kitesecret + | service_on + | service_cfg + +let lns = ( entries | Util.empty | Util.comment )* + +(* View: filter *) +let filter = incl "/etc/pagekite.d/*.rc" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/pam.aug b/Sharp.Augeas.Test/lens/pam.aug new file mode 100644 index 0000000..80cdfb4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/pam.aug @@ -0,0 +1,76 @@ +(* +Module: Pam + Parses /etc/pam.conf and /etc/pam.d/* service files + +Author: David Lutterkort <lutter@redhat.com> + +About: Reference + This lens tries to keep as close as possible to `man pam.conf` where + possible. + +About: Licence + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + +About: Configuration files + This lens autoloads /etc/pam.d/* for service specific files. See <filter>. + It provides a lens for /etc/pam.conf, which is used in the PamConf module. +*) +module Pam = + autoload xfm + + let eol = Util.eol + let indent = Util.indent + let space = del /([ \t]|\\\\\n)+/ " " + + (* For the control syntax of [key=value ..] we could split the key value *) + (* pairs into an array and generate a subtree control/N/KEY = VALUE *) + (* The valid control values if the [...] syntax is not used, is *) + (* required|requisite|optional|sufficient|include|substack *) + (* We allow more than that because this list is not case sensitive and *) + (* to be more lenient with typos *) + let control = /(\[[^]#\n]*\]|[a-zA-Z]+)/ + let word = /([^# \t\n\\]|\\\\.)+/ + (* Allowed types *) + let types = /(auth|session|account|password)/i + + (* This isn't entirely right: arguments enclosed in [ .. ] can contain *) + (* a ']' if escaped with a '\' and can be on multiple lines ('\') *) + let argument = /(\[[^]#\n]+\]|[^[#\n \t\\][^#\n \t\\]*)/ + + let comment = Util.comment + let comment_or_eol = Util.comment_or_eol + let empty = Util.empty + + + (* Not mentioned in the man page, but Debian uses the syntax *) + (* @include module *) + (* quite a bit *) + let include = [ indent . Util.del_str "@" . key "include" . + space . store word . eol ] + + (* Shared with PamConf *) + let record = [ label "optional" . del "-" "-" ]? . + [ label "type" . store types ] . + space . + [ label "control" . store control] . + space . + [ label "module" . store word ] . + [ space . label "argument" . store argument ]* . + comment_or_eol + + let record_svc = [ seq "record" . indent . record ] + + let lns = ( empty | comment | include | record_svc ) * + + let filter = incl "/etc/pam.d/*" + . excl "/etc/pam.d/allow.pamlist" + . excl "/etc/pam.d/README" + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/pamconf.aug b/Sharp.Augeas.Test/lens/pamconf.aug new file mode 100644 index 0000000..925d197 --- /dev/null +++ b/Sharp.Augeas.Test/lens/pamconf.aug @@ -0,0 +1,53 @@ +(* +Module: PamConf + Parses /etc/pam.conf files + +Author: Dominic Cleal <dcleal@redhat.com> + +About: Reference + This lens tries to keep as close as possible to `man pam.conf` where + possible. + +About: Licence + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + +About: Configuration files + This lens applies to /etc/pam.conf. See <filter>. +*) +module PamConf = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +let indent = Util.indent + +let comment = Util.comment + +let empty = Util.empty + +let include = Pam.include + +let service = Rx.word + +(************************************************************************ + * Group: LENSES + *************************************************************************) + +let record = [ seq "record" . indent . + [ label "service" . store service ] . + Sep.space . + Pam.record ] + +let lns = ( empty | comment | include | record ) * + +let filter = incl "/etc/pam.conf" + +let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/passwd.aug b/Sharp.Augeas.Test/lens/passwd.aug new file mode 100644 index 0000000..a2ab4f9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/passwd.aug @@ -0,0 +1,128 @@ +(* + Module: Passwd + Parses /etc/passwd + + Author: Free Ekanayaka <free@64studio.com> + + About: Reference + - man 5 passwd + - man 3 getpwnam + + Each line in the unix passwd file represents a single user record, whose + colon-separated attributes correspond to the members of the passwd struct + +*) + +module Passwd = + + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Comments and empty lines *) + +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty +let dels = Util.del_str + +let word = Rx.word +let integer = Rx.integer + +let colon = Sep.colon + +let sto_to_eol = store Rx.space_in +let sto_to_col = store /[^:\r\n]+/ +(* Store an empty string if nothing matches *) +let sto_to_col_or_empty = store /[^:\r\n]*/ + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +let username = /[_.A-Za-z0-9][-_.A-Za-z0-9]*\$?/ + +(* View: password + pw_passwd *) +let password = [ label "password" . sto_to_col? . colon ] + +(* View: uid + pw_uid *) +let uid = [ label "uid" . store integer . colon ] + +(* View: gid + pw_gid *) +let gid = [ label "gid" . store integer . colon ] + +(* View: name + pw_gecos; the user's full name *) +let name = [ label "name" . sto_to_col? . colon ] + +(* View: home + pw_dir *) +let home = [ label "home" . sto_to_col? . colon ] + +(* View: shell + pw_shell *) +let shell = [ label "shell" . sto_to_eol? ] + +(* View: entry + struct passwd *) +let entry = [ key username + . colon + . password + . uid + . gid + . name + . home + . shell + . eol ] + +(* NIS entries *) +let niscommon = [ label "password" . sto_to_col ]? . colon + . [ label "uid" . store integer ]? . colon + . [ label "gid" . store integer ]? . colon + . [ label "name" . sto_to_col ]? . colon + . [ label "home" . sto_to_col ]? . colon + . [ label "shell" . sto_to_eol ]? + +let nisentry = + let overrides = + colon + . niscommon in + [ dels "+@" . label "@nis" . store username . overrides . eol ] + +let nisuserplus = + let overrides = + colon + . niscommon in + [ dels "+" . label "@+nisuser" . store username . overrides . eol ] + +let nisuserminus = + let overrides = + colon + . niscommon in + [ dels "-" . label "@-nisuser" . store username . overrides . eol ] + +let nisdefault = + let overrides = + colon + . [ label "password" . sto_to_col_or_empty . colon ] + . [ label "uid" . store integer? . colon ] + . [ label "gid" . store integer? . colon ] + . [ label "name" . sto_to_col? . colon ] + . [ label "home" . sto_to_col? . colon ] + . [ label "shell" . sto_to_eol? ] in + [ dels "+" . label "@nisdefault" . overrides? . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry|nisentry|nisdefault|nisuserplus|nisuserminus) * + +let filter = incl "/etc/passwd" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/pbuilder.aug b/Sharp.Augeas.Test/lens/pbuilder.aug new file mode 100644 index 0000000..364643c --- /dev/null +++ b/Sharp.Augeas.Test/lens/pbuilder.aug @@ -0,0 +1,31 @@ +(* +Module: Pbuilder + Parses /etc/pbuilderrc, /etc/pbuilder/pbuilderrc + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + Pbuilderrc is a standard shellvars file. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to /etc/pbuilderrc and /etc/pbuilder/pbuilderrc. + See <filter>. +*) + +module Pbuilder = + +autoload xfm + +(* View: filter + The pbuilder conffiles *) +let filter = incl "/etc/pbuilder/pbuilderrc" + . incl "/etc/pbuilderrc" + +(* View: lns + The pbuilder lens *) +let lns = Shellvars.lns + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/pg_hba.aug b/Sharp.Augeas.Test/lens/pg_hba.aug new file mode 100644 index 0000000..a9d165d --- /dev/null +++ b/Sharp.Augeas.Test/lens/pg_hba.aug @@ -0,0 +1,92 @@ +(* +Module: Pg_Hba + Parses PostgreSQL's pg_hba.conf + +Author: Aurelien Bompard <aurelien@bompard.org> +About: Reference + The file format is described in PostgreSQL's documentation: + http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to pg_hba.conf. See <filter> for exact locations. +*) + + +module Pg_Hba = + autoload xfm + + (* Group: Generic primitives *) + + let eol = Util.eol + let word = Rx.neg1 + (* Variable: ipaddr + CIDR or ip+netmask *) + let ipaddr = /[0-9a-fA-F:.]+(\/[0-9]+|[ \t]+[0-9.]+)/ + (* Variable: hostname + Hostname, FQDN or part of an FQDN possibly + starting with a dot. Taken from the syslog lens. *) + let hostname = /\.?[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*/ + + let comma_sep_list (l:string) = + let lns = [ label l . store word ] in + Build.opt_list lns Sep.comma + + (* Group: Columns definitions *) + + (* View: ipaddr_or_hostname *) + let ipaddr_or_hostname = ipaddr | hostname + (* View: database + TODO: support for quoted strings *) + let database = comma_sep_list "database" + (* View: user + TODO: support for quoted strings *) + let user = comma_sep_list "user" + (* View: address *) + let address = [ label "address" . store ipaddr_or_hostname ] + (* View: option + part of <method> *) + let option = + let value_start = label "value" . Sep.equal + in [ label "option" . store Rx.word + . (Quote.quote_spaces value_start)? ] + + (* View: method + can contain an <option> *) + let method = [ label "method" . store /[A-Za-z][A-Za-z0-9]+/ + . ( Sep.tab . option )* ] + + (* Group: Records definitions *) + + (* View: record_local + when type is "local", there is no "address" field *) + let record_local = [ label "type" . store "local" ] . Sep.tab . + database . Sep.tab . user . Sep.tab . method + + (* Variable: remtypes + non-local connection types *) + let remtypes = "host" | "hostssl" | "hostnossl" + + (* View: record_remote *) + let record_remote = [ label "type" . store remtypes ] . Sep.tab . + database . Sep.tab . user . Sep.tab . + address . Sep.tab . method + + (* View: record + A sequence of <record_local> or <record_remote> entries *) + let record = [ seq "entries" . (record_local | record_remote) . eol ] + + (* View: filter + The pg_hba.conf conf file *) + let filter = (incl "/var/lib/pgsql/data/pg_hba.conf" . + incl "/var/lib/pgsql/*/data/pg_hba.conf" . + incl "/var/lib/postgresql/*/data/pg_hba.conf" . + incl "/etc/postgresql/*/*/pg_hba.conf" ) + + (* View: lns + The pg_hba.conf lens *) + let lns = ( record | Util.comment | Util.empty ) * + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/pgbouncer.aug b/Sharp.Augeas.Test/lens/pgbouncer.aug new file mode 100644 index 0000000..5539587 --- /dev/null +++ b/Sharp.Augeas.Test/lens/pgbouncer.aug @@ -0,0 +1,55 @@ +(* +Module: Pgbouncer + Parses Pgbouncer ini configuration files. + +Author: Andrew Colin Kissa <andrew@topdog.za.net> + Baruwa Enterprise Edition http://www.baruwa.com + +About: License + This file is licensed under the LGPL v2+. + +About: Configuration files + This lens applies to /etc/pgbouncer.ini See <filter>. + +About: TODO + Create a tree for the database options +*) + +module Pgbouncer = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + ************************************************************************) + +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + +let sep = IniFile.sep "=" "=" + +let eol = Util.eol + +let entry_re = ( /[A-Za-z][:#A-Za-z0-9._-]+|\*/) + +(************************************************************************ + * Group: ENTRY + *************************************************************************) + +let non_db_line = [ key entry_re . sep . IniFile.sto_to_eol? . eol ] + +let entry = non_db_line|comment + +let title = IniFile.title IniFile.record_re + +let record = IniFile.record title entry + +(****************************************************************** + * Group: LENS AND FILTER + ******************************************************************) + +let lns = IniFile.lns record comment + +(* Variable: filter *) +let filter = incl "/etc/pgbouncer.ini" + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/php.aug b/Sharp.Augeas.Test/lens/php.aug new file mode 100644 index 0000000..2254bab --- /dev/null +++ b/Sharp.Augeas.Test/lens/php.aug @@ -0,0 +1,61 @@ +(* PHP module for Augeas *) +(* Author: Raphael Pinson <raphink@gmail.com> *) +(* *) + +module PHP = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) + +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default +let empty = IniFile.empty + + +(************************************************************************ + * ENTRY + * + * We have to remove the keyword "section" from possible entry keywords + * otherwise it would lead to an ambiguity with the "section" label + * since PHP allows entries outside of sections. + *************************************************************************) +let entry = + let word = IniFile.entry_re + in let entry_re = word . ( "[" . word . "]" )? + in IniFile.indented_entry entry_re sep comment + + +(************************************************************************ + * TITLE + * + * We use IniFile.title_label because there can be entries + * outside of sections whose labels would conflict with section names + *************************************************************************) +let title = IniFile.title ( IniFile.record_re - ".anon" ) +let record = IniFile.record title entry + +let record_anon = [ label ".anon" . ( entry | empty )+ ] + + +(************************************************************************ + * LENS & FILTER + * There can be entries before any section + * IniFile.entry includes comment management, so we just pass entry to lns + *************************************************************************) +let lns = record_anon? . record* + +let filter = (incl "/etc/php*/*/*.ini") + . (incl "/etc/php/*/*/*.ini") + . (incl "/etc/php.ini") + . (incl "/etc/php.d/*.ini") + (* PHPFPM Support *) + . (incl "/etc/php*/fpm/pool.d/*.conf") + . (incl "/etc/php/*/fpm/pool.d/*.conf") + (* Zend Community edition *) + . (incl "/usr/local/zend/etc/php.ini") + . (incl "/usr/local/zend/etc/conf.d/*.ini") + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/phpvars.aug b/Sharp.Augeas.Test/lens/phpvars.aug new file mode 100644 index 0000000..f05b922 --- /dev/null +++ b/Sharp.Augeas.Test/lens/phpvars.aug @@ -0,0 +1,119 @@ +(* Phpvars module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: PHP syntax + +*) + +module Phpvars = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let empty = Util.empty_c_style + +let open_php = del /<\?(php)?[ \t]*\n/i "<?php\n" +let close_php = del /([ \t]*(php)?\?>\n[ \t\n]*)?/i "php?>\n" +let sep_eq = del /[ \t\n]*=[ \t\n]*/ " = " +let sep_opt_spc = Sep.opt_space +let sep_spc = Sep.space +let sep_dollar = del /\$/ "$" +let sep_scl = del /[ \t]*;/ ";" + +let chr_blank = /[ \t]/ +let chr_nblank = /[^ \t\n]/ +let chr_any = /./ +let chr_star = /\*/ +let chr_nstar = /[^* \t\n]/ +let chr_slash = /\// +let chr_nslash = /[^\/ \t\n]/ +let chr_variable = /\$[A-Za-z0-9'"_:-]+/ + +let sto_to_scl = store (/([^ \t\n].*[^ \t\n;]|[^ \t\n;])/ - /.*;[ \t]*(\/\/|#).*/) (* " *) +let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + +(************************************************************************ + * COMMENTS + *************************************************************************) + +(* Both c-style and shell-style comments are valid + Default to c-style *) +let comment_one_line = Util.comment_generic /[ \t]*(\/\/|#)[ \t]*/ "// " + +let comment_eol = Util.comment_generic /[ \t]*(\/\/|#)[ \t]*/ " // " + +let comment = Util.comment_multiline | comment_one_line + +let eol_or_comment = eol | comment_eol + + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let simple_line (kw:regexp) (lns:lens) = [ key kw + . lns + . sep_scl + . eol_or_comment ] + +let global = simple_line "global" (sep_opt_spc . sep_dollar . sto_to_scl) + +let assignment = + let arraykey = [ label "@arraykey" . store /\[[][A-Za-z0-9'"_:-]+\]/ ] in (* " *) + simple_line chr_variable (arraykey? . (sep_eq . sto_to_scl)) + +let variable = Util.indent . assignment + +let classvariable = + Util.indent . del /(public|var)/ "public" . Util.del_ws_spc . assignment + +let include = simple_line "@include" (sep_opt_spc . sto_to_scl) + +let generic_function (kw:regexp) (lns:lens) = + let lbracket = del /[ \t]*\([ \t]*/ "(" in + let rbracket = del /[ \t]*\)/ ")" in + simple_line kw (lbracket . lns . rbracket) + +let define = + let variable_re = /[A-Za-z0-9'_:-]+/ in + let quote = del /["']/ "'" in + let sep_comma = del /["'][ \t]*,[ \t]*/ "', " in + let sto_to_rbracket = store (/[^ \t\n][^\n]*[^ \t\n\)]|[^ \t\n\)]/ + - /.*;[ \t]*(\/\/|#).*/) in + generic_function "define" (quote . store variable_re . sep_comma + . [ label "value" . sto_to_rbracket ]) + +let simple_function (kw:regexp) = + let sto_to_rbracket = store (/[^ \t\n][^\n]*[^ \t\n\)]|[^ \t\n\)]/ + - /.*;[ \t]*(\/\/|#).*/) in + generic_function kw sto_to_rbracket + +let entry = Util.indent + . ( global + | include + | define + | simple_function "include" + | simple_function "include_once" + | simple_function "echo" ) + + +let class = + let classname = key /[A-Za-z0-9'"_:-]+/ in (* " *) + del /class[ \t]+/ "class " . + [ classname . Util.del_ws_spc . del "{" "{" . + (empty|comment|entry|classvariable)* + ] . del "}" "}" + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = open_php . (empty|comment|entry|class|variable)* . close_php + +let filter = incl "/etc/squirrelmail/config.php" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/postfix_access.aug b/Sharp.Augeas.Test/lens/postfix_access.aug new file mode 100644 index 0000000..a5654c1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/postfix_access.aug @@ -0,0 +1,29 @@ +(* Parsing /etc/postfix/access *) + +module Postfix_Access = + autoload xfm + + let sep_tab = Util.del_ws_tab + let sep_spc = Util.del_ws_spc + + let eol = del /[ \t]*\n/ "\n" + let indent = del /[ \t]*/ "" + + let comment = Util.comment + let empty = Util.empty + + let char = /[^# \n\t]/ + let text = + let cont = /\n[ \t]+/ in + let any = /[^#\n]/ in + char | (char . (any | cont)* .char) + + let word = char+ + let record = [ seq "spec" . + [ label "pattern" . store word ] . sep_tab . + [ label "action" . store word ] . + [ label "parameters" . sep_spc . store text ]? . eol ] + + let lns = ( empty | comment | record )* + + let xfm = transform lns (incl "/etc/postfix/access" . incl "/usr/local/etc/postfix/access") diff --git a/Sharp.Augeas.Test/lens/postfix_main.aug b/Sharp.Augeas.Test/lens/postfix_main.aug new file mode 100644 index 0000000..2a9de2f --- /dev/null +++ b/Sharp.Augeas.Test/lens/postfix_main.aug @@ -0,0 +1,50 @@ +(* Postfix_Main module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: + + +*) + +module Postfix_Main = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let indent = del /[ \t]*(\n[ \t]+)?/ " " +let comment = Util.comment +let empty = Util.empty +let eq = del /[ \t]*=/ " =" +let word = /[A-Za-z0-9_.-]+/ + +(* The value of a parameter, after the '=' sign. Postfix allows that + * lines are continued by starting continuation lines with spaces. + * The definition needs to make sure we don't add indented comment lines + * into values *) +let value = + let chr = /[^# \t\n]/ in + let any = /.*/ in + let line = (chr . any* . chr | chr) in + let lines = line . (/[ \t]*\n[ \t]+/ . line)* in + store lines + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let entry = [ key word . eq . (indent . value)? . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter = incl "/etc/postfix/main.cf" + . incl "/usr/local/etc/postfix/main.cf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/postfix_master.aug b/Sharp.Augeas.Test/lens/postfix_master.aug new file mode 100644 index 0000000..93b7c52 --- /dev/null +++ b/Sharp.Augeas.Test/lens/postfix_master.aug @@ -0,0 +1,58 @@ +(* Postfix_Master module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: + +*) + +module Postfix_Master = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let ws = del /[ \t\n]+/ " " +let comment = Util.comment +let empty = Util.empty + +let word = /[A-Za-z0-9_.:-]+/ +let words = + let char_start = /[A-Za-z0-9$!(){}=_.,:@-]/ + in let char_end = char_start | /[]["\/]/ + in let char_middle = char_end | " " + in char_start . char_middle* . char_end + +let bool = /y|n|-/ +let integer = /([0-9]+|-)\??/ +let command = words . (/[ \t]*\n[ \t]+/ . words)* + +let field (l:string) (r:regexp) + = [ label l . store r ] + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let entry = [ key word . ws + . field "type" /inet|unix(-dgram)?|fifo|pass/ . ws + . field "private" bool . ws + . field "unprivileged" bool . ws + . field "chroot" bool . ws + . field "wakeup" integer . ws + . field "limit" integer . ws + . field "command" command + . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter = incl "/etc/postfix/master.cf" + . incl "/usr/local/etc/postfix/master.cf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/postfix_passwordmap.aug b/Sharp.Augeas.Test/lens/postfix_passwordmap.aug new file mode 100644 index 0000000..e35e25f --- /dev/null +++ b/Sharp.Augeas.Test/lens/postfix_passwordmap.aug @@ -0,0 +1,52 @@ +(* +Module: Postfix_Passwordmap + Parses /etc/postfix/*passwd + +Author: Anton Baranov <abaranov@linuxfoundation.org> + +About: Reference + This lens tries to keep as close as possible to `man 5 postconf` and + http://www.postfix.org/SASL_README.html#client_sasl_enable where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to /etc/postfix/*passwd. See <filter>. + +About: Examples + The <Test_Postfix_Passwordmap> file contains various examples and tests. +*) + +module Postfix_Passwordmap = + +autoload xfm + +(* View: space_or_eol *) +let space_or_eol = del /([ \t]*\n)?[ \t]+/ " " + +(* View: word *) +let word = store /[A-Za-z0-9@_\+\*.-]+/ + +(* View: colon *) +let colon = Sep.colon + +(* View: username *) +let username = [ label "username" . word ] + +(* View: password *) +let password = [ label "password" . (store Rx.space_in)? ] + +(* View: record *) +let record = [ label "pattern" . store /\[?[A-Za-z0-9@\*.-]+\]?(:?[A-Za-z0-9]*)*/ + . space_or_eol . username . colon . password + . Util.eol ] + +(* View: lns *) +let lns = (Util.empty | Util.comment | record)* + +(* Variable: filter *) +let filter = incl "/etc/postfix/*passwd" + . incl "/usr/local/etc/postfix/*passwd" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/postfix_sasl_smtpd.aug b/Sharp.Augeas.Test/lens/postfix_sasl_smtpd.aug new file mode 100644 index 0000000..eb2ae39 --- /dev/null +++ b/Sharp.Augeas.Test/lens/postfix_sasl_smtpd.aug @@ -0,0 +1,23 @@ +module Postfix_sasl_smtpd = + autoload xfm + + let eol = Util.eol + let colon = del /:[ \t]*/ ": " + let value_to_eol = store Rx.space_in + + let simple_entry (kw:string) = [ key kw . colon . value_to_eol . eol ] + + let entries = simple_entry "pwcheck_method" + | simple_entry "auxprop_plugin" + | simple_entry "saslauthd_path" + | simple_entry "mech_list" + | simple_entry "sql_engine" + | simple_entry "log_level" + | simple_entry "auto_transition" + + let lns = entries+ + + let filter = incl "/etc/postfix/sasl/smtpd.conf" + . incl "/usr/local/etc/postfix/sasl/smtpd.conf" + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/postfix_transport.aug b/Sharp.Augeas.Test/lens/postfix_transport.aug new file mode 100644 index 0000000..6c2c32d --- /dev/null +++ b/Sharp.Augeas.Test/lens/postfix_transport.aug @@ -0,0 +1,61 @@ +(* +Module: Postfix_Transport + Parses /etc/postfix/transport + +Author: Raphael Pinson <raphael.pinson@camptocamp.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 transport` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/postfix/transport. See <filter>. + +About: Examples + The <Test_Postfix_Transport> file contains various examples and tests. +*) + +module Postfix_Transport = + +autoload xfm + +(* View: space_or_eol *) +let space_or_eol = del /([ \t]*\n)?[ \t]+/ " " + +(* View: colon *) +let colon = Sep.colon + +(* View: nexthop *) +let nexthop = + let host_re = "[" . Rx.word . "]" | /[A-Za-z]([^\n]*[^ \t\n])?/ + in [ label "nexthop" . (store host_re)? ] + +(* View: transport *) +let transport = [ label "transport" . (store Rx.word)? ] + . colon . nexthop + +(* View: nexthop_smtp *) +let nexthop_smtp = + let host_re = "[" . Rx.word . "]" | Rx.word + in [ label "host" . store host_re ] + . colon + . [ label "port" . store Rx.integer ] + +(* View: record *) +let record = [ label "pattern" . store /[A-Za-z0-9@\*._-]+/ + . space_or_eol . (transport | nexthop_smtp) + . Util.eol ] + +(* View: lns *) +let lns = (Util.empty | Util.comment | record)* + +(* Variable: filter *) +let filter = incl "/etc/postfix/transport" + . incl "/usr/local/etc/postfix/transport" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/postfix_virtual.aug b/Sharp.Augeas.Test/lens/postfix_virtual.aug new file mode 100644 index 0000000..ef5576f --- /dev/null +++ b/Sharp.Augeas.Test/lens/postfix_virtual.aug @@ -0,0 +1,57 @@ +(* +Module: Postfix_Virtual + Parses /etc/postfix/virtual + +Author: Raphael Pinson <raphael.pinson@camptocamp.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 virtual` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/postfix/virtual. See <filter>. + +About: Examples + The <Test_Postfix_Virtual> file contains various examples and tests. +*) + +module Postfix_Virtual = + +autoload xfm + +(* Variable: space_or_eol_re *) +let space_or_eol_re = /([ \t]*\n)?[ \t]+/ + +(* View: space_or_eol *) +let space_or_eol (sep:regexp) (default:string) = + del (space_or_eol_re? . sep . space_or_eol_re?) default + +(* View: word *) +let word = store /[A-Za-z0-9@\*.+=_-]+/ + +(* View: comma *) +let comma = space_or_eol "," ", " + +(* View: destination *) +let destination = [ label "destination" . word ] + +(* View: record *) +let record = + let destinations = Build.opt_list destination comma + in [ label "pattern" . word + . space_or_eol Rx.space " " . destinations + . Util.eol ] + +(* View: lns *) +let lns = (Util.empty | Util.comment | record)* + +(* Variable: filter *) +let filter = incl "/etc/postfix/virtual" + . incl "/usr/local/etc/postfix/virtual" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/postgresql.aug b/Sharp.Augeas.Test/lens/postgresql.aug new file mode 100644 index 0000000..1f3a5b4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/postgresql.aug @@ -0,0 +1,78 @@ +(* +Module: Postgresql + Parses postgresql.conf + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + http://www.postgresql.org/docs/current/static/config-setting.html + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to postgresql.conf. See <filter>. + +About: Examples + The <Test_Postgresql> file contains various examples and tests. +*) + + +module Postgresql = + autoload xfm + +(* View: sep + Key and values are separated + by either spaces or an equal sign *) +let sep = del /([ \t]+)|([ \t]*=[ \t]*)/ " = " + +(* Variable: word_opt_quot_re + Strings that don't require quotes *) +let word_opt_quot_re = /[A-Za-z][A-Za-z0-9_-]*/ + +(* View: word_opt_quot + Storing a <word_opt_quot_re>, with or without quotes *) +let word_opt_quot = Quote.do_squote_opt (store word_opt_quot_re) + +(* Variable: number_re + A relative decimal number, optionally with unit *) +let number_re = Rx.reldecimal . /[kMG]?B|[m]?s|min|h|d/? + +(* View: number + Storing <number_re>, with or without quotes *) +let number = Quote.do_squote_opt (store number_re) + +(* View: word_quot + Anything other than <word_opt_quot> or <number> + Quotes are mandatory *) +let word_quot = + let esc_squot = /\\\\'/ + in let no_quot = /[^#'\n]/ + in let forbidden = word_opt_quot_re | number_re + in let value = (no_quot|esc_squot)* - forbidden + in Quote.do_squote (store value) + +(* View: entry_gen + Builder to construct entries *) +let entry_gen (lns:lens) = + Util.indent . Build.key_value_line_comment Rx.word sep lns Util.comment_eol + +(* View: entry *) +let entry = entry_gen number + | entry_gen word_opt_quot + | entry_gen word_quot (* anything else *) + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry)* + +(* Variable: filter *) +let filter = (incl "/var/lib/pgsql/data/postgresql.conf" . + incl "/var/lib/pgsql/*/data/postgresql.conf" . + incl "/var/lib/postgresql/*/data/postgresql.conf" . + incl "/etc/postgresql/*/*/postgresql.conf" ) + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/properties.aug b/Sharp.Augeas.Test/lens/properties.aug new file mode 100644 index 0000000..cf7ef6e --- /dev/null +++ b/Sharp.Augeas.Test/lens/properties.aug @@ -0,0 +1,50 @@ +(* Augeas module for editing Java properties files + Author: Craig Dunn <craig@craigdunn.org> + + Limitations: + - doesn't support \ alone on a line + - values are not unescaped + - multi-line properties are broken down by line, and can't be replaced with a single line + + See format info: http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader) +*) + + +module Properties = + (* Define some basic primitives *) + let empty = Util.empty_generic_dos /[ \t]*[#!]?[ \t]*/ + let eol = Util.doseol + let hard_eol = del /\r?\n/ "\n" + let sepch = del /([ \t]*(=|:)|[ \t])/ "=" + let sepspc = del /[ \t]/ " " + let sepch_ns = del /[ \t]*(=|:)/ "=" + let sepch_opt = del /[ \t]*(=|:)?[ \t]*/ "=" + let value_to_eol_ws = store /(:|=)[^\r\n]*[^ \t\r\n\\]/ + let value_to_bs_ws = store /(:|=)[^\n]*[^\\\n]/ + let value_to_eol = store /([^ \t\n:=][^\n]*[^ \t\r\n\\]|[^ \t\r\n\\:=])/ + let value_to_bs = store /([^ \t\n:=][^\n]*[^\\\n]|[^ \t\n\\:=])/ + let indent = Util.indent + let backslash = del /[\\][ \t]*\n/ "\\\n" + let opt_backslash = del /([\\][ \t]*\n)?/ "" + let entry = /([^ \t\r\n:=!#\\]|[\\]:|[\\]=|[\\][\t ]|[\\][^\/\r\n])+/ + + let multi_line_entry = + [ indent . value_to_bs? . backslash ] . + [ indent . value_to_bs . backslash ] * . + [ indent . value_to_eol . eol ] . value " < multi > " + + let multi_line_entry_ws = + opt_backslash . + [ indent . value_to_bs_ws . backslash ] + . + [ indent . value_to_eol . eol ] . value " < multi_ws > " + + (* define comments and properties*) + let bang_comment = [ label "!comment" . del /[ \t]*![ \t]*/ "! " . store /([^ \t\n].*[^ \t\r\n]|[^ \t\r\n])/ . eol ] + let comment = ( Util.comment | bang_comment ) + let property = [ indent . key entry . sepch . ( multi_line_entry | indent . value_to_eol . eol ) ] + let property_ws = [ indent . key entry . sepch_ns . ( multi_line_entry_ws | indent . value_to_eol_ws . eol ) ] + let empty_property = [ indent . key entry . sepch_opt . hard_eol ] + let empty_key = [ sepch_ns . ( multi_line_entry | indent . value_to_eol . eol ) ] + + (* setup our lens and filter*) + let lns = ( empty | comment | property_ws | property | empty_property | empty_key ) * diff --git a/Sharp.Augeas.Test/lens/protocols.aug b/Sharp.Augeas.Test/lens/protocols.aug new file mode 100644 index 0000000..245d466 --- /dev/null +++ b/Sharp.Augeas.Test/lens/protocols.aug @@ -0,0 +1,47 @@ +(* +Module: Protocols + Parses /etc/protocols + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 protocols` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/protocols. See <filter>. + +About: Examples + The <Test_Protocols> file contains various examples and tests. +*) + + +module Protocols = + +autoload xfm + +let protoname = /[^# \t\n]+/ + +(* View: entry *) +let entry = + let protocol = [ label "protocol" . store protoname ] + in let number = [ label "number" . store Rx.integer ] + in let alias = [ label "alias" . store protoname ] + in [ seq "protocol" . protocol + . Sep.space . number + . (Sep.space . Build.opt_list alias Sep.space)? + . Util.comment_or_eol ] + +(* View: lns + The protocols lens *) +let lns = (Util.empty | Util.comment | entry)* + +(* Variable: filter *) +let filter = incl "/etc/protocols" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/puppet.aug b/Sharp.Augeas.Test/lens/puppet.aug new file mode 100644 index 0000000..b1173a0 --- /dev/null +++ b/Sharp.Augeas.Test/lens/puppet.aug @@ -0,0 +1,45 @@ +(* Puppet module for Augeas + Author: Raphael Pinson <raphink@gmail.com> + + puppet.conf is a standard INI File. +*) + + +module Puppet = + autoload xfm + +(************************************************************************ + * INI File settings + * + * puppet.conf only supports "# as commentary and "=" as separator + *************************************************************************) +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" + + +(************************************************************************ + * ENTRY + * puppet.conf uses standard INI File entries + *************************************************************************) +let entry = IniFile.indented_entry IniFile.entry_re sep comment + + +(************************************************************************ + * RECORD + * puppet.conf uses standard INI File records + *************************************************************************) +let title = IniFile.indented_title IniFile.record_re +let record = IniFile.record title entry + + +(************************************************************************ + * LENS & FILTER + * puppet.conf uses standard INI File records + *************************************************************************) +let lns = IniFile.lns record comment + +let filter = (incl "/etc/puppet/puppet.conf" + .incl "/usr/local/etc/puppet/puppet.conf" + .incl "/etc/puppetlabs/puppet/puppet.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/puppet_auth.aug b/Sharp.Augeas.Test/lens/puppet_auth.aug new file mode 100644 index 0000000..a169a14 --- /dev/null +++ b/Sharp.Augeas.Test/lens/puppet_auth.aug @@ -0,0 +1,71 @@ +(* +Module: Puppet_Auth + Parses /etc/puppet/auth.conf + +Author: Raphael Pinson <raphael.pinson@camptocamp.com> + +About: Reference + This lens tries to keep as close as possible to `http://docs.puppetlabs.com/guides/rest_auth_conf.html` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/puppet/auth.conf. See <filter>. + +About: Examples + The <Test_Puppet_Auth> file contains various examples and tests. +*) + +module Puppet_Auth = + +autoload xfm + +(* View: list + A list of values *) +let list (kw:string) (val:regexp) = + let item = [ seq kw . store val ] + in let comma = del /[ \t]*,[ \t]*/ ", " + in [ Util.indent . key kw . Sep.space + . Build.opt_list item comma . Util.comment_or_eol ] + +(* View: auth + An authentication stanza *) +let auth = + [ Util.indent . Build.xchg /auth(enticated)?/ "auth" "auth" + . Sep.space . store /yes|no|on|off|any/ . Util.comment_or_eol ] + +(* View: reset_counters *) +let reset_counters = + counter "environment" . counter "method" + . counter "allow" . counter "allow_ip" + +(* View: setting *) +let setting = list "environment" Rx.word + | list "method" /find|search|save|destroy/ + | list "allow" /[^# \t\n,][^#\n,]*[^# \t\n,]|[^# \t\n,]/ + | list "allow_ip" /[A-Za-z0-9.:\/]+/ + | auth + +(* View: record *) +let record = + let operator = [ label "operator" . store "~" ] + in [ Util.indent . key "path" + . (Sep.space . operator)? + . Sep.space . store /[^~# \t\n][^#\n]*[^# \t\n]|[^~# \t\n]/ . Util.eol + . reset_counters + . (Util.empty | Util.comment | setting)* + . setting ] + +(* View: lns *) +let lns = (Util.empty | Util.comment | record)* + +(* Variable: filter *) +let filter = (incl "/etc/puppet/auth.conf" + .incl "/usr/local/etc/puppet/auth.conf" + .incl "/etc/puppetlabs/puppet/auth.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/puppetfile.aug b/Sharp.Augeas.Test/lens/puppetfile.aug new file mode 100644 index 0000000..fbd2e81 --- /dev/null +++ b/Sharp.Augeas.Test/lens/puppetfile.aug @@ -0,0 +1,69 @@ +(* +Module: Puppetfile + Parses libarian-puppet's Puppetfile format + +Author: Raphael Pinson <raphael.pinson@camptocamp.com> + +About: Reference + See https://github.com/rodjek/librarian-puppet + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to Puppetfiles. + +About: Examples + The <Test_Puppetfile> file contains various examples and tests. +*) + +module Puppetfile = + +(* View: comma + a comma, optionally preceded or followed by spaces or newlines *) +let comma = del /[ \t\n]*,[ \t\n]*/ ", " +let comma_nospace = del /[ \t\n]*,/ "," + +let comment_or_eol = Util.eol | Util.comment_eol +let quote_to_comment_or_eol = Quote.do_quote (store /[^#\n]*/) . comment_or_eol + +(* View: moduledir + The moduledir setting specifies where modules from the Puppetfile will be installed *) +let moduledir = [ Util.indent . key "moduledir" . Sep.space + . quote_to_comment_or_eol ] + +(* View: forge + a forge entry *) +let forge = [ Util.indent . key "forge" . Sep.space + . quote_to_comment_or_eol ] + +(* View: metadata + a metadata entry *) +let metadata = [ Util.indent . key "metadata" . comment_or_eol ] + +(* View: mod + a module entry, with optional version and options *) +let mod = + let mod_name = Quote.do_quote (store ((Rx.word . /[\/-]/)? . Rx.word)) + in let version = [ label "@version" . Quote.do_quote (store /[^#:\n]+/) . Util.comment_eol? ] + in let sto_opt_val = store /[^#"', \t\n][^#"',\n]*[^#"', \t\n]|[^#"', \t\n]/ + in let opt = [ + Util.del_str ":" . key Rx.word + . (del /[ \t]*=>[ \t]*/ " => " . Quote.do_quote_opt sto_opt_val)? + ] + in let opt_eol = del /([ \t\n]*\n)?/ "" + in let opt_space_or_eol = del /[ \t\n]*/ " " + in let comma_opt_eol_comment = comma_nospace . (opt_eol . Util.comment_eol)* + . opt_space_or_eol + in let opts = Build.opt_list opt comma_opt_eol_comment + in [ Util.indent . Util.del_str "mod" . seq "mod" . Sep.space . mod_name + . (comma_opt_eol_comment . version)? + . (comma_opt_eol_comment . opts . Util.comment_eol?)? + . Util.eol ] + +(* View: lns + the Puppetfile lens *) +let lns = (Util.empty | Util.comment | forge | metadata | mod | moduledir )* diff --git a/Sharp.Augeas.Test/lens/puppetfileserver.aug b/Sharp.Augeas.Test/lens/puppetfileserver.aug new file mode 100644 index 0000000..225a1de --- /dev/null +++ b/Sharp.Augeas.Test/lens/puppetfileserver.aug @@ -0,0 +1,112 @@ +(* -*- coding: utf-8 -*- +Module: PuppetFileserver + Parses /etc/puppet/fileserver.conf used by puppetmasterd daemon. + +Author: Frédéric Lespez <frederic.lespez@free.fr> + +About: Reference + This lens tries to keep as close as possible to puppet documentation + for this file: + http://docs.puppetlabs.com/guides/file_serving.html + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Create a new mount point + > ins test_mount after /files/etc/puppet/fileserver.conf/*[last()] + > defvar test_mount /files/etc/puppet/fileserver.conf/test_mount + > set $test_mount/path /etc/puppet/files + > set $test_mount/allow *.example.com + > ins allow after $test_mount/*[last()] + > set $test_mount/allow[last()] server.domain.com + > set $test_mount/deny dangerous.server.com + * List the definition of a mount point + > print /files/etc/puppet/fileserver.conf/files + * Remove a mount point + > rm /files/etc/puppet/fileserver.conf/test_mount + +About: Configuration files + This lens applies to /etc/puppet/fileserver.conf. See <filter>. +*) + + +module PuppetFileserver = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: INI File settings *) + +(* Variable: eol *) +let eol = IniFile.eol + +(* Variable: sep + Only treat one space as the sep, extras are stripped by IniFile *) +let sep = Util.del_str " " + +(* +Variable: comment + Only supports "#" as commentary +*) +let comment = IniFile.comment "#" "#" + +(* +Variable: entry_re + Regexp for possible <entry> keyword (path, allow, deny) +*) +let entry_re = /path|allow|deny/ + + +(************************************************************************ + * Group: ENTRY + *************************************************************************) + +(* +View: entry + - It might be indented with an arbitrary amount of whitespace + - It does not have any separator between keywords and their values + - It can only have keywords with the following values (path, allow, deny) +*) +let entry = IniFile.indented_entry entry_re sep comment + + +(************************************************************************ + * Group: RECORD + *************************************************************************) + +(* Group: Title definition *) + +(* +View: title + Uses standard INI File title +*) +let title = IniFile.indented_title IniFile.record_re + +(* +View: title + Uses standard INI File record +*) +let record = IniFile.record title entry + + +(************************************************************************ + * Group: LENS + *************************************************************************) + +(* +View: lns + Uses standard INI File lens +*) +let lns = IniFile.lns record comment + +(* Variable: filter *) +let filter = (incl "/etc/puppet/fileserver.conf" + .incl "/usr/local/etc/puppet/fileserver.conf" + .incl "/etc/puppetlabs/puppet/fileserver.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/pylonspaste.aug b/Sharp.Augeas.Test/lens/pylonspaste.aug new file mode 100644 index 0000000..0b56ddd --- /dev/null +++ b/Sharp.Augeas.Test/lens/pylonspaste.aug @@ -0,0 +1,78 @@ +(* +Module: PylonsPaste + Parses Pylons Paste ini configuration files. + +Author: Andrew Colin Kissa <andrew@topdog.za.net> + Baruwa Enterprise Edition http://www.baruwa.com + +About: License + This file is licensed under the LGPL v2+. + +About: Configuration files + This lens applies to /etc/baruwa See <filter>. +*) + +module Pylonspaste = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + +let sep = IniFile.sep "=" "=" + +let eol = Util.eol + +let optspace = del /\n/ "\n" + +let entry_re = ( /[A-Za-z][:#A-Za-z0-9._-]+/) + +let plugin_re = /[A-Za-z][;:#A-Za-z0-9._-]+/ + +let plugins_kw = /plugins/ + +let debug_kw = /debug/ + +let normal_opts = entry_re - (debug_kw|plugins_kw) + +let del_opt_ws = del /[\t ]*/ "" + +let new_ln_sep = optspace . del_opt_ws . store plugin_re + +let plugins_multiline = sep . counter "items" . [ seq "items" . new_ln_sep]* + +let sto_multiline = optspace . Sep.opt_space . store (Rx.space_in . (/[ \t]*\n/ . Rx.space . Rx.space_in)*) + +(************************************************************************ + * Group: ENTRY + *************************************************************************) + +let set_option = Util.del_str "set " +let no_inline_comment_entry (kw:regexp) (sep:lens) (comment:lens) = + [ set_option . key debug_kw . sep . IniFile.sto_to_eol . eol ] + | [ key plugins_kw . plugins_multiline . eol] + | [ key kw . sep . IniFile.sto_to_eol? . eol ] + | comment + +let entry = no_inline_comment_entry normal_opts sep comment + +(************************************************************************ + * RECORD + *************************************************************************) + +let title = IniFile.title IniFile.record_re + +let record = IniFile.record title entry + +(************************************************************************ + * Group: LENS & FILTER + *************************************************************************) + +let lns = IniFile.lns record comment + +let filter = incl "/etc/baruwa/*.ini" + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/pythonpaste.aug b/Sharp.Augeas.Test/lens/pythonpaste.aug new file mode 100644 index 0000000..e9a1f78 --- /dev/null +++ b/Sharp.Augeas.Test/lens/pythonpaste.aug @@ -0,0 +1,56 @@ +(* Python paste config file lens for Augeas + Author: Dan Prince <dprince@redhat.com> +*) +module PythonPaste = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) + +let comment = IniFile.comment "#" "#" + +let sep = IniFile.sep "=" "=" + +let eol = Util.eol + +(************************************************************************ + * ENTRY + *************************************************************************) + +let url_entry = /\/[\/A-Za-z0-9.-_]* ?[:|=] [A-Za-z0-9.-_]+/ + +let set_kw = [ Util.del_str "set" . Util.del_ws_spc . label "@set" ] + +let no_inline_comment_entry (kw:regexp) (sep:lens) (comment:lens) + = [ set_kw? . key kw . sep . IniFile.sto_to_eol? . eol ] + | comment + | [ seq "urls" . store url_entry . eol ] + +let entry_re = ( /[A-Za-z][:#A-Za-z0-9._-]+/ ) + +let entry = no_inline_comment_entry entry_re sep comment + +(************************************************************************ + * RECORD + *************************************************************************) + +let title = IniFile.title IniFile.record_re + +let record = IniFile.record title entry + +(************************************************************************ + * LENS & FILTER + *************************************************************************) +let lns = IniFile.lns record comment + +let filter = ((incl "/etc/glance/*.ini") + . (incl "/etc/keystone/keystone.conf") + . (incl "/etc/nova/api-paste.ini") + . (incl "/etc/swift/swift.conf") + . (incl "/etc/swift/proxy-server.conf") + . (incl "/etc/swift/account-server/*.conf") + . (incl "/etc/swift/container-server/*.conf") + . (incl "/etc/swift/object-server/*.conf")) + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/qpid.aug b/Sharp.Augeas.Test/lens/qpid.aug new file mode 100644 index 0000000..93dea09 --- /dev/null +++ b/Sharp.Augeas.Test/lens/qpid.aug @@ -0,0 +1,32 @@ +(* +Module: Qpid + Parses Apache Qpid daemon/client configuration files + +Author: Andrew Replogle <areplogl@redhat.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Examples + The <Test_Qpid> file contains various examples and tests. +*) + +module Qpid = + +autoload xfm + +(* View: entry *) +let entry = Build.key_value_line Rx.word Sep.equal + (store Rx.space_in) + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry)* + +(* Variable: filter *) +let filter = incl "/etc/qpidd.conf" + . incl "/etc/qpid/qpidc.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/quote.aug b/Sharp.Augeas.Test/lens/quote.aug new file mode 100644 index 0000000..32e56ac --- /dev/null +++ b/Sharp.Augeas.Test/lens/quote.aug @@ -0,0 +1,264 @@ +(* +Module: Quote + Generic module providing useful primitives for quoting + +Author: Raphael Pinson <raphael.pinson@camptocamp.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + This is a generic module which doesn't apply to files directly. + You can use its definitions to build lenses that require quoted values. + It provides several levels of definitions, allowing to define more or less fine-grained quoted values: + + - the quote separators are separators that are useful to define quoted values; + - the quoting functions are useful wrappers to easily enclose a lens in various kinds of quotes (single, double, any, optional or not); + - the quoted values definitions are common quoted patterns. They use the quoting functions in order to provide useful shortcuts for commonly met needs. In particular, the <quote_spaces> (and similar) function force values that contain spaces to be quoted, but allow values without spaces to be unquoted. + +About: Examples + The <Test_Quote> file contains various examples and tests. +*) + +module Quote = + +(* Group: QUOTE SEPARATORS *) + +(* Variable: dquote + A double quote *) +let dquote = Util.del_str "\"" + +(* Variable: dquote_opt + An optional double quote, default to double *) +let dquote_opt = del /"?/ "\"" + +(* Variable: dquote_opt_nil + An optional double quote, default to nothing *) +let dquote_opt_nil = del /"?/ "" + +(* Variable: squote + A single quote *) +let squote = Util.del_str "'" + +(* Variable: squote_opt + An optional single quote, default to single *) +let squote_opt = del /'?/ "'" + +(* Variable: squote_opt_nil + An optional single quote, default to nothing *) +let squote_opt_nil = del /'?/ "" + +(* Variable: quote + A quote, either double or single, default to double *) +let quote = del /["']/ "\"" + +(* Variable: quote_opt + An optional quote, either double or single, default to double *) +let quote_opt = del /["']?/ "\"" + +(* Variable: quote_opt_nil + An optional quote, either double or single, default to nothing *) +let quote_opt_nil = del /["']?/ "" + + +(* Group: QUOTING FUNCTIONS *) + +(* +View: do_dquote + Enclose a lens in <dquote>s + + Parameters: + body:lens - the lens to be enclosed +*) +let do_dquote (body:lens) = + square dquote body dquote + +(* +View: do_dquote_opt + Enclose a lens in optional <dquote>s, + use <dquote>s by default. + + Parameters: + body:lens - the lens to be enclosed +*) +let do_dquote_opt (body:lens) = + square dquote_opt body dquote_opt + +(* +View: do_dquote_opt_nil + Enclose a lens in optional <dquote>s, + default to no quotes. + + Parameters: + body:lens - the lens to be enclosed +*) +let do_dquote_opt_nil (body:lens) = + square dquote_opt_nil body dquote_opt_nil + +(* +View: do_squote + Enclose a lens in <squote>s + + Parameters: + body:lens - the lens to be enclosed +*) +let do_squote (body:lens) = + square squote body squote + +(* +View: do_squote_opt + Enclose a lens in optional <squote>s, + use <squote>s by default. + + Parameters: + body:lens - the lens to be enclosed +*) +let do_squote_opt (body:lens) = + square squote_opt body squote_opt + +(* +View: do_squote_opt_nil + Enclose a lens in optional <squote>s, + default to no quotes. + + Parameters: + body:lens - the lens to be enclosed +*) +let do_squote_opt_nil (body:lens) = + square squote_opt_nil body squote_opt_nil + +(* +View: do_quote + Enclose a lens in <quote>s. + + Parameters: + body:lens - the lens to be enclosed +*) +let do_quote (body:lens) = + square quote body quote + +(* +View: do_quote + Enclose a lens in options <quote>s. + + Parameters: + body:lens - the lens to be enclosed +*) +let do_quote_opt (body:lens) = + square quote_opt body quote_opt + +(* +View: do_quote + Enclose a lens in options <quote>s, + default to no quotes. + + Parameters: + body:lens - the lens to be enclosed +*) +let do_quote_opt_nil (body:lens) = + square quote_opt_nil body quote_opt_nil + + +(* Group: QUOTED VALUES *) + +(* View: double + A double-quoted value *) +let double = + let body = store /[^\n]*/ + in do_dquote body + +(* Variable: double_opt_re + The regexp to store when value + is optionally double-quoted *) +let double_opt_re = /[^\n\t "]([^\n"]*[^\n\t "])?/ + +(* View: double_opt + An optionally double-quoted value + Double quotes are not allowed in value + Value cannot begin or end with spaces *) +let double_opt = + let body = store double_opt_re + in do_dquote_opt body + +(* View: single + A single-quoted value *) +let single = + let body = store /[^\n]*/ + in do_squote body + +(* Variable: single_opt_re + The regexp to store when value + is optionally single-quoted *) +let single_opt_re = /[^\n\t ']([^\n']*[^\n\t '])?/ + +(* View: single_opt + An optionally single-quoted value + Single quotes are not allowed in value + Value cannot begin or end with spaces *) +let single_opt = + let body = store single_opt_re + in do_squote_opt body + +(* View: any + A quoted value *) +let any = + let body = store /[^\n]*/ + in do_quote body + +(* Variable: any_opt_re + The regexp to store when value + is optionally single- or double-quoted *) +let any_opt_re = /[^\n\t "']([^\n"']*[^\n\t "'])?/ + +(* View: any_opt + An optionally quoted value + Double or single quotes are not allowed in value + Value cannot begin or end with spaces *) +let any_opt = + let body = store any_opt_re + in do_quote_opt body + +(* +View: quote_spaces + Make quotes mandatory if value contains spaces, + and optional if value doesn't contain spaces. + +Parameters: + lns:lens - the lens to be enclosed +*) +let quote_spaces (lns:lens) = + (* bare has no spaces, and is optionally quoted *) + let bare = Quote.do_quote_opt (store /[^"' \t\n]+/) + (* quoted has at least one space, and must be quoted *) + in let quoted = Quote.do_quote (store /[^"'\n]*[ \t]+[^"'\n]*/) + in [ lns . bare ] | [ lns . quoted ] + +(* +View: dquote_spaces + Make double quotes mandatory if value contains spaces, + and optional if value doesn't contain spaces. + +Parameters: + lns:lens - the lens to be enclosed +*) +let dquote_spaces (lns:lens) = + (* bare has no spaces, and is optionally quoted *) + let bare = Quote.do_dquote_opt (store /[^" \t\n]+/) + (* quoted has at least one space, and must be quoted *) + in let quoted = Quote.do_dquote (store /[^"\n]*[ \t]+[^"\n]*/) + in [ lns . bare ] | [ lns . quoted ] + +(* +View: squote_spaces + Make single quotes mandatory if value contains spaces, + and optional if value doesn't contain spaces. + +Parameters: + lns:lens - the lens to be enclosed +*) +let squote_spaces (lns:lens) = + (* bare has no spaces, and is optionally quoted *) + let bare = Quote.do_squote_opt (store /[^' \t\n]+/) + (* quoted has at least one space, and must be quoted *) + in let quoted = Quote.do_squote (store /[^'\n]*[ \t]+[^'\n]*/) + in [ lns . bare ] | [ lns . quoted ] diff --git a/Sharp.Augeas.Test/lens/rabbitmq.aug b/Sharp.Augeas.Test/lens/rabbitmq.aug new file mode 100644 index 0000000..7543de6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/rabbitmq.aug @@ -0,0 +1,125 @@ +(* +Module: Rabbitmq + Parses Rabbitmq configuration files + +Author: Raphael Pinson <raphael.pinson@camptocamp.com> + +About: Reference + This lens tries to keep as close as possible to `http://www.rabbitmq.com/configure.html` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to Rabbitmq configuration files. See <filter>. + +About: Examples + The <Test_Rabbitmq> file contains various examples and tests. +*) +module Rabbitmq = + +autoload xfm + +(* View: listeners + A tcp/ssl listener *) +let listeners = + let value = Erlang.make_value Erlang.integer + | Erlang.tuple Erlang.quoted Erlang.integer + in Erlang.list /(tcp|ssl)_listeners/ value + + +(* View: ssl_options + (Incomplete) list of SSL options *) +let ssl_options = + let versions_list = Erlang.opt_list (Erlang.make_value Erlang.quoted) + in let option = Erlang.value /((ca)?cert|key)file/ Erlang.path + | Erlang.value "verify" Erlang.bare + | Erlang.value "verify_fun" Erlang.boolean + | Erlang.value /fail_if_no_peer_cert|reuse_sessions/ Erlang.boolean + | Erlang.value "depth" Erlang.integer + | Erlang.value "password" Erlang.quoted + | Erlang.value "versions" versions_list + in Erlang.list "ssl_options" option + +(* View: disk_free_limit *) +let disk_free_limit = + let value = Erlang.integer | Erlang.tuple Erlang.bare Erlang.decimal + in Erlang.value "disk_free_limit" value + +(* View: log_levels *) +let log_levels = + let category = Erlang.tuple Erlang.bare Erlang.bare + in Erlang.list "log_levels" category + +(* View: cluster_nodes + Can be a tuple `(nodes, node_type)` or simple `nodes` *) +let cluster_nodes = + let nodes = Erlang.opt_list (Erlang.make_value Erlang.quoted) + in let value = Erlang.tuple nodes Erlang.bare + | nodes + in Erlang.value "cluster_nodes" value + +(* View: cluster_partition_handling + Can be single value or + `{pause_if_all_down, [nodes], ignore | autoheal}` *) +let cluster_partition_handling = + let nodes = Erlang.opt_list (Erlang.make_value Erlang.quoted) + in let value = Erlang.tuple3 Erlang.bare nodes Erlang.bare + | Erlang.bare + in Erlang.value "cluster_partition_handling" value + +(* View: tcp_listen_options *) +let tcp_listen_options = + let value = Erlang.make_value Erlang.bare + | Erlang.tuple Erlang.bare Erlang.bare + in Erlang.list "tcp_listen_options" value + +(* View: parameters + Top-level parameters for the lens *) +let parameters = listeners + | ssl_options + | disk_free_limit + | log_levels + | Erlang.value /vm_memory_high_watermark(_paging_ratio)?/ Erlang.decimal + | Erlang.value "frame_max" Erlang.integer + | Erlang.value "heartbeat" Erlang.integer + | Erlang.value /default_(vhost|user|pass)/ Erlang.glob + | Erlang.value_list "default_user_tags" Erlang.bare + | Erlang.value_list "default_permissions" Erlang.glob + | cluster_nodes + | Erlang.value_list "server_properties" Erlang.bare + | Erlang.value "collect_statistics" Erlang.bare + | Erlang.value "collect_statistics_interval" Erlang.integer + | Erlang.value_list "auth_mechanisms" Erlang.quoted + | Erlang.value_list "auth_backends" Erlang.bare + | Erlang.value "delegate_count" Erlang.integer + | Erlang.value_list "trace_vhosts" Erlang.bare + | tcp_listen_options + | Erlang.value "hipe_compile" Erlang.boolean + | Erlang.value "msg_store_index_module" Erlang.bare + | Erlang.value "backing_queue_module" Erlang.bare + | Erlang.value "msg_store_file_size_limit" Erlang.integer + | Erlang.value /queue_index_(max_journal_entries|embed_msgs_below)/ Erlang.integer + | cluster_partition_handling + | Erlang.value /(ssl_)?handshake_timeout/ Erlang.integer + | Erlang.value "channel_max" Erlang.integer + | Erlang.value_list "loopback_users" Erlang.glob + | Erlang.value "reverse_dns_lookups" Erlang.boolean + | Erlang.value "cluster_keepalive_interval" Erlang.integer + | Erlang.value "mnesia_table_loading_timeout" Erlang.integer + +(* View: rabbit + The rabbit <Erlang.application> config *) +let rabbit = Erlang.application "rabbit" parameters + +(* View: lns + A top-level <Erlang.config> *) +let lns = Erlang.config rabbit + +(* Variable: filter *) +let filter = incl "/etc/rabbitmq/rabbitmq.config" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/radicale.aug b/Sharp.Augeas.Test/lens/radicale.aug new file mode 100644 index 0000000..7e50e69 --- /dev/null +++ b/Sharp.Augeas.Test/lens/radicale.aug @@ -0,0 +1,44 @@ +(* Radicale module for Augeas + Based on Puppet lens. + + Manage config file for http://radicale.org/ + /etc/radicale/config is a standard INI File. +*) + + +module Radicale = + autoload xfm + +(************************************************************************ + * INI File settings + * + * /etc/radicale/config only supports "#" as commentary and "=" as separator + *************************************************************************) +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" + + +(************************************************************************ + * ENTRY + * /etc/radicale/config uses standard INI File entries + *************************************************************************) +let entry = IniFile.indented_entry IniFile.entry_re sep comment + + +(************************************************************************ + * RECORD + * /etc/radicale/config uses standard INI File records + *************************************************************************) +let title = IniFile.indented_title IniFile.record_re +let record = IniFile.record title entry + + +(************************************************************************ + * LENS & FILTER + * /etc/radicale/config uses standard INI File records + *************************************************************************) +let lns = IniFile.lns record comment + +let filter = (incl "/etc/radicale/config") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/rancid.aug b/Sharp.Augeas.Test/lens/rancid.aug new file mode 100644 index 0000000..a582b32 --- /dev/null +++ b/Sharp.Augeas.Test/lens/rancid.aug @@ -0,0 +1,34 @@ +(* +Module: Rancid + Parses RANCiD router database + +Author: Matt Dainty <matt@bodgit-n-scarper.com> + +About: Reference + - man 5 router.db + +Each line represents a record consisting of a number of ';'-separated fields +the first of which is the IP/Hostname of the device, followed by the type, its +state and optionally a comment. + +*) + +module Rancid = + autoload xfm + + let sep = Util.del_str ";" + let field = /[^;#\n]+/ + let comment = [ label "comment" . store /[^;#\n]*/ ] + let eol = Util.del_str "\n" + let record = [ label "device" . store field . sep . [ label "type" . store field ] . sep . [ label "state" . store field ] . ( sep . comment )? . eol ] + + let lns = ( Util.empty | Util.comment_generic /#[ \t]*/ "# " | record )* + + let filter = incl "/var/rancid/*/router.db" + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/redis.aug b/Sharp.Augeas.Test/lens/redis.aug new file mode 100644 index 0000000..eb6c5ff --- /dev/null +++ b/Sharp.Augeas.Test/lens/redis.aug @@ -0,0 +1,172 @@ +(* +Module: Redis + Parses Redis's configuration files + +Author: Marc Fournier <marc.fournier@camptocamp.com> + +About: Reference + This lens is based on Redis's default redis.conf + +About: Usage Example +(start code) +augtool> set /augeas/load/Redis/incl "/etc/redis/redis.conf" +augtool> set /augeas/load/Redis/lens "Redis.lns" +augtool> load + +augtool> get /files/etc/redis/redis.conf/vm-enabled +/files/etc/redis/redis.conf/vm-enabled = no +augtool> print /files/etc/redis/redis.conf/rename-command[1]/ +/files/etc/redis/redis.conf/rename-command +/files/etc/redis/redis.conf/rename-command/from = "CONFIG" +/files/etc/redis/redis.conf/rename-command/to = "CONFIG2" + +augtool> set /files/etc/redis/redis.conf/activerehashing no +augtool> save +Saved 1 file(s) +augtool> set /files/etc/redis/redis.conf/save[1]/seconds 123 +augtool> set /files/etc/redis/redis.conf/save[1]/keys 456 +augtool> save +Saved 1 file(s) +(end code) + The <Test_Redis> file also contains various examples. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Redis = +autoload xfm + +let k = Rx.word +let v = /[^ \t\n'"]+/ +let comment = Util.comment +let empty = Util.empty +let indent = Util.indent +let eol = Util.eol +let del_ws_spc = Util.del_ws_spc +let dquote = Util.del_str "\"" + +(* View: standard_entry +A standard entry is a key-value pair, separated by blank space, with optional +blank spaces at line beginning & end. The value part can be optionnaly enclosed +in single or double quotes. Comments at end-of-line ar NOT allowed by +redis-server. +*) +let standard_entry = + let reserved_k = "save" | "rename-command" | "replicaof" | "slaveof" + | "bind" | "client-output-buffer-limit" + | "sentinel" + in let entry_noempty = [ indent . key (k - reserved_k) . del_ws_spc + . Quote.do_quote_opt_nil (store v) . eol ] + in let entry_empty = [ indent . key (k - reserved_k) . del_ws_spc + . dquote . store "" . dquote . eol ] + in entry_noempty | entry_empty + +let save = /save/ +let seconds = [ label "seconds" . Quote.do_quote_opt_nil (store Rx.integer) ] +let keys = [ label "keys" . Quote.do_quote_opt_nil (store Rx.integer) ] +(* View: save_entry +Entries identified by the "save" keyword can be found more than once. They have +2 mandatory parameters, both integers. The same rules as standard_entry apply +for quoting, comments and whitespaces. +*) +let save_entry = [ indent . key save . del_ws_spc . seconds . del_ws_spc . keys . eol ] + +let replicaof = /replicaof|slaveof/ +let ip = [ label "ip" . Quote.do_quote_opt_nil (store Rx.ip) ] +let port = [ label "port" . Quote.do_quote_opt_nil (store Rx.integer) ] +(* View: replicaof_entry +Entries identified by the "replicaof" keyword can be found more than once. They +have 2 mandatory parameters, the 1st one is an IP address, the 2nd one is a +port number. The same rules as standard_entry apply for quoting, comments and +whitespaces. +*) +let replicaof_entry = [ indent . key replicaof . del_ws_spc . ip . del_ws_spc . port . eol ] + +let sentinel_global_entry = + let keys = "deny-scripts-reconfig" | "current-epoch" | "myid" + in store keys . + del_ws_spc . [ label "value" . store ( Rx.word | Rx.integer ) ] + +let sentinel_cluster_setup = + let keys = "config-epoch" | "leader-epoch" + in store keys . + del_ws_spc . [ label "cluster" . store Rx.word ] . + del_ws_spc . [ label "epoch" . store Rx.integer ] + +let sentinel_cluster_instance_setup = + let keys = "monitor" | "known-replica" + in store keys . + del_ws_spc . [ label "cluster" . store Rx.word ] . + del_ws_spc. [ label "ip" . store Rx.ip ] . + del_ws_spc . [ label "port" . store Rx.integer ] . + (del_ws_spc . [ label "quorum" . store Rx.integer ])? + +let sentinel_clustering = + let keys = "known-sentinel" + in store keys . + del_ws_spc . [ label "cluster" . store Rx.word ] . + del_ws_spc . [ label "ip" . store Rx.ip ] . + del_ws_spc . [ label "port" . store Rx.integer ] . + del_ws_spc . [ label "id" . store Rx.word ] + +(* View: sentinel_entry +*) +let sentinel_entry = + indent . [ key "sentinel" . del_ws_spc . + (sentinel_global_entry | sentinel_cluster_setup | sentinel_cluster_instance_setup | sentinel_clustering) + ] . eol + +(* View: bind_entry +The "bind" entry can be passed one or several ip addresses. A bind +statement "bind ip1 ip2 .. ipn" results in a tree +{ "bind" { "ip" = ip1 } { "ip" = ip2 } ... { "ip" = ipn } } +*) +let bind_entry = + let ip = del_ws_spc . Quote.do_quote_opt_nil (store Rx.ip) in + indent . [ key "bind" . [ label "ip" . ip ]+ ] . eol + +let renamecmd = /rename-command/ +let from = [ label "from" . Quote.do_quote_opt_nil (store Rx.word) ] +let to = [ label "to" . Quote.do_quote_opt_nil (store Rx.word) ] +(* View: save_entry +Entries identified by the "rename-command" keyword can be found more than once. +They have 2 mandatory parameters, both strings. The same rules as +standard_entry apply for quoting, comments and whitespaces. +*) +let renamecmd_entry = [ indent . key renamecmd . del_ws_spc . from . del_ws_spc . to . eol ] + +let cobl_cmd = /client-output-buffer-limit/ +let class = [ label "class" . Quote.do_quote_opt_nil (store Rx.word) ] +let hard_limit = [ label "hard_limit" . Quote.do_quote_opt_nil (store Rx.word) ] +let soft_limit = [ label "soft_limit" . Quote.do_quote_opt_nil (store Rx.word) ] +let soft_seconds = [ label "soft_seconds" . Quote.do_quote_opt_nil (store Rx.integer) ] +(* View: client_output_buffer_limit_entry +Entries identified by the "client-output-buffer-limit" keyword can be found +more than once. They have four mandatory parameters, of which the first is a +string, the last one is an integer and the others are either integers or words, +although redis is very liberal and takes "4242yadayadabytes" as a valid limit. +The same rules as standard_entry apply for quoting, comments and whitespaces. +*) +let client_output_buffer_limit_entry = + [ indent . key cobl_cmd . del_ws_spc . class . del_ws_spc . hard_limit . + del_ws_spc . soft_limit . del_ws_spc . soft_seconds . eol ] + +let entry = standard_entry + | save_entry + | renamecmd_entry + | replicaof_entry + | bind_entry + | sentinel_entry + | client_output_buffer_limit_entry + +(* View: lns +The Redis lens +*) +let lns = (comment | empty | entry )* + +let filter = + incl "/etc/redis.conf" + . incl "/etc/redis/redis.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/reprepro_uploaders.aug b/Sharp.Augeas.Test/lens/reprepro_uploaders.aug new file mode 100644 index 0000000..b8acef8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/reprepro_uploaders.aug @@ -0,0 +1,200 @@ +(* +Module: Reprepro_Uploaders + Parses reprepro's uploaders files + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 1 reprepro` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. +About: Lens Usage + See <lns>. + +About: Configuration files + This lens applies to reprepro's uploaders files. + +About: Examples + The <Test_Reprepro_Uploaders> file contains various examples and tests. +*) + +module Reprepro_Uploaders = + +(* View: logic_construct_condition + A logical construction for <condition> and <condition_list> *) +let logic_construct_condition (kw:string) (lns:lens) = + [ label kw . lns ] + . [ Sep.space . key kw . Sep.space . lns ]* + +(* View: logic_construct_field + A generic definition for <condition_field> *) +let logic_construct_field (kw:string) (sep:string) (lns:lens) = + [ label kw . lns ] + . [ Build.xchgs sep kw . lns ]* + +(* View: condition_re + A condition can be of several types: + + - source + - byhand + - sections + - sections contain + - binaries + - binaries contain + - architectures + - architectures contain + + While the lens technically also accepts "source contain" + and "byhand contain", these are not understood by reprepro. + + The "contain" types are built by adding a "contain" subnode. + See the <condition_field> definition. + + *) +let condition_re = + "source" + | "byhand" + | "sections" + | "binaries" + | "architectures" + | "distribution" + +(* View: condition_field + A single condition field is an 'or' node. + It may contain several values, listed in 'or' subnodes: + + > $reprepro/allow[1]/and/or = "architectures" + > $reprepro/allow[1]/and/or/or[1] = "i386" + > $reprepro/allow[1]/and/or/or[2] = "amd64" + > $reprepro/allow[1]/and/or/or[3] = "all" + + *) +let condition_field = + let sto_condition = Util.del_str "'" . store /[^'\n]+/ . Util.del_str "'" in + [ key "not" . Sep.space ]? . + store condition_re + . [ Sep.space . key "contain" ]? + . Sep.space + . logic_construct_field "or" "|" sto_condition + +(* View: condition + A condition is an 'and' node, + representing a union of <condition_fields>, + listed under 'or' subnodes: + + > $reprepro/allow[1]/and + > $reprepro/allow[1]/and/or = "architectures" + > $reprepro/allow[1]/and/or/or[1] = "i386" + > $reprepro/allow[1]/and/or/or[2] = "amd64" + > $reprepro/allow[1]/and/or/or[3] = "all" + + *) +let condition = + logic_construct_condition "or" condition_field + +(* View: condition_list + A list of <conditions>, inspired by Debctrl.dependency_list + An upload condition list is either the wildcard '*', stored verbatim, + or an intersection of conditions listed under 'and' subnodes: + + > $reprepro/allow[1]/and[1] + > $reprepro/allow[1]/and[1]/or = "architectures" + > $reprepro/allow[1]/and[1]/or/or[1] = "i386" + > $reprepro/allow[1]/and[1]/or/or[2] = "amd64" + > $reprepro/allow[1]/and[1]/or/or[3] = "all" + > $reprepro/allow[1]/and[2] + > $reprepro/allow[1]/and[2]/or = "sections" + > $reprepro/allow[1]/and[2]/or/contain + > $reprepro/allow[1]/and[2]/or/or = "main" + + *) +let condition_list = + store "*" + | logic_construct_condition "and" condition + +(* View: by_key + When a key is used to authenticate packages, + the value can either be a key ID or "any": + + > $reprepro/allow[1]/by/key = "ABCD1234" + > $reprepro/allow[2]/by/key = "any" + + *) +let by_key = + let any_key = [ store "any" . Sep.space + . key "key" ] in + let named_key = [ key "key" . Sep.space + . store (Rx.word - "any") ] in + value "key" . (any_key | named_key) + +(* View: by_group + Authenticate packages by a groupname. + + > $reprepro/allow[1]/by/group = "groupname" + + *) +let by_group = value "group" + . [ key "group" . Sep.space + . store Rx.word ] + +(* View: by + <by> statements define who is allowed to upload. + It can be simple keywords, like "anybody" or "unsigned", + or a key ID, in which case a "key" subnode is added: + + > $reprepro/allow[1]/by/key = "ABCD1234" + > $reprepro/allow[2]/by/key = "any" + > $reprepro/allow[3]/by = "anybody" + > $reprepro/allow[4]/by = "unsigned" + + *) +let by = + [ key "by" . Sep.space + . ( store ("anybody"|"unsigned") + | by_key | by_group ) ] + +(* View: allow + An allow entry, e.g.: + + > $reprepro/allow[1] + > $reprepro/allow[1]/and[1] + > $reprepro/allow[1]/and[1]/or = "architectures" + > $reprepro/allow[1]/and[1]/or/or[1] = "i386" + > $reprepro/allow[1]/and[1]/or/or[2] = "amd64" + > $reprepro/allow[1]/and[1]/or/or[3] = "all" + > $reprepro/allow[1]/and[2] + > $reprepro/allow[1]/and[2]/or = "sections" + > $reprepro/allow[1]/and[2]/or/contain + > $reprepro/allow[1]/and[2]/or/or = "main" + > $reprepro/allow[1]/by = "key" + > $reprepro/allow[1]/by/key = "ABCD1234" + + *) +let allow = + [ key "allow" . Sep.space + . condition_list . Sep.space + . by . Util.eol ] + +(* View: group + A group declaration *) +let group = + let add = [ key "add" . Sep.space + . store Rx.word ] + in let contains = [ key "contains" . Sep.space + . store Rx.word ] + in let empty = [ key "empty" ] + in let unused = [ key "unused" ] + in [ key "group" . Sep.space + . store Rx.word . Sep.space + . (add | contains | empty | unused) . Util.eol ] + +(* View: entry + An entry is either an <allow> statement + or a <group> definition. + *) +let entry = allow | group + +(* View: lns + The lens is made of <Util.empty>, <Util.comment> and <entry> lines *) +let lns = (Util.empty|Util.comment|entry)* diff --git a/Sharp.Augeas.Test/lens/resolv.aug b/Sharp.Augeas.Test/lens/resolv.aug new file mode 100644 index 0000000..ffa260e --- /dev/null +++ b/Sharp.Augeas.Test/lens/resolv.aug @@ -0,0 +1,137 @@ +(* +Module: Resolv + Parses /etc/resolv.conf + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man resolv.conf` where possible. + +About: Licence + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + +About: Configuration files + This lens applies to /etc/resolv.conf. See <filter>. +*) + +module Resolv = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: comment *) +let comment = Util.comment_generic /[ \t]*[;#][ \t]*/ "# " + +(* View: comment_eol *) +let comment_eol = Util.comment_generic /[ \t]*[;#][ \t]*/ " # " + +(* View: empty *) +let empty = Util.empty_generic_dos /[ \t]*[#;]?[ \t]*/ + + +(************************************************************************ + * Group: MAIN OPTIONS + *************************************************************************) + +(* View: netmask +A network mask for IP addresses *) +let netmask = [ label "netmask" . Util.del_str "/" . store Rx.ip ] + +(* View: ipaddr +An IP address or range with an optional mask *) +let ipaddr = [label "ipaddr" . store Rx.ip . netmask?] + + +(* View: nameserver + A nameserver entry *) +let nameserver = Build.key_value_line_comment + "nameserver" Sep.space (store Rx.ip) comment_eol + +(* View: domain *) +let domain = Build.key_value_line_comment + "domain" Sep.space (store Rx.word) comment_eol + +(* View: search *) +let search = Build.key_value_line_comment + "search" Sep.space + (Build.opt_list + [label "domain" . store Rx.word] + Sep.space) + comment_eol + +(* View: sortlist *) +let sortlist = Build.key_value_line_comment + "sortlist" Sep.space + (Build.opt_list + ipaddr + Sep.space) + comment_eol + +(* View: lookup *) +let lookup = + let lookup_entry = Build.flag("bind"|"file"|"yp") + in Build.key_value_line_comment + "lookup" Sep.space + (Build.opt_list + lookup_entry + Sep.space) + comment_eol + +(* View: family *) +let family = + let family_entry = Build.flag("inet4"|"inet6") + in Build.key_value_line_comment + "family" Sep.space + (Build.opt_list + family_entry + Sep.space) + comment_eol + +(************************************************************************ + * Group: SPECIAL OPTIONS + *************************************************************************) + +(* View: ip6_dotint + ip6-dotint option, which supports negation *) +let ip6_dotint = + let negate = [ del "no-" "no-" . label "negate" ] + in [ negate? . key "ip6-dotint" ] + +(* View: options + Options values *) +let options = + let options_entry = Build.key_value ("ndots"|"timeout"|"attempts") + (Util.del_str ":") (store Rx.integer) + | Build.flag ("debug"|"rotate"|"no-check-names" + |"inet6"|"ip6-bytestring"|"edns0" + |"single-request"|"single-request-reopen" + |"no-tld-query"|"use-vc"|"no-reload") + | ip6_dotint + + in Build.key_value_line_comment + "options" Sep.space + (Build.opt_list + options_entry + Sep.space) + comment_eol + +(* View: entry *) +let entry = nameserver + | domain + | search + | sortlist + | options + | lookup + | family + +(* View: lns *) +let lns = ( empty | comment | entry )* + +(* Variable: filter *) +let filter = (incl "/etc/resolv.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/rhsm.aug b/Sharp.Augeas.Test/lens/rhsm.aug new file mode 100644 index 0000000..56cc82e --- /dev/null +++ b/Sharp.Augeas.Test/lens/rhsm.aug @@ -0,0 +1,42 @@ +(* +Module: Rhsm + Parses subscription-manager config files + +Author: Dominic Cleal <dcleal@redhat.com> + +About: Reference + This lens tries to keep as close as possible to rhsm.conf(5) and + Python's SafeConfigParser. All settings must be in sections without + indentation. Semicolons and hashes are permitted for comments. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to: + /etc/rhsm/rhsm.conf + + See <filter>. +*) + +module Rhsm = + autoload xfm + +(* Semicolons and hashes are permitted for comments *) +let comment = IniFile.comment IniFile.comment_re "#" +(* Equals and colons are permitted for separators *) +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default + +(* All settings must be in sections without indentation *) +let entry = IniFile.entry_multiline IniFile.entry_re sep comment +let title = IniFile.title IniFile.record_re +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = incl "/etc/rhsm/rhsm.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/rmt.aug b/Sharp.Augeas.Test/lens/rmt.aug new file mode 100644 index 0000000..36ed2d3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/rmt.aug @@ -0,0 +1,30 @@ +(* +Module: Rmt + Parses rmt's configuration file + +Author: Dominic Cleal <dcleal@redhat.com> + +About: Reference + This lens is based on rmt(1) + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Rmt = + autoload xfm + +let sto_to_tab = store Rx.no_spaces + +let debug = Build.key_value_line "DEBUG" Sep.equal ( store Rx.fspath ) +let user = Build.key_value_line "USER" Sep.equal sto_to_tab +let access = Build.key_value_line "ACCESS" Sep.equal + ( [ label "name" . sto_to_tab ] . Sep.tab . + [ label "host" . sto_to_tab ] . Sep.tab . + [ label "path" . sto_to_tab ] ) + +let lns = ( debug | user | access | Util.comment | Util.empty )* + +let filter = incl "/etc/default/rmt" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/rsyncd.aug b/Sharp.Augeas.Test/lens/rsyncd.aug new file mode 100644 index 0000000..713cb23 --- /dev/null +++ b/Sharp.Augeas.Test/lens/rsyncd.aug @@ -0,0 +1,54 @@ +(* Rsyncd module for Augeas + Author: Marc Fournier <marc.fournier@camptocamp.com> + + Reference: man rsyncd.conf(5) + +*) + +module Rsyncd = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) +let comment = IniFile.comment IniFile.comment_re "#" +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default +let indent = del /[ \t]*/ " " + +(* Import useful INI File primitives *) +let eol = IniFile.eol +let empty = IniFile.empty +let sto_to_comment + = Util.del_opt_ws " " + . store /[^;# \t\n][^;#\n]*[^;# \t\n]|[^;# \t\n]/ + + +(************************************************************************ + * ENTRY + * rsyncd.conf allows indented entries, but by default entries outside + * sections are unindented + *************************************************************************) +let entry_re = /[A-Za-z0-9_.-][A-Za-z0-9 _.-]*[A-Za-z0-9_.-]/ + +let entry = IniFile.indented_entry entry_re sep comment + +(************************************************************************ + * RECORD & TITLE + * We use IniFile.title_label because there can be entries + * outside of sections whose labels would conflict with section names + *************************************************************************) +let title = IniFile.indented_title ( IniFile.record_re - ".anon" ) +let record = IniFile.record title entry + +let record_anon = [ label ".anon" . ( entry | empty )+ ] + +(************************************************************************ + * LENS & FILTER + * There can be entries before any section + * IniFile.entry includes comment management, so we just pass entry to lns + *************************************************************************) +let lns = record_anon? . record* + +let filter = (incl "/etc/rsyncd.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/rsyslog.aug b/Sharp.Augeas.Test/lens/rsyslog.aug new file mode 100644 index 0000000..29ff9b1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/rsyslog.aug @@ -0,0 +1,98 @@ +(* +Module: Rsyslog + Parses /etc/rsyslog.conf + +Author: Raphael Pinson <raphael.pinsons@camptocamp.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 rsyslog.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/rsyslog.conf. See <filter>. + +About: Examples + The <Test_Rsyslog> file contains various examples and tests. +*) +module Rsyslog = + +autoload xfm + +let macro_rx = /[^,# \n\t][^#\n]*[^,# \n\t]|[^,# \n\t]/ +let macro = [ key /$[A-Za-z0-9]+/ . Sep.space . store macro_rx . Util.comment_or_eol ] + +let config_object_param = [ key /[A-Za-z.]+/ . Sep.equal . Quote.dquote + . store /[^"]+/ . Quote.dquote ] +(* Inside config objects, we allow embedded comments; we don't surface them + * in the tree though *) +let config_sep = del /[ \t]+|[ \t]*#.*\n[ \t]*/ " " + +let config_object = + [ key /action|global|input|module|parser|timezone|include/ . + Sep.lbracket . + config_object_param . ( config_sep . config_object_param )* . + Sep.rbracket . Util.comment_or_eol ] + +(* View: users + Map :omusrmsg: and a list of users, or a single * +*) +let omusrmsg = Util.del_str ":omusrmsg:" . + Syslog.label_opt_list_or "omusrmsg" (store Syslog.word) + Syslog.comma "*" + +(* View: file_tmpl + File action with a specified template *) +let file_tmpl = Syslog.file . [ label "template" . Util.del_str ";" . store Rx.word ] + +let dynamic = [ Util.del_str "?" . label "dynamic" . store Rx.word ] + +let namedpipe = Syslog.pipe . Sep.space . [ label "pipe" . store Syslog.file_r ] + +let action = Syslog.action | omusrmsg | file_tmpl | dynamic | namedpipe + +(* Cannot use syslog program because rsyslog does not suppport #! *) +let program = [ label "program" . Syslog.bang . + ( Syslog.opt_plus | [ Build.xchgs "-" "reverse" ] ) . + Syslog.programs . Util.eol . Syslog.entries ] + +(* Cannot use syslog hostname because rsyslog does not suppport #+/- *) +let hostname = [ label "hostname" . + ( Syslog.plus | [ Build.xchgs "-" "reverse" ] ) . + Syslog.hostnames . Util.eol . Syslog.entries ] + +(* View: actions *) +let actions = + let prop_act = [ label "action" . action ] + in let act_sep = del /[ \t]*\n&[ \t]*/ "\n& " + in Build.opt_list prop_act act_sep + +(* View: entry + An entry contains selectors and an action +*) +let entry = [ label "entry" . Syslog.selectors . Syslog.sep_tab . + actions . Util.eol ] + +(* View: prop_filter + Parses property-based filters, which start with ":" and the property name *) +let prop_filter = + let sep = Sep.comma . Util.del_opt_ws " " + in let prop_name = [ Util.del_str ":" . label "property" . store Rx.word ] + in let prop_oper = [ label "operation" . store /[A-Za-z!-]+/ ] + in let prop_val = [ label "value" . Quote.do_dquote (store /[^\n"]*/) ] + in [ label "filter" . prop_name . sep . prop_oper . sep . prop_val . + Sep.space . actions . Util.eol ] + +let entries = ( Syslog.empty | Util.comment | entry | macro | config_object | prop_filter )* + +let lns = entries . ( program | hostname )* + +let filter = incl "/etc/rsyslog.conf" + . incl "/etc/rsyslog.d/*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/rtadvd.aug b/Sharp.Augeas.Test/lens/rtadvd.aug new file mode 100644 index 0000000..4f39d22 --- /dev/null +++ b/Sharp.Augeas.Test/lens/rtadvd.aug @@ -0,0 +1,34 @@ +(* +Module: Rtadvd + Parses rtadvd configuration file + +Author: Matt Dainty <matt@bodgit-n-scarper.com> + +About: Reference + - man 5 rtadvd.conf + +Each line represents a record consisting of a number of ':'-separated fields +the first of which is the name or identifier for the record. The name can +optionally be split by '|' and each subsequent value is considered an alias +of the first. Records can be split across multiple lines with '\'. + +*) + +module Rtadvd = + autoload xfm + + let empty = Util.empty + + (* field must not contain ':' unless quoted *) + let cfield = /[a-zA-Z0-9-]+(#?@|#[0-9]+|=("[^"]*"|[^:"]*))?/ + + let lns = ( empty | Getcap.comment | Getcap.record cfield )* + + let filter = incl "/etc/rtadvd.conf" + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/rx.aug b/Sharp.Augeas.Test/lens/rx.aug new file mode 100644 index 0000000..13b8d84 --- /dev/null +++ b/Sharp.Augeas.Test/lens/rx.aug @@ -0,0 +1,167 @@ +(* +Module: Rx + Generic regexps to build lenses + +Author: Raphael Pinson <raphink@gmail.com> + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + + +module Rx = + +(* Group: Spaces *) +(* Variable: space + A mandatory space or tab *) +let space = /[ \t]+/ + +(* Variable: opt_space + An optional space or tab *) +let opt_space = /[ \t]*/ + +(* Variable: cl + A continued line with a backslash *) +let cl = /[ \t]*\\\\\n[ \t]*/ + +(* Variable: cl_or_space + A <cl> or a <space> *) +let cl_or_space = cl | space + +(* Variable: cl_or_opt_space + A <cl> or a <opt_space> *) +let cl_or_opt_space = cl | opt_space + +(* Group: General strings *) + +(* Variable: space_in + A string which does not start or end with a space *) +let space_in = /[^ \r\t\n].*[^ \r\t\n]|[^ \t\n\r]/ + +(* Variable: no_spaces + A string with no spaces *) +let no_spaces = /[^ \t\r\n]+/ + +(* Variable: word + An alphanumeric string *) +let word = /[A-Za-z0-9_.-]+/ + +(* Variable: integer + One or more digits *) +let integer = /[0-9]+/ + +(* Variable: relinteger + A relative <integer> *) +let relinteger = /[-+]?[0-9]+/ + +(* Variable: relinteger_noplus + A relative <integer>, without explicit plus sign *) +let relinteger_noplus = /[-]?[0-9]+/ + +(* Variable: decimal + A decimal value (using ',' or '.' as a separator) *) +let decimal = /[0-9]+([.,][0-9]+)?/ + +(* Variable: reldecimal + A relative <decimal> *) +let reldecimal = /[+-]?[0-9]+([.,][0-9]+)?/ + +(* Variable: byte + A byte (0 - 255) *) +let byte = /25[0-5]?|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]/ + +(* Variable: hex + A hex value *) +let hex = /0x[0-9a-fA-F]+/ + +(* Variable: octal + An octal value *) +let octal = /0[0-7]+/ + +(* Variable: fspath + A filesystem path *) +let fspath = /[^ \t\n]+/ + +(* Group: All but... *) +(* Variable: neg1 + Anything but a space, a comma or a comment sign *) +let neg1 = /[^,# \n\t]+/ + +(* + * Group: IPs + * Cf. http://blog.mes-stats.fr/2008/10/09/regex-ipv4-et-ipv6/ (in fr) + *) + +(* Variable: ipv4 *) +let ipv4 = + let dot = "." in + byte . dot . byte . dot . byte . dot . byte + +(* Variable: ipv6 *) +let ipv6 = + /(([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})/ + | /(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})/ + | /(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})/ + | /(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})/ + | /(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})/ + | /(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})/ + | ( /([0-9A-Fa-f]{1,4}:){6}/ + . /((((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))\.){3}/ + . /(((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))/ + ) + | ( /([0-9A-Fa-f]{1,4}:){0,5}:/ + . /((((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))\.){3}/ + . /(((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))/ + ) + | ( /::([0-9A-Fa-f]{1,4}:){0,5}/ + . /((((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))\.){3}/ + . /(((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))/ + ) + | ( /[0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}/ + . /[0-9A-Fa-f]{1,4}/ + ) + | /(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})/ + | /(([0-9A-Fa-f]{1,4}:){1,7}:)/ + + +(* Variable: ip + An <ipv4> or <ipv6> *) +let ip = ipv4 | ipv6 + + +(* Variable: hostname + A valid RFC 1123 hostname *) +let hostname = /(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*( + [A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])/ + +(* + * Variable: device_name + * A Linux device name like eth0 or i2c-0. Might still be too restrictive + *) + +let device_name = /[a-zA-Z0-9_?.+:!-]+/ + +(* + * Variable: email_addr + * To be refined + *) +let email_addr = /[A-Za-z0-9_+.-]+@[A-Za-z0-9_.-]+/ + +(* + * Variable: iso_8601 + * ISO 8601 date time format + *) +let year = /[0-9]{4}/ +let relyear = /[-+]?/ . year +let monthday = /W?[0-9]{2}(-?[0-9]{1,2})?/ +let time = + let sep = /[T \t]/ + in let digits = /[0-9]{2}(:?[0-9]{2}(:?[0-9]{2})?)?/ + in let precis = /[.,][0-9]+/ + in let zone = "Z" | /[-+]?[0-9]{2}(:?[0-9]{2})?/ + in sep . digits . precis? . zone? +let iso_8601 = year . ("-"? . monthday . time?)? + +(* Variable: url_3986 + A valid RFC 3986 url - See Appendix B *) +let url_3986 = /(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/ diff --git a/Sharp.Augeas.Test/lens/samba.aug b/Sharp.Augeas.Test/lens/samba.aug new file mode 100644 index 0000000..affe616 --- /dev/null +++ b/Sharp.Augeas.Test/lens/samba.aug @@ -0,0 +1,56 @@ +(* Samba module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: man smb.conf(5) + +*) + + +module Samba = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) + +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default +let sep = del /[ \t]*=/ " =" +let indent = del /[ \t]*/ " " + +(* Import useful INI File primitives *) +let eol = IniFile.eol +let empty = IniFile.empty +let sto_to_comment + = Util.del_opt_ws " " + . store /[^;# \t\r\n][^;#\r\n]*[^;# \t\r\n]|[^;# \t\r\n]/ + +(************************************************************************ + * ENTRY + * smb.conf allows indented entries + *************************************************************************) + +let entry_re = /[A-Za-z0-9_.-][A-Za-z0-9 _.:\*-]*[A-Za-z0-9_.\*-]/ +let entry = let kw = entry_re in + [ indent + . key kw + . sep + . sto_to_comment? + . (comment|eol) ] + | comment + +(************************************************************************ + * TITLE + *************************************************************************) + +let title = IniFile.title_label "target" IniFile.record_label_re +let record = IniFile.record title entry + +(************************************************************************ + * LENS & FILTER + *************************************************************************) + +let lns = IniFile.lns record comment + +let filter = (incl "/etc/samba/smb.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/schroot.aug b/Sharp.Augeas.Test/lens/schroot.aug new file mode 100644 index 0000000..c53ea17 --- /dev/null +++ b/Sharp.Augeas.Test/lens/schroot.aug @@ -0,0 +1,69 @@ +(* +Module: Schroot + Parses /etc/schroot/schroot.conf + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 schroot.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/schroot/schroot.conf. See <filter>. +*) + + +module Schroot = +autoload xfm + + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: comment + An <IniFile.comment> entry *) +let comment = IniFile.comment "#" "#" + +(* View: sep + An <IniFile.sep> entry *) +let sep = IniFile.sep "=" "=" + + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +(* View: description + Descriptions are special entries, which can have an optional lang parameter *) +let description = + let lang = [ Util.del_str "[" . label "lang" + . store IniFile.entry_re . Util.del_str "]" ] + in IniFile.entry_generic_nocomment (key "description" . lang?) sep "#" comment + +(* View: entry + An <IniFile.entry>, or <description> *) +let entry = IniFile.entry (IniFile.entry_re - "description") sep comment + | description + +(* View: title + An <IniFile.title> *) +let title = IniFile.title IniFile.record_re + +(* View: record + An <IniFile.record> *) +let record = IniFile.record title entry + +(* View: lns + An <IniFile.lns> *) +let lns = IniFile.lns record comment + +(* View: filter *) +let filter = (incl "/etc/schroot/schroot.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/securetty.aug b/Sharp.Augeas.Test/lens/securetty.aug new file mode 100644 index 0000000..80ba097 --- /dev/null +++ b/Sharp.Augeas.Test/lens/securetty.aug @@ -0,0 +1,18 @@ +(* Parses entries in /etc/securetty + + Author: Simon Josi <josi@yokto.net> +*) +module Securetty = + autoload xfm + + let word = /[^ \t\n#]+/ + let eol = Util.eol + let empty = Util.empty + let comment = Util.comment + let comment_or_eol = Util.comment_or_eol + + let record = [ seq "securetty" . store word . comment_or_eol ] + let lns = ( empty | comment | record )* + + let filter = (incl "/etc/securetty") + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/semanage.aug b/Sharp.Augeas.Test/lens/semanage.aug new file mode 100644 index 0000000..46f93b3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/semanage.aug @@ -0,0 +1,37 @@ +(* +Module: Semanage + Parses /etc/selinux/semanage.conf + +Author: + Pino Toscano <ptoscano@redhat.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to /etc/selinux/semanage.conf. See <filter>. + +About: Examples + The <Test_Semanage> file contains various examples and tests. +*) + +module Semanage = + autoload xfm + +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" +let empty = IniFile.empty +let eol = IniFile.eol + +let entry = IniFile.entry IniFile.entry_re sep comment + | empty + +let title = IniFile.title_label "@group" (IniFile.record_re - /^end$/) +let record = [ title . entry+ . Util.del_str "[end]" . eol ] + +let lns = (entry | record)* + +(* Variable: filter *) +let filter = incl "/etc/selinux/semanage.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/sep.aug b/Sharp.Augeas.Test/lens/sep.aug new file mode 100644 index 0000000..6798e10 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sep.aug @@ -0,0 +1,57 @@ +(* +Module: Sep + Generic separators to build lenses + +Author: Raphael Pinson <raphink@gmail.com> + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + + +module Sep = + +(* Variable: colon *) +let colon = Util.del_str ":" + +(* Variable: semicolon *) +let semicolon = Util.del_str ";" + +(* Variable: comma *) +let comma = Util.del_str "," + +(* Variable: equal *) +let equal = Util.del_str "=" + +(* Variable: space_equal *) +let space_equal = Util.delim "=" + +(* Variable: space + Deletes a <Rx.space> and default to a single space *) +let space = del Rx.space " " + +(* Variable: tab + Deletes a <Rx.space> and default to a tab *) +let tab = del Rx.space "\t" + +(* Variable: opt_space + Deletes a <Rx.opt_space> and default to an empty string *) +let opt_space = del Rx.opt_space "" + +(* Variable: opt_tab + Deletes a <Rx.opt_space> and default to a tab *) +let opt_tab = del Rx.opt_space "\t" + +(* Variable: cl_or_space + Deletes a <Rx.cl_or_space> and default to a single space *) +let cl_or_space = del Rx.cl_or_space " " + +(* Variable: cl_or_opt_space + Deletes a <Rx.cl_or_opt_space> and default to a single space *) +let cl_or_opt_space = del Rx.cl_or_opt_space " " + +(* Variable: lbracket *) +let lbracket = Util.del_str "(" + +(* Variable: rbracket *) +let rbracket = Util.del_str ")" diff --git a/Sharp.Augeas.Test/lens/services.aug b/Sharp.Augeas.Test/lens/services.aug new file mode 100644 index 0000000..bad590f --- /dev/null +++ b/Sharp.Augeas.Test/lens/services.aug @@ -0,0 +1,93 @@ +(* +Module: Services + Parses /etc/services + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to 'man services' where possible. + +The definitions from 'man services' are put as commentaries for reference +throughout the file. More information can be found in the manual. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Get the name of the service running on port 22 with protocol tcp + > match "/files/etc/services/service-name[port = '22'][protocol = 'tcp']" + * Remove the tcp entry for "domain" service + > rm "/files/etc/services/service-name[. = 'domain'][protocol = 'tcp']" + * Add a tcp service named "myservice" on port 55234 + > ins service-name after /files/etc/services/service-name[last()] + > set /files/etc/services/service-name[last()] "myservice" + > set "/files/etc/services/service-name[. = 'myservice']/port" "55234" + > set "/files/etc/services/service-name[. = 'myservice']/protocol" "tcp" + +About: Configuration files + This lens applies to /etc/services. See <filter>. +*) + +module Services = + autoload xfm + + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Generic primitives *) + +(* Variable: eol *) +let eol = del /[ \t]*(#)?[ \t]*\n/ "\n" +let indent = Util.indent +let comment = Util.comment +let comment_or_eol = Util.comment_or_eol +let empty = Util.empty +let protocol_re = /[a-zA-Z]+/ +let word_re = /[a-zA-Z0-9_.+*\/:-]+/ +let num_re = /[0-9]+/ + +(* Group: Separators *) +let sep_spc = Util.del_ws_spc + + +(************************************************************************ + * Group: LENSES + *************************************************************************) + +(* View: port *) +let port = [ label "port" . store num_re ] + +(* View: port_range *) +let port_range = [ label "start" . store num_re ] + . Util.del_str "-" + . [ label "end" . store num_re ] + +(* View: protocol *) +let protocol = [ label "protocol" . store protocol_re ] + +(* View: alias *) +let alias = [ label "alias" . store word_re ] + +(* + * View: record + * A standard /etc/services record + * TODO: make sure a space is added before a comment on new nodes + *) +let record = [ label "service-name" . store word_re + . sep_spc . (port | port_range) + . del "/" "/" . protocol . ( sep_spc . alias )* + . comment_or_eol ] + +(* View: lns + The services lens is either <empty>, <comment> or <record> *) +let lns = ( empty | comment | record )* + + +(* View: filter *) +let filter = (incl "/etc/services") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/shadow.aug b/Sharp.Augeas.Test/lens/shadow.aug new file mode 100644 index 0000000..959cb3a --- /dev/null +++ b/Sharp.Augeas.Test/lens/shadow.aug @@ -0,0 +1,81 @@ +(* + Module: Shadow + Parses /etc/shadow + + Author: Lorenzo M. Catucci <catucci@ccd.uniroma2.it> + + Original Author: Free Ekanayaka <free@64studio.com> + + About: Reference + + - man 5 shadow + - man 3 getspnam + + About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + + About: + + Each line in the shadow files represents the additional shadow-defined attributes + for the corresponding user, as defined in the passwd file. + +*) + +module Shadow = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty +let dels = Util.del_str + +let colon = Sep.colon + +let word = Rx.word +let integer = Rx.integer + +let sto_to_col = Passwd.sto_to_col +let sto_to_eol = Passwd.sto_to_eol + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) +(* Common for entry and nisdefault *) +let common = [ label "lastchange_date" . store integer? . colon ] + . [ label "minage_days" . store integer? . colon ] + . [ label "maxage_days" . store integer? . colon ] + . [ label "warn_days" . store integer? . colon ] + . [ label "inactive_days" . store integer? . colon ] + . [ label "expire_date" . store integer? . colon ] + . [ label "flag" . store integer? ] + +(* View: entry *) +let entry = [ key word + . colon + . [ label "password" . sto_to_col? . colon ] + . common + . eol ] + +let nisdefault = + let overrides = + colon + . [ label "password" . store word? . colon ] + . common in + [ dels "+" . label "@nisdefault" . overrides? . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry|nisdefault) * + +let filter + = incl "/etc/shadow" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/shells.aug b/Sharp.Augeas.Test/lens/shells.aug new file mode 100644 index 0000000..87a4842 --- /dev/null +++ b/Sharp.Augeas.Test/lens/shells.aug @@ -0,0 +1,37 @@ +(* +Module: Shells + Parses /etc/shells + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man 5 shells` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/shells. See <filter>. +*) + + +module Shells = + autoload xfm + +let empty = Util.empty +let comment = Util.comment +let comment_or_eol = Util.comment_or_eol +let shell = [ seq "shell" . store /[^# \t\n]+/ . comment_or_eol ] + +(* View: lns + The shells lens +*) +let lns = ( empty | comment | shell )* + +(* Variable: filter *) +let filter = incl "/etc/shells" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/shellvars.aug b/Sharp.Augeas.Test/lens/shellvars.aug new file mode 100644 index 0000000..3a4c5c5 --- /dev/null +++ b/Sharp.Augeas.Test/lens/shellvars.aug @@ -0,0 +1,338 @@ +(* +Module: Shellvars + Generic lens for shell-script config files like the ones found + in /etc/sysconfig + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented +*) + +module Shellvars = + autoload xfm + + (* Delete a blank line, rather than mapping it *) + let del_empty = del (Util.empty_generic_re . "\n") "\n" + + let empty = Util.empty + let empty_part_re = Util.empty_generic_re . /\n+/ + let eol = del (/[ \t]+|[ \t]*[;\n]/ . empty_part_re*) "\n" + let semicol_eol = del (/[ \t]*[;\n]/ . empty_part_re*) "\n" + let brace_eol = del /[ \t\n]+/ "\n" + + let key_re = /[A-Za-z0-9_][-A-Za-z0-9_]*(\[[0-9A-Za-z_,]+\])?/ - ("unset" | "export") + let matching_re = "${!" . key_re . /[\*@]\}/ + let eq = Util.del_str "=" + + let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n" + let comment = Util.comment_generic_seteol /[ \t]*#[ \t]*/ " # " eol_for_comment + (* comment_eol in shell MUST begin with a space *) + let comment_eol = Util.comment_generic_seteol /[ \t]+#[ \t]*/ " # " eol_for_comment + let comment_or_eol = comment_eol | semicol_eol + + let xchgs = Build.xchgs + let semicol = del /;?/ "" + + let char = /[^`;()'"&|\n\\# \t]#*|\\\\./ + let dquot = + let char = /[^"\\]|\\\\./ | Rx.cl + in "\"" . char* . "\"" (* " Emacs, relax *) + let squot = /'[^']*'/ + let bquot = /`[^`\n]+`/ + (* dbquot don't take spaces or semi-colons *) + let dbquot = /``[^` \t\n;]+``/ + let dollar_assign = /\$\([^\(\)#\n]*\)/ + let dollar_arithm = /\$\(\([^\)#\n]*\)\)/ + + let anyquot = (char|dquot|squot|dollar_assign|dollar_arithm)+ | bquot | dbquot + let sto_to_semicol = store (anyquot . (Rx.cl_or_space . anyquot)*) + + (* Array values of the form '(val1 val2 val3)'. We do not handle empty *) + (* arrays here because of typechecking headaches. Instead, they are *) + (* treated as a simple value *) + let array = + let array_value = store anyquot in + del /\([ \t]*/ "(" . counter "values" . + [ seq "values" . array_value ] . + [ del /[ \t\n]+/ " " . seq "values" . array_value ] * + . del /[ \t]*\)/ ")" + + (* Treat an empty list () as a value '()'; that's not quite correct *) + (* but fairly close. *) + let simple_value = + let empty_array = /\([ \t]*\)/ in + store (anyquot | empty_array)? + + let export = [ key "export" . Util.del_ws_spc ] + let kv = Util.indent . export? . key key_re + . eq . (simple_value | array) + + let var_action (name:string) = + Util.indent . del name name . Util.del_ws_spc + . label ("@" . name) . counter "var_action" + . Build.opt_list [ seq "var_action" . store (key_re | matching_re) ] Util.del_ws_spc + + let unset = var_action "unset" + let bare_export = var_action "export" + + let source = + Util.indent + . del /\.|source/ "." . label ".source" + . Util.del_ws_spc . store /[^;=# \t\n]+/ + + let shell_builtin_cmds = "ulimit" | "shift" | "exit" + + let eval = + Util.indent . Util.del_str "eval" . Util.del_ws_spc + . label "@eval" . store anyquot + + let alias = + Util.indent . Util.del_str "alias" . Util.del_ws_spc + . label "@alias" . store key_re . eq + . [ label "value" . store anyquot ] + + let builtin = + Util.indent . label "@builtin" + . store shell_builtin_cmds + . (Sep.cl_or_space + . [ label "args" . sto_to_semicol ])? + + let keyword (kw:string) = Util.indent . Util.del_str kw + let keyword_label (kw:string) (lbl:string) = keyword kw . label lbl + + let return = + Util.indent . label "@return" + . Util.del_str "return" + . ( Util.del_ws_spc . store Rx.integer )? + + let action (operator:string) (lbl:string) (sto:lens) = + let sp = Rx.cl_or_opt_space | /[ \t\n]+/ + in [ del (sp . operator . sp) (" " . operator . " ") + . label ("@".lbl) . sto ] + + let action_pipe = action "|" "pipe" + let action_and = action "&&" "and" + let action_or = action "||" "or" + + let condition = + let cond (start:string) (end:string) = [ label "type" . store start ] + . Util.del_ws_spc . sto_to_semicol + . Util.del_ws_spc . Util.del_str end + . ( action_and sto_to_semicol | action_or sto_to_semicol )* + in Util.indent . label "@condition" . (cond "[" "]" | cond "[[" "]]") + + (* Entry types *) + let entry_eol_item (item:lens) = [ item . comment_or_eol ] + let entry_item (item:lens) = [ item ] + + let entry_eol_nocommand = + entry_eol_item source + | entry_eol_item kv + | entry_eol_item unset + | entry_eol_item bare_export + | entry_eol_item builtin + | entry_eol_item return + | entry_eol_item condition + | entry_eol_item eval + | entry_eol_item alias + + let entry_noeol_nocommand = + entry_item source + | entry_item kv + | entry_item unset + | entry_item bare_export + | entry_item builtin + | entry_item return + | entry_item condition + | entry_item eval + | entry_item alias + + (* Command *) + let rec command = + let env = [ key key_re . eq . store anyquot . Sep.cl_or_space ] + in let reserved_key = /exit|shift|return|ulimit|unset|export|source|\.|if|for|select|while|until|then|else|fi|done|case|eval|alias/ + in let word = /\$?[-A-Za-z0-9_.\/]+/ + in let entry_eol = entry_eol_nocommand | entry_eol_item command + in let entry_noeol = entry_noeol_nocommand | entry_item command + in let entry = entry_eol | entry_noeol + in let pipe = action_pipe (entry_eol_item command | entry_item command) + in let and = action_and entry + in let or = action_or entry + in Util.indent . label "@command" . env* . store (word - reserved_key) + . [ Sep.cl_or_space . label "@arg" . sto_to_semicol]? + . ( pipe | and | or )? + + let entry_eol = entry_eol_nocommand + | entry_eol_item command + + let entry_noeol = entry_noeol_nocommand + | entry_item command + +(************************************************************************ + * Group: CONDITIONALS AND LOOPS + *************************************************************************) + + let generic_cond_start (start_kw:string) (lbl:string) + (then_kw:string) (contents:lens) = + keyword_label start_kw lbl . Sep.space + . sto_to_semicol + . ( action_and sto_to_semicol | action_or sto_to_semicol )* + . semicol_eol + . keyword then_kw . eol + . contents + + let generic_cond (start_kw:string) (lbl:string) + (then_kw:string) (contents:lens) (end_kw:string) = + [ generic_cond_start start_kw lbl then_kw contents + . keyword end_kw . comment_or_eol ] + + let cond_if (entry:lens) = + let elif = [ generic_cond_start "elif" "@elif" "then" entry+ ] in + let else = [ keyword_label "else" "@else" . eol . entry+ ] in + generic_cond "if" "@if" "then" (entry+ . elif* . else?) "fi" + + let loop_for (entry:lens) = + generic_cond "for" "@for" "do" entry+ "done" + + let loop_while (entry:lens) = + generic_cond "while" "@while" "do" entry+ "done" + + let loop_until (entry:lens) = + generic_cond "until" "@until" "do" entry+ "done" + + let loop_select (entry:lens) = + generic_cond "select" "@select" "do" entry+ "done" + + let case (entry:lens) (entry_noeol:lens) = + let pattern = [ label "@pattern" . sto_to_semicol . Sep.opt_space ] + in let case_entry = [ label "@case_entry" + . Util.indent . pattern + . (Util.del_str "|" . Sep.opt_space . pattern)* + . Util.del_str ")" . eol + . entry* . entry_noeol? + . Util.indent . Util.del_str ";;" . eol ] in + [ keyword_label "case" "@case" . Sep.space + . store (char+ | ("\"" . char+ . "\"")) + . del /[ \t\n]+/ " " . Util.del_str "in" . eol + . (empty* . comment* . case_entry)* + . empty* . comment* + . keyword "esac" . comment_or_eol ] + + let subshell (entry:lens) = + [ Util.indent . label "@subshell" + . Util.del_str "{" . brace_eol + . entry+ + . Util.indent . Util.del_str "}" . eol ] + + let function (entry:lens) (start_kw:string) (end_kw:string) = + [ Util.indent . label "@function" + . del /(function[ \t]+)?/ "" + . store Rx.word . del /[ \t]*\(\)/ "()" + . (comment_eol|brace_eol) . Util.del_str start_kw . brace_eol + . entry+ + . Util.indent . Util.del_str end_kw . eol ] + + let rec rec_entry = + let entry = comment | entry_eol | rec_entry in + cond_if entry + | loop_for entry + | loop_select entry + | loop_while entry + | loop_until entry + | case entry entry_noeol + | function entry "{" "}" + | function entry "(" ")" + | subshell entry + + let lns_norec = del_empty* . (comment | entry_eol) * + + let lns = del_empty* . (comment | entry_eol | rec_entry) * + + let sc_incl (n:string) = (incl ("/etc/sysconfig/" . n)) + let sc_excl (n:string) = (excl ("/etc/sysconfig/" . n)) + + let filter_sysconfig = + sc_incl "*" . + sc_excl "anaconda" . + sc_excl "bootloader" . + sc_excl "hw-uuid" . + sc_excl "hwconf" . + sc_excl "ip*tables" . + sc_excl "ip*tables.save" . + sc_excl "kernel" . + sc_excl "*.pub" . + sc_excl "sysstat.ioconf" . + sc_excl "system-config-firewall" . + sc_excl "system-config-securitylevel" . + sc_incl "network/config" . + sc_incl "network/dhcp" . + sc_incl "network/dhcp6r" . + sc_incl "network/dhcp6s" . + sc_incl "network/ifcfg-*" . + sc_incl "network/if-down.d/*" . + sc_incl "network/ifroute-*" . + sc_incl "network/if-up.d/*" . + sc_excl "network/if-up.d/SuSEfirewall2" . + sc_incl "network/providers/*" . + sc_excl "network-scripts" . + sc_incl "network-scripts/ifcfg-*" . + sc_excl "rhn" . + sc_incl "rhn/allowed-actions/*" . + sc_excl "rhn/allowed-actions/script" . + sc_incl "rhn/allowed-actions/script/*" . + sc_incl "rhn/rhnsd" . + sc_excl "SuSEfirewall2.d" . + sc_incl "SuSEfirewall2.d/cobbler" . + sc_incl "SuSEfirewall2.d/services/*" . + sc_excl "SuSEfirewall2.d/services/TEMPLATE" . + sc_excl "*.systemd" + + let filter_default = incl "/etc/default/*" + . excl "/etc/default/grub_installdevice*" + . excl "/etc/default/rmt" + . excl "/etc/default/star" + . excl "/etc/default/whoopsie" + . incl "/etc/profile" + . incl "/etc/profile.d/*" + . excl "/etc/profile.d/*.csh" + . excl "/etc/profile.d/*.tcsh" + . excl "/etc/profile.d/csh.local" + let filter_misc = incl "/etc/arno-iptables-firewall/debconf.cfg" + . incl "/etc/conf.d/*" + . incl "/etc/cron-apt/config" + . incl "/etc/environment" + . incl "/etc/firewalld/firewalld.conf" + . incl "/etc/blkid.conf" + . incl "/etc/adduser.conf" + . incl "/etc/cowpoke.conf" + . incl "/etc/cvs-cron.conf" + . incl "/etc/cvs-pserver.conf" + . incl "/etc/devscripts.conf" + . incl "/etc/kamailio/kamctlrc" + . incl "/etc/lbu/lbu.conf" + . incl "/etc/lintianrc" + . incl "/etc/lsb-release" + . incl "/etc/os-release" + . incl "/etc/periodic.conf" + . incl "/etc/popularity-contest.conf" + . incl "/etc/rc.conf" + . incl "/etc/rc.conf.d/*" + . incl "/etc/rc.conf.local" + . incl "/etc/selinux/config" + . incl "/etc/ucf.conf" + . incl "/etc/locale.conf" + . incl "/etc/vconsole.conf" + . incl "/etc/byobu/*" + + let filter = filter_sysconfig + . filter_default + . filter_misc + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/shellvars_list.aug b/Sharp.Augeas.Test/lens/shellvars_list.aug new file mode 100644 index 0000000..105939c --- /dev/null +++ b/Sharp.Augeas.Test/lens/shellvars_list.aug @@ -0,0 +1,59 @@ +(* Generic lens for shell-script config files like the ones found *) +(* in /etc/sysconfig, where a string needs to be split into *) +(* single words. *) +module Shellvars_list = + autoload xfm + + let eol = Util.eol + + let key_re = /[A-Za-z0-9_]+/ + let eq = Util.del_str "=" + let comment = Util.comment + let comment_or_eol = Util.comment_or_eol + let empty = Util.empty + let indent = Util.indent + + let sqword = /[^ '\t\n]+/ + let dqword = /([^ "\\\t\n]|\\\\.)+/ + let uqword = /([^ `"'\\\t\n]|\\\\.)+/ + let bqword = /`[^`\n]*`/ + let space_or_nl = /[ \t\n]+/ + let space_or_cl = space_or_nl | Rx.cl + + (* lists values of the form ... val1 val2 val3 ... *) + let list (word:regexp) (sep:regexp) = + let list_value = store word in + indent . + [ label "value" . list_value ] . + [ del sep " " . label "value" . list_value ]* . indent + + + (* handle single quoted lists *) + let squote_arr = [ label "quote" . store /'/ ] + . (list sqword space_or_nl)? . del /'/ "'" + + (* similarly handle double quoted lists *) + let dquote_arr = [ label "quote" . store /"/ ] + . (list dqword space_or_cl)? . del /"/ "\"" + + (* handle unquoted single value *) + let unquot_val = [ label "quote" . store "" ] + . [ label "value" . store (uqword+ | bqword)]? + + + (* lens for key value pairs *) + let kv = [ key key_re . eq . + ( (squote_arr | dquote_arr) . comment_or_eol + | unquot_val . eol ) + ] + + let lns = ( comment | empty | kv )* + + let filter = incl "/etc/sysconfig/bootloader" + . incl "/etc/sysconfig/kernel" + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/simplelines.aug b/Sharp.Augeas.Test/lens/simplelines.aug new file mode 100644 index 0000000..8ff25fb --- /dev/null +++ b/Sharp.Augeas.Test/lens/simplelines.aug @@ -0,0 +1,48 @@ +(* +Module: Simplelines + Parses simple lines conffiles + +Author: Raphael Pinson <raphink@gmail.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + See <filter>. + +About: Examples + The <Test_Simplelines> file contains various examples and tests. +*) + +module Simplelines = + +autoload xfm + +(* View: line + A simple, uncommented, line *) +let line = + let line_re = /[^# \t\n].*[^ \t\n]|[^# \t\n]/ + in [ seq "line" . Util.indent + . store line_re . Util.eol ] + +(* View: lns + The simplelines lens *) +let lns = (Util.empty | Util.comment | line)* + +(* Variable: filter *) +let filter = incl "/etc/at.allow" + . incl "/etc/at.deny" + . incl "/etc/cron.allow" + . incl "/etc/cron.deny" + . incl "/etc/cron.d/at.allow" + . incl "/etc/cron.d/at.deny" + . incl "/etc/cron.d/cron.allow" + . incl "/etc/cron.d/cron.deny" + . incl "/etc/default/grub_installdevice" + . incl "/etc/pam.d/allow.pamlist" + . incl "/etc/hostname.*" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/simplevars.aug b/Sharp.Augeas.Test/lens/simplevars.aug new file mode 100644 index 0000000..1863564 --- /dev/null +++ b/Sharp.Augeas.Test/lens/simplevars.aug @@ -0,0 +1,51 @@ +(* +Module: Simplevars + Parses simple key = value conffiles + +Author: Raphael Pinson <raphink@gmail.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Examples + The <Test_Simplevars> file contains various examples and tests. +*) + +module Simplevars = + +autoload xfm + +(* Variable: to_comment_re + The regexp to match the value *) +let to_comment_re = + let to_comment_squote = /'[^\n']*'/ + in let to_comment_dquote = /"[^\n"]*"/ + in let to_comment_noquote = /[^\n \t'"#][^\n#]*[^\n \t#]|[^\n \t'"#]/ + in to_comment_squote | to_comment_dquote | to_comment_noquote + +(* View: entry *) +let entry = + let some_value = Sep.space_equal . store to_comment_re + (* Avoid ambiguity in tree by making a subtree here *) + in let empty_value = [del /[ \t]*=/ "="] . store "" + in [ Util.indent . key Rx.word + . (some_value? | empty_value) + . (Util.eol | Util.comment_eol) ] + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry)* + +(* Variable: filter *) +let filter = incl "/etc/kernel-img.conf" + . incl "/etc/kerneloops.conf" + . incl "/etc/wgetrc" + . incl "/etc/zabbix/*.conf" + . incl "/etc/audit/auditd.conf" + . incl "/etc/mixerctl.conf" + . incl "/etc/wsconsctlctl.conf" + . incl "/etc/ocsinventory/ocsinventory-agent.cfg" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/sip_conf.aug b/Sharp.Augeas.Test/lens/sip_conf.aug new file mode 100644 index 0000000..2674558 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sip_conf.aug @@ -0,0 +1,57 @@ +(* +Module: Sip_Conf + Parses /etc/asterisk/sip.conf + +Author: Rob Tucker <rtucker@mozilla.com> + +About: Reference + Lens parses the sip.conf with support for template structure + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/asterisk/sip.conf. See <filter>. +*) + +module Sip_Conf = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) + +let comment = IniFile.comment IniFile.comment_re IniFile.comment_default +let sep = IniFile.sep IniFile.sep_re IniFile.sep_default +let empty = IniFile.empty +let eol = IniFile.eol +let comment_or_eol = comment | eol + + +let entry = IniFile.indented_entry IniFile.entry_re sep comment + +let text_re = Rx.word +let tmpl = + let is_tmpl = [ label "@is_template" . Util.del_str "!" ] + in let use_tmpl = [ label "@use_template" . store Rx.word ] + in let comma = Util.delim "," + in Util.del_str "(" . Sep.opt_space + . Build.opt_list (is_tmpl|use_tmpl) comma + . Sep.opt_space . Util.del_str ")" +let title_comment_re = /[ \t]*[#;].*$/ + +let title_comment = [ label "#title_comment" + . store title_comment_re ] +let title = label "title" . Util.del_str "[" + . store text_re . Util.del_str "]" + . tmpl? . title_comment? . eol +let record = IniFile.record title entry + +let lns = IniFile.lns record comment + +let filter = incl "/etc/asterisk/sip.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/slapd.aug b/Sharp.Augeas.Test/lens/slapd.aug new file mode 100644 index 0000000..12725b6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/slapd.aug @@ -0,0 +1,162 @@ +(* Slapd module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: man slapd.conf(5), man slapd.access (5) + +*) + +module Slapd = + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let spc = Util.del_ws_spc +let sep = del /[ \t\n]+/ " " + +let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ +let sto_to_spc = store /[^\\# \t\n]+/ + +let comment = Util.comment +let empty = Util.empty + +(************************************************************************ + * ACCESS TO + *************************************************************************) + +let access_re = "access to" +let control_re = "stop" | "continue" | "break" +let what = [ spc . label "access" + . store (/[^\\# \t\n]+/ - ("by" | control_re)) ] + +(* TODO: parse the control field, see man slapd.access (5) *) +let control = [ spc . label "control" . store control_re ] +let by = [ sep . key "by" . spc . sto_to_spc + . what? . control? ] + +let access = [ key access_re . spc. sto_to_spc . by+ . eol ] + +(************************************************************************ + * GLOBAL + *************************************************************************) + +(* TODO: parse special field separately, see man slapd.conf (5) *) +let global_re = "allow" + | "argsfile" + | "attributeoptions" + | "attributetype" + | "authz-policy" + | "ldap" + | "dn" + | "concurrency" + | "cron_max_pending" + | "conn_max_pending_auth" + | "defaultsearchbase" + | "disallow" + | "ditcontentrule" + | "gentlehup" + | "idletimeout" + | "include" + | "index_substr_if_minlen" + | "index_substr_if_maxlen" + | "index_substr_any_len" + | "index_substr_any_step" + | "localSSF" + | "loglevel" + | "moduleload" + | "modulepath" + | "objectclass" + | "objectidentifier" + | "password-hash" + | "password-crypt-salt-format" + | "pidfile" + | "referral" + | "replica-argsfile" + | "replica-pidfile" + | "replicationinterval" + | "require" + | "reverse-lookup" + | "rootDSE" + | "sasl-host" + | "sasl-realm" + | "sasl-secprops" + | "schemadn" + | "security" + | "sizelimit" + | "sockbuf_max_incoming " + | "sockbuf_max_incoming_auth" + | "threads" + | "timelimit time" + | "tool-threads" + | "TLSCipherSuite" + | "TLSCACertificateFile" + | "TLSCACertificatePath" + | "TLSCertificateFile" + | "TLSCertificateKeyFile" + | "TLSDHParamFile" + | "TLSRandFile" + | "TLSVerifyClient" + | "TLSCRLCheck" + | "backend" + +let global = Build.key_ws_value global_re + +(************************************************************************ + * DATABASE + *************************************************************************) + +(* TODO: support all types of database backend *) +let database_hdb = "cachesize" + | "cachefree" + | "checkpoint" + | "dbconfig" + | "dbnosync" + | "directory" + | "dirtyread" + | "idlcachesize" + | "index" + | "linearindex" + | "lockdetect" + | "mode" + | "searchstack" + | "shm_key" + +let database_re = "suffix" + | "lastmod" + | "limits" + | "maxderefdepth" + | "overlay" + | "readonly" + | "replica uri" + | "replogfile" + | "restrict" + | "rootdn" + | "rootpw" + | "subordinate" + | "syncrepl rid" + | "updatedn" + | "updateref" + | database_hdb + +let database_entry = + let val = Quote.double_opt + in Build.key_value_line database_re Sep.space val + +let database = [ key "database" + . spc + . sto_to_eol + . eol + . (comment|empty|database_entry|access)* ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|global|access)* . (database)* + +let filter = incl "/etc/ldap/slapd.conf" + . incl "/etc/openldap/slapd.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/smbusers.aug b/Sharp.Augeas.Test/lens/smbusers.aug new file mode 100644 index 0000000..aa70dc1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/smbusers.aug @@ -0,0 +1,34 @@ +(* +Module: SmbUsers + Parses Samba username maps + +Author: Raphael Pinson <raphink@gmail.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Examples + The <Test_SmbUsers> file contains various examples and tests. +*) + +module SmbUsers = + +autoload xfm + +(* View: entry *) +let entry = + let username = [ label "username" . store Rx.no_spaces ] + in let usernames = Build.opt_list username Sep.space + in Build.key_value_line Rx.word Sep.space_equal usernames + +(* View: lns *) +let lns = (Util.empty | (Util.comment_generic /[ \t]*[#;][ \t]*/ "# ") | entry)* + +(* Variable: filter *) +let filter = incl "/etc/samba/smbusers" + . incl "/etc/samba/usermap.txt" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/solaris_system.aug b/Sharp.Augeas.Test/lens/solaris_system.aug new file mode 100644 index 0000000..bb528dc --- /dev/null +++ b/Sharp.Augeas.Test/lens/solaris_system.aug @@ -0,0 +1,109 @@ +(* +Module: Solaris_System + Parses /etc/system on Solaris + +Author: Dominic Cleal <dcleal@redhat.com> + +About: Reference + This lens tries to keep as close as possible to `man 4 system` where possible. + +About: Licence + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + +About: Configuration files + This lens applies to /etc/system on Solaris. See <filter>. +*) + +module Solaris_System = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + ************************************************************************) + +(* View: comment *) +let comment = Util.comment_generic /[ \t]*\*[ \t]*/ "* " + +(* View: empty + Map empty lines, including empty asterisk comments *) +let empty = [ del /[ \t]*\*?[ \t]*\n/ "\n" ] + +(* View: sep_colon + The separator for key/value entries *) +let sep_colon = del /:[ \t]*/ ": " + +(* View: sep_moddir + The separator of directories in a moddir search path *) +let sep_moddir = del /[: ]+/ " " + +(* View: modpath + Individual moddir search path entry *) +let modpath = [ seq "modpath" . store /[^ :\t\n]+/ ] + +(* Variable: set_operator + Valid set operators: equals, bitwise AND and OR *) +let set_operators = /[=&|]/ + +(* View: set_value + Sets an integer value or char pointer *) +let set_value = [ label "value" . store Rx.no_spaces ] + +(************************************************************************ + * Group: COMMANDS + ************************************************************************) + +(* View: cmd_kv + Function for simple key/value setting commands such as rootfs *) +let cmd_kv (cmd:string) (value:regexp) = + Build.key_value_line cmd sep_colon (store value) + +(* View: cmd_moddir + The moddir command for specifying module search paths *) +let cmd_moddir = + Build.key_value_line "moddir" sep_colon + (Build.opt_list modpath sep_moddir) + +(* View: set_var + Loads the variable name from a set command, no module *) +let set_var = [ label "variable" . store Rx.word ] + +(* View: set_var + Loads the module and variable names from a set command *) +let set_varmod = [ label "module" . store Rx.word ] + . Util.del_str ":" . set_var + +(* View: set_sep_spc *) +let set_sep_spc = Util.del_opt_ws " " + +(* View: cmd_set + The set command for individual kernel/module parameters *) +let cmd_set = [ key "set" + . Util.del_ws_spc + . ( set_var | set_varmod ) + . set_sep_spc + . [ label "operator" . store set_operators ] + . set_sep_spc + . set_value + . Util.eol ] + +(************************************************************************ + * Group: LENS + ************************************************************************) + +(* View: lns *) +let lns = ( empty + | comment + | cmd_moddir + | cmd_kv "rootdev" Rx.fspath + | cmd_kv "rootfs" Rx.word + | cmd_kv "exclude" Rx.fspath + | cmd_kv "include" Rx.fspath + | cmd_kv "forceload" Rx.fspath + | cmd_set )* + +(* Variable: filter *) +let filter = (incl "/etc/system") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/soma.aug b/Sharp.Augeas.Test/lens/soma.aug new file mode 100644 index 0000000..93181ea --- /dev/null +++ b/Sharp.Augeas.Test/lens/soma.aug @@ -0,0 +1,43 @@ +(* Soma module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: man 5 soma.cfg + +*) + +module Soma = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty + +let sep_eq = del /[ \t]*=[ \t]*/ " = " + +let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + +let word = /[A-Za-z0-9_.-]+/ + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let entry = [ key word + . sep_eq + . sto_to_eol + . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let filter = incl "/etc/somad/soma.cfg" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/spacevars.aug b/Sharp.Augeas.Test/lens/spacevars.aug new file mode 100644 index 0000000..9f70b06 --- /dev/null +++ b/Sharp.Augeas.Test/lens/spacevars.aug @@ -0,0 +1,44 @@ +(* Spacevars module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: man interfaces + This is a generic lens for simple key/value configuration files where + keys and values are separated by a sequence of spaces or tabs. + +*) + +module Spacevars = + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let comment = Util.comment +let empty = Util.empty + +(************************************************************************ + * ENTRIES + *************************************************************************) + + +let entry = Build.key_ws_value /[A-Za-z0-9._-]+(\[[0-9]+\])?/ + +let flag = [ key /[A-Za-z0-9._-]+(\[[0-9]+\])?/ . Util.doseol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry|flag)* + +let simple_lns = lns (* An alias for compatibility reasons *) + +(* configuration files that can be parsed without customizing the lens *) +let filter = incl "/etc/havp/havp.config" + . incl "/etc/ldap.conf" + . incl "/etc/ldap/ldap.conf" + . incl "/etc/libnss-ldap.conf" + . incl "/etc/pam_ldap.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/splunk.aug b/Sharp.Augeas.Test/lens/splunk.aug new file mode 100644 index 0000000..f209bb5 --- /dev/null +++ b/Sharp.Augeas.Test/lens/splunk.aug @@ -0,0 +1,45 @@ +(* +Module: Splunk + Parses /opt/splunk/etc/*, /opt/splunkforwarder/etc/system/local/*.conf and /opt/splunkforwarder/etc/apps/*/(default|local)/*.conf + +Author: Tim Brigham, Jason Antman + +About: Reference + https://docs.splunk.com/Documentation/Splunk/6.5.0/Admin/AboutConfigurationFiles + +About: License + This file is licenced under the LGPL v2+ + +About: Lens Usage + Works like IniFile lens, with anonymous section for entries without enclosing section and allowing underscore-prefixed keys. + +About: Configuration files + This lens applies to conf files under /opt/splunk/etc and /opt/splunkforwarder/etc See <filter>. + +About: Examples + The <Test_Splunk> file contains various examples and tests. +*) + +module Splunk = + autoload xfm + + let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + let sep = IniFile.sep IniFile.sep_re IniFile.sep_default + let empty = IniFile.empty + + let entry_re = ( /[A-Za-z_][A-Za-z0-9._-]*/ ) + let setting = entry_re + let title = IniFile.indented_title_label "target" IniFile.record_label_re + let entry = [ key entry_re . sep . IniFile.sto_to_eol? . IniFile.eol ] | comment + + + let record = IniFile.record title entry + let anon = [ label ".anon" . (entry|empty)+ ] + let lns = anon . (record)* | (record)* + + let filter = incl "/opt/splunk/etc/system/local/*.conf" + . incl "/opt/splunk/etc/apps/*/local/*.conf" + . incl "/opt/splunkforwarder/etc/system/local/*.conf" + . incl "/opt/splunkforwarder/etc/apps/*/default/*.conf" + . incl "/opt/splunkforwarder/etc/apps/*/local/*.conf" + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/squid.aug b/Sharp.Augeas.Test/lens/squid.aug new file mode 100644 index 0000000..aacf787 --- /dev/null +++ b/Sharp.Augeas.Test/lens/squid.aug @@ -0,0 +1,438 @@ +(* Squid module for Augeas + Author: Free Ekanayaka <free@64studio.com> + + Reference: the self-documented default squid.conf file + +*) + +module Squid = + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let spc = Util.del_ws_spc +let indent = Util.indent + +let word = /[A-Za-z0-9!_.-]+(\[[0-9]+\])?/ +let sto_to_spc = store /[^# \t\n]+/ +let sto_to_eol = store /([^# \t\n][^#\n]*[^# \t\n])|[^# \t\n]/ + +let comment = Util.comment +let empty = Util.empty +let comment_or_eol = Util.comment_or_eol +let value (kw:string) + = [ spc . label kw . sto_to_spc ] + +let value_space_in (kw:string) + = [ spc . label kw . sto_to_eol ] + +let parameters = [ label "parameters" + . counter "parameters" + . [ spc . seq "parameters" . sto_to_spc ]+ ] + +(************************************************************************ + * SPACEVARS SETTINGS + *************************************************************************) + +let entry_re = "accept_filter" + | "access_log" + | "acl_uses_indirect_client" + | "adaptation_access" + | "adaptation_service_set" + | "allow_underscore" + | "always_direct" + | "announce_file" + | "announce_host" + | "announce_period" + | "announce_port" + | "append_domain" + | "as_whois_server" + | "authenticate_cache_garbage_interval" + | "authenticate_ip_shortcircuit_access" + | "authenticate_ip_shortcircuit_ttl" + | "authenticate_ip_ttl" + | "authenticate_ttl" + | "background_ping_rate" + | "balance_on_multiple_ip" + | "broken_posts" + | "buffered_logs" + | "cache" + | "cache_dir" + | "cache_dns_program" + | "cache_effective_group" + | "cache_effective_user" + | "cache_log" + | "cache_mem" + | "cache_mgr" + | "cachemgr_passwd" + | "cache_peer" + | "cache_peer_access" + | "cache_peer_domain" + | "cache_replacement_policy" + | "cache_store_log" + | "cache_swap_high" + | "cache_swap_low" + | "cache_swap_state" + | "cache_vary" + | "check_hostnames" + | "chroot" + | "client_db" + | "client_lifetime" + | "client_netmask" + | "client_persistent_connections" + | "clientside_tos" + | "collapsed_forwarding" + | "connect_timeout" + | "coredump_dir" + | "dead_peer_timeout" + | "debug_options" + | "delay_access" + | "delay_class" + | "delay_initial_bucket_level" + | "delay_parameters" + | "delay_pools" + | "delay_pool_uses_indirect_client" + | "deny_info" + | "detect_broken_pconn" + | "digest_bits_per_entry" + | "digest_generation" + | "digest_rebuild_chunk_percentage" + | "digest_rebuild_period" + | "digest_rewrite_period" + | "digest_swapout_chunk_size" + | "diskd_program" + | "dns_children" + | "dns_defnames" + | "dns_nameservers" + | "dns_retransmit_interval" + | "dns_testnames" + | "dns_timeout" + | "dns_v4_fallback" + | "ecap_enable" + | "ecap_service" + | "email_err_data" + | "emulate_httpd_log" + | "err_html_text" + | "error_default_language" + | "error_directory" + | "error_log_languages" + | "error_map" + | "err_page_stylesheet" + | "esi_parser" + | "external_acl_type" + | "external_refresh_check" + | "follow_x_forwarded_for" + | "forwarded_for" + | "forward_log" + | "forward_timeout" + | "fqdncache_size" + | "ftp_epsv_all" + | "ftp_list_width" + | "ftp_passive" + | "ftp_sanitycheck" + | "ftp_telnet_protocol" + | "ftp_user" + | "global_internal_static" + | "half_closed_clients" + | "header_access" + | "header_replace" + | "hierarchy_stoplist" + | "high_memory_warning" + | "high_page_fault_warning" + | "high_response_time_warning" + | "hostname_aliases" + | "hosts_file" + | "htcp_access" + | "htcp_clr_access" + | "htcp_port" + | "http_accel_surrogate_remote" + | "http_access2" + | "httpd_accel_no_pmtu_disc" + | "httpd_accel_surrogate_id" + | "httpd_suppress_version_string" + | "http_port" + | "http_reply_access" + | "https_port" + | "icap_access" + | "icap_class" + | "icap_client_username_encode" + | "icap_client_username_header" + | "icap_connect_timeout" + | "icap_default_options_ttl" + | "icap_enable" + | "icap_io_timeout" + | "icap_persistent_connections" + | "icap_preview_enable" + | "icap_preview_size" + | "icap_send_client_ip" + | "icap_send_client_username" + | "icap_service" + | "icap_service_failure_limit" + | "icap_service_revival_delay" + | "icon_directory" + | "icp_access" + | "icp_hit_stale" + | "icp_port" + | "icp_query_timeout" + | "ident_lookup_access" + | "ident_timeout" + | "ie_refresh" + | "ignore_expect_100" + | "ignore_ims_on_miss" + | "ignore_unknown_nameservers" + | "incoming_dns_average" + | "incoming_http_average" + | "incoming_icp_average" + | "incoming_rate" + | "ipcache_high" + | "ipcache_low" + | "ipcache_size" + | "loadable_modules" + | "location_rewrite_access" + | "location_rewrite_children" + | "location_rewrite_concurrency" + | "location_rewrite_program" + | "log_access" + | "logfile_daemon" + | "logfile_rotate" + | "logformat" + | "log_fqdn" + | "log_icp_queries" + | "log_ip_on_direct" + | "log_mime_hdrs" + | "log_uses_indirect_client" + | "mail_from" + | "mail_program" + | "max_filedescriptors" + | "maximum_icp_query_timeout" + | "maximum_object_size" + | "maximum_object_size_in_memory" + | "maximum_single_addr_tries" + | "max_open_disk_fds" + | "max_stale" + | "mcast_groups" + | "mcast_icp_query_timeout" + | "mcast_miss_addr" + | "mcast_miss_encode_key" + | "mcast_miss_port" + | "mcast_miss_ttl" + | "memory_pools" + | "memory_pools_limit" + | "memory_replacement_policy" + | "mime_table" + | "min_dns_poll_cnt" + | "min_http_poll_cnt" + | "min_icp_poll_cnt" + | "minimum_direct_hops" + | "minimum_direct_rtt" + | "minimum_expiry_time" + | "minimum_icp_query_timeout" + | "minimum_object_size" + | "miss_access" + | "negative_dns_ttl" + | "negative_ttl" + | "neighbor_type_domain" + | "netdb_filename" + | "netdb_high" + | "netdb_low" + | "netdb_ping_period" + | "never_direct" + | "no_cache" + | "nonhierarchical_direct" + | "offline_mode" + | "pconn_timeout" + | "peer_connect_timeout" + | "persistent_connection_after_error" + | "persistent_request_timeout" + | "pid_filename" + | "pinger_enable" + | "pinger_program" + | "pipeline_prefetch" + | "positive_dns_ttl" + | "prefer_direct" + | "qos_flows" + | "query_icmp" + | "quick_abort_max" + | "quick_abort_min" + | "quick_abort_pct" + | "range_offset_limit" + | "read_ahead_gap" + | "read_timeout" + | "redirector_bypass" + | "referer_log" + | "refresh_all_ims" + | "refresh_stale_hit" + | "relaxed_header_parser" + | "reload_into_ims" + | "reply_body_max_size" + | "reply_header_access" + | "reply_header_max_size" + | "request_body_max_size" + | "request_entities" + | "request_header_access" + | "request_header_max_size" + | "request_timeout" + | "retry_on_error" + | "server_http11" + | "server_persistent_connections" + | "short_icon_urls" + | "shutdown_lifetime" + | "sleep_after_fork" + | "snmp_access" + | "snmp_incoming_address" + | "snmp_outgoing_address" + | "snmp_port" + | "ssl_bump" + | "ssl_engine" + | "sslpassword_program" + | "sslproxy_cafile" + | "sslproxy_capath" + | "sslproxy_cert_error" + | "sslproxy_cipher" + | "sslproxy_client_certificate" + | "sslproxy_client_key" + | "sslproxy_flags" + | "sslproxy_options" + | "sslproxy_version" + | "ssl_unclean_shutdown" + | "store_avg_object_size" + | "store_dir_select_algorithm" + | "store_objects_per_bucket" + | "storeurl_access" + | "storeurl_rewrite_children" + | "storeurl_rewrite_concurrency" + | "storeurl_rewrite_program" + | "strip_query_terms" + | "tcp_outgoing_address" + | "tcp_outgoing_tos" + | "tcp_recv_bufsize" + | "test_reachability" + | "udp_incoming_address" + | "udp_outgoing_address" + | "umask" + | "unique_hostname" + | "unlinkd_program" + | "update_headers" + | "uri_whitespace" + | "url_rewrite_access" + | "url_rewrite_bypass" + | "url_rewrite_children" + | "url_rewrite_concurrency" + | "url_rewrite_host_header" + | "url_rewrite_program" + | "useragent_log" + | "vary_ignore_expire" + | "via" + | "visible_hostname" + | "wccp2_address" + | "wccp2_assignment_method" + | "wccp2_forwarding_method" + | "wccp2_rebuild_wait" + | "wccp2_return_method" + | "wccp2_router" + | "wccp2_service" + | "wccp2_service_info" + | "wccp2_weight" + | "wccp_address" + | "wccp_router" + | "wccp_version" + | "windows_ipaddrchangemonitor" + | "zero_buffers" + | "zph_local" + | "zph_mode" + | "zph_option" + | "zph_parent" + | "zph_sibling" + +let entry = indent . (Build.key_ws_value entry_re) + +(************************************************************************ + * AUTH + *************************************************************************) + +let auth_re = "auth_param" +let auth = indent + . [ key "auth_param" + . value "scheme" + . value "parameter" + . (value_space_in "setting") ? + . comment_or_eol ] + +(************************************************************************ + * ACL + *************************************************************************) + +let acl_re = "acl" +let acl = indent + . [ key acl_re . spc + . [ key word + . value "type" + . value "setting" + . parameters? + . comment_or_eol ] ] + +(************************************************************************ + * HTTP ACCESS + *************************************************************************) + +let http_access_re + = "http_access" + | "upgrade_http0.9" + | "broken_vary_encoding" + +let http_access + = indent + . [ key http_access_re + . spc + . [ key /allow|deny/ + . spc + . sto_to_spc + . parameters? ] + . comment_or_eol ] + +(************************************************************************ + * REFRESH PATTERN + *************************************************************************) + +let refresh_pattern_option_re = "override-expire" + | "override-lastmod" + | "reload-into-ims" + | "ignore-reload" + | "ignore-no-cache" + | "ignore-no-store" + | "ignore-must-revalidate" + | "ignore-private" + | "ignore-auth" + | "refresh-ims" + | "store-stale" + +let refresh_pattern = indent . [ key "refresh_pattern" . spc + . [ label "case_insensitive" . Util.del_str "-i" . spc ]? + . store /[^ \t\n]+/ . spc + . [ label "min" . store Rx.integer ] . spc + . [ label "percent" . store Rx.integer . Util.del_str "%" ] . spc + . [ label "max" . store Rx.integer ] + . (spc . Build.opt_list [ label "option" . store refresh_pattern_option_re ] spc)? + . comment_or_eol ] + +(************************************************************************ + * EXTENSION METHODS + *************************************************************************) + +let extension_methods = indent . [ key "extension_methods" . spc + . Build.opt_list [ seq "extension_method" . store Rx.word ] spc + . comment_or_eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry|auth|acl|http_access|refresh_pattern|extension_methods)* + +let filter = incl "/etc/squid/squid.conf" + . incl "/etc/squid3/squid.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/ssh.aug b/Sharp.Augeas.Test/lens/ssh.aug new file mode 100644 index 0000000..e9585d3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/ssh.aug @@ -0,0 +1,134 @@ +(* +Module: Ssh + Parses ssh client configuration + +Author: Jiri Suchomel <jsuchome@suse.cz> + +About: Reference + ssh_config man page + +About: License + This file is licensed under the GPL. + +About: Lens Usage + Sample usage of this lens in augtool + +(start code) +augtool> set /files/etc/ssh/ssh_config/Host example.com +augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/RemoteForward/machine1:1234 machine2:5678 +augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/Ciphers/1 aes128-ctr +augtool> set /files/etc/ssh/ssh_config/Host[.='example.com']/Ciphers/2 aes192-ctr +(end code) + +*) + +module Ssh = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + let eol = Util.doseol + let spc = Util.del_ws_spc + let spc_eq = del /[ \t]+|[ \t]*=[ \t]*/ " " + let comment = Util.comment + let empty = Util.empty + let comma = Util.del_str "," + let indent = Util.indent + let value_to_eol = store Rx.space_in + let value_to_spc = store /[^ \t\r\n=][^ \t\r\n]*/ + let value_to_comma = store /[^, \t\r\n=][^, \t\r\n]*/ + + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + + let array_entry (k:regexp) = + [ indent . key k . counter "array_entry" + . [ spc . seq "array_entry" . value_to_spc]* . eol ] + + let commas_entry (k:regexp) = + let value = [ seq "commas_entry" . value_to_comma] + in [ indent . key k . counter "commas_entry" . spc_eq . + Build.opt_list value comma . eol ] + + let spaces_entry (k:regexp) = + let value = [ seq "spaces_entry" . value_to_spc ] + in [ indent . key k . counter "spaces_entry" . spc_eq . + Build.opt_list value spc . eol ] + + let fw_entry (k:regexp) = [ indent . key k . spc_eq . + [ key /[^ \t\r\n\/=][^ \t\r\n\/]*/ . spc . value_to_eol . eol ]] + + let send_env = array_entry /SendEnv/i + + let proxy_command = [ indent . key /ProxyCommand/i . spc . value_to_eol . eol ] + + let remote_fw = fw_entry /RemoteForward/i + let local_fw = fw_entry /LocalForward/i + + let ciphers = commas_entry /Ciphers/i + let macs = commas_entry /MACs/i + let algorithms = commas_entry /(HostKey|Kex)Algorithms/i + let pubkey_accepted_key_types = commas_entry /PubkeyAcceptedKeyTypes/i + + let global_knownhosts_file = spaces_entry /GlobalKnownHostsFile/i + + let rekey_limit = [ indent . key /RekeyLimit/i . spc_eq . + [ label "amount" . value_to_spc ] . + [ spc . label "duration" . value_to_spc ]? . eol ] + + let special_entry = send_env + | proxy_command + | remote_fw + | local_fw + | macs + | ciphers + | algorithms + | pubkey_accepted_key_types + | global_knownhosts_file + | rekey_limit + + let key_re = /[A-Za-z0-9]+/ + - /SendEnv|Host|Match|ProxyCommand|RemoteForward|LocalForward|MACs|Ciphers|(HostKey|Kex)Algorithms|PubkeyAcceptedKeyTypes|GlobalKnownHostsFile|RekeyLimit/i + + + let other_entry = [ indent . key key_re + . spc_eq . value_to_spc . eol ] + + let entry = comment | empty + | special_entry + | other_entry + + let host = [ key /Host/i . spc . value_to_eol . eol . entry* ] + + + let condition_entry = + let k = /[A-Za-z0-9]+/ in + let no_spc = Quote.do_dquote_opt (store /[^"' \t\r\n=]+/) in + let with_spc = Quote.do_quote (store /[^"'\t\r\n]* [^"'\t\r\n]*/) in + [ spc . key k . spc . no_spc ] + | [ spc . key k . spc . with_spc ] + + let match_cond = + [ label "Condition" . condition_entry+ . eol ] + + let match_entry = entry + + let match = + [ key /Match/i . match_cond + . [ label "Settings" . match_entry+ ] + ] + + +(************************************************************************ + * Group: LENS + *************************************************************************) + + let lns = entry* . (host | match)* + + let xfm = transform lns (incl "/etc/ssh/ssh_config" . + incl (Sys.getenv("HOME") . "/.ssh/config") . + incl "/etc/ssh/ssh_config.d/*.conf") diff --git a/Sharp.Augeas.Test/lens/sshd.aug b/Sharp.Augeas.Test/lens/sshd.aug new file mode 100644 index 0000000..398f836 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sshd.aug @@ -0,0 +1,151 @@ +(* +Module: Sshd + Parses /etc/ssh/sshd_config + +Author: David Lutterkort lutter@redhat.com + Dominique Dumont dominique.dumont@hp.com + +About: Reference + sshd_config man page. + See http://www.openbsd.org/cgi-bin/man.cgi?query=sshd_config&sektion=5 + +About: License + This file is licensed under the LGPL v2+. + +About: Lens Usage + Sample usage of this lens in augtool: + + * Get your current setup + > print /files/etc/ssh/sshd_config + ... + + * Set X11Forwarding to "no" + > set /files/etc/ssh/sshd_config/X11Forwarding "no" + + More advanced usage: + + * Set a Match section + > set /files/etc/ssh/sshd_config/Match[1]/Condition/User "foo" + > set /files/etc/ssh/sshd_config/Match[1]/Settings/X11Forwarding "yes" + + Saving your file: + + > save + + +About: CAVEATS + + In sshd_config, Match blocks must be located at the end of the file. + This means that any new "global" parameters (i.e. outside of a Match + block) must be written before the first Match block. By default, + Augeas will write new parameters at the end of the file. + + I.e. if you have a Match section and no ChrootDirectory parameter, + this command: + + > set /files/etc/ssh/sshd_config/ChrootDirectory "foo" + + will be stored in a new node after the Match section and Augeas will + refuse to save sshd_config file. + + To create a new parameter as the right place, you must first create + a new Augeas node before the Match section: + + > ins ChrootDirectory before /files/etc/ssh/sshd_config/Match + + Then, you can set the parameter + + > set /files/etc/ssh/sshd_config/ChrootDirectory "foo" + + +About: Configuration files + This lens applies to /etc/ssh/sshd_config + +*) + +module Sshd = + autoload xfm + + let eol = del /[ \t]*\n/ "\n" + + let sep = del /[ \t=]+/ " " + + let indent = del /[ \t]*/ " " + + let key_re = /[A-Za-z0-9]+/ + - /MACs|Match|AcceptEnv|Subsystem|Ciphers|(Kex|HostKey)Algorithms|(Allow|Deny)(Groups|Users)/i + + let comment = Util.comment + let comment_noindent = Util.comment_noindent + let empty = Util.empty + + let array_entry (kw:regexp) (sq:string) = + let bare = Quote.do_quote_opt_nil (store /[^"' \t\n=]+/) in + let quoted = Quote.do_quote (store /[^"'\n]*[ \t]+[^"'\n]*/) in + [ key kw + . ( [ sep . seq sq . bare ] | [ sep . seq sq . quoted ] )* + . eol ] + + let other_entry = + let value = store /[^ \t\n=]+([ \t=]+[^ \t\n=]+)*/ in + [ key key_re . sep . value . eol ] + + let accept_env = array_entry /AcceptEnv/i "AcceptEnv" + + let allow_groups = array_entry /AllowGroups/i "AllowGroups" + let allow_users = array_entry /AllowUsers/i "AllowUsers" + let deny_groups = array_entry /DenyGroups/i "DenyGroups" + let deny_users = array_entry /DenyUsers/i "DenyUsers" + + let subsystemvalue = + let value = store (/[^ \t\n=](.*[^ \t\n=])?/) in + [ key /[A-Za-z0-9\-]+/ . sep . value . eol ] + + let subsystem = + [ key /Subsystem/i . sep . subsystemvalue ] + + let list (kw:regexp) (sq:string) = + let value = store /[^, \t\n=]+/ in + [ key kw . sep . + [ seq sq . value ] . + ([ seq sq . Util.del_str "," . value])* . + eol ] + + let macs = list /MACs/i "MACs" + + let ciphers = list /Ciphers/i "Ciphers" + + let kexalgorithms = list /KexAlgorithms/i "KexAlgorithms" + + let hostkeyalgorithms = list /HostKeyAlgorithms/i "HostKeyAlgorithms" + + let entry = accept_env | allow_groups | allow_users + | deny_groups | subsystem | deny_users + | macs | ciphers | kexalgorithms | hostkeyalgorithms + | other_entry + + let condition_entry = + let k = /[A-Za-z0-9]+/ in + let no_spc = Quote.do_dquote_opt (store /[^"' \t\n=]+/) in + let spc = Quote.do_quote (store /[^"'\t\n]* [^"'\t\n]*/) in + [ sep . key k . sep . no_spc ] + | [ sep . key k . sep . spc ] + + let match_cond = + [ label "Condition" . condition_entry+ . eol ] + + let match_entry = indent . (entry | comment_noindent) + | empty + + let match = + [ key /Match/i . match_cond + . [ label "Settings" . match_entry+ ] + ] + + let lns = (entry | comment | empty)* . match* + + let xfm = transform lns (incl "/etc/ssh/sshd_config") + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/sssd.aug b/Sharp.Augeas.Test/lens/sssd.aug new file mode 100644 index 0000000..d854554 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sssd.aug @@ -0,0 +1,39 @@ +(* +Module Sssd + Lens for parsing sssd.conf + +Author: Erinn Looney-Triggs <erinn.looneytriggs@gmail.com> + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + +About: Configuration files + This lens applies to /etc/sssd/sssd.conf. See <filter>. +*) + +module Sssd = + autoload xfm + +let comment = IniFile.comment /[#;]/ "#" + +let sep = IniFile.sep "=" "=" + +let entry = IniFile.indented_entry IniFile.entry_re sep comment + +(* View: title + An sssd.conf section title *) +let title = IniFile.indented_title_label "target" IniFile.record_label_re + +(* View: record + An sssd.conf record *) +let record = IniFile.record title entry + +(* View: lns + The sssd.conf lens *) +let lns = ( comment | IniFile.empty )* . (record)* + +(* View: filter *) +let filter = (incl "/etc/sssd/sssd.conf") + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/star.aug b/Sharp.Augeas.Test/lens/star.aug new file mode 100644 index 0000000..b8c0a44 --- /dev/null +++ b/Sharp.Augeas.Test/lens/star.aug @@ -0,0 +1,31 @@ +(* +Module: Star + Parses star's configuration file + +Author: Cedric Bosdonnat <cbosdonnat@suse.com> + +About: Reference + This lens is based on star(1) + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Star = + autoload xfm + +let sto_to_tab = store Rx.no_spaces + +let size = Build.key_value_line "STAR_FIFOSIZE" Sep.space_equal ( store /[0-9x*.a-z]+/ ) +let size_max = Build.key_value_line "STAR_FIFOSIZE_MAX" Sep.space_equal ( store /[0-9x*.a-z]+/ ) +let archive = Build.key_value_line ( "archive". /[0-7]/ ) Sep.equal + ( [ label "device" . sto_to_tab ] . Sep.tab . + [ label "block" . sto_to_tab ] . Sep.tab . + [ label "size" . sto_to_tab ] . ( Sep.tab . + [ label "istape" . sto_to_tab ] )? ) + +let lns = ( size | size_max | archive | Util.comment | Util.empty )* + +let filter = incl "/etc/default/star" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/strongswan.aug b/Sharp.Augeas.Test/lens/strongswan.aug new file mode 100644 index 0000000..32b79fa --- /dev/null +++ b/Sharp.Augeas.Test/lens/strongswan.aug @@ -0,0 +1,51 @@ +(* +Module: Strongswan + Lens for parsing strongSwan configuration files + +Authors: + Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> + +About: Reference + strongswan.conf(5), swanctl.conf(5) + +About: License + This file is licensed under the LGPL v2+ +*) + +module Strongswan = + +autoload xfm + +let ws = del /[\n\t ]*(#[\t ]*\n[\n\t ]*)*/ + +let rec conf = + let keys = /[^\/.\{\}#\n\t ]+/ - /include/ + in let lists = /(crl|oscp)_uris|(local|remote)_(addrs|ts)|vips|pools|(ca)?certs|pubkeys|groups|cert_policy|dns|nbns|dhcp|netmask|server|subnet|split_(in|ex)clude|interfaces_(ignore|use)|preferred/ + in let proposals = /((ah|esp)_)?proposals/ + in let name (pat:lens) (sep:string) = + pat . Util.del_ws_spc . Util.del_str sep + in let val = store /[^\n\t ].*/ . Util.del_str "\n" . ws "" + in let sval = Util.del_ws_spc . val + in let ival (pat:lens) (end:string) = + Util.del_opt_ws " " . seq "item" . pat . Util.del_str end + in let list (l:string) (k:regexp) (v:lens) = + [ label l . name (store k) "=" . counter "item" . + [ ival v "," ]* . [ ival v "\n" ] . ws "" ] + in let alg = seq "alg" . store /[a-z0-9]+/ +in ( + [ Util.del_str "#" . label "#comment" . Util.del_opt_ws " " . val ] | + [ key "include" . sval ] | + [ name (key (keys - lists - proposals)) "=" . sval ] | + list "#list" lists (store /[^\n\t ,][^\n,]*/) | + list "#proposals" proposals (counter "alg" . [ alg ] . [ Util.del_str "-" . alg ]*) | + [ name (key keys) "{" . ws "\n" . conf . Util.del_str "}" . ws "\n" ] +)* + +let lns = ws "" . conf + +let xfm = transform lns ( + incl "/etc/strongswan.d/*.conf" . + incl "/etc/strongswan.d/**/*.conf" . + incl "/etc/swanctl/conf.d/*.conf" . + incl "/etc/swanctl/swanctl.conf" +) diff --git a/Sharp.Augeas.Test/lens/stunnel.aug b/Sharp.Augeas.Test/lens/stunnel.aug new file mode 100644 index 0000000..59a816a --- /dev/null +++ b/Sharp.Augeas.Test/lens/stunnel.aug @@ -0,0 +1,80 @@ +(* Stunnel configuration file module for Augeas *) + +module Stunnel = + autoload xfm + + let comment = IniFile.comment IniFile.comment_re IniFile.comment_default + let sep = IniFile.sep "=" "=" + + let setting = "chroot" + | "compression" + | "debug" + | "EGD" + | "engine" + | "engineCtrl" + | "fips" + | "foreground" + | "output" + | "pid" + | "RNDbytes" + | "RNDfile" + | "RNDoverwrite" + | "service" + | "setgid" + | "setuid" + | "socket" + | "syslog" + | "taskbar" + | "accept" + | "CApath" + | "CAfile" + | "cert" + | "ciphers" + | "client" + | "connect" + | "CRLpath" + | "CRLfile" + | "curve" + | "delay" + | "engineNum" + | "exec" + | "execargs" + | "failover" + | "ident" + | "key" + | "local" + | "OCSP" + | "OCSPflag" + | "options" + | "protocol" + | "protocolAuthentication" + | "protocolHost" + | "protocolPassword" + | "protocolUsername" + | "pty" + | "retry" + | "session" + | "sessiond" + | "sni" + | "sslVersion" + | "stack" + | "TIMEOUTbusy" + | "TIMEOUTclose" + | "TIMEOUTconnect" + | "TIMEOUTidle" + | "transparent" + | "verify" + + let entry = IniFile.indented_entry setting sep comment + let empty = IniFile.empty + + let title = IniFile.indented_title ( IniFile.record_re - ".anon" ) + let record = IniFile.record title entry + + let rc_anon = [ label ".anon" . ( entry | empty )+ ] + + let lns = rc_anon? . record* + + let filter = (incl "/etc/stunnel/stunnel.conf") + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/subversion.aug b/Sharp.Augeas.Test/lens/subversion.aug new file mode 100644 index 0000000..57d4393 --- /dev/null +++ b/Sharp.Augeas.Test/lens/subversion.aug @@ -0,0 +1,96 @@ +(* +Module: Subversion + Parses subversion's INI files + +Authors: + Marc Fournier <marc.fournier@camptocamp.com> + Raphael Pinson <raphael.pinson@camptocamp.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Examples + The <Test_Subversion> file contains various examples and tests. + +*) + +module Subversion = +autoload xfm + +(************************************************************************ + * Group: INI File settings + * + * subversion only supports comments starting with "#" + * + *************************************************************************) + +(* View: comment *) +let comment = IniFile.comment_noindent "#" "#" + +(* View: empty + An empty line or a non-indented empty comment *) +let empty = IniFile.empty_noindent + +(* View: sep *) +let sep = IniFile.sep IniFile.sep_default IniFile.sep_default + +(************************************************************************ + * Group: ENTRY + * + * subversion doesn't support indented entries + * + *************************************************************************) + +(* Variable: comma_list_re *) +let comma_list_re = "password-stores" + +(* Variable: space_list_re *) +let space_list_re = "global-ignores" | "preserved-conflict-file-exts" + +(* Variable: std_re *) +let std_re = /[^ \t\r\n\/=#]+/ - (comma_list_re | space_list_re) + +(* View: entry_std + A standard entry + Similar to a <IniFile.entry_multiline_nocomment> entry, + but allows ';' *) +let entry_std = + IniFile.entry_multiline_generic (key std_re) sep "#" comment IniFile.eol + +(* View: entry *) +let entry = + let comma_list_re = "password-stores" + in let space_list_re = "global-ignores" | "preserved-conflict-file-exts" + in let std_re = /[^ \t\r\n\/=#]+/ - (comma_list_re | space_list_re) + in entry_std + | IniFile.entry_list_nocomment comma_list_re sep Rx.word Sep.comma + | IniFile.entry_list_nocomment space_list_re sep Rx.no_spaces (del /(\r?\n)?[ \t]+/ " ") + + + +(************************************************************************ + * Group: TITLE + * + * subversion doesn't allow anonymous entries (outside sections) + * + *************************************************************************) + +(* View: title *) +let title = IniFile.title IniFile.entry_re + +(* View: record + Use the non-indented <empty> *) +let record = IniFile.record_noempty title (entry|empty) + +(************************************************************************ + * Group: LENS & FILTER + *************************************************************************) + +(* View: lns *) +let lns = IniFile.lns record comment + +(* Variable: filter *) +let filter = incl "/etc/subversion/config" + . incl "/etc/subversion/servers" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/sudoers.aug b/Sharp.Augeas.Test/lens/sudoers.aug new file mode 100644 index 0000000..f90b629 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sudoers.aug @@ -0,0 +1,549 @@ +(* +Module: Sudoers + Parses /etc/sudoers + +Author: Raphael Pinson <raphink@gmail.com> + +About: Reference + This lens tries to keep as close as possible to `man sudoers` where possible. + +For example, recursive definitions such as + + > Cmnd_Spec_List ::= Cmnd_Spec | + > Cmnd_Spec ',' Cmnd_Spec_List + +are replaced by + + > let cmnd_spec_list = cmnd_spec . ( sep_com . cmnd_spec )* + +since Augeas cannot deal with recursive definitions. +The definitions from `man sudoers` are put as commentaries for reference +throughout the file. More information can be found in the manual. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. + + +About: Lens Usage + Sample usage of this lens in augtool + + * Set first Defaults to apply to the "LOCALNET" network alias + > set /files/etc/sudoers/Defaults[1]/type "@LOCALNET" + * List all user specifications applying explicitly to the "admin" Unix group + > match /files/etc/sudoers/spec/user "%admin" + * Remove the full 3rd user specification + > rm /files/etc/sudoers/spec[3] + +About: Configuration files + This lens applies to /etc/sudoers. See <filter>. +*) + + + +module Sudoers = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Generic primitives *) +(* Variable: eol *) +let eol = Util.eol + +(* Variable: indent *) +let indent = Util.indent + + +(* Group: Separators *) + +(* Variable: sep_spc *) +let sep_spc = Sep.space + +(* Variable: sep_cont *) +let sep_cont = Sep.cl_or_space + +(* Variable: sep_cont_opt *) +let sep_cont_opt = Sep.cl_or_opt_space + +(* Variable: sep_cont_opt_build *) +let sep_cont_opt_build (sep:string) = + del (Rx.cl_or_opt_space . sep . Rx.cl_or_opt_space) (" " . sep . " ") + +(* Variable: sep_com *) +let sep_com = sep_cont_opt_build "," + +(* Variable: sep_eq *) +let sep_eq = sep_cont_opt_build "=" + +(* Variable: sep_col *) +let sep_col = sep_cont_opt_build ":" + +(* Variable: sep_dquote *) +let sep_dquote = Util.del_str "\"" + +(* Group: Negation expressions *) + +(************************************************************************ + * View: del_negate + * Delete an even number of '!' signs + *************************************************************************) +let del_negate = del /(!!)*/ "" + +(************************************************************************ + * View: negate_node + * Negation of boolean values for <defaults>. Accept one optional '!' + * and produce a 'negate' node if there is one. + *************************************************************************) +let negate_node = [ del "!" "!" . label "negate" ] + +(************************************************************************ + * View: negate_or_value + * A <del_negate>, followed by either a negated key, or a key/value pair + *************************************************************************) +let negate_or_value (key:lens) (value:lens) = + [ del_negate . (negate_node . key | key . value) ] + +(* Group: Stores *) + +(* Variable: sto_to_com_cmnd +sto_to_com_cmnd does not begin or end with a space *) + +let sto_to_com_cmnd = del_negate . negate_node? . ( + let alias = Rx.word - /(NO)?(PASSWD|EXEC|SETENV)/ + in let non_alias = /[\/a-z]([^,:#()\n\\]|\\\\[=:,\\])*[^,=:#() \t\n\\]|[^,=:#() \t\n\\]/ + in store (alias | non_alias)) + +(* Variable: sto_to_com + +There could be a \ in the middle of a command *) +let sto_to_com = store /([^,=:#() \t\n\\][^,=:#()\n]*[^,=:#() \t\n\\])|[^,=:#() \t\n\\]/ + +(* Variable: sto_to_com_host *) +let sto_to_com_host = store /[^,=:#() \t\n\\]+/ + + +(* Variable: sto_to_com_user +Escaped spaces and NIS domains and allowed*) +let sto_to_com_user = + let nis_re = /([A-Z]([-A-Z0-9]|(\\\\[ \t]))*+\\\\\\\\)/ + in let user_re = /[%+@a-z]([-A-Za-z0-9._+]|(\\\\[ \t])|\\\\\\\\[A-Za-z0-9])*/ - /@include(dir)?/ + in let alias_re = /[A-Z_]+/ + in store ((nis_re? . user_re) | alias_re) + +(* Variable: to_com_chars *) +let to_com_chars = /[^",=#() \t\n\\]+/ (* " relax emacs *) + +(* Variable: to_com_dquot *) +let to_com_dquot = /"[^",=#()\n\\]+"/ (* " relax emacs *) + +(* Variable: sto_to_com_dquot *) +let sto_to_com_dquot = store (to_com_chars|to_com_dquot) + +(* Variable: sto_to_com_col *) +let sto_to_com_col = store to_com_chars + +(* Variable: sto_to_eq *) +let sto_to_eq = store /[^,=:#() \t\n\\]+/ + +(* Variable: sto_to_spc *) +let sto_to_spc = store /[^", \t\n\\]+|"[^", \t\n\\]+"/ + +(* Variable: sto_to_spc_no_dquote *) +let sto_to_spc_no_dquote = store /[^",# \t\n\\]+/ (* " relax emacs *) + +(* Variable: sto_integer *) +let sto_integer = store /-?[0-9]+/ + + +(* Group: Comments and empty lines *) + +(* View: comment +Map comments in "#comment" nodes *) +let comment = + let sto_to_eol = store (/([^ \t\n].*[^ \t\n]|[^ \t\n])/ - /include(dir)?.*/) in + [ label "#comment" . del /[ \t]*#[ \t]*/ "# " . sto_to_eol . eol ] + +(* View: comment_eol +Requires a space before the # *) +let comment_eol = Util.comment_generic /[ \t]+#[ \t]*/ " # " + +(* View: comment_or_eol +A <comment_eol> or <eol> *) +let comment_or_eol = comment_eol | (del /([ \t]+#\n|[ \t]*\n)/ "\n") + +(* View: empty +Map empty lines *) +let empty = [ del /[ \t]*#?[ \t]*\n/ "\n" ] + +(* View: includedir *) +let includedir = + [ key /(#|@)include(dir)?/ . Sep.space . store Rx.fspath . eol ] + + +(************************************************************************ + * Group: ALIASES + *************************************************************************) + +(************************************************************************ + * View: alias_field + * Generic alias field to gather all Alias definitions + * + * Definition: + * > User_Alias ::= NAME '=' User_List + * > Runas_Alias ::= NAME '=' Runas_List + * > Host_Alias ::= NAME '=' Host_List + * > Cmnd_Alias ::= NAME '=' Cmnd_List + * + * Parameters: + * kw:string - the label string + * sto:lens - the store lens + *************************************************************************) +let alias_field (kw:string) (sto:lens) = [ label kw . sto ] + +(* View: alias_list + List of <alias_fields>, separated by commas *) +let alias_list (kw:string) (sto:lens) = + Build.opt_list (alias_field kw sto) sep_com + +(************************************************************************ + * View: alias_name + * Name of an <alias_entry_single> + * + * Definition: + * > NAME ::= [A-Z]([A-Z][0-9]_)* + *************************************************************************) +let alias_name + = [ label "name" . store /[A-Z][A-Z0-9_]*/ ] + +(************************************************************************ + * View: alias_entry_single + * Single <alias_entry>, named using <alias_name> and listing <alias_list> + * + * Definition: + * > Alias_Type NAME = item1, item2, ... + * + * Parameters: + * field:string - the field name, passed to <alias_list> + * sto:lens - the store lens, passed to <alias_list> + *************************************************************************) +let alias_entry_single (field:string) (sto:lens) + = [ label "alias" . alias_name . sep_eq . alias_list field sto ] + +(************************************************************************ + * View: alias_entry + * Alias entry, a list of comma-separated <alias_entry_single> fields + * + * Definition: + * > Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 + * + * Parameters: + * kw:string - the alias keyword string + * field:string - the field name, passed to <alias_entry_single> + * sto:lens - the store lens, passed to <alias_entry_single> + *************************************************************************) +let alias_entry (kw:string) (field:string) (sto:lens) + = [ indent . key kw . sep_cont . alias_entry_single field sto + . ( sep_col . alias_entry_single field sto )* . comment_or_eol ] + +(* TODO: go further in user definitions *) +(* View: user_alias + User_Alias, see <alias_field> *) +let user_alias = alias_entry "User_Alias" "user" sto_to_com +(* View: runas_alias + Run_Alias, see <alias_field> *) +let runas_alias = alias_entry "Runas_Alias" "runas_user" sto_to_com +(* View: host_alias + Host_Alias, see <alias_field> *) +let host_alias = alias_entry "Host_Alias" "host" sto_to_com +(* View: cmnd_alias + Cmnd_Alias, see <alias_field> *) +let cmnd_alias = alias_entry "Cmnd_Alias" "command" sto_to_com_cmnd + + +(************************************************************************ + * View: alias + * Every kind of Alias entry, + * see <user_alias>, <runas_alias>, <host_alias> and <cmnd_alias> + * + * Definition: + * > Alias ::= 'User_Alias' User_Alias (':' User_Alias)* | + * > 'Runas_Alias' Runas_Alias (':' Runas_Alias)* | + * > 'Host_Alias' Host_Alias (':' Host_Alias)* | + * > 'Cmnd_Alias' Cmnd_Alias (':' Cmnd_Alias)* + *************************************************************************) +let alias = user_alias | runas_alias | host_alias | cmnd_alias + +(************************************************************************ + * Group: DEFAULTS + *************************************************************************) + + +(************************************************************************ + * View: default_type + * Type definition for <defaults> + * + * Definition: + * > Default_Type ::= 'Defaults' | + * > 'Defaults' '@' Host_List | + * > 'Defaults' ':' User_List | + * > 'Defaults' '!' Cmnd_List | + * > 'Defaults' '>' Runas_List + *************************************************************************) +let default_type = + let value = store /[@:!>][^ \t\n\\]+/ in + [ label "type" . value ] + +(************************************************************************ + * View: parameter_flag + * A flag parameter for <defaults> + * + * Flags are implicitly boolean and can be turned off via the '!' operator. + * Some integer, string and list parameters may also be used in a boolean + * context to disable them. + *************************************************************************) +let parameter_flag_kw = "always_set_home" | "authenticate" | "env_editor" + | "env_reset" | "fqdn" | "ignore_dot" + | "ignore_local_sudoers" | "insults" | "log_host" + | "log_year" | "long_otp_prompt" | "mail_always" + | "mail_badpass" | "mail_no_host" | "mail_no_perms" + | "mail_no_user" | "noexec" | "path_info" + | "passprompt_override" | "preserve_groups" + | "requiretty" | "root_sudo" | "rootpw" | "runaspw" + | "set_home" | "set_logname" | "setenv" + | "shell_noargs" | "stay_setuid" | "targetpw" + | "tty_tickets" | "visiblepw" | "closefrom_override" + | "closefrom_override" | "compress_io" | "fast_glob" + | "log_input" | "log_output" | "pwfeedback" + | "umask_override" | "use_pty" | "match_group_by_gid" + | "always_query_group_plugin" + +let parameter_flag = [ del_negate . negate_node? + . key parameter_flag_kw ] + +(************************************************************************ + * View: parameter_integer + * An integer parameter for <defaults> + *************************************************************************) +let parameter_integer_nobool_kw = "passwd_tries" + +let parameter_integer_nobool = [ key parameter_integer_nobool_kw . sep_eq + . del /"?/ "" . sto_integer + . del /"?/ "" ] + + +let parameter_integer_bool_kw = "loglinelen" | "passwd_timeout" + | "timestamp_timeout" | "umask" + +let parameter_integer_bool = + negate_or_value + (key parameter_integer_bool_kw) + (sep_eq . del /"?/ "" . sto_integer . del /"?/ "") + +let parameter_integer = parameter_integer_nobool + | parameter_integer_bool + +(************************************************************************ + * View: parameter_string + * A string parameter for <defaults> + * + * An odd number of '!' operators negate the value of the item; + * an even number just cancel each other out. + *************************************************************************) +let parameter_string_nobool_kw = "badpass_message" | "editor" | "mailsub" + | "noexec_file" | "passprompt" | "runas_default" + | "syslog_badpri" | "syslog_goodpri" + | "timestampdir" | "timestampowner" | "secure_path" + +let parameter_string_nobool = [ key parameter_string_nobool_kw . sep_eq + . sto_to_com_dquot ] + +let parameter_string_bool_kw = "exempt_group" | "lecture" | "lecture_file" + | "listpw" | "logfile" | "mailerflags" + | "mailerpath" | "mailto" | "mailfrom" + | "syslog" | "verifypw" + +let parameter_string_bool = + negate_or_value + (key parameter_string_bool_kw) + (sep_eq . sto_to_com_dquot) + +let parameter_string = parameter_string_nobool + | parameter_string_bool + +(************************************************************************ + * View: parameter_lists + * A single list parameter for <defaults> + * + * All lists can be used in a boolean context + * The argument may be a double-quoted, space-separated list or a single + * value without double-quotes. + * The list can be replaced, added to, deleted from, or disabled + * by using the =, +=, -=, and ! operators respectively. + * An odd number of '!' operators negate the value of the item; + * an even number just cancel each other out. + *************************************************************************) +let parameter_lists_kw = "env_check" | "env_delete" | "env_keep" +let parameter_lists_value = [ label "var" . sto_to_spc_no_dquote ] +let parameter_lists_value_dquote = [ label "var" + . del /"?/ "" . sto_to_spc_no_dquote + . del /"?/ "" ] + +let parameter_lists_values = parameter_lists_value_dquote + | ( sep_dquote . parameter_lists_value + . ( sep_cont . parameter_lists_value )+ + . sep_dquote ) + +let parameter_lists_sep = sep_cont_opt + . ( [ del "+" "+" . label "append" ] + | [ del "-" "-" . label "remove" ] )? + . del "=" "=" . sep_cont_opt + +let parameter_lists = + negate_or_value + (key parameter_lists_kw) + (parameter_lists_sep . parameter_lists_values) + +(************************************************************************ + * View: parameter + * A single parameter for <defaults> + * + * Definition: + * > Parameter ::= Parameter '=' Value | + * > Parameter '+=' Value | + * > Parameter '-=' Value | + * > '!'* Parameter + * + * Parameters may be flags, integer values, strings, or lists. + * + *************************************************************************) +let parameter = parameter_flag | parameter_integer + | parameter_string | parameter_lists + +(************************************************************************ + * View: parameter_list + * A list of comma-separated <parameters> for <defaults> + * + * Definition: + * > Parameter_List ::= Parameter | + * > Parameter ',' Parameter_List + *************************************************************************) +let parameter_list = parameter . ( sep_com . parameter )* + +(************************************************************************ + * View: defaults + * A Defaults entry + * + * Definition: + * > Default_Entry ::= Default_Type Parameter_List + *************************************************************************) +let defaults = [ indent . key "Defaults" . default_type? . sep_cont + . parameter_list . comment_or_eol ] + + + +(************************************************************************ + * Group: USER SPECIFICATION + *************************************************************************) + +(************************************************************************ + * View: runas_spec + * A runas specification for <spec>, using <alias_list> for listing + * users and/or groups used to run a command + * + * Definition: + * > Runas_Spec ::= '(' Runas_List ')' | + * > '(:' Runas_List ')' | + * > '(' Runas_List ':' Runas_List ')' + *************************************************************************) +let runas_spec_user = alias_list "runas_user" sto_to_com +let runas_spec_group = Util.del_str ":" . indent + . alias_list "runas_group" sto_to_com + +let runas_spec_usergroup = runas_spec_user . indent . runas_spec_group + +let runas_spec = Util.del_str "(" + . (runas_spec_user + | runas_spec_group + | runas_spec_usergroup ) + . Util.del_str ")" . sep_cont_opt + +(************************************************************************ + * View: tag_spec + * Tag specification for <spec> + * + * Definition: + * > Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | + * > 'SETENV:' | 'NOSETENV:') + *************************************************************************) +let tag_spec = + [ label "tag" . store /(NO)?(PASSWD|EXEC|SETENV)/ . sep_col ] + +(************************************************************************ + * View: cmnd_spec + * Command specification for <spec>, + * with optional <runas_spec> and any amount of <tag_specs> + * + * Definition: + * > Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd + *************************************************************************) +let cmnd_spec = + [ label "command" . runas_spec? . tag_spec* . sto_to_com_cmnd ] + +(************************************************************************ + * View: cmnd_spec_list + * A list of comma-separated <cmnd_specs> + * + * Definition: + * > Cmnd_Spec_List ::= Cmnd_Spec | + * > Cmnd_Spec ',' Cmnd_Spec_List + *************************************************************************) +let cmnd_spec_list = Build.opt_list cmnd_spec sep_com + + +(************************************************************************ + * View: spec_list + * Group of hosts with <cmnd_spec_list> + *************************************************************************) +let spec_list = [ label "host_group" . alias_list "host" sto_to_com_host + . sep_eq . cmnd_spec_list ] + +(************************************************************************ + * View: spec + * A user specification, listing colon-separated <spec_lists> + * + * Definition: + * > User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \ + * > (':' Host_List '=' Cmnd_Spec_List)* + *************************************************************************) +let spec = [ label "spec" . indent + . alias_list "user" sto_to_com_user . sep_cont + . Build.opt_list spec_list sep_col + . comment_or_eol ] + + +(************************************************************************ + * Group: LENS & FILTER + *************************************************************************) + +(* View: lns + The sudoers lens, any amount of + * <empty> lines + * <comments> + * <includedirs> + * <aliases> + * <defaults> + * <specs> +*) +let lns = ( empty | comment | includedir | alias | defaults | spec )* + +(* View: filter *) +let filter = (incl "/etc/sudoers") + . (incl "/usr/local/etc/sudoers") + . (incl "/etc/sudoers.d/*") + . (incl "/usr/local/etc/sudoers.d/*") + . (incl "/opt/csw/etc/sudoers") + . (incl "/etc/opt/csw/sudoers") + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/sysconfig.aug b/Sharp.Augeas.Test/lens/sysconfig.aug new file mode 100644 index 0000000..5fd6c38 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sysconfig.aug @@ -0,0 +1,74 @@ +(* Variation of the Shellvars lens *) +(* Supports only what's needed to handle sysconfig files *) +(* Modified to strip quotes. In the put direction, add double quotes *) +(* around values that need them *) +(* To keep things simple, we also do not support shell variable arrays *) +module Sysconfig = + + let eol = Shellvars.eol + let semicol_eol = Shellvars.semicol_eol + + let key_re = Shellvars.key_re + let eq = Util.del_str "=" + + let eol_for_comment = del /([ \t]*\n)([ \t]*(#[ \t]*)?\n)*/ "\n" + let comment = Util.comment_generic_seteol /[ \t]*#[ \t]*/ "# " eol_for_comment + let comment_or_eol = Shellvars.comment_or_eol + + let empty = Util.empty + + let bchar = /[^; \t\n"'\\]|\\\\./ (* " Emacs, relax *) + let qchar = /["']/ (* " Emacs, relax *) + + (* We split the handling of right hand sides into a few cases: + * bare - strings that contain no spaces, optionally enclosed in + * single or double quotes + * quot - strings that must be enclosed in single or double quotes + * dquot - strings that contain at least one space or apostrophe, + * which must be enclosed in double quotes + * squot - strings that contain an unescaped double quote + *) + let bare = Quote.do_quote_opt (store bchar+) + + let quot = + let word = bchar* . /[; \t]/ . bchar* in + Quote.do_quote (store word+) + + let dquot = + let char = /[^"\\]|\\\\./ in (* " *) + let word = char* . "'" . char* in + Quote.do_dquote (store word+) + + let squot = + (* We do not allow escaped double quotes in single quoted strings, as *) + (* that leads to a put ambiguity with bare, e.g. for the string '\"'. *) + let char = /[^'\\]|\\\\[^"]/ in (* " *) + let word = char* . "\"" . char* in + Quote.do_squote (store word+) + + let kv (value:lens) = + let export = Shellvars.export in + let indent = Util.del_opt_ws "" in + [ indent . export? . key key_re . eq . value . comment_or_eol ] + + let assign = + let nothing = del /(""|'')?/ "" . value "" in + kv nothing | kv bare | kv quot | kv dquot | kv squot + + let var_action = Shellvars.var_action + + let unset = [ var_action "unset" . comment_or_eol ] + let bare_export = [ var_action "export" . comment_or_eol ] + + let source = [ Shellvars.source . comment_or_eol ] + + let lns = empty* . (comment | source | assign | unset | bare_export)* + +(* + Examples: + + abc -> abc -> abc + "abc" -> abc -> abc + "a b" -> a b -> "a b" + 'a"b' -> a"b -> 'a"b' +*) diff --git a/Sharp.Augeas.Test/lens/sysconfig_route.aug b/Sharp.Augeas.Test/lens/sysconfig_route.aug new file mode 100644 index 0000000..d3222e8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sysconfig_route.aug @@ -0,0 +1,78 @@ +(* +Module: Sysconfig_Route + Parses /etc/sysconfig/network-scripts/route-${device} + +Author: Stephen P. Schaefer + +About: Reference + This lens allows manipulation of *one* IPv4 variant of the +/etc/sysconfig/network-scripts/route-${device} script found in RHEL5+, CentOS5+ +and Fedora. + + The variant handled consists of lines like + "destination_subnet/cidr via router_ip", e.g., + "10.132.11.0/24 via 10.10.2.1" + + There are other variants; if you use them, please enhance this lens. + + The natural key would be "10.132.11.0/24" with value "10.10.2.1", but since + augeas cannot deal with slashes in the key value, I reverse them, so that the + key is "10.10.2.1[1]" (and "10.10.2.1[2]"... if multiple subnets are reachable + via that router). + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Set the first subnet reachable by a router reachable on the eth0 subnet + > set /files/etc/sysconfig/network-scripts/route-eth0/10.10.2.1[1] 172.16.254.0/24 + * List all the subnets reachable by a router reachable on eth0 subnet + > match /files/etc/sysconfig/network-scripts/route-eth0/10.10.2.1 + +About: Configuration files + This lens applies to /etc/sysconfig/network-scripts/route-* + +About: Examples + The <Test_Sysconfig_Route> file contains various examples and tests. +*) + +module Sysconfig_Route = + autoload xfm + +(****************************************************************************** + * Group: USEFUL PRIMITIVES + ******************************************************************************) + +(* Variable: router + A router *) +let router = Rx.ipv4 +(* Variable: cidr + A subnet mask can be 0 to 32 bits *) +let cidr = /(3[012]|[12][0-9]|[0-9])/ +(* Variable: subnet + Subnet specification *) +let subnet = Rx.ipv4 . "/" . cidr + +(****************************************************************************** + * Group: ENTRY TYPES + ******************************************************************************) + +(* View: entry + One route *) +let entry = [ store subnet . del /[ \t]*via[ \t]*/ " via " + . key router . Util.del_str "\n" ] + +(****************************************************************************** + * Group: LENS AND FILTER + ******************************************************************************) + +(* View: lns *) +let lns = entry+ + +(* View: filter *) +let filter = incl "/etc/sysconfig/network-scripts/route-*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/sysctl.aug b/Sharp.Augeas.Test/lens/sysctl.aug new file mode 100644 index 0000000..2803145 --- /dev/null +++ b/Sharp.Augeas.Test/lens/sysctl.aug @@ -0,0 +1,40 @@ +(* +Module: Sysctl + Parses /etc/sysctl.conf and /etc/sysctl.d/* + +Author: David Lutterkort <lutter@redhat.com> + +About: Reference + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/sysctl.conf and /etc/sysctl.d/*. See <filter>. + +About: Examples + The <Test_Sysctl> file contains various examples and tests. +*) + +module Sysctl = +autoload xfm + +(* Variable: filter *) +let filter = incl "/boot/loader.conf" + . incl "/etc/sysctl.conf" + . incl "/etc/sysctl.d/*" + . excl "/etc/sysctl.d/README" + . excl "/etc/sysctl.d/README.sysctl" + . Util.stdexcl + +(* View: comment *) +let comment = Util.comment_generic /[ \t]*[#;][ \t]*/ "# " + +(* View: lns + The sysctl lens *) +let lns = (Util.empty | comment | Simplevars.entry)* + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/syslog.aug b/Sharp.Augeas.Test/lens/syslog.aug new file mode 100644 index 0000000..bf5f7b4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/syslog.aug @@ -0,0 +1,269 @@ +(* +Module: Syslog + parses /etc/syslog.conf + +Author: Mathieu Arnold <mat@FreeBSD.org> + +About: Reference + This lens tries to keep as close as possible to `man 5 resolv.conf` where possible. + An online source being : + http://www.freebsd.org/cgi/man.cgi?query=syslog.conf&sektion=5 + +About: Licence + This file is licensed under the BSD License. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/syslog.conf. See <filter>. + + *) +module Syslog = + autoload xfm + + (************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + (* Group: Comments and empty lines *) + + (* Variable: empty *) + let empty = Util.empty + (* Variable: eol *) + let eol = Util.eol + (* Variable: sep_tab *) + let sep_tab = del /([ \t]+|[ \t]*\\\\\n[ \t]*)/ "\t" + + (* Variable: sep_tab_opt *) + let sep_tab_opt = del /([ \t]*|[ \t]*\\\\\n[ \t]*)/ "" + + (* View: comment + Map comments into "#comment" nodes + Can't use Util.comment as #+ and #! have a special meaning. + However, '# !' and '# +' have no special meaning so they should be allowed. + *) + + let comment_gen (space:regexp) (sto:regexp) = + [ label "#comment" . del (Rx.opt_space . "#" . space) "# " + . store sto . eol ] + + let comment = + let comment_withsign = comment_gen Rx.space /([!+-].*[^ \t\n]|[!+-])/ + in let comment_nosign = comment_gen Rx.opt_space /([^ \t\n+!-].*[^ \t\n]|[^ \t\n+!-])/ + in comment_withsign | comment_nosign + + (* Group: single characters macro *) + + (* Variable: comma + Deletes a comma and default to it + *) + let comma = sep_tab_opt . Util.del_str "," . sep_tab_opt + (* Variable: colon + Deletes a colon and default to it + *) + let colon = sep_tab_opt . Util.del_str ":" . sep_tab_opt + (* Variable: semicolon + Deletes a semicolon and default to it + *) + let semicolon = sep_tab_opt . Util.del_str ";" . sep_tab_opt + (* Variable: dot + Deletes a dot and default to it + *) + let dot = Util.del_str "." + (* Variable: pipe + Deletes a pipe and default to it + *) + let pipe = Util.del_str "|" + (* Variable: plus + Deletes a plus and default to it + *) + let plus = Util.del_str "+" + (* Variable: bang + Deletes a bang and default to it + *) + let bang = Util.del_str "!" + + (* Variable: opt_hash + deletes an optional # sign + *) + let opt_hash = del /#?/ "" + (* Variable: opt_plus + deletes an optional + sign + *) + let opt_plus = del /\+?/ "" + + (* Group: various macros *) + + (* Variable: word + our version can't start with [_.-] because it would mess up the grammar + *) + let word = /[A-Za-z0-9][A-Za-z0-9_.-]*/ + + (* Variable: comparison + a comparison is an optional ! with optionally some of [<=>] + *) + let comparison = /(!|[<=>]+|![<=>]+)/ + + (* Variable: protocol + @ means UDP + @@ means TCP + *) + let protocol = /@{1,2}/ + + (* Variable: token + alphanum or "*" + *) + let token = /([A-Za-z0-9]+|\*)/ + + (* Variable: file_r + a file begins with a / and get almost anything else after + *) + let file_r = /\/[^ \t\n;]+/ + + (* Variable: loghost_r + Matches a hostname, that is labels speparated by dots, labels can't + start or end with a "-". maybe a bit too complicated for what it's worth *) + let loghost_r = /[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*/ | + "[" . Rx.ipv6 . "]" + + (* Group: Function *) + + (* View: label_opt_list + Uses Build.opt_list to generate a list of labels + + Parameters: + l:string - the label name + r:lens - the lens going after the label + s:lens - the separator lens passed to Build.opt_list + *) + let label_opt_list (l:string) (r:lens) (s:lens) = Build.opt_list [ label l . r ] s + + (* View: label_opt_list_or + Either label_opt_list matches something or it emits a single label + with the "or" string. + + Parameters: + l:string - the label name + r:lens - the lens going after the label + s:lens - the separator lens passed to Build.opt_list + or:string - the string used if the label_opt_list does not match anything + *) + let label_opt_list_or (l:string) (r:lens) (s:lens) (or:string) = + ( label_opt_list l r s | [ label l . store or ] ) + + + (************************************************************************ + * Group: LENSE DEFINITION + *************************************************************************) + + (* Group: selector *) + + (* View: facilities + a list of facilities, separated by commas + *) + let facilities = label_opt_list "facility" (store token) comma + + (* View: selector + a selector is a list of facilities, an optional comparison and a level + *) + let selector = facilities . dot . + [ label "comparison" . store comparison]? . + [ label "level" . store token ] + + (* View: selectors + a list of selectors, separated by semicolons + *) + let selectors = label_opt_list "selector" selector semicolon + + (* Group: action *) + + (* View: file + a file may start with a "-" meaning it does not gets sync'ed everytime + *) + let file = [ Build.xchgs "-" "no_sync" ]? . [ label "file" . store file_r ] + + (* View: loghost + a loghost is an @ sign followed by the hostname and a possible port + *) + let loghost = [label "protocol" . store protocol] . [ label "hostname" . store loghost_r ] . + (colon . [ label "port" . store /[0-9]+/ ] )? + + (* View: users + a list of users or a "*" + *) + let users = label_opt_list_or "user" (store word) comma "*" + + (* View: logprogram + a log program begins with a pipe + *) + let logprogram = pipe . [ label "program" . store /[^ \t\n][^\n]+[^ \t\n]/ ] + + (* View: discard + discards matching messages + *) + let discard = [ label "discard" . Util.del_str "~" ] + + (* View: action + an action is either a file, a host, users, a program, or discard + *) + let action = (file | loghost | users | logprogram | discard) + + (* Group: Entry *) + + (* View: entry + an entry contains selectors and an action + *) + let entry = [ label "entry" . + selectors . sep_tab . + [ label "action" . action ] . eol ] + + (* View: entries + entries are either comments/empty lines or entries + *) + let entries = (empty | comment | entry )* + + (* Group: Program matching *) + + (* View: programs + a list of programs + *) + let programs = label_opt_list_or "program" (store word) comma "*" + + (* View: program + a program begins with an optional hash, a bang, and an optional + or - + *) + let program = [ label "program" . opt_hash . bang . + ( opt_plus | [ Build.xchgs "-" "reverse" ] ) . + programs . eol . entries ] + + (* Group: Hostname maching *) + + (* View: hostnames + a list of hostnames + *) + let hostnames = label_opt_list_or "hostname" (store Rx.word) comma "*" + + (* View: hostname + a program begins with an optional hash, and a + or - + *) + let hostname = [ label "hostname" . opt_hash . + ( plus | [ Build.xchgs "-" "reverse" ] ) . + hostnames . eol . entries ] + + (* Group: Top of the tree *) + + let include = + [ key "include" . sep_tab . store file_r . eol ] + + (* View: lns + generic entries then programs or hostnames matching blocs + *) + let lns = entries . ( program | hostname | include )* + + (* Variable: filter + all you need is /etc/syslog.conf + *) + let filter = incl "/etc/syslog.conf" + + let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/systemd.aug b/Sharp.Augeas.Test/lens/systemd.aug new file mode 100644 index 0000000..42258d9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/systemd.aug @@ -0,0 +1,184 @@ +(* +Module: Systemd + Parses systemd unit files. + +Author: Dominic Cleal <dcleal@redhat.com> + +About: Reference + This lens tries to keep as close as possible to systemd.unit(5) and + systemd.service(5) etc where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /lib/systemd/system/* and /etc/systemd/system/*. + See <filter>. +*) + +module Systemd = +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: eol *) +let eol = Util.eol + +(* View: eol_comment + An <IniFile.comment> entry for standalone comment lines (; or #) *) +let comment = IniFile.comment IniFile.comment_re "#" + +(* View: eol_comment + An <IniFile.comment> entry for end of line comments (# only) *) +let eol_comment = IniFile.comment "#" "#" + +(* View: sep + An <IniFile.sep> entry *) +let sep = IniFile.sep "=" "=" + +(* Variable: entry_single_kw *) +let entry_single_kw = "Description" + +(* Variable: entry_command_kw *) +let entry_command_kw = /Exec[A-Za-z][A-Za-z0-9._-]+/ + +(* Variable: entry_env_kw *) +let entry_env_kw = "Environment" + +(* Variable: entry_multi_kw *) +let entry_multi_kw = + let forbidden = entry_single_kw | entry_command_kw | entry_env_kw + in /[A-Za-z][A-Za-z0-9._-]+/ - forbidden + +(* Variable: value_single_re *) +let value_single_re = /[^# \t\n\\][^#\n\\]*[^# \t\n\\]|[^# \t\n\\]/ + +(* View: sto_value_single + Support multiline values with a backslash *) +let sto_value_single = Util.del_opt_ws "" + . store (value_single_re + . (/\\\\\n/ . value_single_re)*) + +(* View: sto_value *) +let sto_value = store /[^# \t\n]*[^# \t\n\\]/ + +(* Variable: value_sep + Multi-value entries separated by whitespace or backslash and newline *) +let value_sep = del /[ \t]+|[ \t]*\\\\[ \t]*\n[ \t]*/ " " + +(* Variable: value_cmd_re + Don't parse @ and - prefix flags *) +let value_cmd_re = /[^#@ \t\n\\-][^#@ \t\n\\-][^# \t\n\\]*/ + +(* Variable: env_key *) +let env_key = /[A-Za-z0-9_]+(\[[0-9]+\])?/ + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +(* +Supported entry features, selected by key names: + * multi-value space separated attrs (the default) + * single-value attrs (Description) + * systemd.service: Exec* attrs with flags, command and arguments + * systemd.service: Environment NAME=arg +*) + +(* View: entry_fn + Prototype for our various key=value lines, with optional comment *) +let entry_fn (kw:regexp) (val:lens) = + [ key kw . sep . val . (eol_comment|eol) ] + +(* View: entry_value + Store a value that doesn't contain spaces *) +let entry_value = [ label "value" . sto_value ] + +(* View: entry_single + Entry that takes a single value containing spaces *) +let entry_single = entry_fn entry_single_kw + [ label "value" . sto_value_single ]? + +(* View: entry_command + Entry that takes a space separated set of values (the default) *) +let entry_multi = entry_fn entry_multi_kw + ( Util.del_opt_ws "" + . Build.opt_list entry_value value_sep )? + +(* View: entry_command_flags + Exec* flags "@" and "-". Order is important, see systemd.service(8) *) +let entry_command_flags = + let exit = [ label "ignoreexit" . Util.del_str "-" ] + in let arg0 = [ label "arg0" . Util.del_str "@" ] + in exit? . arg0? + +(* View: entry_command + Entry that takes a command, arguments and the optional prefix flags *) +let entry_command = + let cmd = [ label "command" . store value_cmd_re ] + in let arg = [ seq "args" . sto_value ] + in let args = [ counter "args" . label "arguments" + . (value_sep . arg)+ ] + in entry_fn entry_command_kw ( entry_command_flags . cmd . args? )? + +(* View: entry_env + Entry that takes a space separated set of ENV=value key/value pairs *) +let entry_env = + let envkv (env_val:lens) = key env_key . Util.del_str "=" . env_val + (* bare has no spaces, and is optionally quoted *) + in let bare = Quote.do_quote_opt (envkv (store /[^#'" \t\n]*[^#'" \t\n\\]/)?) + in let bare_dqval = envkv (store /"[^#"\t\n]*[^#"\t\n\\]"/) + in let bare_sqval = envkv (store /'[^#'\t\n]*[^#'\t\n\\]'/) + (* quoted has at least one space, and must be quoted *) + in let quoted = Quote.do_quote (envkv (store /[^#"'\n]*[ \t]+[^#"'\n]*/)) + in let envkv_quoted = [ bare ] | [ bare_dqval ] | [ bare_sqval ] | [ quoted ] + in entry_fn entry_env_kw ( Build.opt_list envkv_quoted value_sep ) + + +(************************************************************************ + * Group: LENS + *************************************************************************) + +(* View: entry + An <IniFile.entry> *) +let entry = entry_single | entry_multi | entry_command | entry_env | comment + +(* View: include + Includes another file at this position *) +let include = [ key ".include" . Util.del_ws_spc . sto_value + . (eol_comment|eol) ] + +(* View: title + An <IniFile.title> *) +let title = IniFile.title IniFile.record_re + +(* View: record + An <IniFile.record> *) +let record = IniFile.record title (entry|include) + +(* View: lns + An <IniFile.lns> *) +let lns = IniFile.lns record (comment|include) + +(* View: filter *) +let filter = incl "/lib/systemd/system/*" + . incl "/lib/systemd/system/*/*" + . incl "/etc/systemd/system/*" + . incl "/etc/systemd/system/*/*" + . incl "/etc/systemd/logind.conf" + . incl "/etc/sysconfig/*.systemd" + . incl "/lib/systemd/network/*" + . incl "/usr/local/lib/systemd/network/*" + . incl "/etc/systemd/network/*" + . excl "/lib/systemd/system/*.d" + . excl "/etc/systemd/system/*.d" + . excl "/lib/systemd/system/*.wants" + . excl "/etc/systemd/system/*.wants" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/termcap.aug b/Sharp.Augeas.Test/lens/termcap.aug new file mode 100644 index 0000000..13e96d2 --- /dev/null +++ b/Sharp.Augeas.Test/lens/termcap.aug @@ -0,0 +1,34 @@ +(* +Module: Termcap + Parses termcap capability database + +Author: Matt Dainty <matt@bodgit-n-scarper.com> + +About: Reference + - man 5 termcap + +Each line represents a record consisting of a number of ':'-separated fields +the first of which is the name or identifier for the record. The name can +optionally be split by '|' and each subsequent value is considered an alias +of the first. Records can be split across multiple lines with '\'. + +*) + +module Termcap = + autoload xfm + + (* All termcap capabilities are two characters, optionally preceded by *) + (* upto two periods and the only types are boolean, numeric or string *) + let cfield = /\.{0,2}([a-zA-Z0-9]{2}|[@#%&*!][a-zA-Z0-9]|k;)(#?@|#[0-9]+|=([^:\\\\^]|\\\\[0-7]{3}|\\\\[:bBcCeEfFnNrRstT0\\^]|\^.)*)?/ + + let lns = ( Util.empty | Getcap.comment | Getcap.record cfield )* + + let filter = incl "/etc/termcap" + . incl "/usr/share/misc/termcap" + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_access.aug b/Sharp.Augeas.Test/lens/tests/test_access.aug new file mode 100644 index 0000000..2dcd8c8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_access.aug @@ -0,0 +1,120 @@ +(* +Module: Test_Access + Provides unit tests and examples for the <Access> lens. +*) + +module Test_access = + +(* Variable: conf + A full configuration *) +let conf = "+ : ALL : LOCAL ++ : root : localhost.localdomain +- : root : 127.0.0.1 .localdomain ++ : root alice@server1 @admins (wheel) : cron crond :0 tty1 tty2 tty3 tty4 tty5 tty6 +# IP v6 support ++ : john foo : 2001:4ca0:0:101::1 2001:4ca0:0:101::/64 +# Except ++ : ALL EXCEPT john @wheel : ALL EXCEPT LOCAL .win.tue.nl +# No spaces ++:root:.example.com +" + +(* Test: Access.lns + Test the full <conf> *) +test Access.lns get conf = + { "access" = "+" + { "user" = "ALL" } + { "origin" = "LOCAL" } } + { "access" = "+" + { "user" = "root" } + { "origin" = "localhost.localdomain" } } + { "access" = "-" + { "user" = "root" } + { "origin" = "127.0.0.1" } + { "origin" = ".localdomain" } } + { "access" = "+" + { "user" = "root" } + { "user" = "alice" + { "host" = "server1" } } + { "netgroup" = "admins" } + { "group" = "wheel" } + { "origin" = "cron" } + { "origin" = "crond" } + { "origin" = ":0" } + { "origin" = "tty1" } + { "origin" = "tty2" } + { "origin" = "tty3" } + { "origin" = "tty4" } + { "origin" = "tty5" } + { "origin" = "tty6" } } + { "#comment" = "IP v6 support" } + { "access" = "+" + { "user" = "john" } + { "user" = "foo" } + { "origin" = "2001:4ca0:0:101::1" } + { "origin" = "2001:4ca0:0:101::/64" } } + { "#comment" = "Except" } + { "access" = "+" + { "user" = "ALL" } + { "except" + { "user" = "john" } + { "netgroup" = "wheel" } } + { "origin" = "ALL" } + { "except" + { "origin" = "LOCAL" } + { "origin" = ".win.tue.nl" } } } + { "#comment" = "No spaces" } + { "access" = "+" + { "user" = "root" } + { "origin" = ".example.com" } } + +test Access.lns put conf after + insa "access" "access[last()]" ; + set "access[last()]" "-" ; + set "access[last()]/user" "ALL" ; + set "access[last()]/origin" "ALL" + = "+ : ALL : LOCAL ++ : root : localhost.localdomain +- : root : 127.0.0.1 .localdomain ++ : root alice@server1 @admins (wheel) : cron crond :0 tty1 tty2 tty3 tty4 tty5 tty6 +# IP v6 support ++ : john foo : 2001:4ca0:0:101::1 2001:4ca0:0:101::/64 +# Except ++ : ALL EXCEPT john @wheel : ALL EXCEPT LOCAL .win.tue.nl +# No spaces ++:root:.example.com +- : ALL : ALL +" + +(* Test: Access.lns + - netgroups (starting with '@') are mapped as "netgroup" nodes; + - nisdomains (starting with '@@') are mapped as "nisdomain" nodes. + + This closes <ticket #190 at https://fedorahosted.org/augeas/ticket/190>. + *) +test Access.lns get "+ : @group@@domain : ALL \n" = + { "access" = "+" + { "netgroup" = "group" + { "nisdomain" = "domain" } } + { "origin" = "ALL" } } + +(* Test Access.lns + Put test for netgroup and nisdomain *) +test Access.lns put "+ : @group : ALL \n" after + set "/access/netgroup[. = 'group']/nisdomain" "domain" = +"+ : @group@@domain : ALL \n" + +(* Check DOMAIN\user style entry *) +test Access.lns get "+ : root : foo1.bar.org foo3.bar.org ++ : (DOMAIN\linux_users) : ALL ++ : DOMAIN\linux_user : ALL\n" = + { "access" = "+" + { "user" = "root" } + { "origin" = "foo1.bar.org" } + { "origin" = "foo3.bar.org" } } + { "access" = "+" + { "group" = "DOMAIN\linux_users" } + { "origin" = "ALL" } } + { "access" = "+" + { "user" = "DOMAIN\linux_user" } + { "origin" = "ALL" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_activemq_conf.aug b/Sharp.Augeas.Test/lens/tests/test_activemq_conf.aug new file mode 100644 index 0000000..8443e2f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_activemq_conf.aug @@ -0,0 +1,35 @@ +(* +Module: Test_ActiveMQ_Conf + Provides unit tests and examples for the <ActiveMQ_Conf> lens. +*) + +module Test_ActiveMQ_Conf = + +(* Variable: conf *) +let conf = " +ACTIVEMQ_HOME=/usr/share/activemq +ACTIVEMQ_BASE=${ACTIVEMQ_HOME} +" + +(* Variable: new_conf *) +let new_conf = " +ACTIVEMQ_HOME=/usr/local/share/activemq +ACTIVEMQ_BASE=${ACTIVEMQ_HOME} +" + +let lns = ActiveMQ_Conf.lns + +(* Test: ActiveMQ_Conf.lns + * Get test against tree structure +*) +test lns get conf = + { } + { "ACTIVEMQ_HOME" = "/usr/share/activemq" } + { "ACTIVEMQ_BASE" = "${ACTIVEMQ_HOME}" } + +(* Test: ActiveMQ_Conf.lns + * Put test changing user to nobody +*) +test lns put conf after set "/ACTIVEMQ_HOME" "/usr/local/share/activemq" = new_conf + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_activemq_xml.aug b/Sharp.Augeas.Test/lens/tests/test_activemq_xml.aug new file mode 100644 index 0000000..c31a5b6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_activemq_xml.aug @@ -0,0 +1,65 @@ +(* +Module: Test_ActiveMQ_XML + Provides unit tests and examples for the <ActiveMQ_XML> lens. +*) + +module Test_ActiveMQ_XML = + +(* Variable: conf *) +let conf = "<beans> + <broker xmlns=\"http://activemq.apache.org/schema/core\" brokerName=\"localhost\" dataDirectory=\"${activemq.data}\"> + <transportConnectors> + <transportConnector name=\"openwire\" uri=\"tcp://0.0.0.0:61616\"/> + </transportConnectors> + </broker> +</beans> +" + +(* Variable: new_conf *) +let new_conf = "<beans> + <broker xmlns=\"http://activemq.apache.org/schema/core\" brokerName=\"localhost\" dataDirectory=\"${activemq.data}\"> + <transportConnectors> + <transportConnector name=\"openwire\" uri=\"tcp://127.0.0.1:61616\"/> + </transportConnectors> + </broker> +</beans> +" + +let lns = ActiveMQ_XML.lns + +(* Test: ActiveMQ_XML.lns + * Get test against tree structure +*) +test lns get conf = + { "beans" + { "#text" = " + " } + { "broker" + { "#attribute" + { "xmlns" = "http://activemq.apache.org/schema/core" } + { "brokerName" = "localhost" } + { "dataDirectory" = "${activemq.data}" } + } + { "#text" = " + " } + { "transportConnectors" + { "#text" = " + " } + { "transportConnector" = "#empty" + { "#attribute" + { "name" = "openwire" } + { "uri" = "tcp://0.0.0.0:61616" } + } + } + { "#text" = " " } + } + { "#text" = " " } + } + } + +(* Test: ActiveMQ_XML.lns + * Put test changing transport connector to localhost +*) +test lns put conf after set "/beans/broker/transportConnectors/transportConnector/#attribute/uri" "tcp://127.0.0.1:61616" = new_conf + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_afs_cellalias.aug b/Sharp.Augeas.Test/lens/tests/test_afs_cellalias.aug new file mode 100644 index 0000000..891a346 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_afs_cellalias.aug @@ -0,0 +1,42 @@ +(* +Module: Test_AFS_cellalias + Provides unit tests and examples for the <AFS_cellalias> lens. +*) + +module Test_AFS_cellalias = + +(* Variable: conf + A full configuration *) +let conf = "# Cell Aliases are meant to act like symlinks like '/afs/openafs.org -> oao' +# in root.afs, so sites relying on such a link for their cell can use dynroot. +# These aliases are set with 'fs newalias', or read from +# /usr/vice/etc/CellAlias +# +# Formatting for /usr/vice/etc/CellAlias is in the form +# <target> <alias> +# an example would be +# fnal.gov/common/usr usr + +fnal.gov fnal +fnal.gov/files fnal-files +" + +(* Test: AFS_cellalias.lns + Test the full <conf> *) +test AFS_cellalias.lns get conf = { "#comment" = "Cell Aliases are meant to act like symlinks like '/afs/openafs.org -> oao'" } + { "#comment" = "in root.afs, so sites relying on such a link for their cell can use dynroot." } + { "#comment" = "These aliases are set with 'fs newalias', or read from" } + { "#comment" = "/usr/vice/etc/CellAlias" } + { } + { "#comment" = "Formatting for /usr/vice/etc/CellAlias is in the form" } + { "#comment" = "<target> <alias>" } + { "#comment" = "an example would be" } + { "#comment" = "fnal.gov/common/usr usr" } + { } + { "target" = "fnal.gov" + { "linkname" = "fnal" } + } + { "target" = "fnal.gov/files" + { "linkname" = "fnal-files" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_aliases.aug b/Sharp.Augeas.Test/lens/tests/test_aliases.aug new file mode 100644 index 0000000..6db14dd --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_aliases.aug @@ -0,0 +1,111 @@ +(* +Module: Test_Aliases + Provides unit tests and examples for the <Aliases> lens. +*) + +module Test_aliases = + +(* Variable: file + A full configuration file *) + let file = "# +# Aliases in this file will NOT be expanded in the header from +# Mail, but WILL be visible over networks or from /bin/mail. + +# Basic system aliases -- these MUST be present. +mailer-daemon: postmaster +postmaster: root + +# General redirections for pseudo accounts. +bin: root , adm, + bob +daemon: root +adm: root +file: /var/foo +pipe1: |/bin/ls +pipe2 : |\"/usr/bin/ls args,\" +" + +(* Test: Aliases.lns + Testing <Aliases.lns> on <file> *) + test Aliases.lns get file = + { } + { "#comment" = "Aliases in this file will NOT be expanded in the header from" } + { "#comment" = "Mail, but WILL be visible over networks or from /bin/mail." } + {} + { "#comment" = "Basic system aliases -- these MUST be present." } + { "1" { "name" = "mailer-daemon" } + { "value" = "postmaster" } } + { "2" { "name" = "postmaster" } + { "value" = "root" } } + {} + { "#comment" = "General redirections for pseudo accounts." } + { "3" { "name" = "bin" } + { "value" = "root" } + { "value" = "adm" } + { "value" = "bob" } } + { "4" { "name" = "daemon" } + { "value" = "root" } } + { "5" { "name" = "adm" } + { "value" = "root" } } + { "6" { "name" = "file" } + { "value" = "/var/foo" } } + { "7" { "name" = "pipe1" } + { "value" = "|/bin/ls" } } + { "8" { "name" = "pipe2" } + { "value" = "|\"/usr/bin/ls args,\"" } } + +(* Test: Aliases.lns + Put test for <Aliases.lns> on <file> *) + test Aliases.lns put file after + rm "/4" ; rm "/5" ; rm "/6" ; rm "/7" ; rm "/8" ; + set "/1/value[2]" "barbar" ; + set "/3/value[2]" "ruth" + = "# +# Aliases in this file will NOT be expanded in the header from +# Mail, but WILL be visible over networks or from /bin/mail. + +# Basic system aliases -- these MUST be present. +mailer-daemon: postmaster, barbar +postmaster: root + +# General redirections for pseudo accounts. +bin: root , ruth, + bob +" + + (* Test: Aliases.lns + Schema violation, no 3/name *) + test Aliases.lns put file after + rm "/3" ; + set "/3/value/2" "ruth" + = * + + (* Variable: nocomma + Don't have to have whitespace after a comma *) + let nocomma = "alias: target1,target2\n" + + (* Test: Aliases.lns + Testing <Aliases.lns> on <nocomma> *) + test Aliases.lns get nocomma = + { "1" + { "name" = "alias" } + { "value" = "target1" } + { "value" = "target2" } } + + (* Test: Aliases.lns + Ticket #229: commands can be fully enclosed in quotes *) + test Aliases.lns get "somebody: \"|exit 67\"\n" = + { "1" + { "name" = "somebody" } + { "value" = "\"|exit 67\"" } } + + (* Test: Aliases.lns + Don't have to have whitespace after the colon *) + test Aliases.lns get "alias:target\n" = + { "1" + { "name" = "alias" } + { "value" = "target" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_anaconda.aug b/Sharp.Augeas.Test/lens/tests/test_anaconda.aug new file mode 100644 index 0000000..50b0ac2 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_anaconda.aug @@ -0,0 +1,89 @@ +(* +Module: Test_Anaconda + Provides unit tests and examples for the <Anaconda> lens. + + - 'exampleN' snippets are taken from the documentation: + https://anaconda-installer.readthedocs.io/en/latest/user-interaction-config-file-spec.html + - 'installedN' snippets are taken from the resulting files after + a successful installation +*) + +module Test_Anaconda = + +let example1 = "# comment example - before the section headers + +[section_1] +# comment example - inside section 1 +key_a_in_section1=some_value +key_b_in_section1=some_value + +[section_2] +# comment example - inside section 2 +key_a_in_section2=some_value +" + +test Anaconda.lns get example1 = + { "#comment" = "comment example - before the section headers" } + { } + { "section_1" + { "#comment" = "comment example - inside section 1" } + { "key_a_in_section1" = "some_value" } + { "key_b_in_section1" = "some_value" } + { } + } + { "section_2" + { "#comment" = "comment example - inside section 2" } + { "key_a_in_section2" = "some_value" } + } + +let example2 = "# this is the user interaction config file + +[General] +post_install_tools_disabled=0 + +[DatetimeSpoke] +# the date and time spoke has been visited +visited=1 +changed_timezone=1 +changed_ntp=0 +changed_timedate=1 + +[KeyboardSpoke] +# the keyboard spoke has not been visited +visited=0 +" + +test Anaconda.lns get example2 = + { "#comment" = "this is the user interaction config file" } + { } + { "General" + { "post_install_tools_disabled" = "0" } + { } + } + { "DatetimeSpoke" + { "#comment" = "the date and time spoke has been visited" } + { "visited" = "1" } + { "changed_timezone" = "1" } + { "changed_ntp" = "0" } + { "changed_timedate" = "1" } + { } + } + { "KeyboardSpoke" + { "#comment" = "the keyboard spoke has not been visited" } + { "visited" = "0" } + } + +let installed1 = "# This file has been generated by the Anaconda Installer 21.48.22.134-1 + +[ProgressSpoke] +visited = 1 + +" + +test Anaconda.lns get installed1 = + { "#comment" = "This file has been generated by the Anaconda Installer 21.48.22.134-1" } + { } + { "ProgressSpoke" + { "visited" = "1" } + { } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_anacron.aug b/Sharp.Augeas.Test/lens/tests/test_anacron.aug new file mode 100644 index 0000000..9339855 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_anacron.aug @@ -0,0 +1,39 @@ +(* +Module: Test_Anacron + Provides unit tests and examples for the <Anacron> lens. +*) + +module Test_anacron = + +(* Variable: conf *) +let conf = "# /etc/anacrontab: configuration file for anacron + +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# These replace cron's entries +1 5 cron.daily nice run-parts --report /etc/cron.daily +7 10 cron.weekly nice run-parts --report /etc/cron.weekly +@monthly 15 cron.monthly nice run-parts --report /etc/cron.monthly +" + +(* Test: Anacron.lns *) +test Anacron.lns get conf = + { "#comment" = "/etc/anacrontab: configuration file for anacron" } + { } + { "SHELL" = "/bin/sh" } + { "PATH" = "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" } + { } + { "#comment" = "These replace cron's entries" } + { "entry" = "nice run-parts --report /etc/cron.daily" + { "period" = "1" } + { "delay" = "5" } + { "job-identifier" = "cron.daily" } } + { "entry" = "nice run-parts --report /etc/cron.weekly" + { "period" = "7" } + { "delay" = "10" } + { "job-identifier" = "cron.weekly" } } + { "entry" = "nice run-parts --report /etc/cron.monthly" + { "period_name" = "monthly" } + { "delay" = "15" } + { "job-identifier" = "cron.monthly" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_approx.aug b/Sharp.Augeas.Test/lens/tests/test_approx.aug new file mode 100644 index 0000000..3e8aa0f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_approx.aug @@ -0,0 +1,48 @@ +(* +Module: Test_Approx + Provides unit tests and examples for the <Approx> lens. +*) + +module Test_approx = + +(* Variable: default_approx + A full configuration *) + let default_approx = "# The following are the defaults, so there is no need +# to uncomment them unless you want a different value. +# See approx.conf(5) for details. + +$interface any +$port 9999 +$interval 720 +$max_wait 10 +$max_rate unlimited +$debug false + +# Here are some examples of remote repository mappings. +# See http://www.debian.org/mirror/list for mirror sites. + +debian http://ftp.nl.debian.org/debian +debian-volatile http://ftp.nl.debian.org/debian-volatile +security http://security.debian.org +" + +(* Test: Approx.lns + Testing <Approx.lns> on <default_approx> *) + test Approx.lns get default_approx = + { "#comment" = "The following are the defaults, so there is no need" } + { "#comment" = "to uncomment them unless you want a different value." } + { "#comment" = "See approx.conf(5) for details." } + { } + { "$interface" = "any" } + { "$port" = "9999" } + { "$interval" = "720" } + { "$max_wait" = "10" } + { "$max_rate" = "unlimited" } + { "$debug" = "false" } + { } + { "#comment" = "Here are some examples of remote repository mappings." } + { "#comment" = "See http://www.debian.org/mirror/list for mirror sites." } + { } + { "debian" = "http://ftp.nl.debian.org/debian" } + { "debian-volatile" = "http://ftp.nl.debian.org/debian-volatile" } + { "security" = "http://security.debian.org" } diff --git a/Sharp.Augeas.Test/lens/tests/test_apt_update_manager.aug b/Sharp.Augeas.Test/lens/tests/test_apt_update_manager.aug new file mode 100644 index 0000000..1921a95 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_apt_update_manager.aug @@ -0,0 +1,41 @@ +(* +Module: Test_Apt_Update_Manager + Provides unit tests and examples for the <Apt_Update_Manager> lens. +*) +module Test_Apt_Update_Manager = + +(* Variable: meta_release *) +let meta_release = "# default location for the meta-release file + +[METARELEASE] +URI = http://changelogs.ubuntu.com/meta-release +URI_LTS = http://changelogs.ubuntu.com/meta-release-lts +URI_UNSTABLE_POSTFIX = -development +URI_PROPOSED_POSTFIX = -proposed +" + +(* Test: Apt_Update_Manager.lns *) +test Apt_Update_Manager.lns get meta_release = + { "#comment" = "default location for the meta-release file" } + { } + { "METARELEASE" + { "URI" = "http://changelogs.ubuntu.com/meta-release" } + { "URI_LTS" = "http://changelogs.ubuntu.com/meta-release-lts" } + { "URI_UNSTABLE_POSTFIX" = "-development" } + { "URI_PROPOSED_POSTFIX" = "-proposed" } + } + +(* Variable: release_upgrades *) +let release_upgrades = "# Default behavior for the release upgrader. + +[DEFAULT] +Prompt=lts +" + +(* Test: Apt_Update_Manager.lns *) +test Apt_Update_Manager.lns get release_upgrades = + { "#comment" = "Default behavior for the release upgrader." } + { } + { "DEFAULT" + { "Prompt" = "lts" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_aptcacherngsecurity.aug b/Sharp.Augeas.Test/lens/tests/test_aptcacherngsecurity.aug new file mode 100644 index 0000000..a10d5d3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_aptcacherngsecurity.aug @@ -0,0 +1,34 @@ +(* Test for AptCacherNGSecurity lens. + +About: License + Copyright 2013 Erik B. Andersen; this file is licenced under the LGPL v2+. + +*) +module Test_AptCacherNGSecurity = + let conf = " +# This file contains confidential data and should be protected with file +# permissions from being read by untrusted users. +# +# NOTE: permissions are fixated with dpkg-statoverride on Debian systems. +# Read its manual page for details. + +# Basic authentication with username and password, required to +# visit pages with administrative functionality. Format: username:password + +AdminAuth: mooma:moopa +" + + test AptCacherNGSecurity.lns get conf = + {} + { "#comment" = "This file contains confidential data and should be protected with file" } + { "#comment" = "permissions from being read by untrusted users." } + {} + { "#comment" = "NOTE: permissions are fixated with dpkg-statoverride on Debian systems." } + { "#comment" = "Read its manual page for details." } + {} + { "#comment" = "Basic authentication with username and password, required to" } + { "#comment" = "visit pages with administrative functionality. Format: username:password" } + {} + { "AdminAuth" + { "mooma" = "moopa" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_aptconf.aug b/Sharp.Augeas.Test/lens/tests/test_aptconf.aug new file mode 100644 index 0000000..6c11ace --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_aptconf.aug @@ -0,0 +1,181 @@ +module Test_aptconf = + + (* Test multiline C-style comments *) + let comment_multiline = "/* This is a long +/* multiline +comment +*/ +" + + test AptConf.comment get comment_multiline = + { "#mcomment" + { "1" = "This is a long" } + { "2" = "/* multiline" } + { "3" = "comment" } } + + + (* Test empty multiline C-style comments *) + let comment_multiline_empty = "/* */\n" + + test AptConf.empty get comment_multiline_empty = { } + + + (* Test a simple entry *) + let simple_entry = "APT::Clean-Installed \"true\";\n" + + test AptConf.entry get simple_entry = + { "APT" { "Clean-Installed" = "true" } } + + (* Test simple recursivity *) + let simple_recursion = "APT { Clean-Installed \"true\"; };\n" + + test AptConf.entry get simple_recursion = + { "APT" { "Clean-Installed" = "true" } } + + (* Test simple recursivity with several entries *) + let simple_recursion_multi = + "APT { + Clean-Installed \"true\"; + Get::Assume-Yes \"true\"; + }\n" + + test AptConf.entry get simple_recursion_multi = + { "APT" + { "Clean-Installed" = "true" } + { "Get" { "Assume-Yes" = "true" } } } + + (* Test multiple recursivity *) + let multiple_recursion = + "APT { Get { Assume-Yes \"true\"; } };\n" + + test AptConf.entry get multiple_recursion = + { "APT" { "Get" { "Assume-Yes" = "true" } } } + + (* Test simple list *) + let simple_list = "DPKG::options { \"--force-confold\"; }\n" + + test AptConf.entry get simple_list = + { "DPKG" { "options" { "@elem" = "--force-confold" } } } + + + (* Test list elements with spaces *) + let list_spaces = "Unattended-Upgrade::Allowed-Origins { + \"Ubuntu lucid-security\"; };\n" + + test AptConf.entry get list_spaces = + { "Unattended-Upgrade" { "Allowed-Origins" + { "@elem" = "Ubuntu lucid-security" } } } + + (* Test recursive list *) + let recursive_list = + "DPKG { + options { + \"--force-confold\"; + \"--nocheck\"; + } };\n" + + test AptConf.entry get recursive_list = + { "DPKG" + { "options" + { "@elem" = "--force-confold" } + { "@elem" = "--nocheck" } } } + + (* Test empty group *) + let empty_group = + "APT\n{\n};\n" + + test AptConf.entry get empty_group = { "APT" } + + (* Test #include *) + let include = " #include /path/to/file\n" + + test AptConf.include get include = + { "#include" = "/path/to/file" } + + (* Test #clear *) + let clear = "#clear Dpkg::options Apt::Get::Assume-Yes\n" + + test AptConf.clear get clear = + { "#clear" + { "name" = "Dpkg::options" } + { "name" = "Apt::Get::Assume-Yes" } } + + + (* Test put simple value *) + test AptConf.entry put "APT::Clean-Installed \"true\";\n" + after set "/APT/Clean-Installed" "false" = + "APT {\nClean-Installed \"false\";\n};\n" + + (* Test rm everything *) + test AptConf.entry put "APT { Clean-Installed \"true\"; }\n" + after rm "/APT" = "" + + (* Test rm on recursive value *) + test AptConf.entry put "APT { Clean-Installed \"true\"; }\n" + after rm "/APT/Clean-Installed" = "APT { }\n" + + (* Test put recursive value *) + test AptConf.entry put "APT { Clean-Installed \"true\"; }\n" + after set "/APT/Clean-Installed" "false" = + "APT { Clean-Installed \"false\"; }\n" + + (* Test multiple lens *) + let multiple_entries = + "APT { Clean-Installed \"true\"; }\n + APT::Clean-Installed \"true\";\n" + + test AptConf.lns get multiple_entries = + { "APT" { "Clean-Installed" = "true" } } + {} + { "APT" { "Clean-Installed" = "true" } } + + (* Test with full lens *) + test AptConf.lns put "APT { Clean-Installed \"true\"; }\n" + after set "/APT/Clean-Installed" "false" = + "APT { Clean-Installed \"false\"; }\n" + + (* Test single commented entry *) + let commented_entry = + "Unattended-Upgrade::Allowed-Origins { + \"Ubuntu lucid-security\"; +// \"Ubuntu lucid-updates\"; + };\n" + + test AptConf.lns get commented_entry = + { "Unattended-Upgrade" { "Allowed-Origins" + { "@elem" = "Ubuntu lucid-security" } + { "#comment" = "\"Ubuntu lucid-updates\";" } } } + + (* Test multiple commented entries *) + let commented_entries = + "// List of packages to not update +Unattended-Upgrade::Package-Blacklist { +// \"vim\"; +// \"libc6\"; +// \"libc6-dev\"; +// \"libc6-i686\" +}; +" + + test AptConf.lns get commented_entries = + { "#comment" = "List of packages to not update" } + { "Unattended-Upgrade" { "Package-Blacklist" + { "#comment" = "\"vim\";" } + { "#comment" = "\"libc6\";" } + { "#comment" = "\"libc6-dev\";" } + { "#comment" = "\"libc6-i686\"" } + } } + + (* Test complex elem *) + let complex_elem = "DPkg::Post-Invoke {\"if [ -d /var/lib/update-notifier ]; then touch /var/lib/update-notifier/dpkg-run-stamp; fi; if [ -e /var/lib/update-notifier/updates-available ]; then echo > /var/lib/update-notifier/updates-available; fi \"};\n" + + test AptConf.lns get complex_elem = + { "DPkg" { "Post-Invoke" + { "@elem" = "if [ -d /var/lib/update-notifier ]; then touch /var/lib/update-notifier/dpkg-run-stamp; fi; if [ -e /var/lib/update-notifier/updates-available ]; then echo > /var/lib/update-notifier/updates-available; fi " } } } + + (* Accept hash comments *) + test AptConf.lns get "# a comment\n" = + { "#comment" = "a comment" } + + (* Accept empty hash comments *) + test AptConf.lns get "# \n" = { } diff --git a/Sharp.Augeas.Test/lens/tests/test_aptpreferences.aug b/Sharp.Augeas.Test/lens/tests/test_aptpreferences.aug new file mode 100644 index 0000000..bf26348 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_aptpreferences.aug @@ -0,0 +1,66 @@ +module Test_aptpreferences = + + let conf ="Explanation: Backport packages are never prioritary +Package: * +Pin: release a=backports +Pin-Priority: 100 + +# This is a comment +Explanation: My packages are the most prioritary +Package: * +Pin: release l=Raphink, v=3.0 +Pin-Priority: 700 + +Package: liferea-data +Pin: version 1.4.26-4 +Pin-Priority: 600 + +Package: * +Pin: origin packages.linuxmint.com +Pin-Priority: 700 +" + + test AptPreferences.lns get conf = + { "1" + { "Explanation" = "Backport packages are never prioritary" } + { "Package" = "*" } + { "Pin" = "release" + { "a" = "backports" } } + { "Pin-Priority" = "100" } } + { "2" + { "#comment" = "This is a comment" } + { "Explanation" = "My packages are the most prioritary" } + { "Package" = "*" } + { "Pin" = "release" + { "l" = "Raphink" } + { "v" = "3.0" } } + { "Pin-Priority" = "700" } } + { "3" + { "Package" = "liferea-data" } + { "Pin" = "version" + { "version" = "1.4.26-4" } } + { "Pin-Priority" = "600" } } + { "4" + { "Package" = "*" } + { "Pin" = "origin" + { "origin" = "packages.linuxmint.com" } } + { "Pin-Priority" = "700" } } + +(*************************************************************************) + + test AptPreferences.lns put "\n" after + set "/1/Package" "something-funny"; + set "/1/Pin" "version"; + set "/1/Pin/version" "1.2.3-4"; + set "/1/Pin-Priority" "2000" + = " +Package: something-funny +Pin: version 1.2.3-4 +Pin-Priority: 2000 +" + +(* Test: AptPreferences.pin + Spaces in origins are valid *) +test AptPreferences.pin get "Pin: release o=Quantum GIS project\n" = + { "Pin" = "release" + { "o" = "Quantum GIS project" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_aptsources.aug b/Sharp.Augeas.Test/lens/tests/test_aptsources.aug new file mode 100644 index 0000000..7546393 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_aptsources.aug @@ -0,0 +1,102 @@ +module Test_aptsources = + + let simple_source = "deb ftp://mirror.bytemark.co.uk/debian/ etch main\n" + let multi_components = "deb http://security.debian.org/ etch/updates main contrib non-free\n" + + test Aptsources.lns get simple_source = + { "1" + { "type" = "deb" } + { "uri" = "ftp://mirror.bytemark.co.uk/debian/" } + { "distribution" = "etch" } + { "component" = "main" } + } + + test Aptsources.lns get multi_components = + { "1" + { "type" = "deb" } + { "uri" = "http://security.debian.org/" } + { "distribution" = "etch/updates" } + { "component" = "main" } + { "component" = "contrib" } + { "component" = "non-free" } + } + + +let multi_line = "#deb http://www.backports.org/debian/ sarge postfix + # deb http://people.debian.org/~adconrad sarge subversion + +deb ftp://mirror.bytemark.co.uk/debian/ etch main non-free contrib + deb http://security.debian.org/ etch/updates main contrib non-free # security line + deb-src http://mirror.bytemark.co.uk/debian etch main contrib non-free\n" + + test Aptsources.lns get multi_line = + { "#comment" = "deb http://www.backports.org/debian/ sarge postfix" } + { "#comment" = "deb http://people.debian.org/~adconrad sarge subversion" } + {} + { "1" + { "type" = "deb" } + { "uri" = "ftp://mirror.bytemark.co.uk/debian/" } + { "distribution" = "etch" } + { "component" = "main" } + { "component" = "non-free" } + { "component" = "contrib" } + } + { "2" + { "type" = "deb" } + { "uri" = "http://security.debian.org/" } + { "distribution" = "etch/updates" } + { "component" = "main" } + { "component" = "contrib" } + { "component" = "non-free" } + } + { "3" + { "type" = "deb-src" } + { "uri" = "http://mirror.bytemark.co.uk/debian" } + { "distribution" = "etch" } + { "component" = "main" } + { "component" = "contrib" } + { "component" = "non-free" } + } + + let trailing_comment = "deb ftp://server/debian/ etch main # comment\n" + + (* Should be a noop; makes sure that we preserve the trailing comment *) + test Aptsources.lns put trailing_comment after + set "/1/type" "deb" + = trailing_comment + + (* Support options, GH #295 *) + test Aptsources.lns get "deb [arch=amd64] tor+http://ftp.us.debian.org/debian sid main contrib +deb [ arch+=amd64 trusted-=true ] http://ftp.us.debian.org/debian sid main contrib\n" = + { "1" + { "type" = "deb" } + { "options" + { "arch" = "amd64" } + } + { "uri" = "tor+http://ftp.us.debian.org/debian" } + { "distribution" = "sid" } + { "component" = "main" } + { "component" = "contrib" } } + { "2" + { "type" = "deb" } + { "options" + { "arch" = "amd64" { "operation" = "+" } } + { "trusted" = "true" { "operation" = "-" } } + } + { "uri" = "http://ftp.us.debian.org/debian" } + { "distribution" = "sid" } + { "component" = "main" } + { "component" = "contrib" } } + + (* cdrom entries may have spaces, GH #296 *) + test Aptsources.lns get "deb cdrom:[Debian GNU/Linux 7.5.0 _Wheezy_ - Official amd64 CD Binary-1 20140426-13:37]/ wheezy main\n" = + { "1" + { "type" = "deb" } + { "uri" = "cdrom:[Debian GNU/Linux 7.5.0 _Wheezy_ - Official amd64 CD Binary-1 20140426-13:37]/" } + { "distribution" = "wheezy" } + { "component" = "main" } } + + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_authinfo2.aug b/Sharp.Augeas.Test/lens/tests/test_authinfo2.aug new file mode 100644 index 0000000..8da1bdc --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_authinfo2.aug @@ -0,0 +1,44 @@ +module Test_authinfo2 = + +let conf = "# Comment +[s3] +storage-url: s3:// +backend-login: joe +backend-password: notquitesecret + +[fs1] +storage-url: s3://joes-first-bucket +fs-passphrase: neitheristhis + +[fs2] + +storage-url: s3://joes-second-bucket +fs-passphrase: swordfish +[fs3] +storage-url: s3://joes-second-bucket/with-prefix +backend-login: bill +backend-password: bi23ll +fs-passphrase: ll23bi +" + + +test Authinfo2.lns get conf = + { "#comment" = "Comment" } + { "s3" + { "storage-url" = "s3://" } + { "backend-login" = "joe" } + { "backend-password" = "notquitesecret" } + {} } + { "fs1" + { "storage-url" = "s3://joes-first-bucket" } + { "fs-passphrase" = "neitheristhis" } + {} } + { "fs2" + {} + { "storage-url" = "s3://joes-second-bucket" } + { "fs-passphrase" = "swordfish" } } + { "fs3" + { "storage-url" = "s3://joes-second-bucket/with-prefix" } + { "backend-login" = "bill" } + { "backend-password" = "bi23ll" } + { "fs-passphrase" = "ll23bi" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_authorized_keys.aug b/Sharp.Augeas.Test/lens/tests/test_authorized_keys.aug new file mode 100644 index 0000000..69f2f3c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_authorized_keys.aug @@ -0,0 +1,128 @@ +(* +Module: Test_Authorized_Keys + Provides unit tests and examples for the <Authorized_Keys> lens. +*) + +module Test_Authorized_Keys = + +(* Test: Authorized_Keys *) +test Authorized_Keys.lns get "tunnel=\"0\",no-agent-forwarding,command=\"sh /etc/netstart tun0\",permitopen=\"192.0.2.1:80\",permitopen=\"192.0.2.2:25\" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3RC8whKGFx+b7BMTFtnIWl6t/qyvOvnuqIrMNI9J8+1sEYv8Y/pJRh0vAe2RaSKAgB2hyzXwSJ1Fh+ooraUAJ+q7P2gg2kQF1nCFeGVjtV9m4ZrV5kZARcQMhp0Bp67tPo2TCtnthPYZS/YQG6u/6Aco1XZjPvuKujAQMGSgqNskhKBO9zfhhkAMIcKVryjKYHDfqbDUCCSNzlwFLts3nJ0Hfno6Hz+XxuBIfKOGjHfbzFyUQ7smYnzF23jFs4XhvnjmIGQJcZT4kQAsRwQubyuyDuqmQXqa+2SuQfkKTaPOlVqyuEWJdG2weIF8g3YP12czsBgNppz3jsnhEgstnQ== rpinson on rpinson\n" = + { "key" = "AAAAB3NzaC1yc2EAAAABIwAAAQEA3RC8whKGFx+b7BMTFtnIWl6t/qyvOvnuqIrMNI9J8+1sEYv8Y/pJRh0vAe2RaSKAgB2hyzXwSJ1Fh+ooraUAJ+q7P2gg2kQF1nCFeGVjtV9m4ZrV5kZARcQMhp0Bp67tPo2TCtnthPYZS/YQG6u/6Aco1XZjPvuKujAQMGSgqNskhKBO9zfhhkAMIcKVryjKYHDfqbDUCCSNzlwFLts3nJ0Hfno6Hz+XxuBIfKOGjHfbzFyUQ7smYnzF23jFs4XhvnjmIGQJcZT4kQAsRwQubyuyDuqmQXqa+2SuQfkKTaPOlVqyuEWJdG2weIF8g3YP12czsBgNppz3jsnhEgstnQ==" + { "options" + { "tunnel" = "0" } + { "no-agent-forwarding" } + { "command" = "sh /etc/netstart tun0" } + { "permitopen" = "192.0.2.1:80" } + { "permitopen" = "192.0.2.2:25" } + } + { "type" = "ssh-rsa" } + { "comment" = "rpinson on rpinson" } } + +(* Variable: keys *) +let keys = "# Example keys, one of each type +# +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDpWrKYsEsVUyuwMN4ReBN/TMGsaUWzDKDz/uQr6MlNNM95MDK/BPyJ+DiBiNMFVLpRt3gH3eCJBLJKMuUDaTNy5uym2zNgAaAIVct6M2GHI68W3iY3Ja8/MaRPbyTpMh1O74S+McpAW1SGL2YzFchYMjTnu/kOD3lxiWNiDLvdLFZu0wPOi7CYG37VXR4Thb0cC92zqnCjaP1TwfhpEYUZoowElYkoV2vG+19O6cRm/zduYcf8hmegZKB4GFUJTtZ2gZ18XJDSQd0ykK3KPt/+bKskdrtfiOwSZAmUZmd2YuAlY6+CBn1T3UBdQntueukd0z1xhd6SX7Bl8+qyqLQ3 user@example +ssh-dsa AAAA user@example +ecdsa-sha2-nistp256 AAAA user@example +ssh-ed25519 AAAA user@example + +# Example comments +ssh-dsa AAAA +ssh-dsa AAAA user@example +" + +(* Test: Authorized_Keys.lns *) +test Authorized_Keys.lns get keys = + { "#comment" = "Example keys, one of each type" } + { } + { "key" = +"AAAAB3NzaC1yc2EAAAADAQABAAABAQDpWrKYsEsVUyuwMN4ReBN/TMGsaUWzDKDz/uQr6MlNNM95MDK/BPyJ+DiBiNMFVLpRt3gH3eCJBLJKMuUDaTNy5uym2zNgAaAIVct6M2GHI68W3iY3Ja8/MaRPbyTpMh1O74S+McpAW1SGL2YzFchYMjTnu/kOD3lxiWNiDLvdLFZu0wPOi7CYG37VXR4Thb0cC92zqnCjaP1TwfhpEYUZoowElYkoV2vG+19O6cRm/zduYcf8hmegZKB4GFUJTtZ2gZ18XJDSQd0ykK3KPt/+bKskdrtfiOwSZAmUZmd2YuAlY6+CBn1T3UBdQntueukd0z1xhd6SX7Bl8+qyqLQ3" + { "type" = "ssh-rsa" } + { "comment" = "user@example" } + } + { "key" = "AAAA" + { "type" = "ssh-dsa" } + { "comment" = "user@example" } + } + { "key" = "AAAA" + { "type" = "ecdsa-sha2-nistp256" } + { "comment" = "user@example" } + } + { "key" = "AAAA" + { "type" = "ssh-ed25519" } + { "comment" = "user@example" } + } + { } + { "#comment" = "Example comments" } + { "key" = "AAAA" + { "type" = "ssh-dsa" } + } + { "key" = "AAAA" + { "type" = "ssh-dsa" } + { "comment" = "user@example" } + } + +(* Variable: options *) +let options = "# Example options +no-pty ssh-dsa AAAA +no-pty ssh-ed25519 AAAA +no-pty,command=\"foo\" ssh-dsa AAAA +no-pty,command=\"foo bar\" ssh-dsa AAAA +no-pty,from=\"example.com,10.1.1.0/16\" ssh-dsa AAAA +no-pty,environment=\"LANG=en_GB.UTF8\" ssh-dsa AAAA +" + +(* Test: Authorized_Keys.lns *) +test Authorized_Keys.lns get options = + { "#comment" = "Example options" } + { "key" = "AAAA" + { "options" + { "no-pty" } + } + { "type" = "ssh-dsa" } + } + { "key" = "AAAA" + { "options" + { "no-pty" } + } + { "type" = "ssh-ed25519" } + } + { "key" = "AAAA" + { "options" + { "no-pty" } + { "command" = "foo" } + } + { "type" = "ssh-dsa" } + } + { "key" = "AAAA" + { "options" + { "no-pty" } + { "command" = "foo bar" } + } + { "type" = "ssh-dsa" } + } + { "key" = "AAAA" + { "options" + { "no-pty" } + { "from" = "example.com,10.1.1.0/16" } + } + { "type" = "ssh-dsa" } + } + { "key" = "AAAA" + { "options" + { "no-pty" } + { "environment" = "LANG=en_GB.UTF8" } + } + { "type" = "ssh-dsa" } + } + +(* Test: Authorized_keys.lns + GH 165 *) +test Authorized_keys.lns get "command=\"echo 'Please login as the user \\\"blaauser\\\" rather than the user \\\"root\\\".';echo;sleep 10\" ssh-rsa DEADBEEF== username1\n" = + { "key" = "DEADBEEF==" + { "options" + { "command" = "echo 'Please login as the user \\\"blaauser\\\" rather than the user \\\"root\\\".';echo;sleep 10" } + } + { "type" = "ssh-rsa" } + { "comment" = "username1" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_authselectpam.aug b/Sharp.Augeas.Test/lens/tests/test_authselectpam.aug new file mode 100644 index 0000000..78506d0 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_authselectpam.aug @@ -0,0 +1,37 @@ +module Test_AuthselectPam = + +let example ="auth required pam_env.so +auth required pam_faildelay.so delay=2000000 +auth required pam_faillock.so preauth silent {include if \"with-faillock\"} +auth required pam_u2f.so cue {if not \"without-pam-u2f-nouserok\":nouserok} {include if \"with-pam-u2f-2fa\"} +" + +test AuthselectPam.lns get example = + { "1" + { "type" = "auth" } + { "control" = "required" } + { "module" = "pam_env.so" } } + { "2" + { "type" = "auth" } + { "control" = "required" } + { "module" = "pam_faildelay.so" } + { "argument" = "delay=2000000" } } + { "3" + { "type" = "auth" } + { "control" = "required" } + { "module" = "pam_faillock.so" } + { "argument" = "preauth" } + { "argument" = "silent" } + { "authselect_conditional" = "include if" + { "feature" = "with-faillock" } } } + { "4" + { "type" = "auth" } + { "control" = "required" } + { "module" = "pam_u2f.so" } + { "argument" = "cue" } + { "authselect_conditional" = "if" + { "not" } + { "feature" = "without-pam-u2f-nouserok" } + { "on_true" = "nouserok" } } + { "authselect_conditional" = "include if" + { "feature" = "with-pam-u2f-2fa" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_automaster.aug b/Sharp.Augeas.Test/lens/tests/test_automaster.aug new file mode 100644 index 0000000..696acb9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_automaster.aug @@ -0,0 +1,64 @@ +module Test_automaster = + + let example = "# +# Sample auto.master file +# + +/- auto.data +/net -hosts ro +/misc /etc/auto.misc +/home /etc/auto.home +/home ldap:example.com:ou=auto.home,dc=example,dc=com +/mnt yp:mnt.map -strict,-Dfoo=bar,uid=1000 +/mnt yp,sun:mnt.map +/auto /etc/auto.HD --timeout=15 --ghost + ++dir:/etc/auto.master.d ++ auto.master +" + + test Automaster.lns get example = + { } + { "#comment" = "Sample auto.master file" } + { } + { } + { "1" = "/-" + { "map" = "auto.data" } } + { "2" = "/net" + { "map" = "-hosts" } + { "opt" = "ro" } } + { "3" = "/misc" + { "map" = "/etc/auto.misc" } } + { "4" = "/home" + { "map" = "/etc/auto.home" } } + { "5" = "/home" + { "type" = "ldap" } + { "host" = "example.com" } + { "map" = "ou=auto.home,dc=example,dc=com" } } + { "6" = "/mnt" + { "type" = "yp" } + { "map" = "mnt.map" } + { "opt" = "-strict" } + { "opt" = "-Dfoo" + { "value" = "bar" } } + { "opt" = "uid" + { "value" = "1000" } } } + { "7" = "/mnt" + { "type" = "yp" } + { "format" = "sun" } + { "map" = "mnt.map" } } + { "8" = "/auto" + { "map" = "/etc/auto.HD" } + { "opt" = "--timeout" + { "value" = "15" } } + { "opt" = "--ghost" } } + { } + { "9" = "+" + { "type" = "dir" } + { "map" = "/etc/auto.master.d" } } + { "10" = "+" + { "map" = "auto.master" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_automounter.aug b/Sharp.Augeas.Test/lens/tests/test_automounter.aug new file mode 100644 index 0000000..c84fc0a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_automounter.aug @@ -0,0 +1,171 @@ +module Test_automounter = + + let example = "# +# This is an automounter map and it has the following format +# key [ -mount-options-separated-by-comma ] location +# Details may be found in the autofs(5) manpage + +# indirect map +cd -fstype=iso9660,ro,nosuid,nodev :/dev/cdrom +kernel -ro,soft,intr ftp.kernel.org:/pub/linux +* -fstype=auto,loop,ro :/srv/distros/isos/&.iso + +# direct map +/nfs/apps/mozilla bogus:/usr/local/moxill + +# replicated server +path host1,host2,hostn:/path/path +path host1,host2:/blah host3(1):/some/other/path +path host1(5),host2(6),host3(1):/path/path + +# multi-mount map +server -rw,hard,intr / -ro myserver.me.org:/ +server -rw,hard,intr / -ro myserver.me.org:/ /usr myserver.me.org:/usr +server -rw,hard,intr / -ro myserver.me.org:/ \ + /usr myserver.me.org:/usr \ + /home myserver.me.org:/home + +server -rw,hard,intr / -ro my-with-dash-server.me.org:/ + +# included maps ++auto_home +" + + test Automounter.lns get example = + { } + { "#comment" = "This is an automounter map and it has the following format" } + { "#comment" = "key [ -mount-options-separated-by-comma ] location" } + { "#comment" = "Details may be found in the autofs(5) manpage" } + { } + { "#comment" = "indirect map" } + { "1" = "cd" + { "opt" = "fstype" + { "value" = "iso9660" } } + { "opt" = "ro" } + { "opt" = "nosuid" } + { "opt" = "nodev" } + { "location" + { "1" + { "path" = "/dev/cdrom" } } } } + { "2" = "kernel" + { "opt" = "ro" } + { "opt" = "soft" } + { "opt" = "intr" } + { "location" + { "1" + { "host" = "ftp.kernel.org" } + { "path" = "/pub/linux" } } } } + { "3" = "*" + { "opt" = "fstype" + { "value" = "auto" } } + { "opt" = "loop" } + { "opt" = "ro" } + { "location" + { "1" + { "path" = "/srv/distros/isos/&.iso" } } } } + { } + { "#comment" = "direct map" } + { "4" = "/nfs/apps/mozilla" + { "location" + { "1" + { "host" = "bogus" } + { "path" = "/usr/local/moxill" } } } } + { } + { "#comment" = "replicated server" } + { "5" = "path" + { "location" + { "1" + { "host" = "host1" } + { "host" = "host2" } + { "host" = "hostn" } + { "path" = "/path/path" } } } } + { "6" = "path" + { "location" + { "1" + { "host" = "host1" } + { "host" = "host2" } + { "path" = "/blah" } } + { "2" + { "host" = "host3" + { "weight" = "1" } } + { "path" = "/some/other/path" } } } } + { "7" = "path" + { "location" + { "1" + { "host" = "host1" + { "weight" = "5" } } + { "host" = "host2" + { "weight" = "6" } } + { "host" = "host3" + { "weight" = "1" } } + { "path" = "/path/path" } } } } + { } + { "#comment" = "multi-mount map" } + { "8" = "server" + { "opt" = "rw" } + { "opt" = "hard" } + { "opt" = "intr" } + { "mount" + { "1" = "/" + { "opt" = "ro" } + { "location" + { "1" + { "host" = "myserver.me.org" } + { "path" = "/" } } } } } } + { "9" = "server" + { "opt" = "rw" } + { "opt" = "hard" } + { "opt" = "intr" } + { "mount" + { "1" = "/" + { "opt" = "ro" } + { "location" + { "1" + { "host" = "myserver.me.org" } + { "path" = "/" } } } } + { "2" = "/usr" + { "location" + { "1" + { "host" = "myserver.me.org" } + { "path" = "/usr" } } } } } } + { "10" = "server" + { "opt" = "rw" } + { "opt" = "hard" } + { "opt" = "intr" } + { "mount" + { "1" = "/" + { "opt" = "ro" } + { "location" + { "1" + { "host" = "myserver.me.org" } + { "path" = "/" } } } } + { "2" = "/usr" + { "location" + { "1" + { "host" = "myserver.me.org" } + { "path" = "/usr" } } } } + { "3" = "/home" + { "location" + { "1" + { "host" = "myserver.me.org" } + { "path" = "/home" } } } } } } + { } + { "11" = "server" + { "opt" = "rw" } + { "opt" = "hard" } + { "opt" = "intr" } + { "mount" + { "1" = "/" + { "opt" = "ro" } + { "location" + { "1" + { "host" = "my-with-dash-server.me.org" } + { "path" = "/" } } } } } } + { } + { "#comment" = "included maps" } + { "12" = "+" + { "map" = "auto_home" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_avahi.aug b/Sharp.Augeas.Test/lens/tests/test_avahi.aug new file mode 100644 index 0000000..cd417a2 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_avahi.aug @@ -0,0 +1,34 @@ +module Test_avahi = + + let conf = " +[server] +host-name=web +domain=example.com + +[wide-area] +enable-wide-area=yes +" + + test Avahi.lns get conf = + {} + { "server" + { "host-name" = "web" } + { "domain" = "example.com" } + {} } + { "wide-area" + { "enable-wide-area" = "yes" } } + + test Avahi.lns put conf after + set "server/use-ipv4" "yes"; + set "server/clients-max" "4096" + = " +[server] +host-name=web +domain=example.com + +use-ipv4=yes +clients-max=4096 +[wide-area] +enable-wide-area=yes +" + diff --git a/Sharp.Augeas.Test/lens/tests/test_backuppchosts.aug b/Sharp.Augeas.Test/lens/tests/test_backuppchosts.aug new file mode 100644 index 0000000..b1c145d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_backuppchosts.aug @@ -0,0 +1,26 @@ +module Test_BackupPCHosts = + +let conf = "host dhcp user moreUsers +hostname1 0 user1 anotheruser,athirduser +hostname2 1 user2 stillanotheruser\n" + +test BackupPCHosts.lns get conf = + { "1" + { "host" = "host" } + { "dhcp" = "dhcp" } + { "user" = "user" } + { "moreusers" = "moreUsers" } + } + { "2" + { "host" = "hostname1" } + { "dhcp" = "0" } + { "user" = "user1" } + { "moreusers" = "anotheruser" } + { "moreusers" = "athirduser" } + } + { "3" + { "host" = "hostname2" } + { "dhcp" = "1" } + { "user" = "user2" } + { "moreusers" = "stillanotheruser" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_bbhosts.aug b/Sharp.Augeas.Test/lens/tests/test_bbhosts.aug new file mode 100644 index 0000000..48ff7d7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_bbhosts.aug @@ -0,0 +1,131 @@ +module Test_bbhosts = + + let conf = " +# A comment + +page firstpage My first page + +group-compress A group +1.2.3.4 amachine # http://url.to/monitor https://another.url/to/monitor cont;http://a.cont.url/to/monitor;wordtofind +1.2.3.5 amachine2 # http://url.to/monitor https://another.url/to/monitor !cont;http://a.cont.url/to/monitor;wordtofind + +group-only dns VIP DNS +10.50.25.48 mydnsmachine.network # +10.50.25.49 myotherdnsmachine.network #noping noconn !ssh dns;mydnstocheck +# a comment in a group + + +page anotherpage A new page + +# a comment in a page + +group-compress My test +192.168.0.2 myhost # https://myurl.com:1256 noconn pop3 imap2 ssh +192.168.0.3 myhost2 # !imap2 telnet dns + +group-compress DownTime +0.0.0.0 myhost3 # DOWNTIME=fping,http:*:1800:1015:\"Frontal 01 Redirect Amazon eteint entre 18h et 10h\" +0.0.0.0 myhost4 # ftps imaps imap4 pop-3 pop2s pop smtp smtps ssh ssh1 ssh2 telnet telnets +" + + test BBhosts.lns get conf = + {} + { "#comment" = "A comment" } + {} + { "page" = "firstpage" + { "title" = "My first page" } + {} + { "group-compress" = "A group" + { "host" + { "ip" = "1.2.3.4" } + { "fqdn" = "amachine" } + { "probes" + { "url" = "http://url.to/monitor" } + { "url" = "https://another.url/to/monitor" } + { "cont" = "" + { "url" = "http://a.cont.url/to/monitor" } + { "keyword" = "wordtofind" } } } } + { "host" + { "ip" = "1.2.3.5" } + { "fqdn" = "amachine2" } + { "probes" + { "url" = "http://url.to/monitor" } + { "url" = "https://another.url/to/monitor" } + { "cont" = "!" + { "url" = "http://a.cont.url/to/monitor" } + { "keyword" = "wordtofind" } } } } + {} } + { "group-only" = "VIP DNS" + { "col" = "dns" } + { "host" + { "ip" = "10.50.25.48" } + { "fqdn" = "mydnsmachine.network" } + { "probes" } } + { "host" + { "ip" = "10.50.25.49" } + { "fqdn" = "myotherdnsmachine.network" } + { "probes" + { "noping" = "" } + { "noconn" = "" } + { "ssh" = "!" } + { "dns" = "" + { "url" = "mydnstocheck" } } } } + { "#comment" = "a comment in a group" } + {} + {} } } + { "page" = "anotherpage" + { "title" = "A new page" } + {} + { "#comment" = "a comment in a page" } + {} + { "group-compress" = "My test" + { "host" + { "ip" = "192.168.0.2" } + { "fqdn" = "myhost" } + { "probes" + { "url" = "https://myurl.com:1256" } + { "noconn" = "" } + { "pop3" = "" } + { "imap2" = "" } + { "ssh" = "" } } } + { "host" + { "ip" = "192.168.0.3" } + { "fqdn" = "myhost2" } + { "probes" + { "imap2" = "!" } + { "telnet" = "" } + { "dns" = "" } } } + {} + } + { "group-compress" = "DownTime" + { "host" + { "ip" = "0.0.0.0" } + { "fqdn" = "myhost3" } + { "probes" + { "DOWNTIME" + { "probe" = "fping" } + { "probe" = "http" } + { "day" = "*" } + { "starttime" = "1800" } + { "endtime" = "1015" } + { "cause" = "Frontal 01 Redirect Amazon eteint entre 18h et 10h" } + } } } + { "host" + { "ip" = "0.0.0.0" } + { "fqdn" = "myhost4" } + { "probes" + { "ftps" = "" } + { "imaps" = "" } + { "imap4" = "" } + { "pop-3" = "" } + { "pop2s" = "" } + { "pop" = "" } + { "smtp" = "" } + { "smtps" = "" } + { "ssh" = "" } + { "ssh1" = "" } + { "ssh2" = "" } + { "telnet" = "" } + { "telnets" = "" } + } } } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_bootconf.aug b/Sharp.Augeas.Test/lens/tests/test_bootconf.aug new file mode 100644 index 0000000..577760f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_bootconf.aug @@ -0,0 +1,47 @@ +(* +Module: Test_BootConf + Provides unit tests for the <BootConf> lens. +*) + +module Test_bootconf = + +test BootConf.boot get "boot /bsd -s\n" = + { "boot" + { "image" = "/bsd" } + { "arg" = "-s" } } + +test BootConf.echo get "echo 42\n" = + { "echo" = "42" } + +test BootConf.ls get "ls /\n" = + { "ls" = "/" } + +test BootConf.ls get "ls //\n" = + { "ls" = "//" } + +test BootConf.ls get "ls /some/path/\n" = + { "ls" = "/some/path/" } + +test BootConf.machine get "machine diskinfo\n" = + { "machine" + { "diskinfo" } } + +test BootConf.machine get "machine comaddr 0xdeadbeef\n" = + { "machine" + { "comaddr" = "0xdeadbeef" } } + +test BootConf.set get "set tty com0\n" = + { "set" + { "tty" = "com0" } } + +test BootConf.single_command get "help\n" = + { "help" } + +test BootConf.stty get "stty /dev/cuaU0 115200\n" = + { "stty" + { "device" = "/dev/cuaU0" } + { "speed" = "115200" } } + +test BootConf.stty get "stty /dev/cuaU0\n" = + { "stty" + { "device" = "/dev/cuaU0" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_build.aug b/Sharp.Augeas.Test/lens/tests/test_build.aug new file mode 100644 index 0000000..be7d897 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_build.aug @@ -0,0 +1,319 @@ +(* +Module: Test_Build + Provides unit tests and examples for the <Build> lens. +*) + +module Test_Build = + +(************************************************************************ + * Group: GENERIC CONSTRUCTIONS + ************************************************************************) + +(* View: brackets + Test brackets *) +let brackets = [ Build.brackets Sep.lbracket Sep.rbracket (key Rx.word) ] + +(* Test: brackets *) +test brackets get "(foo)" = { "foo" } + + +(************************************************************************ + * Group: LIST CONSTRUCTIONS + ************************************************************************) + +(* View: list *) +let list = Build.list [ key Rx.word ] Sep.space + +(* Test: list *) +test list get "foo bar baz" = { "foo" } { "bar" } { "baz" } + +(* Test: list *) +test list get "foo" = * + +(* View: opt_list *) +let opt_list = Build.opt_list [ key Rx.word ] Sep.space + +(* Test: opt_list *) +test opt_list get "foo bar baz" = { "foo" } { "bar" } { "baz" } + + +(************************************************************************ + * Group: LABEL OPERATIONS + ************************************************************************) + +(* View: xchg *) +let xchg = [ Build.xchg Rx.space " " "space" ] + +(* Test: xchg *) +test xchg get " \t " = { "space" } + +(* View: xchgs *) +let xchgs = [ Build.xchgs " " "space" ] + +(* Test: xchgs *) +test xchgs get " " = { "space" } + + +(************************************************************************ + * Group: SUBNODE CONSTRUCTIONS + ************************************************************************) + +(* View: key_value_line *) +let key_value_line = Build.key_value_line Rx.word Sep.equal (store Rx.word) + +(* Test: key_value_line *) +test key_value_line get "foo=bar\n" = { "foo" = "bar" } + +(* View: key_value_line_comment *) +let key_value_line_comment = Build.key_value_line_comment Rx.word + Sep.equal (store Rx.word) Util.comment + +(* Test: key_value_line_comment *) +test key_value_line_comment get "foo=bar # comment\n" = + { "foo" = "bar" { "#comment" = "comment" } } + +(* View: key_value *) +let key_value = Build.key_value Rx.word Sep.equal (store Rx.word) + +(* Test: key_value *) +test key_value get "foo=bar" = { "foo" = "bar" } + +(* View: key_ws_value *) +let key_ws_value = Build.key_ws_value Rx.word + +(* Test: key_ws_value *) +test key_ws_value get "foo bar\n" = { "foo" = "bar" } + +(* View: flag *) +let flag = Build.flag Rx.word + +(* Test: flag *) +test flag get "foo" = { "foo" } + +(* View: flag_line *) +let flag_line = Build.flag_line Rx.word + +(* Test: flag_line *) +test flag_line get "foo\n" = { "foo" } + + +(************************************************************************ + * Group: BLOCK CONSTRUCTIONS + ************************************************************************) + +(* View: block_entry + The block entry used for testing *) +let block_entry = Build.key_value "test" Sep.equal (store Rx.word) + +(* View: block + The block used for testing *) +let block = Build.block block_entry + +(* Test: block + Simple test for <block> *) +test block get " {test=1}" = + { "test" = "1" } + +(* Test: block + Simple test for <block> with newlines *) +test block get " {\n test=1\n}" = + { "test" = "1" } + +(* Test: block + Simple test for <block> two indented entries *) +test block get " {\n test=1 \n test=2 \n}" = + { "test" = "1" } + { "test" = "2" } + +(* Test: block + Test <block> with a comment *) +test block get " { # This is a comment\n}" = + { "#comment" = "This is a comment" } + +(* Test: block + Test <block> with comments and newlines *) +test block get " { # This is a comment\n# Another comment\n}" = + { "#comment" = "This is a comment" } + { "#comment" = "Another comment" } + +(* Test: block + Test defaults for blocks *) +test block put " { test=1 }" after + set "/#comment" "a comment"; + rm "/test"; + set "/test" "2" = + " { # a comment\ntest=2 }" + +(* View: named_block + The named block used for testing *) +let named_block = Build.named_block "foo" block_entry + +(* Test: named_block + Simple test for <named_block> *) +test named_block get "foo {test=1}\n" = + { "foo" { "test" = "1" } } + +(* View: logrotate_block + A minimalistic logrotate block *) +let logrotate_block = + let entry = [ key Rx.word ] + in let filename = [ label "file" . store /\/[^,#= \n\t{}]+/ ] + in let filename_sep = del /[ \t\n]+/ " " + in let filenames = Build.opt_list filename filename_sep + in [ label "rule" . filenames . Build.block entry ] + +(* Test: logrotate_block *) +test logrotate_block get "/var/log/wtmp\n/var/log/wtmp2\n{ + missingok + monthly +}" = + { "rule" + { "file" = "/var/log/wtmp" } + { "file" = "/var/log/wtmp2" } + { "missingok" } + { "monthly" } + } + + +(************************************************************************ + * Group: COMBINATORICS + ************************************************************************) + +(* View: combine_two + A minimalistic combination lens *) +let combine_two = + let entry (k:string) = [ key k ] + in Build.combine_two (entry "a") (entry "b") + +(* Test: combine_two + Should parse ab *) +test combine_two get "ab" = { "a" } { "b" } + +(* Test: combine_two + Should parse ba *) +test combine_two get "ba" = { "b" } { "a" } + +(* Test: combine_two + Should not parse a *) +test combine_two get "a" = * + +(* Test: combine_two + Should not parse b *) +test combine_two get "b" = * + +(* Test: combine_two + Should not parse aa *) +test combine_two get "aa" = * + +(* Test: combine_two + Should not parse bb *) +test combine_two get "bb" = * + + +(* View: combine_two_opt + A minimalistic optional combination lens *) +let combine_two_opt = + let entry (k:string) = [ key k ] + in Build.combine_two_opt (entry "a") (entry "b") + +(* Test: combine_two_opt + Should parse ab *) +test combine_two_opt get "ab" = { "a" } { "b" } + +(* Test: combine_two_opt + Should parse ba *) +test combine_two_opt get "ba" = { "b" } { "a" } + +(* Test: combine_two_opt + Should parse a *) +test combine_two_opt get "a" = { "a" } + +(* Test: combine_two_opt + Should parse b *) +test combine_two_opt get "b" = { "b" } + +(* Test: combine_two_opt + Should not parse aa *) +test combine_two_opt get "aa" = * + +(* Test: combine_two_opt + Should not parse bb *) +test combine_two_opt get "bb" = * + + +(* View: combine_three + A minimalistic optional combination lens *) +let combine_three = + let entry (k:string) = [ key k ] + in Build.combine_three (entry "a") (entry "b") (entry "c") + +(* Test: combine_three + Should not parse ab *) +test combine_three get "ab" = * + +(* Test: combine_three + Should not parse ba *) +test combine_three get "ba" = * + +(* Test: combine_three + Should not parse a *) +test combine_three get "a" = * + +(* Test: combine_three + Should not parse b *) +test combine_three get "b" = * + +(* Test: combine_three + Should not parse aa *) +test combine_three get "aa" = * + +(* Test: combine_three + Should not parse bbc *) +test combine_three get "bbc" = * + +(* Test: combine_three + Should parse abc *) +test combine_three get "abc" = { "a" } { "b" } { "c" } + +(* Test: combine_three + Should parse cab *) +test combine_three get "cab" = { "c" } { "a" } { "b" } + + +(* View: combine_three_opt + A minimalistic optional combination lens *) +let combine_three_opt = + let entry (k:string) = [ key k ] + in Build.combine_three_opt (entry "a") (entry "b") (entry "c") + +(* Test: combine_three_opt + Should parse ab *) +test combine_three_opt get "ab" = { "a" } { "b" } + +(* Test: combine_three_opt + Should parse ba *) +test combine_three_opt get "ba" = { "b" } { "a" } + +(* Test: combine_three_opt + Should parse a *) +test combine_three_opt get "a" = { "a" } + +(* Test: combine_three_opt + Should parse b *) +test combine_three_opt get "b" = { "b" } + +(* Test: combine_three_opt + Should not parse aa *) +test combine_three_opt get "aa" = * + +(* Test: combine_three_opt + Should not parse bbc *) +test combine_three_opt get "bbc" = * + +(* Test: combine_three_opt + Should parse abc *) +test combine_three_opt get "abc" = { "a" } { "b" } { "c" } + +(* Test: combine_three_opt + Should parse cab *) +test combine_three_opt get "cab" = { "c" } { "a" } { "b" } diff --git a/Sharp.Augeas.Test/lens/tests/test_cachefilesd.aug b/Sharp.Augeas.Test/lens/tests/test_cachefilesd.aug new file mode 100644 index 0000000..2ddb7b7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cachefilesd.aug @@ -0,0 +1,30 @@ +module Test_Cachefilesd = + + let conf = " +# I am a comment +dir /var/cache/fscache +tAg mycache +brun 10% +bcull 7% +bstop 3% +frun 10% +fcull 7% +fstop 3% +nocull + +secctx system_u:system_r:cachefiles_kernel_t:s0 +" + test Cachefilesd.lns get conf = + { } + { "#comment" = "I am a comment" } + { "dir" = "/var/cache/fscache" } + { "tAg" = "mycache" } + { "brun" = "10%" } + { "bcull" = "7%" } + { "bstop" = "3%" } + { "frun" = "10%" } + { "fcull" = "7%" } + { "fstop" = "3%" } + { "nocull" } + { } + { "secctx" = "system_u:system_r:cachefiles_kernel_t:s0" } diff --git a/Sharp.Augeas.Test/lens/tests/test_carbon.aug b/Sharp.Augeas.Test/lens/tests/test_carbon.aug new file mode 100644 index 0000000..b124bf3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_carbon.aug @@ -0,0 +1,84 @@ +(* +Module: Test_Carbon + Provides unit tests and examples for the <Carbon> lens. +*) + +module Test_Carbon = + +let carbon_conf = "[cache] +# Configure carbon directories. + +# Specify the user to drop privileges to +# If this is blank carbon runs as the user that invokes it +# This user must have write access to the local data directory +USER = + +MAX_CACHE_SIZE = inf # comment at EOL +LINE_RECEIVER_INTERFACE=0.0.0.0 +LINE_RECEIVER_PORT = 2003 +ENABLE_UDP_LISTENER = False + +[relay] +LINE_RECEIVER_INTERFACE = 0.0.0.0 +LINE_RECEIVER_PORT = 2013 +PICKLE_RECEIVER_INTERFACE = 0.0.0.0 +PICKLE_RECEIVER_PORT = 2014 +" + +test Carbon.lns get carbon_conf = + { "cache" + { "#comment" = "Configure carbon directories." } + { } + { "#comment" = "Specify the user to drop privileges to" } + { "#comment" = "If this is blank carbon runs as the user that invokes it" } + { "#comment" = "This user must have write access to the local data directory" } + { "USER" } + { } + { "MAX_CACHE_SIZE" = "inf" + { "#comment" = "comment at EOL" } + } + { "LINE_RECEIVER_INTERFACE" = "0.0.0.0" } + { "LINE_RECEIVER_PORT" = "2003" } + { "ENABLE_UDP_LISTENER" = "False" } + { } + } + { "relay" + { "LINE_RECEIVER_INTERFACE" = "0.0.0.0" } + { "LINE_RECEIVER_PORT" = "2013" } + { "PICKLE_RECEIVER_INTERFACE" = "0.0.0.0" } + { "PICKLE_RECEIVER_PORT" = "2014" } + } + +let relay_rules_conf = "# You must have exactly one section with 'default = true' +# Note that all destinations listed must also exist in carbon.conf +# in the DESTINATIONS setting in the [relay] section +[default] +default = true +destinations = 127.0.0.1:2004:a, 127.0.0.1:2104:b +" + +test Carbon.lns get relay_rules_conf = + { "#comment" = "You must have exactly one section with 'default = true'" } + { "#comment" = "Note that all destinations listed must also exist in carbon.conf" } + { "#comment" = "in the DESTINATIONS setting in the [relay] section" } + { "default" + { "default" = "true" } + { "destinations" = "127.0.0.1:2004:a, 127.0.0.1:2104:b" } + } + +let storage_aggregation_conf = "# Aggregation methods for whisper files. Entries are scanned in order, +# and first match wins. This file is scanned for changes every 60 seconds +[max] +pattern = \.max$ +xFilesFactor = 0.1 +aggregationMethod = max +" + +test Carbon.lns get storage_aggregation_conf = + { "#comment" = "Aggregation methods for whisper files. Entries are scanned in order," } + { "#comment" = "and first match wins. This file is scanned for changes every 60 seconds" } + { "max" + { "pattern" = "\.max$" } + { "xFilesFactor" = "0.1" } + { "aggregationMethod" = "max" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_ceph.aug b/Sharp.Augeas.Test/lens/tests/test_ceph.aug new file mode 100644 index 0000000..4f4bf37 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ceph.aug @@ -0,0 +1,180 @@ + +module Test_ceph = + + let ceph_simple = "[global] +### http://ceph.com/docs/master/rados/configuration/general-config-ref/ + + fsid = b4b2e571-fbbf-4ff3-a9f8-ab80f08b7fe6 # use `uuidgen` to generate your own UUID + public network = 192.168.0.0/24 + cluster network = 192.168.0.0/24 +" + + let ceph_extended = "## +# Sample ceph ceph.conf file. +## +# This file defines cluster membership, the various locations +# that Ceph stores data, and any other runtime options. + +[global] + ; Start-line comment + log file = /var/log/ceph/$cluster-$name.log ; End-line comment + + [mon.alpha] + host = alpha + mon addr = 192.168.0.10:6789 + + [mon.beta] + host = beta + mon addr = 192.168.0.11:6789 + +[mon.gamma] + host = gamma + mon addr = 192.168.0.12:6789 + + +[mon] +mon initial members = mycephhost + +mon host = cephhost01,cephhost02 + mon addr = 192.168.0.101,192.168.0.102 + +mon osd nearfull ratio = .85 + + # logging, for debugging monitor crashes, in order of + # their likelihood of being helpful :) + debug ms = 1 + debug mon = 20 + debug paxos = 20 + debug auth = 20 + +[mds] + + osd max backfills = 5 + + #osd mkfs type = {fs-type} + #osd mkfs options {fs-type} = {mkfs options} # default for xfs is \"-f\" + #osd mount options {fs-type} = {mount options} # default mount option is \"rw, noatime\" + osd mkfs type = btrfs + osd mount options btrfs = noatime,nodiratime + journal dio = false + + debug ms = 1 + debug osd = 20 + debug filestore = 20 + debug journal = 20 + + filestore merge threshold = 10 + + osd crush update on start = false + +[osd.0] + host = delta + +[osd.1] + host = epsilon + +[osd.2] + host = zeta + +[osd.3] + host = eta + + rgw dns name = radosgw.ceph.internal +" + + test Ceph.lns get ceph_simple = + { "global" + { "#comment" = "## http://ceph.com/docs/master/rados/configuration/general-config-ref/" } + { } + { "fsid" = "b4b2e571-fbbf-4ff3-a9f8-ab80f08b7fe6" + { "#comment" = "use `uuidgen` to generate your own UUID" } + } + { "public network" = "192.168.0.0/24" } + { "cluster network" = "192.168.0.0/24" } + } + + test Ceph.lns get ceph_extended = + { "#comment" = "#" } + { "#comment" = "Sample ceph ceph.conf file." } + { "#comment" = "#" } + { "#comment" = "This file defines cluster membership, the various locations" } + { "#comment" = "that Ceph stores data, and any other runtime options." } + { } + { "global" + { "#comment" = "Start-line comment" } + { "log file" = "/var/log/ceph/$cluster-$name.log" + { "#comment" = "End-line comment" } + } + { } + } + { "mon.alpha" + { "host" = "alpha" } + { "mon addr" = "192.168.0.10:6789" } + { } + } + { "mon.beta" + { "host" = "beta" } + { "mon addr" = "192.168.0.11:6789" } + { } + } + { "mon.gamma" + { "host" = "gamma" } + { "mon addr" = "192.168.0.12:6789" } + { } + { } + } + { "mon" + { "mon initial members" = "mycephhost" } + { } + { "mon host" = "cephhost01,cephhost02" } + { "mon addr" = "192.168.0.101,192.168.0.102" } + { } + { "mon osd nearfull ratio" = ".85" } + { } + { "#comment" = "logging, for debugging monitor crashes, in order of" } + { "#comment" = "their likelihood of being helpful :)" } + { "debug ms" = "1" } + { "debug mon" = "20" } + { "debug paxos" = "20" } + { "debug auth" = "20" } + { } + } + { "mds" + { } + { "osd max backfills" = "5" } + { } + { "#comment" = "osd mkfs type = {fs-type}" } + { "#comment" = "osd mkfs options {fs-type} = {mkfs options} # default for xfs is \"-f\"" } + { "#comment" = "osd mount options {fs-type} = {mount options} # default mount option is \"rw, noatime\"" } + { "osd mkfs type" = "btrfs" } + { "osd mount options btrfs" = "noatime,nodiratime" } + { "journal dio" = "false" } + { } + { "debug ms" = "1" } + { "debug osd" = "20" } + { "debug filestore" = "20" } + { "debug journal" = "20" } + { } + { "filestore merge threshold" = "10" } + { } + { "osd crush update on start" = "false" } + { } + } + { "osd.0" + { "host" = "delta" } + { } + } + { "osd.1" + { "host" = "epsilon" } + { } + } + { "osd.2" + { "host" = "zeta" } + { } + } + { "osd.3" + { "host" = "eta" } + { } + { "rgw dns name" = "radosgw.ceph.internal" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_cgconfig.aug b/Sharp.Augeas.Test/lens/tests/test_cgconfig.aug new file mode 100644 index 0000000..84fd2de --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cgconfig.aug @@ -0,0 +1,365 @@ +module Test_cgconfig = + +let conf="#cgconfig test cofiguration file +mount { 123 = 456; 456 = 789;} +" + +test Cgconfig.lns get conf = + { "#comment" = "cgconfig test cofiguration file" } + { "mount" + { "123" = "456" } + { "456" = "789" } } + {} + +(* white spaces before mount sign *) +let conf2=" + mount { 123 = 456;} + mount { 123 = 456;} + +mount { 123 = 456;}mount { 123 = 456;} +" + +test Cgconfig.lns get conf2 = + { } + { "mount" { "123" = "456"} } + { } + { "mount" { "123" = "456"} } + { } + { } + { "mount" { "123" = "456"} } + { "mount" { "123" = "456" } } + { } + +let conf3="#cgconfig test cofiguration file +mount { 123 = 456; +#eswkh + 456 = 789;} +" +test Cgconfig.lns get conf3 = + { "#comment" = "cgconfig test cofiguration file" } + { "mount" + { "123" = "456" } + {} + { "#comment" = "eswkh" } + { "456" = "789" } } + {} + +let conf4="#cgconfig test cofiguration file +mount { +123 = 456;1245=456; +} +mount { 323=324;}mount{324=5343; }# this is a comment +" + +test Cgconfig.lns get conf4 = + {"#comment" = "cgconfig test cofiguration file" } + {"mount" + { } + { "123" = "456"} + { "1245" = "456" } + { }} + { } + { "mount" { "323" = "324" } } + { "mount" { "324" = "5343" } } + { "#comment" = "this is a comment" } + +let group1=" +group user { + cpuacct { + lll = jjj; + } + cpu { + } +}" + +test Cgconfig.lns get group1 = + { } + { "group" = "user" + { } + { "controller" = "cpuacct" + { } + { "lll" = "jjj" } + { } } + { } + { "controller" = "cpu" { } } + { } } + +let group2=" +group aa-1{ + perm { + task { } + admin { } + } +}" + +test Cgconfig.lns get group2 = + { } + { "group" = "aa-1" + { } + { "perm" + { } + { "task" } + { } + { "admin" } + { } } + { } } + + +let group3 =" +group xx/www { + perm { + task { + gid = root; + uid = root; + } + admin { + gid = aaa; +# no aaa + uid = aaa; + } +} +} +" + +test Cgconfig.lns get group3 = + { } + { "group" = "xx/www" + { } + { "perm" + { } + { "task" + { } + { "gid" = "root" } + { } + { "uid" = "root" } + { } } + { } + { "admin" + { } + { "gid" = "aaa" } + { } + { "#comment" = "no aaa" } + { "uid" = "aaa" } + { } } + { } } + { } } + { } + +let group4 =" +#group daemons { +# cpuacct{ +# } +#} + +group daemons/ftp { + cpuacct{ + } +} + + group daemons/www { + perm { + task { + uid = root; + gid = root; + } + admin { + uid = root; + gid = root; + } + } +# cpu { +# cpu.shares = 1000; +# } +} +# +# + + mount { + devices = /mnt/cgroups/devices;cpuacct = /mnt/cgroups/cpuset; + cpuset = /mnt/cgroups/cpuset; + + + cpu = /mnt/cpu; +# cpuset = /mnt/cgroups/cpuset2; +} +mount { +devices = /mnt/cgroups/devices; +# cpuacct = /mnt/cgroups/cpuacct; + ns = /mnt/cgroups/ns; +# +} + +" + +test Cgconfig.lns get group4 = + { } + { "#comment" = "group daemons {" } + { "#comment" = "cpuacct{" } + { "#comment" = "}" } + { "#comment" = "}" } + { } + { "group" = "daemons/ftp" + { } + { "controller" = "cpuacct" { } } + { } } + { } + { } + { "group" = "daemons/www" + { } + { "perm" + { } + { "task" + { } + { "uid" = "root" } + { } + { "gid" = "root" } + { } } + { } + { "admin" + { } + { "uid" = "root" } + { } + { "gid" = "root" } + { } } + { } } + { } + { "#comment" = "cpu {" } + { "#comment" = "cpu.shares = 1000;" } + { "#comment" = "}" } } + { } + { } + { } + { } + { "mount" + { } + { "devices" = "/mnt/cgroups/devices" } + { "cpuacct" = "/mnt/cgroups/cpuset" } + { } + { "cpuset" = "/mnt/cgroups/cpuset" } + { } + { } + { } + { "cpu" = "/mnt/cpu" } + { } + { "#comment" = "cpuset = /mnt/cgroups/cpuset2;" } } + { } + { "mount" + { } + { "devices" = "/mnt/cgroups/devices" } + { } + { "#comment" = "cpuacct = /mnt/cgroups/cpuacct;" } + { "ns" = "/mnt/cgroups/ns" } + { } + { } } + { } + { } + +test Cgconfig.lns put "group tst {memory {}}" after + set "/group" "tst2" += "group tst2 {memory {}}" + +let group5=" +group user { + cpuacct {} + cpu {} + cpuset {} + devices {} + freezer {} + memory {} + net_cls {} + blkio {} + hugetlb {} + perf_event {} +}" + +test Cgconfig.lns get group5 = + { } + { "group" = "user" + { } + { "controller" = "cpuacct" } + { } + { "controller" = "cpu" } + { } + { "controller" = "cpuset" } + { } + { "controller" = "devices" } + { } + { "controller" = "freezer" } + { } + { "controller" = "memory" } + { } + { "controller" = "net_cls" } + { } + { "controller" = "blkio" } + { } + { "controller" = "hugetlb" } + { } + { "controller" = "perf_event" } + { } + } + +(* quoted controller parameter whitespace *) +let group6=" +group blklimit { + blkio { + blkio.throttle.read_iops_device=\"8:0 50\"; + } +}" + +test Cgconfig.lns get group6 = + { } + { "group" = "blklimit" + { } + { "controller" = "blkio" + { } + { "blkio.throttle.read_iops_device" = "\"8:0 50\"" } + { } + } + { } + } + +let group7 =" +group daemons/www { + perm { + task { + uid = root; + gid = root; + fperm = 770; + } + admin { + uid = root; + gid = root; + dperm = 777; + } + } +} +" + +test Cgconfig.lns get group7 = + { } + { "group" = "daemons/www" + { } + { "perm" + { } + { "task" + { } + { "uid" = "root" } + { } + { "gid" = "root" } + { } + { "fperm" = "770" } + { } } + { } + { "admin" + { } + { "uid" = "root" } + { } + { "gid" = "root" } + { } + { "dperm" = "777" } + { } } + { } } + { } + } + { } + diff --git a/Sharp.Augeas.Test/lens/tests/test_cgrules.aug b/Sharp.Augeas.Test/lens/tests/test_cgrules.aug new file mode 100644 index 0000000..3e29d4f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cgrules.aug @@ -0,0 +1,32 @@ +module Test_cgrules = + +let conf="#cgrules test configuration file +poooeter cpu test1/ +% memory test2/ +@somegroup cpu toto/ +% devices toto1/ +% memory toto3/ +" +test Cgrules.lns get conf = + { "#comment" = "cgrules test configuration file" } + { "user" = "poooeter" + { "cpu" = "test1/" } + { "memory" = "test2/" } } + { "group" = "somegroup" + { "cpu" = "toto/" } + { "devices" = "toto1/" } + { "memory" = "toto3/" } } + +test Cgrules.lns put conf after + set "user/cpu" "test3/"; + rm "user/memory"; + rm "group"; + insa "devices" "user/*[last()]"; + set "user/devices" "newtest/"; + insb "memory" "user/devices"; + set "user/memory" "memtest/" += "#cgrules test configuration file +poooeter cpu test3/ +% memory memtest/ +% devices newtest/ +" diff --git a/Sharp.Augeas.Test/lens/tests/test_channels.aug b/Sharp.Augeas.Test/lens/tests/test_channels.aug new file mode 100644 index 0000000..a387494 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_channels.aug @@ -0,0 +1,138 @@ +(* +Module: Test_Channels + Provides unit tests and examples for the <Channels> lens. +*) + +module Test_Channels = + +(* Variable: conf + A full configuration file *) +let conf = "Direct 8 TV;SES ASTRA:12551:VC56M2O0S0:S19.2E:22000:1111=2:1112=fra@3:1116:0:12174:1:1108:0 +:FAVORIS +Direct 8 TV;SES ASTRA:12551:VC56M2O0S0:S19.2E:22000:1111=2:1112=fra@3:1116:0:12175:1:1108:0 +TF1;CSAT:11895:VC34M2O0S0:S19.2E:27500:171=2:124=fra+spa@4,125=eng@4;126=deu@4:53:500,1811,1863,100:8371:1:1074:0 +:TNT +TF1;SMR6:690167:I999B8C999D999M998T999G999Y0:T:27500:120=2:130=fra@3,131=eng@3,133=qad@3:140;150=fra,151=eng:0:1537:8442:6:0 +; this is a comment +France 5;GR1:618167:I999B8C999D999M998T999G999Y0:T:27500:374+320=2:330=fra@3,331=qad@3:0;340=fra:0:260:8442:1:0 +CANAL+ FAMILY HD:12012:VC23M5O35S1:S19.2E:27500:164=27:0;98=@106,99=eng@106:0;45=fra+fra:1811,500,1863,100,9C4,9C7,9AF:8825:1:1080:0 +" + +(* Test: Channels.lns + Test the full <conf> *) +test Channels.lns get conf = + { "entry" = "Direct 8 TV" + { "provider" = "SES ASTRA" } + { "frequency" = "12551" } + { "parameter" = "VC56M2O0S0" } + { "signal_source" = "S19.2E" } + { "symbol_rate" = "22000" } + { "vpid" = "1111" { "codec" = "2" } } + { "apid" = "1112" { "lang" = "fra" } { "codec" = "3" } } + { "tpid" = "1116" } + { "caid" = "0" } + { "sid" = "12174" } + { "nid" = "1" } + { "tid" = "1108" } + { "rid" = "0" } + } + { "group" = "FAVORIS" + { "entry" = "Direct 8 TV" + { "provider" = "SES ASTRA" } + { "frequency" = "12551" } + { "parameter" = "VC56M2O0S0" } + { "signal_source" = "S19.2E" } + { "symbol_rate" = "22000" } + { "vpid" = "1111" { "codec" = "2" } } + { "apid" = "1112" { "lang" = "fra" } { "codec" = "3" } } + { "tpid" = "1116" } + { "caid" = "0" } + { "sid" = "12175" } + { "nid" = "1" } + { "tid" = "1108" } + { "rid" = "0" } + } + { "entry" = "TF1" + { "provider" = "CSAT" } + { "frequency" = "11895" } + { "parameter" = "VC34M2O0S0" } + { "signal_source" = "S19.2E" } + { "symbol_rate" = "27500" } + { "vpid" = "171" { "codec" = "2" } } + { "apid" = "124" { "lang" = "fra" } { "lang" = "spa" } { "codec" = "4" } } + { "apid" = "125" { "lang" = "eng" } { "codec" = "4" } } + { "apid_dolby" = "126" { "lang" = "deu" } { "codec" = "4" } } + { "tpid" = "53" } + { "caid" = "500" } + { "caid" = "1811" } + { "caid" = "1863" } + { "caid" = "100" } + { "sid" = "8371" } + { "nid" = "1" } + { "tid" = "1074" } + { "rid" = "0" } + } + } + { "group" = "TNT" + { "entry" = "TF1" + { "provider" = "SMR6" } + { "frequency" = "690167" } + { "parameter" = "I999B8C999D999M998T999G999Y0" } + { "signal_source" = "T" } + { "symbol_rate" = "27500" } + { "vpid" = "120" { "codec" = "2" } } + { "apid" = "130" { "lang" = "fra" } { "codec" = "3" } } + { "apid" = "131" { "lang" = "eng" } { "codec" = "3" } } + { "apid" = "133" { "lang" = "qad" } { "codec" = "3" } } + { "tpid" = "140" } + { "tpid_bylang" = "150" { "lang" = "fra" } } + { "tpid_bylang" = "151" { "lang" = "eng" } } + { "caid" = "0" } + { "sid" = "1537" } + { "nid" = "8442" } + { "tid" = "6" } + { "rid" = "0" } + } + { "#comment" = "this is a comment" } + { "entry" = "France 5" + { "provider" = "GR1" } + { "frequency" = "618167" } + { "parameter" = "I999B8C999D999M998T999G999Y0" } + { "signal_source" = "T" } + { "symbol_rate" = "27500" } + { "vpid" = "374" } + { "vpid_pcr" = "320" { "codec" = "2" } } + { "apid" = "330" { "lang" = "fra" } { "codec" = "3" } } + { "apid" = "331" { "lang" = "qad" } { "codec" = "3" } } + { "tpid" = "0" } + { "tpid_bylang" = "340" { "lang" = "fra" } } + { "caid" = "0" } + { "sid" = "260" } + { "nid" = "8442" } + { "tid" = "1" } + { "rid" = "0" } + } + { "entry" = "CANAL+ FAMILY HD" + { "frequency" = "12012" } + { "parameter" = "VC23M5O35S1" } + { "signal_source" = "S19.2E" } + { "symbol_rate" = "27500" } + { "vpid" = "164" { "codec" = "27" } } + { "apid" = "0" } + { "apid_dolby" = "98" { "codec" = "106" } } + { "apid_dolby" = "99" { "lang" = "eng" } { "codec" = "106" } } + { "tpid" = "0" } + { "tpid_bylang" = "45" { "lang" = "fra" } { "lang" = "fra" } } + { "caid" = "1811" } + { "caid" = "500" } + { "caid" = "1863" } + { "caid" = "100" } + { "caid" = "9C4" } + { "caid" = "9C7" } + { "caid" = "9AF" } + { "sid" = "8825" } + { "nid" = "1" } + { "tid" = "1080" } + { "rid" = "0" } + } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_chrony.aug b/Sharp.Augeas.Test/lens/tests/test_chrony.aug new file mode 100644 index 0000000..0c86cde --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_chrony.aug @@ -0,0 +1,319 @@ +(* +Module: Test_Chrony + Provides unit tests and examples for the <Chrony> lens. +*) + +module Test_Chrony = + + let exampleconf = "# Comment +#Comment +! Comment +!Comment +; Comment +;Comment +% Comment +%Comment + +server ntp1.example.com +server ntp2.example.com iburst +server ntp3.example.com presend 2 +server ntp4.example.com offline polltarget 4 +server ntp5.example.com maxdelay 2 offline +server ntp6.example.com maxdelay 2 iburst presend 2 xleave offset 1e-4 +server ntp7.example.com iburst presend 2 offline prefer trust require +server ntp8.example.com minsamples 8 maxsamples 16 version 3 +server ntp9.example.com burst mindelay 0.1 asymmetry 0.5 nts filter 3 +peer ntpc1.example.com +pool pool1.example.com iburst maxsources 3 +allow +deny all +cmdallow 192.168.1.0/24 +cmddeny all 192.168.2.0/24 +stratumweight 0 + driftfile /var/lib/chrony/drift + rtcsync +makestep 10 -1 +bindcmdaddress 127.0.0.1 +bindcmdaddress ::1 +bindacqdevice eth0 +bindcmddevice eth0 +binddevice eth0 +clockprecision 10e-9 +local +local stratum 10 +local distance 1.0 orphan +keyfile /etc/chrony.keys +commandkey 1 +generatecommandkey +manual +noclientlog +logchange 0.5 +logdir /var/log/chrony +log rtc measurements rawmeasurements statistics tracking refclocks tempcomp +leapsectz right/UTC +broadcast 10 192.168.1.255 +broadcast 10 192.168.100.255 123 +fallbackdrift 16 19 +mailonchange root@localhost 0.5 +maxchange 1000 1 2 +maxdistance 1.0 +maxdrift 100 +hwtimestamp eth0 minpoll -2 txcomp 300e-9 rxcomp 645e-9 nocrossts rxfilter all +hwtimestamp eth1 minsamples 10 maxsamples 20 +initstepslew 30 foo.bar.com +initstepslew 30 foo.bar.com baz.quz.com +ratelimit interval 4 burst 16 leak 2 +cmdratelimit +ntsratelimit +refclock SHM 0 refid SHM0 delay 0.1 offset 0.2 noselect tai stratum 3 +refclock SOCK /var/run/chrony-GPS.sock pps width 0.1 +refclock PPS /dev/pps0 dpoll 2 poll 3 lock SHM0 rate 5 minsamples 8 +smoothtime 400 0.001 leaponly +tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 26000 0.0 0.000183 0.0 +tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp +ntpsigndsocket /var/lib/samba/ntp_signd +confdir /etc/chrony.d /usr/lib/chrony.d +sourcedir /etc/chrony.d /var/run/chrony.d +authselectmode require +dscp 46 +maxntsconnections 10 +nocerttimecheck 1 +nosystemcert +ntsservercert /etc/chrony/server.crt +ntsserverkey /etc/chrony/server.key +ntstrustedcerts /etc/chrony/trusted.crt +ntsdumpdir /var/lib/chrony +ntsntpserver foo.example.com +ntsport 123 +ntsprocesses 2 +ntsrefresh 86400 +ntsrotate 86400 +" + + test Chrony.lns get exampleconf = + { "#comment" = "Comment" } + { "#comment" = "Comment" } + { "#comment" = "Comment" } + { "#comment" = "Comment" } + { "#comment" = "Comment" } + { "#comment" = "Comment" } + { "#comment" = "Comment" } + { "#comment" = "Comment" } + { } + { "server" = "ntp1.example.com" } + { "server" = "ntp2.example.com" + { "iburst" } + } + { "server" = "ntp3.example.com" + { "presend" = "2" } + } + { "server" = "ntp4.example.com" + { "offline" } + { "polltarget" = "4" } + } + { "server" = "ntp5.example.com" + { "maxdelay" = "2" } + { "offline" } + } + { "server" = "ntp6.example.com" + { "maxdelay" = "2" } + { "iburst" } + { "presend" = "2" } + { "xleave" } + { "offset" = "1e-4" } + } + { "server" = "ntp7.example.com" + { "iburst" } + { "presend" = "2" } + { "offline" } + { "prefer" } + { "trust" } + { "require" } + } + { "server" = "ntp8.example.com" + { "minsamples" = "8" } + { "maxsamples" = "16" } + { "version" = "3" } + } + { "server" = "ntp9.example.com" + { "burst" } + { "mindelay" = "0.1" } + { "asymmetry" = "0.5" } + { "nts" } + { "filter" = "3" } + } + { "peer" = "ntpc1.example.com" } + { "pool" = "pool1.example.com" + { "iburst" } + { "maxsources" = "3" } + } + { "allow" } + { "deny" + { "all" } + } + { "cmdallow" = "192.168.1.0/24" } + { "cmddeny" = "192.168.2.0/24" + { "all" } + } + { "stratumweight" = "0" } + { "driftfile" = "/var/lib/chrony/drift" } + { "rtcsync" } + { "makestep" + { "threshold" = "10" } + { "limit" = "-1" } + } + { "bindcmdaddress" = "127.0.0.1" } + { "bindcmdaddress" = "::1" } + { "bindacqdevice" = "eth0" } + { "bindcmddevice" = "eth0" } + { "binddevice" = "eth0" } + { "clockprecision" = "10e-9" } + { "local" } + { "local" + { "stratum" = "10" } + } + { "local" + { "distance" = "1.0" } + { "orphan" } + } + { "keyfile" = "/etc/chrony.keys" } + { "commandkey" = "1" } + { "generatecommandkey" } + { "manual" } + { "noclientlog" } + { "logchange" = "0.5" } + { "logdir" = "/var/log/chrony" } + { "log" + { "rtc" } + { "measurements" } + { "rawmeasurements" } + { "statistics" } + { "tracking" } + { "refclocks" } + { "tempcomp" } + } + { "leapsectz" = "right/UTC" } + { "broadcast" + { "interval" = "10" } + { "address" = "192.168.1.255" } + } + { "broadcast" + { "interval" = "10" } + { "address" = "192.168.100.255" } + { "port" = "123" } + } + { "fallbackdrift" + { "min" = "16" } + { "max" = "19" } + } + { "mailonchange" + { "emailaddress" = "root@localhost" } + { "threshold" = "0.5" } + } + { "maxchange" + { "threshold" = "1000" } + { "delay" = "1" } + { "limit" = "2" } + } + { "maxdistance" = "1.0" } + { "maxdrift" = "100" } + { "hwtimestamp" + { "interface" = "eth0" } + { "minpoll" = "-2" } + { "txcomp" = "300e-9" } + { "rxcomp" = "645e-9" } + { "nocrossts" } + { "rxfilter" = "all" } + } + { "hwtimestamp" + { "interface" = "eth1" } + { "minsamples" = "10" } + { "maxsamples" = "20" } + } + { "initstepslew" + { "threshold" = "30" } + { "address" = "foo.bar.com" } + } + { "initstepslew" + { "threshold" = "30" } + { "address" = "foo.bar.com" } + { "address" = "baz.quz.com" } + } + { "ratelimit" + { "interval" = "4" } + { "burst" = "16" } + { "leak" = "2" } + } + { "cmdratelimit" } + { "ntsratelimit" } + { "refclock" + { "driver" = "SHM" } + { "parameter" = "0" } + { "refid" = "SHM0" } + { "delay" = "0.1" } + { "offset" = "0.2" } + { "noselect" } + { "tai" } + { "stratum" = "3" } + } + { "refclock" + { "driver" = "SOCK" } + { "parameter" = "/var/run/chrony-GPS.sock" } + { "pps" } + { "width" = "0.1" } + } + { "refclock" + { "driver" = "PPS" } + { "parameter" = "/dev/pps0" } + { "dpoll" = "2" } + { "poll" = "3" } + { "lock" = "SHM0" } + { "rate" = "5" } + { "minsamples" = "8" } + } + { "smoothtime" + { "maxfreq" = "400" } + { "maxwander" = "0.001" } + { "leaponly" } + } + { "tempcomp" + { "sensorfile" = "/sys/class/hwmon/hwmon0/temp2_input" } + { "interval" = "30" } + { "t0" = "26000" } + { "k0" = "0.0" } + { "k1" = "0.000183" } + { "k2" = "0.0" } + } + { "tempcomp" + { "sensorfile" = "/sys/class/hwmon/hwmon0/temp2_input" } + { "interval" = "30" } + { "pointfile" = "/etc/chrony.tempcomp" } + } + { "ntpsigndsocket" = "/var/lib/samba/ntp_signd" } + { "confdir" + { "directory" = "/etc/chrony.d" } + { "directory" = "/usr/lib/chrony.d" } + } + { "sourcedir" + { "directory" = "/etc/chrony.d" } + { "directory" = "/var/run/chrony.d" } + } + { "authselectmode" = "require" } + { "dscp" = "46" } + { "maxntsconnections" = "10" } + { "nocerttimecheck" = "1" } + { "nosystemcert" } + { "ntsservercert" = "/etc/chrony/server.crt" } + { "ntsserverkey" = "/etc/chrony/server.key" } + { "ntstrustedcerts" = "/etc/chrony/trusted.crt" } + { "ntsdumpdir" = "/var/lib/chrony" } + { "ntsntpserver" = "foo.example.com" } + { "ntsport" = "123" } + { "ntsprocesses" = "2" } + { "ntsrefresh" = "86400" } + { "ntsrotate" = "86400" } + + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_clamav.aug b/Sharp.Augeas.Test/lens/tests/test_clamav.aug new file mode 100644 index 0000000..5764e26 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_clamav.aug @@ -0,0 +1,299 @@ +module Test_ClamAV = + +let clamd_conf ="## +## Example config file for the Clam AV daemon +## Please read the clamd.conf(5) manual before editing this file. +## + +# Comment or remove the line below. +Example +# LogFile must be writable for the user running daemon. +LogFile /var/log/clamav/clamd.log +LogFileUnlock yes +LogFileMaxSize 0 +LogTime yes +LogClean yes +LogSyslog yes +LogFacility LOG_MAIL +LogVerbose yes +LogRotate yes +ExtendedDetectionInfo yes +PidFile /var/run/clamav/clamd.pid +TemporaryDirectory /var/tmp +DatabaseDirectory /var/lib/clamav +OfficialDatabaseOnly no +LocalSocket /var/run/clamav/clamd.sock +LocalSocketGroup virusgroup +LocalSocketMode 660 +FixStaleSocket yes +TCPSocket 3310 +TCPAddr 127.0.0.1 +MaxConnectionQueueLength 30 +StreamMaxLength 10M +StreamMinPort 30000 +StreamMaxPort 32000 +MaxThreads 50 +ReadTimeout 300 +CommandReadTimeout 5 +SendBufTimeout 200 +MaxQueue 200 +IdleTimeout 60 +ExcludePath ^/proc/ +ExcludePath ^/sys/ +MaxDirectoryRecursion 20 +FollowDirectorySymlinks yes +FollowFileSymlinks yes +CrossFilesystems yes +SelfCheck 600 +VirusEvent /usr/local/bin/send_sms 123456789 \"VIRUS ALERT: %v\" +User clam +AllowSupplementaryGroups yes +ExitOnOOM yes +Foreground yes +Debug yes +LeaveTemporaryFiles yes +AllowAllMatchScan no +DetectPUA yes +ExcludePUA NetTool +ExcludePUA PWTool +IncludePUA Spy +IncludePUA Scanner +IncludePUA RAT +AlgorithmicDetection yes +ForceToDisk yes +DisableCache yes +ScanPE yes +DisableCertCheck yes +ScanELF yes +DetectBrokenExecutables yes +ScanOLE2 yes +OLE2BlockMacros no +ScanPDF yes +ScanSWF yes +ScanMail yes +ScanPartialMessages yes +PhishingSignatures yes +PhishingScanURLs yes +PhishingAlwaysBlockSSLMismatch no +PhishingAlwaysBlockCloak no +PartitionIntersection no +HeuristicScanPrecedence yes +StructuredDataDetection yes +StructuredMinCreditCardCount 5 +StructuredMinSSNCount 5 +StructuredSSNFormatNormal yes +StructuredSSNFormatStripped yes +ScanHTML yes +ScanArchive yes +ArchiveBlockEncrypted no +MaxScanSize 150M +MaxFileSize 30M +MaxRecursion 10 +MaxFiles 15000 +MaxEmbeddedPE 10M +MaxHTMLNormalize 10M +" + +let freshclam_conf ="## +## Example config file for freshclam +## Please read the freshclam.conf(5) manual before editing this file. +## + + +# Comment or remove the line below. +Example + +DatabaseDirectory /var/lib/clamav +UpdateLogFile /var/log/clamav/freshclam.log +LogFileMaxSize 2M +LogTime yes +LogVerbose yes +LogSyslog yes +LogFacility LOG_MAIL +LogRotate yes +PidFile /var/run/freshclam.pid +DatabaseOwner clam +AllowSupplementaryGroups yes +DNSDatabaseInfo current.cvd.clamav.net +DatabaseMirror db.XY.clamav.net +DatabaseMirror database.clamav.net +MaxAttempts 5 +ScriptedUpdates yes +CompressLocalDatabase no +DatabaseCustomURL http://myserver.com/mysigs.ndb +DatabaseCustomURL file:///mnt/nfs/local.hdb +PrivateMirror mirror1.mynetwork.com +PrivateMirror mirror2.mynetwork.com +Checks 24 +HTTPProxyServer myproxy.com +HTTPProxyPort 1234 +HTTPProxyUsername myusername +HTTPProxyPassword mypass +HTTPUserAgent SomeUserAgentIdString +LocalIPAddress aaa.bbb.ccc.ddd +NotifyClamd /etc/clamd.conf +OnUpdateExecute command +OnErrorExecute command +OnOutdatedExecute command +Foreground yes +Debug yes +ConnectTimeout 60 +ReceiveTimeout 60 +TestDatabases yes +SubmitDetectionStats /etc/clamd.conf +DetectionStatsCountry za +DetectionStatsCountry zw +SafeBrowsing yes +Bytecode yes +ExtraDatabase dbname1 +ExtraDatabase dbname2 +" + +test ClamAV.lns get clamd_conf = + { "#comment" = "#" } + { "#comment" = "# Example config file for the Clam AV daemon" } + { "#comment" = "# Please read the clamd.conf(5) manual before editing this file." } + { "#comment" = "#" } + { } + { "#comment" = "Comment or remove the line below." } + { "Example" } + { "#comment" = "LogFile must be writable for the user running daemon." } + { "LogFile" = "/var/log/clamav/clamd.log" } + { "LogFileUnlock" = "yes" } + { "LogFileMaxSize" = "0" } + { "LogTime" = "yes" } + { "LogClean" = "yes" } + { "LogSyslog" = "yes" } + { "LogFacility" = "LOG_MAIL" } + { "LogVerbose" = "yes" } + { "LogRotate" = "yes" } + { "ExtendedDetectionInfo" = "yes" } + { "PidFile" = "/var/run/clamav/clamd.pid" } + { "TemporaryDirectory" = "/var/tmp" } + { "DatabaseDirectory" = "/var/lib/clamav" } + { "OfficialDatabaseOnly" = "no" } + { "LocalSocket" = "/var/run/clamav/clamd.sock" } + { "LocalSocketGroup" = "virusgroup" } + { "LocalSocketMode" = "660" } + { "FixStaleSocket" = "yes" } + { "TCPSocket" = "3310" } + { "TCPAddr" = "127.0.0.1" } + { "MaxConnectionQueueLength" = "30" } + { "StreamMaxLength" = "10M" } + { "StreamMinPort" = "30000" } + { "StreamMaxPort" = "32000" } + { "MaxThreads" = "50" } + { "ReadTimeout" = "300" } + { "CommandReadTimeout" = "5" } + { "SendBufTimeout" = "200" } + { "MaxQueue" = "200" } + { "IdleTimeout" = "60" } + { "ExcludePath" = "^/proc/" } + { "ExcludePath" = "^/sys/" } + { "MaxDirectoryRecursion" = "20" } + { "FollowDirectorySymlinks" = "yes" } + { "FollowFileSymlinks" = "yes" } + { "CrossFilesystems" = "yes" } + { "SelfCheck" = "600" } + { "VirusEvent" = "/usr/local/bin/send_sms 123456789 \"VIRUS ALERT: %v\"" } + { "User" = "clam" } + { "AllowSupplementaryGroups" = "yes" } + { "ExitOnOOM" = "yes" } + { "Foreground" = "yes" } + { "Debug" = "yes" } + { "LeaveTemporaryFiles" = "yes" } + { "AllowAllMatchScan" = "no" } + { "DetectPUA" = "yes" } + { "ExcludePUA" = "NetTool" } + { "ExcludePUA" = "PWTool" } + { "IncludePUA" = "Spy" } + { "IncludePUA" = "Scanner" } + { "IncludePUA" = "RAT" } + { "AlgorithmicDetection" = "yes" } + { "ForceToDisk" = "yes" } + { "DisableCache" = "yes" } + { "ScanPE" = "yes" } + { "DisableCertCheck" = "yes" } + { "ScanELF" = "yes" } + { "DetectBrokenExecutables" = "yes" } + { "ScanOLE2" = "yes" } + { "OLE2BlockMacros" = "no" } + { "ScanPDF" = "yes" } + { "ScanSWF" = "yes" } + { "ScanMail" = "yes" } + { "ScanPartialMessages" = "yes" } + { "PhishingSignatures" = "yes" } + { "PhishingScanURLs" = "yes" } + { "PhishingAlwaysBlockSSLMismatch" = "no" } + { "PhishingAlwaysBlockCloak" = "no" } + { "PartitionIntersection" = "no" } + { "HeuristicScanPrecedence" = "yes" } + { "StructuredDataDetection" = "yes" } + { "StructuredMinCreditCardCount" = "5" } + { "StructuredMinSSNCount" = "5" } + { "StructuredSSNFormatNormal" = "yes" } + { "StructuredSSNFormatStripped" = "yes" } + { "ScanHTML" = "yes" } + { "ScanArchive" = "yes" } + { "ArchiveBlockEncrypted" = "no" } + { "MaxScanSize" = "150M" } + { "MaxFileSize" = "30M" } + { "MaxRecursion" = "10" } + { "MaxFiles" = "15000" } + { "MaxEmbeddedPE" = "10M" } + { "MaxHTMLNormalize" = "10M" } + +test ClamAV.lns get freshclam_conf = + { "#comment" = "#" } + { "#comment" = "# Example config file for freshclam" } + { "#comment" = "# Please read the freshclam.conf(5) manual before editing this file." } + { "#comment" = "#" } + { } + { } + { "#comment" = "Comment or remove the line below." } + { "Example" } + { } + { "DatabaseDirectory" = "/var/lib/clamav" } + { "UpdateLogFile" = "/var/log/clamav/freshclam.log" } + { "LogFileMaxSize" = "2M" } + { "LogTime" = "yes" } + { "LogVerbose" = "yes" } + { "LogSyslog" = "yes" } + { "LogFacility" = "LOG_MAIL" } + { "LogRotate" = "yes" } + { "PidFile" = "/var/run/freshclam.pid" } + { "DatabaseOwner" = "clam" } + { "AllowSupplementaryGroups" = "yes" } + { "DNSDatabaseInfo" = "current.cvd.clamav.net" } + { "DatabaseMirror" = "db.XY.clamav.net" } + { "DatabaseMirror" = "database.clamav.net" } + { "MaxAttempts" = "5" } + { "ScriptedUpdates" = "yes" } + { "CompressLocalDatabase" = "no" } + { "DatabaseCustomURL" = "http://myserver.com/mysigs.ndb" } + { "DatabaseCustomURL" = "file:///mnt/nfs/local.hdb" } + { "PrivateMirror" = "mirror1.mynetwork.com" } + { "PrivateMirror" = "mirror2.mynetwork.com" } + { "Checks" = "24" } + { "HTTPProxyServer" = "myproxy.com" } + { "HTTPProxyPort" = "1234" } + { "HTTPProxyUsername" = "myusername" } + { "HTTPProxyPassword" = "mypass" } + { "HTTPUserAgent" = "SomeUserAgentIdString" } + { "LocalIPAddress" = "aaa.bbb.ccc.ddd" } + { "NotifyClamd" = "/etc/clamd.conf" } + { "OnUpdateExecute" = "command" } + { "OnErrorExecute" = "command" } + { "OnOutdatedExecute" = "command" } + { "Foreground" = "yes" } + { "Debug" = "yes" } + { "ConnectTimeout" = "60" } + { "ReceiveTimeout" = "60" } + { "TestDatabases" = "yes" } + { "SubmitDetectionStats" = "/etc/clamd.conf" } + { "DetectionStatsCountry" = "za" } + { "DetectionStatsCountry" = "zw" } + { "SafeBrowsing" = "yes" } + { "Bytecode" = "yes" } + { "ExtraDatabase" = "dbname1" } + { "ExtraDatabase" = "dbname2" } diff --git a/Sharp.Augeas.Test/lens/tests/test_cmdline.aug b/Sharp.Augeas.Test/lens/tests/test_cmdline.aug new file mode 100644 index 0000000..0624a0b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cmdline.aug @@ -0,0 +1,22 @@ +module Test_cmdline = + +let lns = Cmdline.lns + +test lns get "foo\nbar" = * +test lns get "foo\n" = { "foo" } +test lns get "foo" = { "foo" } +test lns get "foo bar" = { "foo" } { "bar" } +test lns get "foo bar" = { "foo" } { "bar" } +test lns get "foo=bar" = { "foo" = "bar" } +test lns get "foo=bar foo=baz" = { "foo" = "bar" } { "foo" = "baz" } +test lns get "foo bar=bar quux baz=x" = + { "foo" } { "bar" = "bar" } { "quux" } { "baz" = "x" } +test lns get "initrd=\linux\initrd.img-4.19.0-6-amd64 root=UUID=SOME_UUID rw" = + { "initrd" = "\linux\initrd.img-4.19.0-6-amd64" } { "root" = "UUID=SOME_UUID" } { "rw" } + +test lns put "" after set "foo" "bar" = "foo=bar" +test lns put "foo=bar" after rm "foo" = "" +test lns put "x=y foo=bar" after set "foo" "baz" = "x=y foo=baz" +test lns put "foo=bar foo=baz" after set "foo[. = 'bar']" "quux" = "foo=quux foo=baz" +test lns put "foo=bar foo=baz" after set "foo[. = 'baz']" "quux" = "foo=bar foo=quux" +test lns put "" after set "foo" "" = "foo" diff --git a/Sharp.Augeas.Test/lens/tests/test_cobblermodules.aug b/Sharp.Augeas.Test/lens/tests/test_cobblermodules.aug new file mode 100644 index 0000000..c525f6c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cobblermodules.aug @@ -0,0 +1,30 @@ +module Test_cobblermodules = + + let conf = " +[serializes] +settings = serializer_catalog + +[authentication] +modules = auth_denyall +" + + test CobblerModules.lns get conf = + {} + { "serializes" + { "settings" = "serializer_catalog" } + {} } + { "authentication" + { "modules" = "auth_denyall" } } + + test CobblerModules.lns put conf after + set "serializes/distro" "serializer_catalog"; + set "serializes/repo" "serializer_catalog" + = " +[serializes] +settings = serializer_catalog + +distro=serializer_catalog +repo=serializer_catalog +[authentication] +modules = auth_denyall +" diff --git a/Sharp.Augeas.Test/lens/tests/test_cobblersettings.aug b/Sharp.Augeas.Test/lens/tests/test_cobblersettings.aug new file mode 100644 index 0000000..9646741 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cobblersettings.aug @@ -0,0 +1,46 @@ +module Test_cobblersettings = + +test Cobblersettings.lns get "Simple_Setting: Value \n" = + { "Simple_Setting" = "Value" } + +test Cobblersettings.lns get "Simple_Setting2: 'Value2@acme.com' \n" = + { "Simple_Setting2" = "'Value2@acme.com'" } + +test Cobblersettings.lns get "Simple_Setting3: ''\n" = + { "Simple_Setting3" = "''" } + +test Cobblersettings.lns get "Simple_Setting4: \"\"\n" = + { "Simple_Setting4" = "\"\"" } + +test Cobblersettings.lns get "Simple_Setting_Trailing_Space : Value \n" = + { "Simple_Setting_Trailing_Space" = "Value" } + +test Cobblersettings.lns get "Setting_List:[Value1, Value2, Value3]\n" = + { "Setting_List" + { "sequence" + { "item" = "Value1" } + { "item" = "Value2" } + { "item" = "Value3" } } } + +test Cobblersettings.lns get "Empty_Setting_List: []\n" = + { "Empty_Setting_List" + { "sequence" } } + +test Cobblersettings.lns get "# Commented_Out_Setting: 'some value'\n" = + { "#comment" = "Commented_Out_Setting: 'some value'" } + +test Cobblersettings.lns get "---\n" = + { "---" = "---"} + +test Cobblersettings.lns get "Nested_Setting:\n Test: Value\n" = + { "Nested_Setting" + { "Test" = "Value" } } + +test Cobblersettings.lns get "Nested_Setting:\n - Test \n" = + { "Nested_Setting" + { "list" + { "value" = "Test" } } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_collectd.aug b/Sharp.Augeas.Test/lens/tests/test_collectd.aug new file mode 100644 index 0000000..abecdcf --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_collectd.aug @@ -0,0 +1,65 @@ +(* +Module: Test_Collectd + Provides unit tests and examples for the <Collectd> lens. +*) +module Test_Collectd = + +(* Variable: simple *) +let simple = "LoadPlugin contextswitch +LoadPlugin cpu +FQDNLookup \"true\" +Include \"/var/lib/puppet/modules/collectd/plugins/*.conf\" +" + +(* Test: Collectd.lns *) +test Collectd.lns get simple = + { "directive" = "LoadPlugin" + { "arg" = "contextswitch" } + } + { "directive" = "LoadPlugin" + { "arg" = "cpu" } + } + { "directive" = "FQDNLookup" + { "arg" = "\"true\"" } + } + { "directive" = "Include" + { "arg" = "\"/var/lib/puppet/modules/collectd/plugins/*.conf\"" } + } + + +(* Variable: filters *) +let filters = "<Chain \"PreCache\"> + <Rule \"no_fqdn\"> + <Match \"regex\"> + Host \"^[^\.]*$\" + Invert false + </Match> + Target \"stop\" + </Rule> +</Chain> +" + + +(* Test: Collectd.lns *) +test Collectd.lns get filters = + { "Chain" + { "arg" = "\"PreCache\"" } + { "Rule" + { "arg" = "\"no_fqdn\"" } + { "Match" + { "arg" = "\"regex\"" } + { "directive" = "Host" + { "arg" = "\"^[^\.]*$\"" } + } + { "directive" = "Invert" + { "arg" = "false" } + } + } + { "directive" = "Target" + { "arg" = "\"stop\"" } + } + } + } + + + diff --git a/Sharp.Augeas.Test/lens/tests/test_cpanel.aug b/Sharp.Augeas.Test/lens/tests/test_cpanel.aug new file mode 100644 index 0000000..c38d02f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cpanel.aug @@ -0,0 +1,48 @@ +(* +Module: Test_CPanel + Provides unit tests and examples for the <CPanel> lens. +*) +module Test_CPanel = + +(* Variable: config + A sample cpanel.config file *) +let config = "#### NOTICE #### +# After manually editing any configuration settings in this file, +# please run '/usr/local/cpanel/whostmgr/bin/whostmgr2 --updatetweaksettings' +# to fully update your server's configuration. + +skipantirelayd=1 +ionice_optimizefs=6 +account_login_access=owner_root +enginepl=cpanel.pl +stats_log=/usr/local/cpanel/logs/stats_log +cpaddons_notify_users=Allow users to choose +apache_port=0.0.0.0:80 +allow_server_info_status_from= +system_diskusage_warn_percent=82.5500 +maxemailsperhour +email_send_limits_max_defer_fail_percentage +default_archive-logs=1 +SecurityPolicy::xml-api=1\n" + +(* Test: CPanel.lns + Get <config> *) +test CPanel.lns get config = + { "#comment" = "### NOTICE ####" } + { "#comment" = "After manually editing any configuration settings in this file," } + { "#comment" = "please run '/usr/local/cpanel/whostmgr/bin/whostmgr2 --updatetweaksettings'" } + { "#comment" = "to fully update your server's configuration." } + { } + { "skipantirelayd" = "1" } + { "ionice_optimizefs" = "6" } + { "account_login_access" = "owner_root" } + { "enginepl" = "cpanel.pl" } + { "stats_log" = "/usr/local/cpanel/logs/stats_log" } + { "cpaddons_notify_users" = "Allow users to choose" } + { "apache_port" = "0.0.0.0:80" } + { "allow_server_info_status_from" = "" } + { "system_diskusage_warn_percent" = "82.5500" } + { "maxemailsperhour" } + { "email_send_limits_max_defer_fail_percentage" } + { "default_archive-logs" = "1" } + { "SecurityPolicy::xml-api" = "1" } diff --git a/Sharp.Augeas.Test/lens/tests/test_cron.aug b/Sharp.Augeas.Test/lens/tests/test_cron.aug new file mode 100644 index 0000000..7181751 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cron.aug @@ -0,0 +1,51 @@ +module Test_cron = + + let conf = "# /etc/cron.d/anacron: crontab entries for the anacron package + +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +CRON_TZ=America/Los_Angeles +MAILTO=user1@tld1,user2@tld2;user3@tld3 + + 30 7 * * * root test -x /etc/init.d/anacron && /usr/sbin/invoke-rc.d anacron start >/dev/null + 00 */3 15-25/2 May 1-5 user somecommand + 00 */3 15-25/2 May mon-tue user somecommand +# a comment +@yearly foo a command\n" + + test Cron.lns get conf = + { "#comment" = "/etc/cron.d/anacron: crontab entries for the anacron package" } + {} + { "SHELL" = "/bin/sh" } + { "PATH" = "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" } + { "CRON_TZ" = "America/Los_Angeles" } + { "MAILTO" = "user1@tld1,user2@tld2;user3@tld3" } + {} + { "entry" = "test -x /etc/init.d/anacron && /usr/sbin/invoke-rc.d anacron start >/dev/null" + { "time" + { "minute" = "30" } + { "hour" = "7" } + { "dayofmonth" = "*" } + { "month" = "*" } + { "dayofweek" = "*" } } + { "user" = "root" } } + { "entry" = "somecommand" + { "time" + { "minute" = "00" } + { "hour" = "*/3" } + { "dayofmonth" = "15-25/2" } + { "month" = "May" } + { "dayofweek" = "1-5" } } + { "user" = "user" } } + { "entry" = "somecommand" + { "time" + { "minute" = "00" } + { "hour" = "*/3" } + { "dayofmonth" = "15-25/2" } + { "month" = "May" } + { "dayofweek" = "mon-tue" } } + { "user" = "user" } } + { "#comment" = "a comment" } + { "entry" = "a command" + { "schedule" = "yearly" } + { "user" = "foo" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_cron_user.aug b/Sharp.Augeas.Test/lens/tests/test_cron_user.aug new file mode 100644 index 0000000..19073c3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cron_user.aug @@ -0,0 +1,34 @@ +module Test_Cron_User = + +let s = "MAILTO=cron@example.com +31 * * * * ${HOME}/bin/stuff +54 16 * * * /usr/sbin/tmpwatch -umc 30d ${HOME}/tmp\n" + +let lns = Cron_User.lns + +test lns get s = + { "MAILTO" = "cron@example.com" } + { "entry" = "${HOME}/bin/stuff" + { "time" + { "minute" = "31" } + { "hour" = "*" } + { "dayofmonth" = "*" } + { "month" = "*" } + { "dayofweek" = "*" } + } + } + { "entry" = "/usr/sbin/tmpwatch -umc 30d ${HOME}/tmp" + { "time" + { "minute" = "54" } + { "hour" = "16" } + { "dayofmonth" = "*" } + { "month" = "*" } + { "dayofweek" = "*" } + } + } + +test lns put s after +rm "/MAILTO"; +rm "/entry[time/minute = '54']"; +set "/entry[. = '${HOME}/bin/stuff']/time/minute" "24" = + "24 * * * * ${HOME}/bin/stuff\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_crypttab.aug b/Sharp.Augeas.Test/lens/tests/test_crypttab.aug new file mode 100644 index 0000000..e687814 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_crypttab.aug @@ -0,0 +1,62 @@ +module Test_crypttab = + + let simple = "sda1_crypt\t /dev/sda1\t /dev/random \t swap\n" + + let simple_tree = + { "1" + { "target" = "sda1_crypt" } + { "device" = "/dev/sda1" } + { "password" = "/dev/random" } + { "opt" = "swap" } } + + let trailing_ws = "sda1_crypt\t /dev/sda1\t /dev/random \t swap\t\n" + + let no_opts = "sda1_crypt\t /dev/sda1\t /etc/key\n" + + let no_opts_tree = + { "1" + { "target" = "sda1_crypt" } + { "device" = "/dev/sda1" } + { "password" = "/etc/key" } } + + let no_password = "sda1_crypt\t /dev/sda1\n" + + let no_password_tree = + { "1" + { "target" = "sda1_crypt" } + { "device" = "/dev/sda1" } } + + let multi_opts = "sda1_crypt\t /dev/sda1\t /etc/key \t cipher=aes-cbc-essiv:sha256,verify\n" + + let multi_opts_tree = + { "1" + { "target" = "sda1_crypt" } + { "device" = "/dev/sda1" } + { "password" = "/etc/key" } + { "opt" = "cipher" + { "value" = "aes-cbc-essiv:sha256" } } + { "opt" = "verify" } } + + let uuid = "sda3_crypt UUID=5b8b6e72-acf9-43bc-bd2d-8dbcaee82f99 none luks,keyscript=/usr/share/yubikey-luks/ykluks-keyscript,discard\n" + + let uuid_tree = + { "1" + { "target" = "sda3_crypt" } + { "device" = "UUID=5b8b6e72-acf9-43bc-bd2d-8dbcaee82f99" } + { "password" = "none" } + { "opt" = "luks" } + { "opt" = "keyscript" + { "value" = "/usr/share/yubikey-luks/ykluks-keyscript" } } + { "opt" = "discard" } } + + test Crypttab.lns get simple = simple_tree + + test Crypttab.lns get trailing_ws = simple_tree + + test Crypttab.lns get no_opts = no_opts_tree + + test Crypttab.lns get no_password = no_password_tree + + test Crypttab.lns get multi_opts = multi_opts_tree + + test Crypttab.lns get uuid = uuid_tree diff --git a/Sharp.Augeas.Test/lens/tests/test_csv.aug b/Sharp.Augeas.Test/lens/tests/test_csv.aug new file mode 100644 index 0000000..b24f447 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_csv.aug @@ -0,0 +1,91 @@ +module Test_CSV = + +(* Test: CSV.lns + Simple test *) +test CSV.lns get "a,b,c\n" = + { "1" + { "1" = "a" } + { "2" = "b" } + { "3" = "c" } } + +(* Test: CSV.lns + Values with spaces *) +test CSV.lns get "a,b c,d\n" = + { "1" + { "1" = "a" } + { "2" = "b c" } + { "3" = "d" } } + +(* Test: CSV.lns + Quoted values *) +test CSV.lns get "a,\"b,c\",d +# comment +# +e,f,with space\n" = + { "1" + { "1" = "a" } + { "2" = "\"b,c\"" } + { "3" = "d" } } + { "#comment" = "comment" } + { } + { "2" + { "1" = "e" } + { "2" = "f" } + { "3" = "with space" } } + +(* Test: CSV.lns + Empty values *) +test CSV.lns get ", +,,\n" = + { "1" + { "1" = "" } + { "2" = "" } } + { "2" + { "1" = "" } + { "2" = "" } + { "3" = "" } } + +(* Test: CSV.lns + Trailing spaces *) +test CSV.lns get "a , b + \n" = + { "1" + { "1" = "a " } + { "2" = " b " } } + { "2" + { "1" = " " } } + +(* Test: CSV.lns + Quoted values in quoted values *) +test CSV.lns get "\"a,b\"\"c d\"\"\"\n" = + { "1" { "1" = "\"a,b\"\"c d\"\"\"" } } + +(* Test: CSV.lns + Quote in quoted values *) +test CSV.lns get "\"a,b\"\"c d\"\n" = + { "1" { "1" = "\"a,b\"\"c d\"" } } + +(* Test: CSV.lns + Values with newlines *) +test CSV.lns get "a,\"b\n c\"\n" = + { "1" + { "1" = "a" } + { "2" = "\"b\n c\"" } } + +(* Test: CSV.lns_semicol + Semi-colon lens *) +test CSV.lns_semicol get "a;\"b;c\";d +# comment +# +e;f;with space\n" = + { "1" + { "1" = "a" } + { "2" = "\"b;c\"" } + { "3" = "d" } } + { "#comment" = "comment" } + { } + { "2" + { "1" = "e" } + { "2" = "f" } + { "3" = "with space" } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_cups.aug b/Sharp.Augeas.Test/lens/tests/test_cups.aug new file mode 100644 index 0000000..276c5d1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cups.aug @@ -0,0 +1,481 @@ +(* +Module: Test_Cups + Provides unit tests and examples for the <Cups> lens. +*) + +module Test_Cups = + +(* Variable: conf *) +let conf = "# Sample configuration file for the CUPS scheduler. +LogLevel warn + +# Deactivate CUPS' internal logrotating, as we provide a better one, especially +# LogLevel debug2 gets usable now +MaxLogSize 0 + +# Administrator user group... +SystemGroup lpadmin + + +# Only listen for connections from the local machine. +Listen localhost:631 +Listen /var/run/cups/cups.sock + +# Show shared printers on the local network. +BrowseOrder allow,deny +BrowseAllow all +BrowseLocalProtocols CUPS dnssd +BrowseAddress @LOCAL + +# Default authentication type, when authentication is required... +DefaultAuthType Basic + +# Web interface setting... +WebInterface Yes + +# Restrict access to the server... +<Location /> + Order allow,deny +</Location> + +# Restrict access to the admin pages... +<Location /admin> + Order allow,deny +</Location> + +# Restrict access to configuration files... +<Location /admin/conf> + AuthType Default + Require user @SYSTEM + Order allow,deny +</Location> + +# Set the default printer/job policies... +<Policy default> + # Job/subscription privacy... + JobPrivateAccess default + JobPrivateValues default + SubscriptionPrivateAccess default + SubscriptionPrivateValues default + + # Job-related operations must be done by the owner or an administrator... + <Limit Create-Job Print-Job Print-URI Validate-Job> + Order deny,allow + </Limit> + + <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document> + Require user @OWNER @SYSTEM + Order deny,allow + </Limit> + + # All administration operations require an administrator to authenticate... + <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices> + AuthType Default + Require user @SYSTEM + Order deny,allow + </Limit> + + # All printer operations require a printer operator to authenticate... + <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs> + AuthType Default + Require user @SYSTEM + Order deny,allow + </Limit> + + # Only the owner or an administrator can cancel or authenticate a job... + <Limit Cancel-Job CUPS-Authenticate-Job> + Require user @OWNER @SYSTEM + Order deny,allow + </Limit> + + <Limit All> + Order deny,allow + </Limit> +</Policy> + +# Set the authenticated printer/job policies... +<Policy authenticated> + # Job/subscription privacy... + JobPrivateAccess default + JobPrivateValues default + SubscriptionPrivateAccess default + SubscriptionPrivateValues default + + # Job-related operations must be done by the owner or an administrator... + <Limit Create-Job Print-Job Print-URI Validate-Job> + AuthType Default + Order deny,allow + </Limit> + + <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document> + AuthType Default + Require user @OWNER @SYSTEM + Order deny,allow + </Limit> + + # All administration operations require an administrator to authenticate... + <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default> + AuthType Default + Require user @SYSTEM + Order deny,allow + </Limit> + + # All printer operations require a printer operator to authenticate... + <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs> + AuthType Default + Require user @SYSTEM + Order deny,allow + </Limit> + + # Only the owner or an administrator can cancel or authenticate a job... + <Limit Cancel-Job CUPS-Authenticate-Job> + AuthType Default + Require user @OWNER @SYSTEM + Order deny,allow + </Limit> + + <Limit All> + Order deny,allow + </Limit> +</Policy> +" + +(* Test: Simplevars.lns *) +test Cups.lns get conf = + { "#comment" = "Sample configuration file for the CUPS scheduler." } + { "directive" = "LogLevel" + { "arg" = "warn" } + } + { } + { "#comment" = "Deactivate CUPS' internal logrotating, as we provide a better one, especially" } + { "#comment" = "LogLevel debug2 gets usable now" } + { "directive" = "MaxLogSize" + { "arg" = "0" } + } + { } + { "#comment" = "Administrator user group..." } + { "directive" = "SystemGroup" + { "arg" = "lpadmin" } + } + { } + { } + { "#comment" = "Only listen for connections from the local machine." } + { "directive" = "Listen" + { "arg" = "localhost:631" } + } + { "directive" = "Listen" + { "arg" = "/var/run/cups/cups.sock" } + } + { } + { "#comment" = "Show shared printers on the local network." } + { "directive" = "BrowseOrder" + { "arg" = "allow,deny" } + } + { "directive" = "BrowseAllow" + { "arg" = "all" } + } + { "directive" = "BrowseLocalProtocols" + { "arg" = "CUPS" } + { "arg" = "dnssd" } + } + { "directive" = "BrowseAddress" + { "arg" = "@LOCAL" } + } + { } + { "#comment" = "Default authentication type, when authentication is required..." } + { "directive" = "DefaultAuthType" + { "arg" = "Basic" } + } + { } + { "#comment" = "Web interface setting..." } + { "directive" = "WebInterface" + { "arg" = "Yes" } + } + { } + { "#comment" = "Restrict access to the server..." } + { "Location" + { "arg" = "/" } + { "directive" = "Order" + { "arg" = "allow,deny" } + } + } + { "#comment" = "Restrict access to the admin pages..." } + { "Location" + { "arg" = "/admin" } + { "directive" = "Order" + { "arg" = "allow,deny" } + } + } + { "#comment" = "Restrict access to configuration files..." } + { "Location" + { "arg" = "/admin/conf" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "allow,deny" } + } + } + { "#comment" = "Set the default printer/job policies..." } + { "Policy" + { "arg" = "default" } + { "#comment" = "Job/subscription privacy..." } + { "directive" = "JobPrivateAccess" + { "arg" = "default" } + } + { "directive" = "JobPrivateValues" + { "arg" = "default" } + } + { "directive" = "SubscriptionPrivateAccess" + { "arg" = "default" } + } + { "directive" = "SubscriptionPrivateValues" + { "arg" = "default" } + } + { } + { "#comment" = "Job-related operations must be done by the owner or an administrator..." } + { "Limit" + { "arg" = "Create-Job" } + { "arg" = "Print-Job" } + { "arg" = "Print-URI" } + { "arg" = "Validate-Job" } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "Limit" + { "arg" = "Send-Document" } + { "arg" = "Send-URI" } + { "arg" = "Hold-Job" } + { "arg" = "Release-Job" } + { "arg" = "Restart-Job" } + { "arg" = "Purge-Jobs" } + { "arg" = "Set-Job-Attributes" } + { "arg" = "Create-Job-Subscription" } + { "arg" = "Renew-Subscription" } + { "arg" = "Cancel-Subscription" } + { "arg" = "Get-Notifications" } + { "arg" = "Reprocess-Job" } + { "arg" = "Cancel-Current-Job" } + { "arg" = "Suspend-Current-Job" } + { "arg" = "Resume-Job" } + { "arg" = "Cancel-My-Jobs" } + { "arg" = "Close-Job" } + { "arg" = "CUPS-Move-Job" } + { "arg" = "CUPS-Get-Document" } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@OWNER" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "#comment" = "All administration operations require an administrator to authenticate..." } + { "Limit" + { "arg" = "CUPS-Add-Modify-Printer" } + { "arg" = "CUPS-Delete-Printer" } + { "arg" = "CUPS-Add-Modify-Class" } + { "arg" = "CUPS-Delete-Class" } + { "arg" = "CUPS-Set-Default" } + { "arg" = "CUPS-Get-Devices" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "#comment" = "All printer operations require a printer operator to authenticate..." } + { "Limit" + { "arg" = "Pause-Printer" } + { "arg" = "Resume-Printer" } + { "arg" = "Enable-Printer" } + { "arg" = "Disable-Printer" } + { "arg" = "Pause-Printer-After-Current-Job" } + { "arg" = "Hold-New-Jobs" } + { "arg" = "Release-Held-New-Jobs" } + { "arg" = "Deactivate-Printer" } + { "arg" = "Activate-Printer" } + { "arg" = "Restart-Printer" } + { "arg" = "Shutdown-Printer" } + { "arg" = "Startup-Printer" } + { "arg" = "Promote-Job" } + { "arg" = "Schedule-Job-After" } + { "arg" = "Cancel-Jobs" } + { "arg" = "CUPS-Accept-Jobs" } + { "arg" = "CUPS-Reject-Jobs" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "#comment" = "Only the owner or an administrator can cancel or authenticate a job..." } + { "Limit" + { "arg" = "Cancel-Job" } + { "arg" = "CUPS-Authenticate-Job" } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@OWNER" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "Limit" + { "arg" = "All" } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + } + { "#comment" = "Set the authenticated printer/job policies..." } + { "Policy" + { "arg" = "authenticated" } + { "#comment" = "Job/subscription privacy..." } + { "directive" = "JobPrivateAccess" + { "arg" = "default" } + } + { "directive" = "JobPrivateValues" + { "arg" = "default" } + } + { "directive" = "SubscriptionPrivateAccess" + { "arg" = "default" } + } + { "directive" = "SubscriptionPrivateValues" + { "arg" = "default" } + } + { } + { "#comment" = "Job-related operations must be done by the owner or an administrator..." } + { "Limit" + { "arg" = "Create-Job" } + { "arg" = "Print-Job" } + { "arg" = "Print-URI" } + { "arg" = "Validate-Job" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "Limit" + { "arg" = "Send-Document" } + { "arg" = "Send-URI" } + { "arg" = "Hold-Job" } + { "arg" = "Release-Job" } + { "arg" = "Restart-Job" } + { "arg" = "Purge-Jobs" } + { "arg" = "Set-Job-Attributes" } + { "arg" = "Create-Job-Subscription" } + { "arg" = "Renew-Subscription" } + { "arg" = "Cancel-Subscription" } + { "arg" = "Get-Notifications" } + { "arg" = "Reprocess-Job" } + { "arg" = "Cancel-Current-Job" } + { "arg" = "Suspend-Current-Job" } + { "arg" = "Resume-Job" } + { "arg" = "Cancel-My-Jobs" } + { "arg" = "Close-Job" } + { "arg" = "CUPS-Move-Job" } + { "arg" = "CUPS-Get-Document" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@OWNER" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "#comment" = "All administration operations require an administrator to authenticate..." } + { "Limit" + { "arg" = "CUPS-Add-Modify-Printer" } + { "arg" = "CUPS-Delete-Printer" } + { "arg" = "CUPS-Add-Modify-Class" } + { "arg" = "CUPS-Delete-Class" } + { "arg" = "CUPS-Set-Default" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "#comment" = "All printer operations require a printer operator to authenticate..." } + { "Limit" + { "arg" = "Pause-Printer" } + { "arg" = "Resume-Printer" } + { "arg" = "Enable-Printer" } + { "arg" = "Disable-Printer" } + { "arg" = "Pause-Printer-After-Current-Job" } + { "arg" = "Hold-New-Jobs" } + { "arg" = "Release-Held-New-Jobs" } + { "arg" = "Deactivate-Printer" } + { "arg" = "Activate-Printer" } + { "arg" = "Restart-Printer" } + { "arg" = "Shutdown-Printer" } + { "arg" = "Startup-Printer" } + { "arg" = "Promote-Job" } + { "arg" = "Schedule-Job-After" } + { "arg" = "Cancel-Jobs" } + { "arg" = "CUPS-Accept-Jobs" } + { "arg" = "CUPS-Reject-Jobs" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "#comment" = "Only the owner or an administrator can cancel or authenticate a job..." } + { "Limit" + { "arg" = "Cancel-Job" } + { "arg" = "CUPS-Authenticate-Job" } + { "directive" = "AuthType" + { "arg" = "Default" } + } + { "directive" = "Require" + { "arg" = "user" } + { "arg" = "@OWNER" } + { "arg" = "@SYSTEM" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + { "Limit" + { "arg" = "All" } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_cyrus_imapd.aug b/Sharp.Augeas.Test/lens/tests/test_cyrus_imapd.aug new file mode 100644 index 0000000..ecb4ff1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_cyrus_imapd.aug @@ -0,0 +1,37 @@ +module Test_cyrus_imapd = + +let conf = "configdirectory: /var/lib/imap +partition-default: /var/spool/imap +admins: cyrus-admin +sievedir: /var/lib/imap/sieve +sendmail: /usr/sbin/sendmail +sasl_pwcheck_method: auxprop saslauthd +sasl_mech_list: PLAIN LOGIN +allowplaintext: no +tls_cert_file: /etc/pki/cyrus-imapd/cyrus-imapd.pem +tls_key_file: /etc/pki/cyrus-imapd/cyrus-imapd.pem +tls_ca_file: /etc/pki/tls/certs/ca-bundle.crt +# uncomment this if you're operating in a DSCP environment (RFC-4594) +# qosmarking: af13\n" + +test Cyrus_Imapd.lns get conf = + { "configdirectory" = "/var/lib/imap" } + { "partition-default" = "/var/spool/imap" } + { "admins" = "cyrus-admin" } + { "sievedir" = "/var/lib/imap/sieve" } + { "sendmail" = "/usr/sbin/sendmail" } + { "sasl_pwcheck_method" = "auxprop saslauthd" } + { "sasl_mech_list" = "PLAIN LOGIN" } + { "allowplaintext" = "no" } + { "tls_cert_file" = "/etc/pki/cyrus-imapd/cyrus-imapd.pem" } + { "tls_key_file" = "/etc/pki/cyrus-imapd/cyrus-imapd.pem" } + { "tls_ca_file" = "/etc/pki/tls/certs/ca-bundle.crt" } + { "#comment" = "uncomment this if you're operating in a DSCP environment (RFC-4594)" } + { "#comment" = "qosmarking: af13" } + +test Cyrus_Imapd.lns get "admins: cyrus-admin\n" + = + { "admins" = "cyrus-admin" } + +test Cyrus_Imapd.lns put "" after set "munge8bit" "false" = + "munge8bit: false\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_darkice.aug b/Sharp.Augeas.Test/lens/tests/test_darkice.aug new file mode 100644 index 0000000..a6542b6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_darkice.aug @@ -0,0 +1,24 @@ +module Test_darkice = + + let conf = "# this is a comment + +[general] +duration = 0 +bufferSecs = 5 # size of internal slip buffer, in seconds + +[icecast2-0] +bitrateMode=cbr +format = vorbis +" + + test Darkice.lns get conf = + { "#comment" = "this is a comment" } + {} + { "target" = "general" + { "duration" = "0" } + { "bufferSecs" = "5" + { "#comment" = "size of internal slip buffer, in seconds" } } + {} } + { "target" = "icecast2-0" + { "bitrateMode" = "cbr" } + { "format" = "vorbis" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_debctrl.aug b/Sharp.Augeas.Test/lens/tests/test_debctrl.aug new file mode 100644 index 0000000..11a37e1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_debctrl.aug @@ -0,0 +1,434 @@ +module Test_debctrl = + + let source = "Source: libtest-distmanifest-perl\n" + let source_result = { "Source" = "libtest-distmanifest-perl" } + + test (Debctrl.simple_entry Debctrl.simple_src_keyword ) get source = + source_result + + test (Debctrl.simple_entry Debctrl.simple_src_keyword ) get + "Maintainer: Debian Perl Group <pkg-perl-maintainers@lists.alioth.debian.org>\n" + = { "Maintainer" = "Debian Perl Group <pkg-perl-maintainers@lists.alioth.debian.org>" + } + + let uploaders + = "Uploaders: foo@bar, Dominique Dumont <dominique.dumont@xx.yyy>,\n" + . " gregor herrmann <gregoa@xxx.yy>\n" + + let uploaders_result = + { "Uploaders" + { "1" = "foo@bar"} + { "2" = "Dominique Dumont <dominique.dumont@xx.yyy>" } + { "3" = "gregor herrmann <gregoa@xxx.yy>" } } + + test Debctrl.uploaders get uploaders = uploaders_result + +(* test package dependencies *) +test Debctrl.version_depends get "( >= 5.8.8-12 )" = + { "version" { "relation" = ">=" } { "number" = "5.8.8-12" } } + +test Debctrl.arch_depends get "[ !hurd-i386]" = + { "arch" { "prefix" = "!" } { "name" = "hurd-i386" } } + +test Debctrl.arch_depends get "[ hurd-i386]" = + { "arch" { "prefix" = "" } { "name" = "hurd-i386" } } + +let p_depends_test = "perl ( >= 5.8.8-12 ) [ !hurd-i386]" + +test Debctrl.package_depends get p_depends_test = + { "perl" + { "version" + { "relation" = ">=" } + { "number" = "5.8.8-12" } } + { "arch" { "prefix" = "!" } { "name" = "hurd-i386" } } } + +let dependency_test = "perl-modules (>= 5.10) | libmodule-build-perl" + +test Debctrl.dependency get dependency_test = + { "or" { "perl-modules" + { "version" { "relation" = ">=" } + { "number" = "5.10" } } } } + { "or" { "libmodule-build-perl" } } + +test (Debctrl.dependency_list "Build-Depends-Indep") get + "Build-Depends-Indep: perl (>= 5.8.8-12) [ !hurd-i386], \n" + . " perl-modules (>= 5.10) | libmodule-build-perl,\n" + . " libcarp-assert-more-perl,\n" + . " libconfig-tiny-perl\n" + = { "Build-Depends-Indep" + { "and" { "or" { "perl" + { "version" + { "relation" = ">=" } + { "number" = "5.8.8-12" } } + { "arch" + { "prefix" = "!" } + { "name" = "hurd-i386" } } } } } + { "and" { "or" { "perl-modules" + { "version" { "relation" = ">=" } + { "number" = "5.10" } } } } + { "or" { "libmodule-build-perl" } } } + { "and" { "or" { "libcarp-assert-more-perl" } } } + { "and" { "or" { "libconfig-tiny-perl" } } } } + +test (Debctrl.dependency_list "Depends") get + "Depends: ${perl:Depends}, ${misc:Depends},\n" + ." libparse-recdescent-perl (>= 1.90.0)\n" + = { "Depends" + { "and" { "or" { "${perl:Depends}" }} } + { "and" { "or" { "${misc:Depends}" }} } + { "and" { "or" { "libparse-recdescent-perl" + { "version" + { "relation" = ">=" } + { "number" = "1.90.0" } } } } } + } + + let description = "Description: describe and edit configuration data\n" + ." Config::Model enables [...] must:\n" + ." - if the configuration data\n" + ." .\n" + ." With the elements above, (...) on ReadLine.\n" + + test Debctrl.description get description = + { "Description" + { "summary" = "describe and edit configuration data" } + { "text" = "Config::Model enables [...] must:" } + { "text" = " - if the configuration data" } + { "text" = "." } + { "text" = "With the elements above, (...) on ReadLine."} } + + + let simple_bin_pkg1 = "Package: libconfig-model-perl\n" + . "Architecture: all\n" + . "Description: dummy1\n" + . " dummy text 1\n" + + let simple_bin_pkg2 = "Package: libconfig-model2-perl\n" + . "Architecture: all\n" + . "Description: dummy2\n" + . " dummy text 2\n" + + test Debctrl.src_entries get source.uploaders + = { "Source" = "libtest-distmanifest-perl" } + { "Uploaders" + { "1" = "foo@bar"} + { "2" = "Dominique Dumont <dominique.dumont@xx.yyy>" } + { "3" = "gregor herrmann <gregoa@xxx.yy>" } } + + test Debctrl.bin_entries get simple_bin_pkg1 = + { "Package" = "libconfig-model-perl" } + { "Architecture" = "all" } + { "Description" { "summary" = "dummy1" } {"text" = "dummy text 1" } } + + + let paragraph_simple = source . uploaders ."\n" + . simple_bin_pkg1 . "\n" + . simple_bin_pkg2 + + test Debctrl.lns get paragraph_simple = + { "srcpkg" { "Source" = "libtest-distmanifest-perl" } + { "Uploaders" + { "1" = "foo@bar"} + { "2" = "Dominique Dumont <dominique.dumont@xx.yyy>" } + { "3" = "gregor herrmann <gregoa@xxx.yy>" } } } + { "binpkg" { "Package" = "libconfig-model-perl" } + { "Architecture" = "all" } + { "Description" { "summary" = "dummy1" } + { "text" = "dummy text 1" } } } + { "binpkg" { "Package" = "libconfig-model2-perl" } + { "Architecture" = "all" } + { "Description" { "summary" = "dummy2" } + { "text" = "dummy text 2" } } } + + +(* PUT TESTS *) + +test Debctrl.src_entries + put uploaders + after set "/Uploaders/1" "foo@bar" + = uploaders + +test Debctrl.src_entries + put uploaders + after set "/Uploaders/1" "bar@bar" + = "Uploaders: bar@bar, Dominique Dumont <dominique.dumont@xx.yyy>,\n" + . " gregor herrmann <gregoa@xxx.yy>\n" + +test Debctrl.src_entries + put uploaders + after set "/Uploaders/4" "baz@bar" + = "Uploaders: foo@bar, Dominique Dumont <dominique.dumont@xx.yyy>,\n" + . " gregor herrmann <gregoa@xxx.yy>,\n" + . " baz@bar\n" + +test Debctrl.lns put (source."\nPackage: test\nDescription: foobar\n") + after + set "/srcpkg/Uploaders/1" "foo@bar" ; + set "/srcpkg/Uploaders/2" "Dominique Dumont <dominique.dumont@xx.yyy>" ; + set "/srcpkg/Uploaders/3" "gregor herrmann <gregoa@xxx.yy>" ; + set "/srcpkg/Build-Depends-Indep/and[1]/or/perl/version/relation" ">=" ; + set "/srcpkg/Build-Depends-Indep/and[1]/or/perl/version/number" "5.8.8-12" ; + set "/srcpkg/Build-Depends-Indep/and[1]/or/perl/arch/prefix" "!" ; + set "/srcpkg/Build-Depends-Indep/and[1]/or/perl/arch/name" "hurd-i386" ; + set "/srcpkg/Build-Depends-Indep/and[2]/or[1]/perl-modules/version/relation" ">=" ; + set "/srcpkg/Build-Depends-Indep/and[2]/or[1]/perl-modules/version/number" "5.10" ; + set "/srcpkg/Build-Depends-Indep/and[2]/or[2]/libmodule-build-perl" ""; + set "/srcpkg/Build-Depends-Indep/and[3]/or/libcarp-assert-more-perl" "" ; + set "/srcpkg/Build-Depends-Indep/and[4]/or/libconfig-tiny-perl" "" ; + set "/binpkg[1]/Package" "libconfig-model-perl" ; + (* must remove description because set cannot insert Archi before description *) + rm "/binpkg[1]/Description" ; + set "/binpkg/Architecture" "all" ; + set "/binpkg[1]/Description/summary" "dummy1" ; + set "/binpkg[1]/Description/text" "dummy text 1" ; + set "/binpkg[2]/Package" "libconfig-model2-perl" ; + set "/binpkg[2]/Architecture" "all" ; + set "/binpkg[2]/Description/summary" "dummy2" ; + set "/binpkg[2]/Description/text" "dummy text 2" + = +"Source: libtest-distmanifest-perl +Uploaders: foo@bar, + Dominique Dumont <dominique.dumont@xx.yyy>, + gregor herrmann <gregoa@xxx.yy> +Build-Depends-Indep: perl ( >= 5.8.8-12 ) [ !hurd-i386 ], + perl-modules ( >= 5.10 ) | libmodule-build-perl, + libcarp-assert-more-perl, + libconfig-tiny-perl + +Package: libconfig-model-perl +Architecture: all +Description: dummy1 + dummy text 1 + +Package: libconfig-model2-perl +Architecture: all +Description: dummy2 + dummy text 2 +" + +(* Test Augeas' own control file *) +let augeas_control = "Source: augeas +Priority: optional +Maintainer: Nicolas Valcárcel Scerpella (Canonical) <nicolas.valcarcel@canonical.com> +Uploaders: Free Ekanayaka <freee@debian.org>, Micah Anderson <micah@debian.org> +Build-Depends: debhelper (>= 5), autotools-dev, libreadline-dev, chrpath, + naturaldocs (>= 1.51-1), texlive-latex-base +Standards-Version: 3.9.2 +Section: libs +Homepage: http://augeas.net/ +DM-Upload-Allowed: yes + +Package: augeas-tools +Section: admin +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Augeas command line tools + Augeas is a configuration editing tool. It parses configuration files in their + native formats and transforms them into a tree. Configuration changes are made + by manipulating this tree and saving it back into native config files. + . + This package provides command line tools based on libaugeas0: + - augtool, a tool to manage configuration files. + - augparse, a testing and debugging tool for augeas lenses. + +Package: libaugeas-dev +Section: libdevel +Architecture: any +Depends: libaugeas0 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Development files for writing applications based on libaugeas0 + Augeas is a configuration editing tool. It parses configuration files in their + native formats and transforms them into a tree. Configuration changes are made + by manipulating this tree and saving it back into native config files. + . + This package includes the development files to write programs using the Augeas + API. +" +test DebCtrl.lns get augeas_control = + { "srcpkg" + { "Source" = "augeas" } + { "Priority" = "optional" } + { "Maintainer" = "Nicolas Valcárcel Scerpella (Canonical) <nicolas.valcarcel@canonical.com>" } + { "Uploaders" + { "1" = "Free Ekanayaka <freee@debian.org>" } + { "2" = "Micah Anderson <micah@debian.org>" } + } + { "Build-Depends" + { "and" + { "or" + { "debhelper" + { "version" + { "relation" = ">=" } + { "number" = "5" } + } + } + } + } + { "and" + { "or" + { "autotools-dev" } + } + } + { "and" + { "or" + { "libreadline-dev" } + } + } + { "and" + { "or" + { "chrpath" } + } + } + { "and" + { "or" + { "naturaldocs" + { "version" + { "relation" = ">=" } + { "number" = "1.51-1" } + } + } + } + } + { "and" + { "or" + { "texlive-latex-base" } + } + } + } + { "Standards-Version" = "3.9.2" } + { "Section" = "libs" } + { "Homepage" = "http://augeas.net/" } + { "DM-Upload-Allowed" = "yes" } + } + { "binpkg" + { "Package" = "augeas-tools" } + { "Section" = "admin" } + { "Architecture" = "any" } + { "Depends" + { "and" + { "or" + { "${shlibs:Depends}" } + } + } + { "and" + { "or" + { "${misc:Depends}" } + } + } + } + { "Description" + { "summary" = "Augeas command line tools" } + { "text" = "Augeas is a configuration editing tool. It parses configuration files in their" } + { "text" = "native formats and transforms them into a tree. Configuration changes are made" } + { "text" = "by manipulating this tree and saving it back into native config files." } + { "text" = "." } + { "text" = "This package provides command line tools based on libaugeas0:" } + { "text" = "- augtool, a tool to manage configuration files." } + { "text" = "- augparse, a testing and debugging tool for augeas lenses." } + } + } + { "binpkg" + { "Package" = "libaugeas-dev" } + { "Section" = "libdevel" } + { "Architecture" = "any" } + { "Depends" + { "and" + { "or" + { "libaugeas0" + { "version" + { "relation" = "=" } + { "number" = "${binary:Version}" } + } + } + } + } + { "and" + { "or" + { "${shlibs:Depends}" } + } + } + { "and" + { "or" + { "${misc:Depends}" } + } + } + } + { "Description" + { "summary" = "Development files for writing applications based on libaugeas0" } + { "text" = "Augeas is a configuration editing tool. It parses configuration files in their" } + { "text" = "native formats and transforms them into a tree. Configuration changes are made" } + { "text" = "by manipulating this tree and saving it back into native config files." } + { "text" = "." } + { "text" = "This package includes the development files to write programs using the Augeas" } + { "text" = "API." } + } + } + +(* Bug #267: Python module extensions, from Debian Python Policy, chapter 2 *) +let python_control = "Source: graphite-web +Maintainer: Will Pearson (Editure Key) <wpearson@editure.co.uk> +Section: python +Priority: optional +Build-Depends: debhelper (>= 7), python-support (>= 0.8.4) +Standards-Version: 3.7.2 +XS-Python-Version: current + +Package: python-graphite-web +Architecture: all +Depends: ${python:Depends} +XB-Python-Version: ${python:Versions} +Provides: ${python:Provides} +Description: Enterprise scalable realtime graphing +" +test Debctrl.lns get python_control = + { "srcpkg" + { "Source" = "graphite-web" } + { "Maintainer" = "Will Pearson (Editure Key) <wpearson@editure.co.uk>" } + { "Section" = "python" } + { "Priority" = "optional" } + { "Build-Depends" + { "and" + { "or" + { "debhelper" + { "version" + { "relation" = ">=" } + { "number" = "7" } + } + } + } + } + { "and" + { "or" + { "python-support" + { "version" + { "relation" = ">=" } + { "number" = "0.8.4" } + } + } + } + } + } + { "Standards-Version" = "3.7.2" } + { "XS-Python-Version" = "current" } + } + { "binpkg" + { "Package" = "python-graphite-web" } + { "Architecture" = "all" } + { "Depends" + { "and" + { "or" + { "${python:Depends}" } + } + } + } + { "XB-Python-Version" = "${python:Versions}" } + { "Provides" + { "and" + { "or" + { "${python:Provides}" } + } + } + } + { "Description" + { "summary" = "Enterprise scalable realtime graphing" } + } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_desktop.aug b/Sharp.Augeas.Test/lens/tests/test_desktop.aug new file mode 100644 index 0000000..de530ae --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_desktop.aug @@ -0,0 +1,47 @@ +module Test_desktop = + +let conf = "# A comment +[Desktop Entry] +Version=1.0 +Type=Application +Name=Foo Viewer +# another comment +Comment=The best viewer for Foo objects available! +TryExec=fooview +Exec=fooview %F +Icon=fooview +MimeType=image/x-foo; +X-KDE-Library=libfooview +X-KDE-FactoryName=fooviewfactory +X-KDE-ServiceType=FooService +" + +test Desktop.lns get conf = + { "#comment" = "A comment" } + { "Desktop Entry" + { "Version" = "1.0" } + { "Type" = "Application" } + { "Name" = "Foo Viewer" } + { "#comment" = "another comment" } + { "Comment" = "The best viewer for Foo objects available!" } + { "TryExec" = "fooview" } + { "Exec" = "fooview %F" } + { "Icon" = "fooview" } + { "MimeType" = "image/x-foo;" } + { "X-KDE-Library" = "libfooview" } + { "X-KDE-FactoryName" = "fooviewfactory" } + { "X-KDE-ServiceType" = "FooService" } } + +(* Entries with square brackets *) +test Desktop.lns get "[Desktop Entry] +X-GNOME-FullName[ca]=En canadien +" = + { "Desktop Entry" + { "X-GNOME-FullName[ca]" = "En canadien" } } + +(* Test: Desktop.lns + Allow @ in setting (GH issue #92) *) +test Desktop.lns get "[Desktop Entry] +Name[sr@latin] = foobar\n" = + { "Desktop Entry" + { "Name[sr@latin]" = "foobar" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_devfsrules.aug b/Sharp.Augeas.Test/lens/tests/test_devfsrules.aug new file mode 100644 index 0000000..b27ba6c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_devfsrules.aug @@ -0,0 +1,59 @@ +module Test_DevfsRules = + + let manpage_example = "[localrules=10] +add path 'da*s*' mode 0660 group usb +" + + test DevfsRules.lns get manpage_example = + { "localrules" { "id" = "10" } + { "1" = "add path 'da*s*' mode 0660 group usb" } } + + + let example = "[devfsrules_jail_unhide_usb_printer_and_scanner=30] +add include $devfsrules_hide_all +add include $devfsrules_unhide_basic +add include $devfsrules_unhide_login +add path 'ulpt*' mode 0660 group printscan unhide +add path 'unlpt*' mode 0660 group printscan unhide +add path 'ugen2.8' mode 0660 group printscan unhide # Scanner (ugen2.8 is a symlink to usb/2.8.0) +add path usb unhide +add path usbctl unhide +add path 'usb/2.8.0' mode 0660 group printscan unhide + +[devfsrules_jail_unhide_usb_scanner_only=30] +add include $devfsrules_hide_all +add include $devfsrules_unhide_basic +add include $devfsrules_unhide_login +add path 'ugen2.8' mode 0660 group scan unhide # Scanner +add path usb unhide +add path usbctl unhide +add path 'usb/2.8.0' mode 0660 group scan unhide +" + + test DevfsRules.lns get example = + { "devfsrules_jail_unhide_usb_printer_and_scanner" { "id" = "30" } + { "1" = "add include $devfsrules_hide_all" } + { "2" = "add include $devfsrules_unhide_basic" } + { "3" = "add include $devfsrules_unhide_login" } + { "4" = "add path 'ulpt*' mode 0660 group printscan unhide" } + { "5" = "add path 'unlpt*' mode 0660 group printscan unhide" } + { "6" = "add path 'ugen2.8' mode 0660 group printscan unhide" + { "#comment" = "Scanner (ugen2.8 is a symlink to usb/2.8.0)" } + } + { "7" = "add path usb unhide" } + { "8" = "add path usbctl unhide" } + { "9" = "add path 'usb/2.8.0' mode 0660 group printscan unhide" } + { } + } + { "devfsrules_jail_unhide_usb_scanner_only" { "id" = "30" } + { "1" = "add include $devfsrules_hide_all" } + { "2" = "add include $devfsrules_unhide_basic" } + { "3" = "add include $devfsrules_unhide_login" } + { "4" = "add path 'ugen2.8' mode 0660 group scan unhide" + { "#comment" = "Scanner" } + } + { "5" = "add path usb unhide" } + { "6" = "add path usbctl unhide" } + { "7" = "add path 'usb/2.8.0' mode 0660 group scan unhide" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_device_map.aug b/Sharp.Augeas.Test/lens/tests/test_device_map.aug new file mode 100644 index 0000000..9b5da50 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_device_map.aug @@ -0,0 +1,34 @@ +module Test_device_map = + + let conf = "# this device map was generated by anaconda +(fd0) /dev/fda +(hd0) /dev/sda +(cd0) /dev/cdrom +(hd1,1) /dev/sdb1 +(hd0,a) /dev/sda1 +(0x80) /dev/sda +(128) /dev/sda +" + + test Device_map.lns get conf = + { "#comment" = "this device map was generated by anaconda" } + { "fd0" = "/dev/fda" } + { "hd0" = "/dev/sda" } + { "cd0" = "/dev/cdrom" } + { "hd1,1" = "/dev/sdb1" } + { "hd0,a" = "/dev/sda1" } + { "0x80" = "/dev/sda" } + { "128" = "/dev/sda" } + + test Device_map.lns put conf after + set "hd2\,1" "/dev/sdb1" + = "# this device map was generated by anaconda +(fd0) /dev/fda +(hd0) /dev/sda +(cd0) /dev/cdrom +(hd1,1) /dev/sdb1 +(hd0,a) /dev/sda1 +(0x80) /dev/sda +(128) /dev/sda +(hd2,1)\t/dev/sdb1 +" diff --git a/Sharp.Augeas.Test/lens/tests/test_dhclient.aug b/Sharp.Augeas.Test/lens/tests/test_dhclient.aug new file mode 100644 index 0000000..3db8ac9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_dhclient.aug @@ -0,0 +1,150 @@ +module Test_dhclient = + + let conf =" # Sample dhclient.conf + # Protocol timing +timeout 3; # Expect a fast server +retry + 10; +# Lease requirements and requests +request + subnet-mask, + broadcast-address, + ntp-servers; +# Dynamic DNS +send + fqdn.fqdn + \"grosse.fugue.com.\"; + +option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; + +interface ep0 { + script /sbin/dhclient-script; + send dhcp-client-identifier 1:0:a0:24:ab:fb:9c; + send dhcp-lease-time 3600; + request subnet-mask, broadcast-address, time-offset, routers, + domain-name, domain-name-servers, host-name; + media media10baseT/UTP, \"media10base2/BNC\"; +} + +alias { + interface \"ep0\"; + fixed-address 192.5.5.213; + option subnet-mask 255.255.255.255; +} + +lease { + interface \"eth0\"; + fixed-address 192.33.137.200; + medium \"link0 link1\"; + vendor option space \"name\"; + option host-name \"andare.swiftmedia.com\"; + option subnet-mask 255.255.255.0; + option broadcast-address 192.33.137.255; + option routers 192.33.137.250; + option domain-name-servers 127.0.0.1; + renew 2 2000/1/12 00:00:01; + rebind 2 2000/1/12 00:00:01; + expire 2 2000/1/12 00:00:01; +} +" + + test Dhclient.lns get conf = + { "#comment" = "Sample dhclient.conf" } + { "#comment" = "Protocol timing" } + { "timeout" = "3" + { "#comment" = "Expect a fast server" } } + { "retry" = "10" } + { "#comment" = "Lease requirements and requests" } + { "request" + { "1" = "subnet-mask" } + { "2" = "broadcast-address" } + { "3" = "ntp-servers" } } + { "#comment" = "Dynamic DNS" } + { "send" + { "fqdn.fqdn" = "\"grosse.fugue.com.\"" } } + {} + { "option" + { "rfc3442-classless-static-routes" + { "code" = "121" } + { "value" = "array of unsigned integer 8" } } } + {} + { "interface" = "ep0" + { "script" = "/sbin/dhclient-script" } + { "send" + { "dhcp-client-identifier" = "1:0:a0:24:ab:fb:9c" } } + { "send" + { "dhcp-lease-time" = "3600" } } + { "request" + { "1" = "subnet-mask" } + { "2" = "broadcast-address" } + { "3" = "time-offset" } + { "4" = "routers" } + { "5" = "domain-name" } + { "6" = "domain-name-servers" } + { "7" = "host-name" } } + { "media" + { "1" = "media10baseT/UTP" } + { "2" = "\"media10base2/BNC\"" } } } + {} + { "alias" + { "interface" = "\"ep0\"" } + { "fixed-address" = "192.5.5.213" } + { "option" + { "subnet-mask" = "255.255.255.255" } } } + {} + { "lease" + { "interface" = "\"eth0\"" } + { "fixed-address" = "192.33.137.200" } + { "medium" = "\"link0 link1\"" } + { "vendor option space" = "\"name\"" } + { "option" + { "host-name" = "\"andare.swiftmedia.com\"" } } + { "option" + { "subnet-mask" = "255.255.255.0" } } + { "option" + { "broadcast-address" = "192.33.137.255" } } + { "option" + { "routers" = "192.33.137.250" } } + { "option" + { "domain-name-servers" = "127.0.0.1" } } + { "renew" + { "weekday" = "2" } + { "year" = "2000" } + { "month" = "1" } + { "day" = "12" } + { "hour" = "00" } + { "minute" = "00" } + { "second" = "01" } } + { "rebind" + { "weekday" = "2" } + { "year" = "2000" } + { "month" = "1" } + { "day" = "12" } + { "hour" = "00" } + { "minute" = "00" } + { "second" = "01" } } + { "expire" + { "weekday" = "2" } + { "year" = "2000" } + { "month" = "1" } + { "day" = "12" } + { "hour" = "00" } + { "minute" = "00" } + { "second" = "01" } } } + + +test Dhclient.lns get "append domain-name-servers 127.0.0.1;\n" = + { "append" + { "domain-name-servers" = "127.0.0.1" } } + +test Dhclient.lns put "" after set "/prepend/domain-name-servers" "127.0.0.1" = + "prepend domain-name-servers 127.0.0.1;\n" + +(* When = is used before the value, it's an evaluated string, see dhcp-eval *) +test Dhclient.lns get "send dhcp-client-identifier = hardware;\n" = + { "send" + { "dhcp-client-identifier" + { "#eval" = "hardware" } } } + +test Dhclient.lns put "send host-name = gethostname();\n" + after set "/send/host-name/#eval" "test" = "send host-name = test;\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_dhcpd.aug b/Sharp.Augeas.Test/lens/tests/test_dhcpd.aug new file mode 100644 index 0000000..0af337c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_dhcpd.aug @@ -0,0 +1,606 @@ +module Test_dhcpd = + +let lns = Dhcpd.lns + +let conf = "# +# Sample configuration file for ISC dhcpd for Debian +# +# Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as +# configuration file instead of this file. +# +# $Id: dhcpd.conf,v 1.1.1.1 2002/05/21 00:07:44 peloy Exp $ +# + +# The ddns-updates-style parameter controls whether or not the server will +# attempt to do a DNS update when a lease is confirmed. We default to the +# behavior of the version 2 packages ('none', since DHCP v2 didn't +# have support for DDNS.) +ddns-update-style none; + +# option definitions common to all supported networks... +option domain-name \"example.org\"; +option domain-name-servers ns1.example.org, ns2.example.org; + +default-lease-time 600; +max-lease-time 7200; + +# If this DHCP server is the official DHCP server for the local +# network, the authoritative directive should be uncommented. +authoritative; + +allow booting; +allow bootp; + +# Use this to send dhcp log messages to a different log file (you also +# have to hack syslog.conf to complete the redirection). +log-facility local7; + +# No service will be given on this subnet, but declaring it helps the +# DHCP server to understand the network topology. + +subnet 10.152.187.0 netmask 255.255.255.0 { +} + +# This is a very basic subnet declaration. + +subnet 10.254.239.0 netmask 255.255.255.224 { + range 10.254.239.10 10.254.239.20; + option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; +} + +# This declaration allows BOOTP clients to get dynamic addresses, +# which we don't really recommend. + +subnet 10.254.239.32 netmask 255.255.255.224 { + range dynamic-bootp 10.254.239.40 10.254.239.60; + option broadcast-address 10.254.239.31; + option routers rtr-239-32-1.example.org; +} + +# A slightly different configuration for an internal subnet. +subnet 10.5.5.0 netmask 255.255.255.224 { + range 10.5.5.26 10.5.5.30; + option domain-name-servers ns1.internal.example.org; + option domain-name \"internal.example.org\"; + option routers 10.5.5.1; + option broadcast-address 10.5.5.31; + default-lease-time 600; + max-lease-time 7200; +} + +# Hosts which require special configuration options can be listed in +# host statements. If no address is specified, the address will be +# allocated dynamically (if possible), but the host-specific information +# will still come from the host declaration. + +host passacaglia { + hardware ethernet 0:0:c0:5d:bd:95; + filename \"vmunix.passacaglia\"; + server-name \"toccata.fugue.com\"; +} + +# Fixed IP addresses can also be specified for hosts. These addresses +# should not also be listed as being available for dynamic assignment. +# Hosts for which fixed IP addresses have been specified can boot using +# BOOTP or DHCP. Hosts for which no fixed address is specified can only +# be booted with DHCP, unless there is an address range on the subnet +# to which a BOOTP client is connected which has the dynamic-bootp flag +# set. +host fantasia { + hardware ethernet 08:00:07:26:c0:a5; + fixed-address fantasia.fugue.com; +} + +# You can declare a class of clients and then do address allocation +# based on that. The example below shows a case where all clients +# in a certain class get addresses on the 10.17.224/24 subnet, and all +# other clients get addresses on the 10.0.29/24 subnet. + +#class \"foo\" { +# match if substring (option vendor-class-identifier, 0, 4) = \"SUNW\"; +#} + +shared-network 224-29 { + subnet 10.17.224.0 netmask 255.255.255.0 { + option routers rtr-224.example.org; + } + subnet 10.0.29.0 netmask 255.255.255.0 { + option routers rtr-29.example.org; + } + pool { + allow members of \"foo\"; + range 10.17.224.10 10.17.224.250; + } + pool { + deny members of \"foo\"; + range 10.0.29.10 10.0.29.230; + } +} +" + +test lns get "authoritative;" = { "authoritative" } +test lns get "ddns-update-style none;" = { "ddns-update-style" = "none" } +test lns get "option domain-name \"example.org\";" = + { "option" + { "domain-name" + { "arg" = "example.org" } + } + } + +test lns get "option domain-name-servers ns1.example.org, ns2.example.org;" = + { "option" + { "domain-name-servers" + { "arg" = "ns1.example.org" } + { "arg" = "ns2.example.org" } + } + } + +test lns get "default-lease-time 600;" = { "default-lease-time" = "600" } +test lns get "range 10.254.239.60;" = +{ "range" + { "to" = "10.254.239.60" } + } + +test lns get "range dynamic-bootp 10.254.239.60;" = + { "range" + { "flag" = "dynamic-bootp" } + { "to" = "10.254.239.60" } + } + +test lns get "range dynamic-bootp 10.254.239.40 10.254.239.60;" = + { "range" + { "flag" = "dynamic-bootp" } + { "from" = "10.254.239.40" } + { "to" = "10.254.239.60" } + } + +test lns get "subnet 10.152.187.0 netmask 255.255.255.0 {}\n" = + { "subnet" + { "network" = "10.152.187.0" } + { "netmask" = "255.255.255.0" } + } + +test lns get " pool { + pool { + + } +} +" = + { "pool" + { "pool" } + } + +test lns get "group { host some-host {hardware ethernet 00:00:aa:bb:cc:dd; +fixed-address 10.1.1.1;}}" = + { "group" + { "host" = "some-host" + { "hardware" + { "type" = "ethernet" } + { "address" = "00:00:aa:bb:cc:dd" } + } + { "fixed-address" = "10.1.1.1" } + } + } + +test lns get "group fan-tas_tic { }" = + { "group" = "fan-tas_tic" } + +test Dhcpd.stmt_secu get "allow members of \"foo\";" = { "allow-members-of" = "foo" } +test Dhcpd.stmt_secu get "allow booting;" = { "allow" = "booting" } +test Dhcpd.stmt_secu get "allow bootp;" = { "allow" = "bootp" } +test Dhcpd.stmt_option get "option voip-boot-server code 66 = string;" = + { "rfc-code" + { "label" = "voip-boot-server" } + { "code" = "66" } + { "type" = "string" } + } + +test Dhcpd.stmt_option get "option special-option code 25 = array of string;" = + { "rfc-code" + { "label" = "special-option" } + { "code" = "25" } + { "type" = "array of string" } + } + +test Dhcpd.stmt_option get "option special-option code 25 = integer 32;" = + { "rfc-code" + { "label" = "special-option" } + { "code" = "25" } + { "type" = "integer 32" } + } + + +test Dhcpd.stmt_option get "option special-option code 25 = array of integer 32;" = + { "rfc-code" + { "label" = "special-option" } + { "code" = "25" } + { "type" = "array of integer 32" } + } + + + +test Dhcpd.lns get "authoritative; +log-facility local7; +ddns-update-style none; +default-lease-time 21600; +max-lease-time 43200; + +# Additional options for VOIP +option voip-boot-server code 66 = string; +option voip-vlan-id code 128 = string; +" = + { "authoritative" } + { "log-facility" = "local7" } + { "ddns-update-style" = "none" } + { "default-lease-time" = "21600" } + { "max-lease-time" = "43200" + { "#comment" = "Additional options for VOIP" } + } + { "rfc-code" + { "label" = "voip-boot-server" } + { "code" = "66" } + { "type" = "string" } + } + { "rfc-code" + { "label" = "voip-vlan-id" } + { "code" = "128" } + { "type" = "string" } + } + + +test Dhcpd.lns get " +option domain-name-servers 10.1.1.1, 10.11.2.1, 10.1.3.1; +next-server 10.1.1.1; + +failover peer \"redondance01\" { + primary; + address 10.1.1.1; + port 647; + peer address 10.1.1.1; + peer port 647; + max-response-delay 20; + max-unacked-updates 10; + mclt 3600; #comment. + split 128; #comment. + load balance max seconds 3; + } +" = + { } + { "option" + { "domain-name-servers" + { "arg" = "10.1.1.1" } + { "arg" = "10.11.2.1" } + { "arg" = "10.1.3.1" } + } + } + { "next-server" = "10.1.1.1" } + { "failover peer" = "redondance01" + { "primary" } + { "address" = "10.1.1.1" } + { "port" = "647" } + { "peer address" = "10.1.1.1" } + { "peer port" = "647" } + { "max-response-delay" = "20" } + { "max-unacked-updates" = "10" } + { "mclt" = "3600" + { "#comment" = "comment." } + } + { "split" = "128" + { "#comment" = "comment." } + } + { "load balance max seconds" = "3" } + } + + +(* test get and put for record types *) +let record_test = "option test_records code 123 = { string, ip-address, integer 32, ip6-address, domain-list };" + +test Dhcpd.lns get record_test = + { "rfc-code" + { "label" = "test_records" } + { "code" = "123" } + { "record" + { "1" = "string" } + { "2" = "ip-address" } + { "3" = "integer 32" } + { "4" = "ip6-address" } + { "5" = "domain-list" } + } + } + +test Dhcpd.lns put record_test after set "/rfc-code[1]/code" "124" = + "option test_records code 124 = { string, ip-address, integer 32, ip6-address, domain-list };" + +test Dhcpd.lns get " +option CallManager code 150 = ip-address; +option slp-directory-agent true 10.1.1.1, 10.2.2.2; +option slp-service-scope true \"SLP-GLOBAL\"; +option nds-context \"EXAMPLE\"; +option nds-tree-name \"EXAMPLE\"; +" = + { } + { "rfc-code" + { "label" = "CallManager" } + { "code" = "150" } + { "type" = "ip-address" } + } + { "option" + { "slp-directory-agent" = "true" + { "arg" = "10.1.1.1" } + { "arg" = "10.2.2.2" } + } + } + { "option" + { "slp-service-scope" = "true" + { "arg" = "SLP-GLOBAL" } + } + } + { "option" + { "nds-context" + { "arg" = "EXAMPLE" } + } + } + { "option" + { "nds-tree-name" + { "arg" = "EXAMPLE" } + } + } + + +test Dhcpd.lns get "option voip-vlan-id \"VLAN=1234;\";" = + { "option" + { "voip-vlan-id" + { "arg" = "VLAN=1234;" } + } + } + +test Dhcpd.lns get "option domain-name \"x.example.com y.example.com z.example.com\";" = + { "option" + { "domain-name" + { "arg" = "x.example.com y.example.com z.example.com" } + } + } + +test Dhcpd.lns get "include \"/etc/dhcpd.master\";" = + { "include" = "/etc/dhcpd.master" } + +test Dhcpd.lns put "\n" after set "/include" "/etc/dhcpd.master" = + "\ninclude \"/etc/dhcpd.master\";\n" + +test Dhcpd.fct_args get "(option dhcp-client-identifier, 1, 3)" = + { "args" + { "arg" = "option dhcp-client-identifier" } + { "arg" = "1" } + { "arg" = "3" } + } + +test Dhcpd.stmt_match get "match if substring (option dhcp-client-identifier, 1, 3) = \"RAS\";" = + { "match" + { "function" = "substring" + { "args" + { "arg" = "option dhcp-client-identifier" } + { "arg" = "1" } + { "arg" = "3" } + } + } + { "value" = "RAS" } + } + +test Dhcpd.stmt_match get "match if suffix (option dhcp-client-identifier, 4) = \"RAS\";" = + { "match" + { "function" = "suffix" + { "args" + { "arg" = "option dhcp-client-identifier" } + { "arg" = "4" } + } + } + { "value" = "RAS" } + } + +test Dhcpd.stmt_match get "match if option vendor-class-identifier=\"RAS\";" = + { "match" + { "option" = "vendor-class-identifier" + { "value" = "RAS" } + } + } + + +test Dhcpd.lns get "match pick-first-value (option dhcp-client-identifier, hardware);" = + { "match" + { "function" = "pick-first-value" + { "args" + { "arg" = "option dhcp-client-identifier" } + { "arg" = "hardware" } + } + } + } + +test Dhcpd.fct_args get "(16, 32, \"\", substring(hardware, 0, 4))" = + { "args" + { "arg" = "16" } + { "arg" = "32" } + { "arg" = "\"\"" } + { "arg" = "substring(hardware, 0, 4)" } + } + +test Dhcpd.stmt_match get "match if binary-to-ascii(16, 32, \"\", substring(hardware, 0, 4)) = \"1525400\";" = + { "match" + { "function" = "binary-to-ascii" + { "args" + { "arg" = "16" } + { "arg" = "32" } + { "arg" = "\"\"" } + { "arg" = "substring(hardware, 0, 4)" } + } + } + { "value" = "1525400" } + } + +test Dhcpd.lns get "subclass allocation-class-1 1:8:0:2b:4c:39:ad;" = + { "subclass" + { "name" = "allocation-class-1" } + { "value" = "1:8:0:2b:4c:39:ad" } + } + + +test Dhcpd.lns get "subclass \"allocation-class-1\" 1:8:0:2b:4c:39:ad;" = + { "subclass" + { "name" = "allocation-class-1" } + { "value" = "1:8:0:2b:4c:39:ad" } + } + +test Dhcpd.lns get "subclass \"quoted class\" \"quoted value\";" = + { "subclass" + { "name" = "quoted class" } + { "value" = "quoted value" } + } + + +(* overall test *) +test Dhcpd.lns put conf after rm "/x" = conf + +(* bug #293: primary should support argument *) +let input293 = "zone EXAMPLE.ORG. { + primary 127.0.0.1; +}" + +test Dhcpd.lns get input293 = + { "zone" = "EXAMPLE.ORG." + { "primary" = "127.0.0.1" } + } + +(* bug #311: filename should be quoted *) +let input311 = "subnet 172.16.0.0 netmask 255.255.255.0 { +filename \"pxelinux.0\"; +}" + +test Dhcpd.lns put "subnet 172.16.0.0 netmask 255.255.255.0 { +}" after + set "subnet/filename" "pxelinux.0" = input311 + +(* GH issue #34: support conditional structures *) +let gh34_empty = "if exists dhcp-parameter-request-list { +}\n" + +test Dhcpd.lns get gh34_empty = + { "@if" = "exists dhcp-parameter-request-list" } + +let gh34_empty_multi = "subnet 192.168.100.0 netmask 255.255.255.0 { + if true { + } elsif false { + } else { + } +}\n" + +test Dhcpd.lns get gh34_empty_multi = + { "subnet" + { "network" = "192.168.100.0" } + { "netmask" = "255.255.255.0" } + { "@if" = "true" + { "@elsif" = "false" } + { "@else" } } + } + +let gh34_simple = "if exists dhcp-parameter-request-list { + default-lease-time 600; + } else { +default-lease-time 200; +}\n" + +test Dhcpd.lns get gh34_simple = + { "@if" = "exists dhcp-parameter-request-list" + { "default-lease-time" = "600" } + { "@else" + { "default-lease-time" = "200" } } } + +test Dhcpd.lns get "omapi-key fookey;" = + { "omapi-key" = "fookey" } + +(* almost all DHCP groups should support braces starting on the next line *) +test Dhcpd.lns get "class introduction +{ +}" = + { "class" = "introduction" } + +(* equals should work the same *) +test Dhcpd.lns get "option test_records code 123 = + string;" = + { "rfc-code" + { "label" = "test_records" } + { "code" = "123" } + { "type" = "string" } + } + +test Dhcpd.lns get "deny members of \"Are things like () allowed?\";" = + { "deny-members-of" = "Are things like () allowed?" } + +test Dhcpd.lns get "deny unknown clients;" = + { "deny" = "unknown clients" } +test Dhcpd.lns get "deny known-clients;" = + { "deny" = "known-clients" } + +test Dhcpd.lns get "set ClientMac = binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6));" = + { "set" = "ClientMac" + { "value" = "binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6))" } + } + +test Dhcpd.lns get "set myvariable = foo;" = + { "set" = "myvariable" + { "value" = "foo" } + } + +test Dhcpd.stmt_hardware get "hardware fddi 00:01:02:03:04:05;" = + { "hardware" + { "type" = "fddi" } + { "address" = "00:01:02:03:04:05" } + } + +test Dhcpd.lns get "on commit +{ + set test = thing; +}" = + { "on" = "commit" + { "set" = "test" + { "value" = "thing" } + } + } + +(* key block get/put/set test *) +let key_tests = "key sample { + algorithm hmac-md5; + secret \"secret==\"; +} + +key \"interesting\" { }; + +key \"third key\" { + secret \"two==\"; +}" + +test Dhcpd.lns get key_tests = + { "key_block" = "sample" + { "algorithm" = "hmac-md5" } + { "secret" = "secret==" } + } + { "key_block" = "interesting" } + { "key_block" = "third key" + { "secret" = "two==" } + } + +test Dhcpd.lns put key_tests after set "/key_block[1]" "sample2" = + "key sample2 { + algorithm hmac-md5; + secret \"secret==\"; +} + +key \"interesting\" { }; + +key \"third key\" { + secret \"two==\"; +}" + +test Dhcpd.lns get "group \"hello\" { }" = + { "group" = "hello" } + +test Dhcpd.lns get "class \"testing class with spaces and quotes and ()\" {}" = + { "class" = "testing class with spaces and quotes and ()" } diff --git a/Sharp.Augeas.Test/lens/tests/test_dns_zone.aug b/Sharp.Augeas.Test/lens/tests/test_dns_zone.aug new file mode 100644 index 0000000..2537c4d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_dns_zone.aug @@ -0,0 +1,384 @@ +module Test_Dns_Zone = + +let lns = Dns_Zone.lns + +(* RFC 1034 §6 *) +test lns get " +EDU. IN SOA SRI-NIC.ARPA. HOSTMASTER.SRI-NIC.ARPA. ( + 870729 ;serial + 1800 ;refresh every 30 minutes + 300 ;retry every 5 minutes + 604800 ;expire after a week + 86400 ;minimum of a day + ) + NS SRI-NIC.ARPA. + NS C.ISI.EDU. + +UCI 172800 NS ICS.UCI + 172800 NS ROME.UCI +ICS.UCI 172800 A 192.5.19.1 +ROME.UCI 172800 A 192.5.19.31 + +ISI 172800 NS VAXA.ISI + 172800 NS A.ISI + 172800 NS VENERA.ISI.EDU. +VAXA.ISI 172800 A 10.2.0.27 + 172800 A 128.9.0.33 +VENERA.ISI.EDU. 172800 A 10.1.0.52 + 172800 A 128.9.0.32 +A.ISI 172800 A 26.3.0.103 + +UDEL.EDU. 172800 NS LOUIE.UDEL.EDU. + 172800 NS UMN-REI-UC.ARPA. +LOUIE.UDEL.EDU. 172800 A 10.0.0.96 + 172800 A 192.5.39.3 + +YALE.EDU. 172800 NS YALE.ARPA. +YALE.EDU. 172800 NS YALE-BULLDOG.ARPA. + +MIT.EDU. 43200 NS XX.LCS.MIT.EDU. + 43200 NS ACHILLES.MIT.EDU. +XX.LCS.MIT.EDU. 43200 A 10.0.0.44 +ACHILLES.MIT.EDU. 43200 A 18.72.0.8 +" = + { "EDU." + { "1" + { "class" = "IN" } + { "type" = "SOA" } + { "mname" = "SRI-NIC.ARPA." } + { "rname" = "HOSTMASTER.SRI-NIC.ARPA." } + { "serial" = "870729" } + { "refresh" = "1800" } + { "retry" = "300" } + { "expiry" = "604800" } + { "minimum" = "86400" } + } + { "2" { "type" = "NS" } { "rdata" = "SRI-NIC.ARPA." } } + { "3" { "type" = "NS" } { "rdata" = "C.ISI.EDU." } } + } + { "UCI" + { "1" { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "ICS.UCI" } } + { "2" { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "ROME.UCI" } } + } + { "ICS.UCI" + { "1" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "192.5.19.1" } } + } + { "ROME.UCI" + { "1" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "192.5.19.31" } } + } + { "ISI" + { "1" { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "VAXA.ISI" } } + { "2" { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "A.ISI" } } + { "3" + { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "VENERA.ISI.EDU." } + } + } + { "VAXA.ISI" + { "1" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "10.2.0.27" } } + { "2" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "128.9.0.33" } } + } + { "VENERA.ISI.EDU." + { "1" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "10.1.0.52" } } + { "2" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "128.9.0.32" } } + } + { "A.ISI" + { "1" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "26.3.0.103" } } + } + { "UDEL.EDU." + { "1" + { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "LOUIE.UDEL.EDU." } + } + { "2" + { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "UMN-REI-UC.ARPA." } + } + } + { "LOUIE.UDEL.EDU." + { "1" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "10.0.0.96" } } + { "2" { "ttl" = "172800" } { "type" = "A" } { "rdata" = "192.5.39.3" } } + } + { "YALE.EDU." + { "1" { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "YALE.ARPA." } } + } + { "YALE.EDU." + { "1" + { "ttl" = "172800" } { "type" = "NS" } { "rdata" = "YALE-BULLDOG.ARPA." } + } + } + { "MIT.EDU." + { "1" + { "ttl" = "43200" } { "type" = "NS" } { "rdata" = "XX.LCS.MIT.EDU." } + } + { "2" + { "ttl" = "43200" } { "type" = "NS" } { "rdata" = "ACHILLES.MIT.EDU." } + } + } + { "XX.LCS.MIT.EDU." + { "1" { "ttl" = "43200" } { "type" = "A" } { "rdata" = "10.0.0.44" } } + } + { "ACHILLES.MIT.EDU." + { "1" { "ttl" = "43200" } { "type" = "A" } { "rdata" = "18.72.0.8" } } + } + + +(* RFC 1035 §5.3 *) +test lns get " +@ IN SOA VENERA Action\.domains ( + 20 ; SERIAL + 7200 ; REFRESH + 600 ; RETRY + 3600000; EXPIRE + 60) ; MINIMUM + + NS A.ISI.EDU. + NS VENERA + NS VAXA + MX 10 VENERA + MX 20 VAXA + +A A 26.3.0.103 + +VENERA A 10.1.0.52 + A 128.9.0.32 + +VAXA A 10.2.0.27 + A 128.9.0.33 +" = + { "@" + { "1" + { "class" = "IN" } + { "type" = "SOA" } + { "mname" = "VENERA" } + { "rname" = "Action\\.domains" } + { "serial" = "20" } + { "refresh" = "7200" } + { "retry" = "600" } + { "expiry" = "3600000" } + { "minimum" = "60" } + } + { "2" { "type" = "NS" } { "rdata" = "A.ISI.EDU." } } + { "3" { "type" = "NS" } { "rdata" = "VENERA" } } + { "4" { "type" = "NS" } { "rdata" = "VAXA" } } + { "5" { "type" = "MX" } { "priority" = "10" } { "exchange" = "VENERA" } } + { "6" { "type" = "MX" } { "priority" = "20" } { "exchange" = "VAXA" } } + } + { "A" { "1" { "type" = "A" } { "rdata" = "26.3.0.103" } } } + { "VENERA" + { "1" { "type" = "A" } { "rdata" = "10.1.0.52" } } + { "2" { "type" = "A" } { "rdata" = "128.9.0.32" } } + } + { "VAXA" + { "1" { "type" = "A" } { "rdata" = "10.2.0.27" } } + { "2" { "type" = "A" } { "rdata" = "128.9.0.33" } } + } + + +(* RFC 2782 *) +test lns get " +$ORIGIN example.com. +@ SOA server.example.com. root.example.com. ( + 1995032001 3600 3600 604800 86400 ) + NS server.example.com. + NS ns1.ip-provider.net. + NS ns2.ip-provider.net. +; foobar - use old-slow-box or new-fast-box if either is +; available, make three quarters of the logins go to +; new-fast-box. +_foobar._tcp SRV 0 1 9 old-slow-box.example.com. + SRV 0 3 9 new-fast-box.example.com. +; if neither old-slow-box or new-fast-box is up, switch to +; using the sysdmin's box and the server + SRV 1 0 9 sysadmins-box.example.com. + SRV 1 0 9 server.example.com. +server A 172.30.79.10 +old-slow-box A 172.30.79.11 +sysadmins-box A 172.30.79.12 +new-fast-box A 172.30.79.13 +; NO other services are supported +*._tcp SRV 0 0 0 . +*._udp SRV 0 0 0 . +" = + { "$ORIGIN" = "example.com." } + { "@" + { "1" + { "type" = "SOA" } + { "mname" = "server.example.com." } + { "rname" = "root.example.com." } + { "serial" = "1995032001" } + { "refresh" = "3600" } + { "retry" = "3600" } + { "expiry" = "604800" } + { "minimum" = "86400" } + } + { "2" { "type" = "NS" } { "rdata" = "server.example.com." } } + { "3" { "type" = "NS" } { "rdata" = "ns1.ip-provider.net." } } + { "4" { "type" = "NS" } { "rdata" = "ns2.ip-provider.net." } } + } + { "_foobar._tcp" + { "1" + { "type" = "SRV" } + { "priority" = "0" } + { "weight" = "1" } + { "port" = "9" } + { "target" = "old-slow-box.example.com." } + } + { "2" + { "type" = "SRV" } + { "priority" = "0" } + { "weight" = "3" } + { "port" = "9" } + { "target" = "new-fast-box.example.com." } + } + { "3" + { "type" = "SRV" } + { "priority" = "1" } + { "weight" = "0" } + { "port" = "9" } + { "target" = "sysadmins-box.example.com." } + } + { "4" + { "type" = "SRV" } + { "priority" = "1" } + { "weight" = "0" } + { "port" = "9" } + { "target" = "server.example.com." } + } + } + { "server" { "1" { "type" = "A" } { "rdata" = "172.30.79.10" } } } + { "old-slow-box" { "1" { "type" = "A" } { "rdata" = "172.30.79.11" } } } + { "sysadmins-box" { "1" { "type" = "A" } { "rdata" = "172.30.79.12" } } } + { "new-fast-box" { "1" { "type" = "A" } { "rdata" = "172.30.79.13" } } } + { "*._tcp" + { "1" + { "type" = "SRV" } + { "priority" = "0" } + { "weight" = "0" } + { "port" = "0" } + { "target" = "." } + } + } + { "*._udp" + { "1" + { "type" = "SRV" } + { "priority" = "0" } + { "weight" = "0" } + { "port" = "0" } + { "target" = "." } + } + } + + +(* RFC 3403 §6.2 *) +test lns get " +$ORIGIN 2.1.2.1.5.5.5.0.7.7.1.e164.arpa. + IN NAPTR 100 10 \"u\" \"sip+E2U\" \"!^.*$!sip:information@foo.se!i\" . + IN NAPTR 102 10 \"u\" \"smtp+E2U\" \"!^.*$!mailto:information@foo.se!i\" . +" = + { "$ORIGIN" = "2.1.2.1.5.5.5.0.7.7.1.e164.arpa." } + { "@" + { "1" + { "class" = "IN" } + { "type" = "NAPTR" } + { "order" = "100" } + { "preference" = "10" } + { "flags" = "\"u\"" } + { "service" = "\"sip+E2U\"" } + { "regexp" = "\"!^.*$!sip:information@foo.se!i\"" } + { "replacement" = "." } + } + { "2" + { "class" = "IN" } + { "type" = "NAPTR" } + { "order" = "102" } + { "preference" = "10" } + { "flags" = "\"u\"" } + { "service" = "\"smtp+E2U\"" } + { "regexp" = "\"!^.*$!mailto:information@foo.se!i\"" } + { "replacement" = "." } + } + } + + +(* SOA record on a single line *) +test lns get " +$ORIGIN example.com. +@ IN SOA ns root.example.com. (1 2 3 4 5) +" = + { "$ORIGIN" = "example.com." } + { "@" + { "1" + { "class" = "IN" } + { "type" = "SOA" } + { "mname" = "ns" } + { "rname" = "root.example.com." } + { "serial" = "1" } + { "refresh" = "2" } + { "retry" = "3" } + { "expiry" = "4" } + { "minimum" = "5" } + } + } + + +(* Different ordering of TTL and class *) +test lns get " +$ORIGIN example.com. +foo 1D IN A 10.1.2.3 +bar IN 2W A 10.4.5.6 +" = + { "$ORIGIN" = "example.com." } + { "foo" + { "1" + { "ttl" = "1D" } + { "class" = "IN" } + { "type" = "A" } + { "rdata" = "10.1.2.3" } + } + } + { "bar" + { "1" + { "class" = "IN" } + { "ttl" = "2W" } + { "type" = "A" } + { "rdata" = "10.4.5.6" } + } + } + + +(* Escaping *) +test lns get " +$ORIGIN example.com. +foo TXT abc\\\\def\\\"ghi +bar TXT \"ab cd\\\\ef\\\"gh\" +" = + { "$ORIGIN" = "example.com." } + { "foo" { "1" { "type" = "TXT" } { "rdata" = "abc\\\\def\\\"ghi" } } } + { "bar" { "1" { "type" = "TXT" } { "rdata" = "\"ab cd\\\\ef\\\"gh\"" } } } + + +(* Whitespace at the end of the line *) +test lns get " +$ORIGIN example.com. \n@ IN SOA ns root.example.com. (1 2 3 4 5) \t +foo 1D IN A 10.1.2.3\t +" = + { "$ORIGIN" = "example.com." } + { "@" + { "1" + { "class" = "IN" } + { "type" = "SOA" } + { "mname" = "ns" } + { "rname" = "root.example.com." } + { "serial" = "1" } + { "refresh" = "2" } + { "retry" = "3" } + { "expiry" = "4" } + { "minimum" = "5" } + } + } + { "foo" + { "1" + { "ttl" = "1D" } + { "class" = "IN" } + { "type" = "A" } + { "rdata" = "10.1.2.3" } + } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_dnsmasq.aug b/Sharp.Augeas.Test/lens/tests/test_dnsmasq.aug new file mode 100644 index 0000000..c6a63d9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_dnsmasq.aug @@ -0,0 +1,64 @@ +module Test_dnsmasq = + +let conf = "# Configuration file for dnsmasq. +# +#bogus-priv + +conf-dir=/etc/dnsmasq.d +selfmx + +address=/foo.com/bar.net/10.1.2.3 + +server=10.4.5.6#1234 +server=/bar.com/foo.net/10.7.8.9 +server=/foo.org/bar.org/10.3.2.1@eth0#5678 +server=/baz.org/# +server=/baz.net/#@eth1 +server=10.6.5.4#1234@eth0#5678 +server=/qux.com/qux.net/ +" + +test Dnsmasq.lns get conf = + { "#comment" = "Configuration file for dnsmasq." } + {} + { "#comment" = "bogus-priv" } + {} + { "conf-dir" = "/etc/dnsmasq.d" } + { "selfmx" } + {} + { "address" = "10.1.2.3" + { "domain" = "foo.com" } + { "domain" = "bar.net" } + } + {} + { "server" = "10.4.5.6" + { "port" = "1234" } + } + { "server" = "10.7.8.9" + { "domain" = "bar.com" } + { "domain" = "foo.net" } + } + { "server" = "10.3.2.1" + { "domain" = "foo.org" } + { "domain" = "bar.org" } + { "source" = "eth0" + { "port" = "5678" } + } + } + { "server" = "#" + { "domain" = "baz.org" } + } + { "server" = "#" + { "domain" = "baz.net" } + { "source" = "eth1" } + } + { "server" = "10.6.5.4" + { "port" = "1234" } + { "source" = "eth0" + { "port" = "5678" } + } + } + { "server" + { "domain" = "qux.com" } + { "domain" = "qux.net" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_dovecot.aug b/Sharp.Augeas.Test/lens/tests/test_dovecot.aug new file mode 100644 index 0000000..a9b7484 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_dovecot.aug @@ -0,0 +1,894 @@ +(* +Module: Test_Dovecot + Provides unit tests and examples for the <Dovecot> lens. +*) + +module Test_Dovecot = + +(* *********************** /etc/dovecot.conf ******************************** *) + +let dovecot_conf = "# Dovecot configuration file + +# If you're in a hurry, see http://wiki2.dovecot.org/QuickConfiguration + +# Default values are shown for each setting, it's not required to uncomment +# those. These are exceptions to this though: No sections (e.g. namespace {}) +# or plugin settings are added by default, they're listed only as examples. +# Paths are also just examples with the real defaults being based on configure +# options. The paths listed here are for configure --prefix=/usr +# --sysconfdir=/etc --localstatedir=/var + +# include_try command +!include_try /usr/share/dovecot/protocols.d/*.protocol + +# Wildcard, comma and space in value +listen = *, :: + +# Filesystem path in value +base_dir = /var/run/dovecot/ +instance_name = dovecot + +# Space and dot in value +login_greeting = Dovecot ready. + +# Empty values +login_trusted_networks = +login_access_sockets = + +# Simple values +verbose_proctitle = no +shutdown_clients = yes + +# Number in value +doveadm_worker_count = 0 +# Dash in value +doveadm_socket_path = doveadm-server + +import_environment = TZ + +## +## Comment +## + +# Simple commented dict block +dict { + #quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext + #expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext +} + +# Simple uncommented dict block +dict { + quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext + expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext +} + +# Include command +!include conf.d/*.conf + +# Include_try command +!include_try local.conf + +" + +test Dovecot.lns get dovecot_conf = + { "#comment" = "Dovecot configuration file" } + { } + { "#comment" = "If you're in a hurry, see http://wiki2.dovecot.org/QuickConfiguration" } + { } + { "#comment" = "Default values are shown for each setting, it's not required to uncomment" } + { "#comment" = "those. These are exceptions to this though: No sections (e.g. namespace {})" } + { "#comment" = "or plugin settings are added by default, they're listed only as examples." } + { "#comment" = "Paths are also just examples with the real defaults being based on configure" } + { "#comment" = "options. The paths listed here are for configure --prefix=/usr" } + { "#comment" = "--sysconfdir=/etc --localstatedir=/var" } + { } + { "#comment" = "include_try command" } + { "include_try" = "/usr/share/dovecot/protocols.d/*.protocol" } + { } + { "#comment" = "Wildcard, comma and space in value" } + { "listen" = "*, ::" } + { } + { "#comment" = "Filesystem path in value" } + { "base_dir" = "/var/run/dovecot/" } + { "instance_name" = "dovecot" } + { } + { "#comment" = "Space and dot in value" } + { "login_greeting" = "Dovecot ready." } + { } + { "#comment" = "Empty values" } + { "login_trusted_networks" } + { "login_access_sockets" } + { } + { "#comment" = "Simple values" } + { "verbose_proctitle" = "no" } + { "shutdown_clients" = "yes" } + { } + { "#comment" = "Number in value" } + { "doveadm_worker_count" = "0" } + { "#comment" = "Dash in value" } + { "doveadm_socket_path" = "doveadm-server" } + { } + { "import_environment" = "TZ" } + { } + { "#comment" = "#" } + { "#comment" = "# Comment" } + { "#comment" = "#" } + { } + { "#comment" = "Simple commented dict block" } + { "dict" + { "#comment" = "quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext" } + { "#comment" = "expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext" } + } + { } + { "#comment" = "Simple uncommented dict block" } + { "dict" + { "quota" = "mysql:/etc/dovecot/dovecot-dict-sql.conf.ext" } + { "expire" = "sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext" } + } + { } + { "#comment" = "Include command" } + { "include" = "conf.d/*.conf" } + { } + { "#comment" = "Include_try command" } + { "include_try" = "local.conf" } + { } + + + +(* *********************************** dict ********************************* *) + +let dovecot_dict_sql_conf = "connect = host=localhost dbname=mails user=testuser password=pass + +# CREATE TABLE quota ( +# username varchar(100) not null, +# bytes bigint not null default 0, +# messages integer not null default 0, +# primary key (username) +# ); + +map { + pattern = priv/quota/storage + table = quota + username_field = username + value_field = bytes +} +map { + pattern = priv/quota/messages + table = quota + username_field = username + value_field = messages +} + +# CREATE TABLE expires ( +# username varchar(100) not null, +# mailbox varchar(255) not null, +# expire_stamp integer not null, +# primary key (username, mailbox) +# ); + +map { + pattern = shared/expire/$user/$mailbox + table = expires + value_field = expire_stamp + + fields { + username = $user + mailbox = $mailbox + } +} +" + +test Dovecot.lns get dovecot_dict_sql_conf = + { "connect" = "host=localhost dbname=mails user=testuser password=pass" } + { } + { "#comment" = "CREATE TABLE quota (" } + { "#comment" = "username varchar(100) not null," } + { "#comment" = "bytes bigint not null default 0," } + { "#comment" = "messages integer not null default 0," } + { "#comment" = "primary key (username)" } + { "#comment" = ");" } + { } + { "map" + { "pattern" = "priv/quota/storage" } + { "table" = "quota" } + { "username_field" = "username" } + { "value_field" = "bytes" } + } + { "map" + { "pattern" = "priv/quota/messages" } + { "table" = "quota" } + { "username_field" = "username" } + { "value_field" = "messages" } + } + { } + { "#comment" = "CREATE TABLE expires (" } + { "#comment" = "username varchar(100) not null," } + { "#comment" = "mailbox varchar(255) not null," } + { "#comment" = "expire_stamp integer not null," } + { "#comment" = "primary key (username, mailbox)" } + { "#comment" = ");" } + { } + { "map" + { "pattern" = "shared/expire/$user/$mailbox" } + { "table" = "expires" } + { "value_field" = "expire_stamp" } + { } + { "fields" + { "username" = "$user" } + { "mailbox" = "$mailbox" } + } + } + +(* ********************************** auth ********************************** *) + +let auth_conf = "## Authentication processes + +disable_plaintext_auth = yes +auth_cache_size = 0 +auth_cache_ttl = 1 hour +auth_cache_negative_ttl = 1 hour +auth_realms = +auth_default_realm = +auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@ +auth_username_translation = +auth_username_format = +auth_master_user_separator = +auth_anonymous_username = anonymous +auth_worker_max_count = 30 +auth_gssapi_hostname = +auth_krb5_keytab = +auth_use_winbind = no +auth_winbind_helper_path = /usr/bin/ntlm_auth +auth_failure_delay = 2 secs +auth_ssl_require_client_cert = no +auth_ssl_username_from_cert = no +auth_mechanisms = plain + +!include auth-deny.conf.ext +!include auth-master.conf.ext +!include auth-system.conf.ext +!include auth-sql.conf.ext +!include auth-ldap.conf.ext +!include auth-passwdfile.conf.ext +!include auth-checkpassword.conf.ext +!include auth-vpopmail.conf.ext +!include auth-static.conf.ext + +passdb { + driver = passwd-file + deny = yes + + # File contains a list of usernames, one per line + args = /etc/dovecot/deny-users +} + +passdb { + driver = passwd-file + master = yes + args = /etc/dovecot/master-users + + # Unless you're using PAM, you probably still want the destination user to + # be looked up from passdb that it really exists. pass=yes does that. + pass = yes +} + +userdb { + driver = passwd-file + args = username_format=%u /etc/dovecot/users +} +" + +test Dovecot.lns get auth_conf = + { "#comment" = "# Authentication processes" } + { } + { "disable_plaintext_auth" = "yes" } + { "auth_cache_size" = "0" } + { "auth_cache_ttl" = "1 hour" } + { "auth_cache_negative_ttl" = "1 hour" } + { "auth_realms" } + { "auth_default_realm" } + { "auth_username_chars" = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@" } + { "auth_username_translation" } + { "auth_username_format" } + { "auth_master_user_separator" } + { "auth_anonymous_username" = "anonymous" } + { "auth_worker_max_count" = "30" } + { "auth_gssapi_hostname" } + { "auth_krb5_keytab" } + { "auth_use_winbind" = "no" } + { "auth_winbind_helper_path" = "/usr/bin/ntlm_auth" } + { "auth_failure_delay" = "2 secs" } + { "auth_ssl_require_client_cert" = "no" } + { "auth_ssl_username_from_cert" = "no" } + { "auth_mechanisms" = "plain" } + { } + { "include" = "auth-deny.conf.ext" } + { "include" = "auth-master.conf.ext" } + { "include" = "auth-system.conf.ext" } + { "include" = "auth-sql.conf.ext" } + { "include" = "auth-ldap.conf.ext" } + { "include" = "auth-passwdfile.conf.ext" } + { "include" = "auth-checkpassword.conf.ext" } + { "include" = "auth-vpopmail.conf.ext" } + { "include" = "auth-static.conf.ext" } + { } + { "passdb" + { "driver" = "passwd-file" } + { "deny" = "yes" } + { } + { "#comment" = "File contains a list of usernames, one per line" } + { "args" = "/etc/dovecot/deny-users" } + } + { } + { "passdb" + { "driver" = "passwd-file" } + { "master" = "yes" } + { "args" = "/etc/dovecot/master-users" } + { } + { "#comment" = "Unless you're using PAM, you probably still want the destination user to" } + { "#comment" = "be looked up from passdb that it really exists. pass=yes does that." } + { "pass" = "yes" } + } + { } + { "userdb" + { "driver" = "passwd-file" } + { "args" = "username_format=%u /etc/dovecot/users" } + } + +(* ******************************** director ******************************** *) + +let director_conf = "## Director-specific settings. +director_servers = +director_mail_servers = +director_user_expire = 15 min +director_doveadm_port = 0 + +service director { + unix_listener login/director { + mode = 0666 + } + fifo_listener login/proxy-notify { + mode = 0666 + } + unix_listener director-userdb { + #mode = 0600 + } + inet_listener { + port = + } +} + +service imap-login { + executable = imap-login director +} +service pop3-login { + executable = pop3-login director +} +protocol lmtp { + auth_socket_path = director-userdb +} +" + +test Dovecot.lns get director_conf = + { "#comment" = "# Director-specific settings." } + { "director_servers" } + { "director_mail_servers" } + { "director_user_expire" = "15 min" } + { "director_doveadm_port" = "0" } + { } + { "service" = "director" + { "unix_listener" = "login/director" + { "mode" = "0666" } + } + { "fifo_listener" = "login/proxy-notify" + { "mode" = "0666" } + } + { "unix_listener" = "director-userdb" + { "#comment" = "mode = 0600" } + } + { "inet_listener" + { "port" } + } + } + { } + { "service" = "imap-login" + { "executable" = "imap-login director" } + } + { "service" = "pop3-login" + { "executable" = "pop3-login director" } + } + { "protocol" = "lmtp" + { "auth_socket_path" = "director-userdb" } + } + +(* ********************************* logging ******************************** *) + +let logging_conf = "## Log destination. +log_path = syslog +info_log_path = +debug_log_path = +syslog_facility = mail +auth_verbose = no +auth_verbose_passwords = no +auth_debug = no +auth_debug_passwords = no +mail_debug = no +verbose_ssl = no + +plugin { + mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename + mail_log_fields = uid box msgid size +} + +log_timestamp = \"%b %d %H:%M:%S \" +login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c +login_log_format = %$: %s +mail_log_prefix = \"%s(%u): \" +deliver_log_format = msgid=%m: %$ +" + +test Dovecot.lns get logging_conf = + { "#comment" = "# Log destination." } + { "log_path" = "syslog" } + { "info_log_path" } + { "debug_log_path" } + { "syslog_facility" = "mail" } + { "auth_verbose" = "no" } + { "auth_verbose_passwords" = "no" } + { "auth_debug" = "no" } + { "auth_debug_passwords" = "no" } + { "mail_debug" = "no" } + { "verbose_ssl" = "no" } + { } + { "plugin" + { "mail_log_events" = "delete undelete expunge copy mailbox_delete mailbox_rename" } + { "mail_log_fields" = "uid box msgid size" } + } + { } + { "log_timestamp" = "\"%b %d %H:%M:%S \"" } + { "login_log_format_elements" = "user=<%u> method=%m rip=%r lip=%l mpid=%e %c" } + { "login_log_format" = "%$: %s" } + { "mail_log_prefix" = "\"%s(%u): \"" } + { "deliver_log_format" = "msgid=%m: %$" } + + +(* ********************************** mail ********************************** *) + +let mail_conf = "## Mailbox locations and namespaces +mail_location = +namespace { + type = private + separator = + prefix = + location = + inbox = no + hidden = no + list = yes + subscriptions = yes + mailbox \"Sent Messages\" { + special_use = \Sent + } +} + +# Example shared namespace configuration +namespace { + type = shared + separator = / + prefix = shared/%%u/ + location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u + subscriptions = no + list = children +} + +mail_uid = +mail_gid = +mail_privileged_group = +mail_access_groups = +mail_full_filesystem_access = no +mmap_disable = no +dotlock_use_excl = yes +mail_fsync = optimized +mail_nfs_storage = no +mail_nfs_index = no +lock_method = fcntl +mail_temp_dir = /tmp +first_valid_uid = 500 +last_valid_uid = 0 +first_valid_gid = 1 +last_valid_gid = 0 +mail_max_keyword_length = 50 +valid_chroot_dirs = +mail_chroot = +auth_socket_path = /var/run/dovecot/auth-userdb +mail_plugin_dir = /usr/lib/dovecot/modules +mail_plugins = +mail_cache_min_mail_count = 0 +mailbox_idle_check_interval = 30 secs +mail_save_crlf = no +maildir_stat_dirs = no +maildir_copy_with_hardlinks = yes +maildir_very_dirty_syncs = no +mbox_read_locks = fcntl +mbox_write_locks = dotlock fcntl +mbox_lock_timeout = 5 mins +mbox_dotlock_change_timeout = 2 mins +mbox_dirty_syncs = yes +mbox_very_dirty_syncs = no +mbox_lazy_writes = yes +mbox_min_index_size = 0 +mdbox_rotate_size = 2M +mdbox_rotate_interval = 0 +mdbox_preallocate_space = no +mail_attachment_dir = +mail_attachment_min_size = 128k +mail_attachment_fs = sis posix +mail_attachment_hash = %{sha1} + +protocol !indexer-worker { + mail_vsize_bg_after_count = 0 +} +" +test Dovecot.lns get mail_conf = + { "#comment" = "# Mailbox locations and namespaces" } + { "mail_location" } + { "namespace" + { "type" = "private" } + { "separator" } + { "prefix" } + { "location" } + { "inbox" = "no" } + { "hidden" = "no" } + { "list" = "yes" } + { "subscriptions" = "yes" } + { "mailbox" = "Sent Messages" + { "special_use" = "\Sent" } + } + } + { } + { "#comment" = "Example shared namespace configuration" } + { "namespace" + { "type" = "shared" } + { "separator" = "/" } + { "prefix" = "shared/%%u/" } + { "location" = "maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u" } + { "subscriptions" = "no" } + { "list" = "children" } + } + { } + { "mail_uid" } + { "mail_gid" } + { "mail_privileged_group" } + { "mail_access_groups" } + { "mail_full_filesystem_access" = "no" } + { "mmap_disable" = "no" } + { "dotlock_use_excl" = "yes" } + { "mail_fsync" = "optimized" } + { "mail_nfs_storage" = "no" } + { "mail_nfs_index" = "no" } + { "lock_method" = "fcntl" } + { "mail_temp_dir" = "/tmp" } + { "first_valid_uid" = "500" } + { "last_valid_uid" = "0" } + { "first_valid_gid" = "1" } + { "last_valid_gid" = "0" } + { "mail_max_keyword_length" = "50" } + { "valid_chroot_dirs" } + { "mail_chroot" } + { "auth_socket_path" = "/var/run/dovecot/auth-userdb" } + { "mail_plugin_dir" = "/usr/lib/dovecot/modules" } + { "mail_plugins" } + { "mail_cache_min_mail_count" = "0" } + { "mailbox_idle_check_interval" = "30 secs" } + { "mail_save_crlf" = "no" } + { "maildir_stat_dirs" = "no" } + { "maildir_copy_with_hardlinks" = "yes" } + { "maildir_very_dirty_syncs" = "no" } + { "mbox_read_locks" = "fcntl" } + { "mbox_write_locks" = "dotlock fcntl" } + { "mbox_lock_timeout" = "5 mins" } + { "mbox_dotlock_change_timeout" = "2 mins" } + { "mbox_dirty_syncs" = "yes" } + { "mbox_very_dirty_syncs" = "no" } + { "mbox_lazy_writes" = "yes" } + { "mbox_min_index_size" = "0" } + { "mdbox_rotate_size" = "2M" } + { "mdbox_rotate_interval" = "0" } + { "mdbox_preallocate_space" = "no" } + { "mail_attachment_dir" } + { "mail_attachment_min_size" = "128k" } + { "mail_attachment_fs" = "sis posix" } + { "mail_attachment_hash" = "%{sha1}" } + { } + { "protocol" = "!indexer-worker" + { "mail_vsize_bg_after_count" = "0" } + } + + +(* ********************************* master ********************************* *) + +let master_conf = " +default_process_limit = 100 +default_client_limit = 1000 +default_vsz_limit = 256M +default_login_user = dovenull +default_internal_user = dovecot + +service imap-login { + inet_listener imap { + port = 143 + } + inet_listener imaps { + port = 993 + ssl = yes + } + service_count = 1 + process_min_avail = 0 + vsz_limit = 64M +} + +service pop3-login { + inet_listener pop3 { + port = 110 + } + inet_listener pop3s { + port = 995 + ssl = yes + } +} + +service lmtp { + unix_listener lmtp { + mode = 0666 + } + inet_listener lmtp { + address = + port = + } +} + +service imap { + vsz_limit = 256M + process_limit = 1024 +} + +service auth { + unix_listener auth-userdb { + mode = 0600 + user = + group = + } +} + +service auth-worker { + user = root +} + +service dict { + unix_listener dict { + mode = 0600 + user = + group = + } +} +" + +test Dovecot.lns get master_conf = + { } + { "default_process_limit" = "100" } + { "default_client_limit" = "1000" } + { "default_vsz_limit" = "256M" } + { "default_login_user" = "dovenull" } + { "default_internal_user" = "dovecot" } + { } + { "service" = "imap-login" + { "inet_listener" = "imap" + { "port" = "143" } + } + { "inet_listener" = "imaps" + { "port" = "993" } + { "ssl" = "yes" } + } + { "service_count" = "1" } + { "process_min_avail" = "0" } + { "vsz_limit" = "64M" } + } + { } + { "service" = "pop3-login" + { "inet_listener" = "pop3" + { "port" = "110" } + } + { "inet_listener" = "pop3s" + { "port" = "995" } + { "ssl" = "yes" } + } + } + { } + { "service" = "lmtp" + { "unix_listener" = "lmtp" + { "mode" = "0666" } + } + { "inet_listener" = "lmtp" + { "address" } + { "port" } + } + } + { } + { "service" = "imap" + { "vsz_limit" = "256M" } + { "process_limit" = "1024" } + } + { } + { "service" = "auth" + { "unix_listener" = "auth-userdb" + { "mode" = "0600" } + { "user" } + { "group" } + } + } + { } + { "service" = "auth-worker" + { "user" = "root" } + } + { } + { "service" = "dict" + { "unix_listener" = "dict" + { "mode" = "0600" } + { "user" } + { "group" } + } + } + +(* *********************************** ssl ********************************** *) + +let ssl_conf = "## SSL settings +ssl = yes +ssl_cert = </etc/ssl/certs/dovecot.pem +ssl_key = </etc/ssl/private/dovecot.pem +ssl_key_password = +ssl_ca = +ssl_verify_client_cert = no +ssl_cert_username_field = commonName +ssl_parameters_regenerate = 168 +ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL +" +test Dovecot.lns get ssl_conf = + { "#comment" = "# SSL settings" } + { "ssl" = "yes" } + { "ssl_cert" = "</etc/ssl/certs/dovecot.pem" } + { "ssl_key" = "</etc/ssl/private/dovecot.pem" } + { "ssl_key_password" } + { "ssl_ca" } + { "ssl_verify_client_cert" = "no" } + { "ssl_cert_username_field" = "commonName" } + { "ssl_parameters_regenerate" = "168" } + { "ssl_cipher_list" = "ALL:!LOW:!SSLv2:!EXP:!aNULL" } + +(* ********************* /etc/dovecot/conf.d/15-lda.conf ******************** *) + +let lda_conf = "## LDA specific settings (also used by LMTP) +postmaster_address = +hostname = +quota_full_tempfail = no +sendmail_path = /usr/sbin/sendmail +submission_host = +rejection_subject = Rejected: %s +rejection_reason = Your message to <%t> was automatically rejected:%n%r +recipient_delimiter = + +lda_original_recipient_header = +lda_mailbox_autocreate = no +lda_mailbox_autosubscribe = no + +protocol lda { + mail_plugins = $mail_plugins +} +" +test Dovecot.lns get lda_conf = + { "#comment" = "# LDA specific settings (also used by LMTP)" } + { "postmaster_address" } + { "hostname" } + { "quota_full_tempfail" = "no" } + { "sendmail_path" = "/usr/sbin/sendmail" } + { "submission_host" } + { "rejection_subject" = "Rejected: %s" } + { "rejection_reason" = "Your message to <%t> was automatically rejected:%n%r" } + { "recipient_delimiter" = "+" } + { "lda_original_recipient_header" } + { "lda_mailbox_autocreate" = "no" } + { "lda_mailbox_autosubscribe" = "no" } + { } + { "protocol" = "lda" + { "mail_plugins" = "$mail_plugins" } + } + +(* *********************************** acl ********************************** *) + +let acl_conf = "## Mailbox access control lists. +plugin { + acl = vfile:/etc/dovecot/global-acls:cache_secs=300 +} +plugin { + acl_shared_dict = file:/var/lib/dovecot/shared-mailboxes +} +" + +test Dovecot.lns get acl_conf = + { "#comment" = "# Mailbox access control lists." } + { "plugin" + { "acl" = "vfile:/etc/dovecot/global-acls:cache_secs=300" } + } + { "plugin" + { "acl_shared_dict" = "file:/var/lib/dovecot/shared-mailboxes" } + } + +(* ******************************** plugins ********************************* *) + +let plugins_conf = " +plugin { + quota_rule = *:storage=1G + quota_rule2 = Trash:storage=+100M +} +plugin { + quota_warning = storage=95%% quota-warning 95 %u + quota_warning2 = storage=80%% quota-warning 80 %u +} +service quota-warning { + executable = script /usr/local/bin/quota-warning.sh + user = dovecot + unix_listener quota-warning { + user = vmail + } +} +plugin { + quota = dirsize:User quota + quota = maildir:User quota + quota = dict:User quota::proxy::quota + quota = fs:User quota +} +plugin { + quota = dict:user::proxy::quota + quota2 = dict:domain:%d:proxy::quota_domain + quota_rule = *:storage=102400 + quota2_rule = *:storage=1048576 +} +plugin { + acl = vfile:/etc/dovecot/global-acls:cache_secs=300 +} +plugin { + acl_shared_dict = file:/var/lib/dovecot/shared-mailboxes +} +" +test Dovecot.lns get plugins_conf = + { } + { "plugin" + { "quota_rule" = "*:storage=1G" } + { "quota_rule2" = "Trash:storage=+100M" } + } + { "plugin" + { "quota_warning" = "storage=95%% quota-warning 95 %u" } + { "quota_warning2" = "storage=80%% quota-warning 80 %u" } + } + { "service" = "quota-warning" + { "executable" = "script /usr/local/bin/quota-warning.sh" } + { "user" = "dovecot" } + { "unix_listener" = "quota-warning" + { "user" = "vmail" } + } + } + { "plugin" + { "quota" = "dirsize:User quota" } + { "quota" = "maildir:User quota" } + { "quota" = "dict:User quota::proxy::quota" } + { "quota" = "fs:User quota" } + } + { "plugin" + { "quota" = "dict:user::proxy::quota" } + { "quota2" = "dict:domain:%d:proxy::quota_domain" } + { "quota_rule" = "*:storage=102400" } + { "quota2_rule" = "*:storage=1048576" } + } + { "plugin" + { "acl" = "vfile:/etc/dovecot/global-acls:cache_secs=300" } + } + { "plugin" + { "acl_shared_dict" = "file:/var/lib/dovecot/shared-mailboxes" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_dpkg.aug b/Sharp.Augeas.Test/lens/tests/test_dpkg.aug new file mode 100644 index 0000000..64eda6a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_dpkg.aug @@ -0,0 +1,14 @@ +module Test_dpkg = + +let conf ="# dpkg configuration file +# Do not enable debsig-verify by default +no-debsig + +log /var/log/dpkg.log\n" + +test Dpkg.lns get conf = + { "#comment" = "dpkg configuration file" } + { "#comment" = "Do not enable debsig-verify by default" } + { "no-debsig" } + {} + { "log" = "/var/log/dpkg.log" } diff --git a/Sharp.Augeas.Test/lens/tests/test_dput.aug b/Sharp.Augeas.Test/lens/tests/test_dput.aug new file mode 100644 index 0000000..2e72ce1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_dput.aug @@ -0,0 +1,115 @@ +module Test_dput = + + let conf = "# Example dput.cf that defines the host that can be used +# with dput for uploading. + +[DEFAULT] +login = username +method = ftp +hash = md5 +allow_unsigned_uploads = 0 +run_lintian = 0 +run_dinstall = 0 +check_version = 0 +scp_compress = 0 +post_upload_command = +pre_upload_command = +passive_ftp = 1 +default_host_non-us = +default_host_main = hebex +allowed_distributions = (?!UNRELEASED) + +[hebex] +fqdn = condor.infra.s1.p.fti.net +login = anonymous +method = ftp +incoming = /incoming/hebex +passive_ftp = 0 + +[dop/desktop] +fqdn = condor.infra.s1.p.fti.net +login = anonymous +method = ftp +incoming = /incoming/dop/desktop +passive_ftp = 0 + +[jp-non-us] +fqdn = hp.debian.or.jp +incoming = /pub/Incoming/upload-non-US +login = anonymous + +# DISABLED due to being repaired currently +#[erlangen] +#fqdn = ftp.uni-erlangen.de +#incoming = /public/pub/Linux/debian/UploadQueue/ +#login = anonymous + +[ftp-master] +fqdn = ftp-master.debian.org +incoming = /pub/UploadQueue/ +login = anonymous +post_upload_command = /usr/bin/mini-dinstall --batch +# And if you want to override one of the defaults, add it here. +# # For example, comment out the next line +# # login = another_username +# # post_upload_command = /path/to/some/script +# # pre_upload_command = /path/to/some/script + +" + + test Dput.lns get conf = + { "#comment" = "Example dput.cf that defines the host that can be used" } + { "#comment" = "with dput for uploading." } + {} + { "target" = "DEFAULT" + { "login" = "username" } + { "method" = "ftp" } + { "hash" = "md5" } + { "allow_unsigned_uploads" = "0" } + { "run_lintian" = "0" } + { "run_dinstall" = "0" } + { "check_version" = "0" } + { "scp_compress" = "0" } + { "post_upload_command" } + { "pre_upload_command" } + { "passive_ftp" = "1" } + { "default_host_non-us" } + { "default_host_main" = "hebex" } + { "allowed_distributions" = "(?!UNRELEASED)" } + {} } + { "target" = "hebex" + { "fqdn" = "condor.infra.s1.p.fti.net" } + { "login" = "anonymous" } + { "method" = "ftp" } + { "incoming" = "/incoming/hebex" } + { "passive_ftp" = "0" } + {} } + { "target" = "dop/desktop" + { "fqdn" = "condor.infra.s1.p.fti.net" } + { "login" = "anonymous" } + { "method" = "ftp" } + { "incoming" = "/incoming/dop/desktop" } + { "passive_ftp" = "0" } + {} } + { "target" = "jp-non-us" + { "fqdn" = "hp.debian.or.jp" } + { "incoming" = "/pub/Incoming/upload-non-US" } + { "login" = "anonymous" } + {} + { "#comment" = "DISABLED due to being repaired currently" } + { "#comment" = "[erlangen]" } + { "#comment" = "fqdn = ftp.uni-erlangen.de" } + { "#comment" = "incoming = /public/pub/Linux/debian/UploadQueue/" } + { "#comment" = "login = anonymous" } + {} } + { "target" = "ftp-master" + { "fqdn" = "ftp-master.debian.org" } + { "incoming" = "/pub/UploadQueue/" } + { "login" = "anonymous" } + { "post_upload_command" = "/usr/bin/mini-dinstall --batch" } + { "#comment" = "And if you want to override one of the defaults, add it here." } + { "#comment" = "# For example, comment out the next line" } + { "#comment" = "# login = another_username" } + { "#comment" = "# post_upload_command = /path/to/some/script" } + { "#comment" = "# pre_upload_command = /path/to/some/script" } + {} } diff --git a/Sharp.Augeas.Test/lens/tests/test_erlang.aug b/Sharp.Augeas.Test/lens/tests/test_erlang.aug new file mode 100644 index 0000000..89ca61d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_erlang.aug @@ -0,0 +1,117 @@ +(* +Module: Test_Erlang + Provides unit tests and examples for the <Erlang> lens. +*) +module Test_Erlang = + +(* Group: comments *) +test Erlang.comment get "% This is a comment\n" = + { "#comment" = "This is a comment" } + +(* Group: simple values *) + +let value_bare = Erlang.value Rx.word Erlang.bare + +test value_bare get "{foo, bar}" = { "foo" = "bar" } + +let value_decimal = Erlang.value Rx.word Erlang.decimal + +test value_bare get "{foo, 0.25}" = { "foo" = "0.25" } + +let value_quoted = Erlang.value Rx.word Erlang.quoted + +test value_quoted get "{foo, '0.25'}" = { "foo" = "0.25" } + +let value_glob = Erlang.value Rx.word Erlang.glob + +test value_glob get "{foo, <<\".*\">>}" = { "foo" = ".*" } + +let value_boolean = Erlang.value Rx.word Erlang.boolean + +test value_boolean get "{foo, false}" = { "foo" = "false" } + + +(* Group: list values *) + +let list_bare = Erlang.value_list Rx.word Erlang.bare + +test list_bare get "{foo, [bar, baz]}" = + { "foo" + { "value" = "bar" } + { "value" = "baz" } } + +(* Group: tuple values *) + +let tuple_bare = Erlang.tuple Erlang.bare Erlang.bare + +test tuple_bare get "{foo, bar}" = + { "tuple" + { "value" = "foo" } + { "value" = "bar" } } + +let tuple3_bare = Erlang.tuple3 Erlang.bare Erlang.bare Erlang.bare + +test tuple3_bare get "{foo, bar, baz}" = + { "tuple" + { "value" = "foo" } + { "value" = "bar" } + { "value" = "baz" } } + +(* Group: application *) + +let list_bare_app = Erlang.application (Rx.word - "kernel") list_bare + +test list_bare_app get "{foo, [{bar, [baz, bat]}]}" = + { "foo" + { "bar" + { "value" = "baz" } + { "value" = "bat" } } } + +(* no settings *) +test list_bare_app get "{foo, []}" = + { "foo" } + +(* Group: kernel *) + +test Erlang.kernel get "{kernel, [ + {browser_cmd, \"/foo/bar\"}, + {dist_auto_connect, once}, + {error_logger, tty}, + {net_setuptime, 5}, + {start_dist_ac, true} +]}" = + { "kernel" + { "browser_cmd" = "/foo/bar" } + { "dist_auto_connect" = "once" } + { "error_logger" = "tty" } + { "net_setuptime" = "5" } + { "start_dist_ac" = "true" } } + +(* Group: config *) + +let list_bare_config = Erlang.config list_bare_app + +test list_bare_config get "[ + {foo, [{bar, [baz, bat]}]}, + {goo, [{gar, [gaz, gat]}]} + ].\n" = + { "foo" + { "bar" + { "value" = "baz" } + { "value" = "bat" } } } + { "goo" + { "gar" + { "value" = "gaz" } + { "value" = "gat" } } } + +(* Test Erlang's kernel app config is parsed *) +test list_bare_config get "[ + {foo, [{bar, [baz, bat]}]}, + {kernel, [{start_timer, true}]} + ].\n" = + { "foo" + { "bar" + { "value" = "baz" } + { "value" = "bat" } } } + { "kernel" + { "start_timer" = "true" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_ethers.aug b/Sharp.Augeas.Test/lens/tests/test_ethers.aug new file mode 100644 index 0000000..7209c1b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ethers.aug @@ -0,0 +1,61 @@ +(* Tests for the Ethers module *) + +module Test_ethers = + +(* + let empty_entries = "# see man ethers for syntax\n" + + test Ethers.record get empty_entries = + { "#comment" = "see man ethers for syntax" } +*) + + let three_entries = "54:52:00:01:00:01 192.168.1.1 +# \tcomment\t +54:52:00:01:00:02 foo.example.com +00:16:3e:01:fe:03 bar +" + + test Ethers.lns get three_entries = + { "1" { "mac" = "54:52:00:01:00:01" } + { "ip" = "192.168.1.1" } } + { "#comment" = "comment" } + { "2" { "mac" = "54:52:00:01:00:02" } + { "ip" = "foo.example.com" } } + { "3" { "mac" = "00:16:3e:01:fe:03" } + { "ip" = "bar" } } + + (* Deleting the 'ip' node violates the schema *) + test Ethers.lns put three_entries after + rm "/1/ip" + = * + + test Ethers.lns put three_entries after + set "/2/ip" "192.168.1.2" ; + set "/3/ip" "baz" + = "54:52:00:01:00:01 192.168.1.1 +# \tcomment\t +54:52:00:01:00:02 192.168.1.2 +00:16:3e:01:fe:03 baz +" + + test Ethers.lns put three_entries after + rm "/3" + = "54:52:00:01:00:01 192.168.1.1 +# \tcomment\t +54:52:00:01:00:02 foo.example.com +" + + (* Make sure blank and indented lines get through *) + test Ethers.lns get "54:52:00:01:00:01\tfoo \n \n\n +54:52:00:01:00:02 bar\n" = + { "1" { "mac" = "54:52:00:01:00:01" } + { "ip" = "foo" } } + {} {} {} + { "2" { "mac" = "54:52:00:01:00:02" } + { "ip" = "bar" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) + + diff --git a/Sharp.Augeas.Test/lens/tests/test_exports.aug b/Sharp.Augeas.Test/lens/tests/test_exports.aug new file mode 100644 index 0000000..b0fde40 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_exports.aug @@ -0,0 +1,59 @@ +module Test_exports = + +let s = "/local 172.31.0.0/16(rw,sync) \t + +/home 172.31.0.0/16(rw,root_squash,sync) @netgroup(rw) *.example.com +# Yes, we export /tmp +/tmp 172.31.0.0/16(rw,root_squash,sync,) +/local2 somehost(rw,sync) +/local3 some-host(rw,sync) +/local3 an-other-host(rw,sync) +/local4 2000:123:456::/64(rw) +/local5 somehost-[01](rw) +" + +test Exports.lns get s = + { "dir" = "/local" + { "client" = "172.31.0.0/16" + { "option" = "rw" } + { "option" = "sync" } } } + { } + { "dir" = "/home" + { "client" = "172.31.0.0/16" + { "option" = "rw"} + { "option" = "root_squash" } + { "option" = "sync" } } + { "client" = "@netgroup" + { "option" = "rw" } } + { "client" = "*.example.com" } } + { "#comment" = "Yes, we export /tmp" } + { "dir" = "/tmp" + { "client" = "172.31.0.0/16" + { "option" = "rw" } + { "option" = "root_squash" } + { "option" = "sync" } + { "option" = "" } } } + { "dir" = "/local2" + { "client" = "somehost" + { "option" = "rw" } + { "option" = "sync" } } } + { "dir" = "/local3" + { "client" = "some-host" + { "option" = "rw" } + { "option" = "sync" } } } + { "dir" = "/local3" + { "client" = "an-other-host" + { "option" = "rw" } + { "option" = "sync" } } } + { "dir" = "/local4" + { "client" = "2000:123:456::/64" + { "option" = "rw" } } } + { "dir" = "/local5" + { "client" = "somehost-[01]" + { "option" = "rw" } } } + +test Exports.lns get "\"/path/in/quotes\" 192.168.0.1(rw,all_squash)\n" = + { "dir" = "\"/path/in/quotes\"" + { "client" = "192.168.0.1" + { "option" = "rw" } + { "option" = "all_squash" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_fai_diskconfig.aug b/Sharp.Augeas.Test/lens/tests/test_fai_diskconfig.aug new file mode 100644 index 0000000..1862d9a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_fai_diskconfig.aug @@ -0,0 +1,663 @@ +(* +Module: Test_FAI_DiskConfig + Provides unit tests and examples for the <FAI_DiskConfig> lens. +*) + +module Test_FAI_DiskConfig = + + +(* Test: FAI_DiskConfig.disk_config + Test <FAI_DiskConfig.disk_config> *) +test FAI_DiskConfig.disk_config get + "disk_config hda preserve_always:6,7 disklabel:msdos bootable:3\n" = + + { "disk_config" = "hda" + { "preserve_always" + { "1" = "6" } + { "2" = "7" } } + { "disklabel" = "msdos" } + { "bootable" = "3" } } + +(* Test: FAI_DiskConfig.volume + Test <FAI_DiskConfig.volume> *) +test FAI_DiskConfig.volume get + "primary /boot 20-100 ext3 rw\n" = + + { "primary" + { "mountpoint" = "/boot" } + { "size" = "20-100" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } } } + +(* Test: FAI_DiskConfig.volume + Testing <FAI_DiskConfig.volume> *) +test FAI_DiskConfig.volume get + "primary swap 1000 swap sw\n" = + + { "primary" + { "mountpoint" = "swap" } + { "size" = "1000" } + { "filesystem" = "swap" } + { "mount_options" + { "1" = "sw" } } } + +(* Test: FAI_DiskConfig.volume + Testing <FAI_DiskConfig.volume> *) +test FAI_DiskConfig.volume get + "primary / 12000 ext3 rw createopts=\"-b 2048\"\n" = + + { "primary" + { "mountpoint" = "/" } + { "size" = "12000" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } } + { "fs_options" + { "createopts" = "-b 2048" } } } + +(* Test: FAI_DiskConfig.volume + Testing <FAI_DiskConfig.volume> *) +test FAI_DiskConfig.volume get + "logical /tmp 1000 ext3 rw,nosuid\n" = + + { "logical" + { "mountpoint" = "/tmp" } + { "size" = "1000" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + { "2" = "nosuid" } } } + +(* Test: FAI_DiskConfig.volume + Testing <FAI_DiskConfig.volume> *) +test FAI_DiskConfig.volume get + "logical /var 10%- ext3 rw\n" = + + { "logical" + { "mountpoint" = "/var" } + { "size" = "10%-" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } } } + +(* Test: FAI_DiskConfig.volume + Testing <FAI_DiskConfig.volume> *) +test FAI_DiskConfig.volume get + "logical /nobackup 0- xfs rw\n" = + + { "logical" + { "mountpoint" = "/nobackup" } + { "size" = "0-" } + { "filesystem" = "xfs" } + { "mount_options" + { "1" = "rw" } } } + +(* Variable: simple_config + A simple configuration file *) +let simple_config = "# A comment +disk_config disk2 +raw-disk - 0 - - + +disk_config lvm +vg my_pv sda2 +vg test disk1.9 +my_pv-_swap swap 2048 swap sw +my_pv-_root / 2048 ext3 rw,errors=remount-ro + +disk_config raid +raid1 /boot disk1.1,disk2.1,disk3.1,disk4.1,disk5.1,disk6.1 ext3 rw +raid1 swap disk1.2,disk2.2,disk3.2,disk4.2,disk5.2,disk6.2 swap sw +raid5 /srv/data disk1.11,disk2.11,disk3.11,disk4.11,disk5.11,disk6.11 ext3 ro createopts=\"-m 0\" +raid0 - disk2.2,sdc1,sde1:spare:missing ext2 default + +disk_config tmpfs +tmpfs /var/opt/hosting/tmp 500 defaults +" + +(* Test: FAI_DiskConfig.lns + Testing the full <FAI_DiskConfig.lns> on <simple_config> *) +test FAI_DiskConfig.lns get simple_config = + { "#comment" = "A comment" } + { "disk_config" = "disk2" + { "raw-disk" + { "mountpoint" = "-" } + { "size" = "0" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + } + { } + { "disk_config" = "lvm" + { "vg" + { "name" = "my_pv" } + { "disk" = "sda2" } + } + { "vg" + { "name" = "test" } + { "disk" = "disk1" + { "partition" = "9" } + } + } + { "lv" + { "vg" = "my_pv" } + { "name" = "_swap" } + { "mountpoint" = "swap" } + { "size" = "2048" } + { "filesystem" = "swap" } + { "mount_options" + { "1" = "sw" } + } + } + { "lv" + { "vg" = "my_pv" } + { "name" = "_root" } + { "mountpoint" = "/" } + { "size" = "2048" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + { "2" = "errors" + { "value" = "remount-ro" } + } + } + } + } + { } + { "disk_config" = "raid" + { "raid1" + { "mountpoint" = "/boot" } + { "disk" = "disk1" + { "partition" = "1" } + } + { "disk" = "disk2" + { "partition" = "1" } + } + { "disk" = "disk3" + { "partition" = "1" } + } + { "disk" = "disk4" + { "partition" = "1" } + } + { "disk" = "disk5" + { "partition" = "1" } + } + { "disk" = "disk6" + { "partition" = "1" } + } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + } + } + { "raid1" + { "mountpoint" = "swap" } + { "disk" = "disk1" + { "partition" = "2" } + } + { "disk" = "disk2" + { "partition" = "2" } + } + { "disk" = "disk3" + { "partition" = "2" } + } + { "disk" = "disk4" + { "partition" = "2" } + } + { "disk" = "disk5" + { "partition" = "2" } + } + { "disk" = "disk6" + { "partition" = "2" } + } + { "filesystem" = "swap" } + { "mount_options" + { "1" = "sw" } + } + } + { "raid5" + { "mountpoint" = "/srv/data" } + { "disk" = "disk1" + { "partition" = "11" } + } + { "disk" = "disk2" + { "partition" = "11" } + } + { "disk" = "disk3" + { "partition" = "11" } + } + { "disk" = "disk4" + { "partition" = "11" } + } + { "disk" = "disk5" + { "partition" = "11" } + } + { "disk" = "disk6" + { "partition" = "11" } + } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "ro" } + } + { "fs_options" + { "createopts" = "-m 0" } + } + } + { "raid0" + { "mountpoint" = "-" } + { "disk" = "disk2" + { "partition" = "2" } + } + { "disk" = "sdc1" } + { "disk" = "sde1" + { "spare" } + { "missing" } + } + { "filesystem" = "ext2" } + { "mount_options" + { "1" = "default" } + } + } + } + { } + { "disk_config" = "tmpfs" + { "tmpfs" + { "mountpoint" = "/var/opt/hosting/tmp" } + { "size" = "500" } + { "mount_options" + { "1" = "defaults" } + } + } + } + + +(* Variable: config1 + Another full configuration *) +let config1 = "disk_config disk1 bootable:1 preserve_always:all always_format:5,6,7,8,9,10,11 +primary - 0 - - +primary - 0 - - +logical / 0 ext3 rw,relatime,errors=remount-ro createopts=\"-c -j\" +logical swap 0 swap sw +logical /var 0 ext3 rw,relatime createopts=\"-m 5 -j\" +logical /tmp 0 ext3 rw createopts=\"-m 0 -j\" +logical /usr 0 ext3 rw,relatime createopts=\"-j\" +logical /home 0 ext3 rw,relatime,nosuid,nodev createopts=\"-m 1 -j\" +logical /wrk 0 ext3 rw,relatime,nosuid,nodev createopts=\"-m 1 -j\" +logical /transfer 0 vfat rw +" + +(* Test: FAI_DiskConfig.lns + Testing <FAI_DiskConfig.lns> on <config1> *) +test FAI_DiskConfig.lns get config1 = + { "disk_config" = "disk1" + { "bootable" = "1" } + { "preserve_always" + { "1" = "all" } + } + { "always_format" + { "1" = "5" } + { "2" = "6" } + { "3" = "7" } + { "4" = "8" } + { "5" = "9" } + { "6" = "10" } + { "7" = "11" } + } + { "primary" + { "mountpoint" = "-" } + { "size" = "0" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "primary" + { "mountpoint" = "-" } + { "size" = "0" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "logical" + { "mountpoint" = "/" } + { "size" = "0" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + { "2" = "relatime" } + { "3" = "errors" + { "value" = "remount-ro" } + } + } + { "fs_options" + { "createopts" = "-c -j" } + } + } + { "logical" + { "mountpoint" = "swap" } + { "size" = "0" } + { "filesystem" = "swap" } + { "mount_options" + { "1" = "sw" } + } + } + { "logical" + { "mountpoint" = "/var" } + { "size" = "0" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + { "2" = "relatime" } + } + { "fs_options" + { "createopts" = "-m 5 -j" } + } + } + { "logical" + { "mountpoint" = "/tmp" } + { "size" = "0" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + } + { "fs_options" + { "createopts" = "-m 0 -j" } + } + } + { "logical" + { "mountpoint" = "/usr" } + { "size" = "0" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + { "2" = "relatime" } + } + { "fs_options" + { "createopts" = "-j" } + } + } + { "logical" + { "mountpoint" = "/home" } + { "size" = "0" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + { "2" = "relatime" } + { "3" = "nosuid" } + { "4" = "nodev" } + } + { "fs_options" + { "createopts" = "-m 1 -j" } + } + } + { "logical" + { "mountpoint" = "/wrk" } + { "size" = "0" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "rw" } + { "2" = "relatime" } + { "3" = "nosuid" } + { "4" = "nodev" } + } + { "fs_options" + { "createopts" = "-m 1 -j" } + } + } + { "logical" + { "mountpoint" = "/transfer" } + { "size" = "0" } + { "filesystem" = "vfat" } + { "mount_options" + { "1" = "rw" } + } + } + } + + +(* Variable: config2 + Another full configuration *) +let config2 = "disk_config /dev/sda +primary - 250M - - +primary - 20G - - +logical - 8G - - +logical - 4G - - +logical - 5G - - + +disk_config /dev/sdb sameas:/dev/sda + +disk_config raid +raid1 /boot sda1,sdb1 ext3 defaults +raid1 / sda2,sdb2 ext3 defaults,errors=remount-ro +raid1 swap sda5,sdb5 swap defaults +raid1 /tmp sda6,sdb6 ext3 defaults createopts=\"-m 1\" +raid1 /var sda7,sdb7 ext3 defaults +" + +(* Test: FAI_DiskConfig.lns + Testing <FAI_DiskConfig.lns> on <config2> *) +test FAI_DiskConfig.lns get config2 = + { "disk_config" = "/dev/sda" + { "primary" + { "mountpoint" = "-" } + { "size" = "250M" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "primary" + { "mountpoint" = "-" } + { "size" = "20G" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "logical" + { "mountpoint" = "-" } + { "size" = "8G" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "logical" + { "mountpoint" = "-" } + { "size" = "4G" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "logical" + { "mountpoint" = "-" } + { "size" = "5G" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + } + { } + { "disk_config" = "/dev/sdb" + { "sameas" = "/dev/sda" } + } + { } + { "disk_config" = "raid" + { "raid1" + { "mountpoint" = "/boot" } + { "disk" = "sda1" } + { "disk" = "sdb1" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "defaults" } + } + } + { "raid1" + { "mountpoint" = "/" } + { "disk" = "sda2" } + { "disk" = "sdb2" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "defaults" } + { "2" = "errors" + { "value" = "remount-ro" } + } + } + } + { "raid1" + { "mountpoint" = "swap" } + { "disk" = "sda5" } + { "disk" = "sdb5" } + { "filesystem" = "swap" } + { "mount_options" + { "1" = "defaults" } + } + } + { "raid1" + { "mountpoint" = "/tmp" } + { "disk" = "sda6" } + { "disk" = "sdb6" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "defaults" } + } + { "fs_options" + { "createopts" = "-m 1" } + } + } + { "raid1" + { "mountpoint" = "/var" } + { "disk" = "sda7" } + { "disk" = "sdb7" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "defaults" } + } + } + } + + +(* Variable: config3 + Another full configuration *) +let config3 = "disk_config /dev/sdb +primary / 21750 ext3 defaults,errors=remount-ro +primary /boot 250 ext3 defaults +logical - 4000 - - +logical - 2000 - - +logical - 10- - - + +disk_config cryptsetup randinit +swap swap /dev/sdb5 swap defaults +tmp /tmp /dev/sdb6 ext2 defaults +luks /local00 /dev/sdb7 ext3 defaults,errors=remount-ro createopts=\"-m 0\" +" + +(* Test: FAI_DiskConfig.lns + Testing <FAI_DiskConfig.lns> on <config3> *) +test FAI_DiskConfig.lns get config3 = + { "disk_config" = "/dev/sdb" + { "primary" + { "mountpoint" = "/" } + { "size" = "21750" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "defaults" } + { "2" = "errors" + { "value" = "remount-ro" } + } + } + } + { "primary" + { "mountpoint" = "/boot" } + { "size" = "250" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "defaults" } + } + } + { "logical" + { "mountpoint" = "-" } + { "size" = "4000" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "logical" + { "mountpoint" = "-" } + { "size" = "2000" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + { "logical" + { "mountpoint" = "-" } + { "size" = "10-" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + } + { } + { "disk_config" = "cryptsetup" + { "randinit" } + { "swap" + { "mountpoint" = "swap" } + { "device" = "/dev/sdb5" } + { "filesystem" = "swap" } + { "mount_options" + { "1" = "defaults" } + } + } + { "tmp" + { "mountpoint" = "/tmp" } + { "device" = "/dev/sdb6" } + { "filesystem" = "ext2" } + { "mount_options" + { "1" = "defaults" } + } + } + { "luks" + { "mountpoint" = "/local00" } + { "device" = "/dev/sdb7" } + { "filesystem" = "ext3" } + { "mount_options" + { "1" = "defaults" } + { "2" = "errors" + { "value" = "remount-ro" } + } + } + { "fs_options" + { "createopts" = "-m 0" } + } + } + } + + +(* Variable: with_spaces *) +let with_spaces = "disk_config disk2 + +raw-disk - 0 - - +" + +(* Test: FAI_DiskConfig.lns + Testing <FAI_DiskConfig.lns> with <with_spaces> *) +test FAI_DiskConfig.lns get with_spaces = + { "disk_config" = "disk2" + { } + { "raw-disk" + { "mountpoint" = "-" } + { "size" = "0" } + { "filesystem" = "-" } + { "mount_options" + { "1" = "-" } + } + } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_fail2ban.aug b/Sharp.Augeas.Test/lens/tests/test_fail2ban.aug new file mode 100644 index 0000000..e1c4b57 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_fail2ban.aug @@ -0,0 +1,24 @@ +module Test_fail2ban = + +let conf = "[DEFAULT] +mta = ssmtp +bantime = 432000 +destemail = fail2ban@domain.com +findtime = 3600 +maxretry = 3 + +[sshd] +enabled = true +" + + +test Fail2ban.lns get conf = + { "DEFAULT" + { "mta" = "ssmtp" } + { "bantime" = "432000" } + { "destemail" = "fail2ban@domain.com" } + { "findtime" = "3600" } + { "maxretry" = "3" } + {} } + { "sshd" + { "enabled" = "true" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_fonts.aug b/Sharp.Augeas.Test/lens/tests/test_fonts.aug new file mode 100644 index 0000000..9591149 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_fonts.aug @@ -0,0 +1,809 @@ +(* +Module: Test_Fonts + Provides unit tests and examples for the <Fonts> lens. +*) + +module Test_Fonts = + +(* Variable: conf *) +let conf = "<?xml version=\"1.0\"?> +<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\"> +<!-- /etc/fonts/fonts.conf file to configure system font access --> +<fontconfig> + +<!-- + DO NOT EDIT THIS FILE. + IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED. + LOCAL CHANGES BELONG IN 'local.conf'. + + The intent of this standard configuration file is to be adequate for + most environments. If you have a reasonably normal environment and + have found problems with this configuration, they are probably + things that others will also want fixed. Please submit any + problems to the fontconfig bugzilla system located at fontconfig.org + + Note that the normal 'make install' procedure for fontconfig is to + replace any existing fonts.conf file with the new version. Place + any local customizations in local.conf which this file references. + + Keith Packard +--> + +<!-- Font directory list --> + + <dir>/usr/share/fonts</dir> + <dir>/usr/X11R6/lib/X11/fonts</dir> <dir>/usr/local/share/fonts</dir> + <dir>~/.fonts</dir> + +<!-- + Accept deprecated 'mono' alias, replacing it with 'monospace' +--> + <match target=\"pattern\"> + <test qual=\"any\" name=\"family\"> + <string>mono</string> + </test> + <edit name=\"family\" mode=\"assign\"> + <string>monospace</string> + </edit> + </match> + +<!-- + Accept alternate 'sans serif' spelling, replacing it with 'sans-serif' +--> + <match target=\"pattern\"> + <test qual=\"any\" name=\"family\"> + <string>sans serif</string> + </test> + <edit name=\"family\" mode=\"assign\"> + <string>sans-serif</string> + </edit> + </match> + +<!-- + Accept deprecated 'sans' alias, replacing it with 'sans-serif' +--> + <match target=\"pattern\"> + <test qual=\"any\" name=\"family\"> + <string>sans</string> + </test> + <edit name=\"family\" mode=\"assign\"> + <string>sans-serif</string> + </edit> + </match> + +<!-- + Load local system customization file +--> + <include ignore_missing=\"yes\">conf.d</include> + +<!-- Font cache directory list --> + + <cachedir>/var/cache/fontconfig</cachedir> + <cachedir>~/.fontconfig</cachedir> + + <config> +<!-- + These are the default Unicode chars that are expected to be blank + in fonts. All other blank chars are assumed to be broken and + won't appear in the resulting charsets + --> + <blank> + <int>0x0020</int> <!-- SPACE --> + <int>0x00A0</int> <!-- NO-BREAK SPACE --> + <int>0x00AD</int> <!-- SOFT HYPHEN --> + <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER --> + <int>0x0600</int> <!-- ARABIC NUMBER SIGN --> + <int>0x0601</int> <!-- ARABIC SIGN SANAH --> + <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER --> + <int>0x0603</int> <!-- ARABIC SIGN SAFHA --> + <int>0x06DD</int> <!-- ARABIC END OF AYAH --> + <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK --> + <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER --> + <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER --> + <int>0x1680</int> <!-- OGHAM SPACE MARK --> + <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ --> + <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA --> + <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR --> + <int>0x2000</int> <!-- EN QUAD --> + <int>0x2001</int> <!-- EM QUAD --> + <int>0x2002</int> <!-- EN SPACE --> + <int>0x2003</int> <!-- EM SPACE --> + <int>0x2004</int> <!-- THREE-PER-EM SPACE --> + <int>0x2005</int> <!-- FOUR-PER-EM SPACE --> + <int>0x2006</int> <!-- SIX-PER-EM SPACE --> + <int>0x2007</int> <!-- FIGURE SPACE --> + <int>0x2008</int> <!-- PUNCTUATION SPACE --> + <int>0x2009</int> <!-- THIN SPACE --> + <int>0x200A</int> <!-- HAIR SPACE --> + <int>0x200B</int> <!-- ZERO WIDTH SPACE --> + <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER --> + <int>0x200D</int> <!-- ZERO WIDTH JOINER --> + <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK --> + <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK --> + <int>0x2028</int> <!-- LINE SEPARATOR --> + <int>0x2029</int> <!-- PARAGRAPH SEPARATOR --> + <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING --> + <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING --> + <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING --> + <int>0x202D</int> <!-- LEFT-TO-RIGHT OVERRIDE --> + <int>0x202E</int> <!-- RIGHT-TO-LEFT OVERRIDE --> + <int>0x202F</int> <!-- NARROW NO-BREAK SPACE --> + <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE --> + <int>0x2060</int> <!-- WORD JOINER --> + <int>0x2061</int> <!-- FUNCTION APPLICATION --> + <int>0x2062</int> <!-- INVISIBLE TIMES --> + <int>0x2063</int> <!-- INVISIBLE SEPARATOR --> + <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING --> + <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING --> + <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING --> + <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING --> + <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES --> + <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES --> + <int>0x2800</int> <!-- BRAILLE PATTERN BLANK --> + <int>0x3000</int> <!-- IDEOGRAPHIC SPACE --> + <int>0x3164</int> <!-- HANGUL FILLER --> + <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE --> + <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER --> + <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR --> + <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR --> + <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR --> + </blank> +<!-- + Rescan configuration every 30 seconds when FcFontSetList is called + --> + <rescan> + <int>30</int> + </rescan> + </config> + +</fontconfig> +" + +(* Test: Fonts.lns *) +test Fonts.lns get conf = + { "#declaration" + { "#attribute" + { "version" = "1.0" } + } + } + { "!DOCTYPE" = "fontconfig" + { "SYSTEM" = "fonts.dtd" } + } + { "#comment" = " /etc/fonts/fonts.conf file to configure system font access " } + { "fontconfig" + { "#text" = " + +" } + { "#comment" = " + DO NOT EDIT THIS FILE. + IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED. + LOCAL CHANGES BELONG IN 'local.conf'. + + The intent of this standard configuration file is to be adequate for + most environments. If you have a reasonably normal environment and + have found problems with this configuration, they are probably + things that others will also want fixed. Please submit any + problems to the fontconfig bugzilla system located at fontconfig.org + + Note that the normal 'make install' procedure for fontconfig is to + replace any existing fonts.conf file with the new version. Place + any local customizations in local.conf which this file references. + + Keith Packard +" } + { "#text" = " + +" } + { "#comment" = " Font directory list " } + { "#text" = " + + " } + { "dir" + { "#text" = "/usr/share/fonts" } + } + { "#text" = " " } + { "dir" + { "#text" = "/usr/X11R6/lib/X11/fonts" } + } + { "#text" = " " } + { "dir" + { "#text" = "/usr/local/share/fonts" } + } + { "#text" = " " } + { "dir" + { "#text" = "~/.fonts" } + } + { "#text" = " +" } + { "#comment" = " + Accept deprecated 'mono' alias, replacing it with 'monospace' +" } + { "#text" = " + " } + { "match" + { "#attribute" + { "target" = "pattern" } + } + { "#text" = " + " } + { "test" + { "#attribute" + { "qual" = "any" } + { "name" = "family" } + } + { "#text" = " + " } + { "string" + { "#text" = "mono" } + } + { "#text" = " " } + } + { "#text" = " " } + { "edit" + { "#attribute" + { "name" = "family" } + { "mode" = "assign" } + } + { "#text" = " + " } + { "string" + { "#text" = "monospace" } + } + { "#text" = " " } + } + { "#text" = " " } + } + { "#text" = " +" } + { "#comment" = " + Accept alternate 'sans serif' spelling, replacing it with 'sans-serif' +" } + { "#text" = " + " } + { "match" + { "#attribute" + { "target" = "pattern" } + } + { "#text" = " + " } + { "test" + { "#attribute" + { "qual" = "any" } + { "name" = "family" } + } + { "#text" = " + " } + { "string" + { "#text" = "sans serif" } + } + { "#text" = " " } + } + { "#text" = " " } + { "edit" + { "#attribute" + { "name" = "family" } + { "mode" = "assign" } + } + { "#text" = " + " } + { "string" + { "#text" = "sans-serif" } + } + { "#text" = " " } + } + { "#text" = " " } + } + { "#text" = " +" } + { "#comment" = " + Accept deprecated 'sans' alias, replacing it with 'sans-serif' +" } + { "#text" = " + " } + { "match" + { "#attribute" + { "target" = "pattern" } + } + { "#text" = " + " } + { "test" + { "#attribute" + { "qual" = "any" } + { "name" = "family" } + } + { "#text" = " + " } + { "string" + { "#text" = "sans" } + } + { "#text" = " " } + } + { "#text" = " " } + { "edit" + { "#attribute" + { "name" = "family" } + { "mode" = "assign" } + } + { "#text" = " + " } + { "string" + { "#text" = "sans-serif" } + } + { "#text" = " " } + } + { "#text" = " " } + } + { "#text" = " +" } + { "#comment" = " + Load local system customization file +" } + { "#text" = " + " } + { "include" + { "#attribute" + { "ignore_missing" = "yes" } + } + { "#text" = "conf.d" } + } + { "#text" = " +" } + { "#comment" = " Font cache directory list " } + { "#text" = " + + " } + { "cachedir" + { "#text" = "/var/cache/fontconfig" } + } + { "#text" = " " } + { "cachedir" + { "#text" = "~/.fontconfig" } + } + { "#text" = " + " } + { "config" + { "#text" = " +" } + { "#comment" = " + These are the default Unicode chars that are expected to be blank + in fonts. All other blank chars are assumed to be broken and + won't appear in the resulting charsets + " } + { "#text" = " + " } + { "blank" + { "#text" = " + " } + { "int" + { "#text" = "0x0020" } + } + { "#text" = " " } + { "#comment" = " SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x00A0" } + } + { "#text" = " " } + { "#comment" = " NO-BREAK SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x00AD" } + } + { "#text" = " " } + { "#comment" = " SOFT HYPHEN " } + { "#text" = " + " } + { "int" + { "#text" = "0x034F" } + } + { "#text" = " " } + { "#comment" = " COMBINING GRAPHEME JOINER " } + { "#text" = " + " } + { "int" + { "#text" = "0x0600" } + } + { "#text" = " " } + { "#comment" = " ARABIC NUMBER SIGN " } + { "#text" = " + " } + { "int" + { "#text" = "0x0601" } + } + { "#text" = " " } + { "#comment" = " ARABIC SIGN SANAH " } + { "#text" = " + " } + { "int" + { "#text" = "0x0602" } + } + { "#text" = " " } + { "#comment" = " ARABIC FOOTNOTE MARKER " } + { "#text" = " + " } + { "int" + { "#text" = "0x0603" } + } + { "#text" = " " } + { "#comment" = " ARABIC SIGN SAFHA " } + { "#text" = " + " } + { "int" + { "#text" = "0x06DD" } + } + { "#text" = " " } + { "#comment" = " ARABIC END OF AYAH " } + { "#text" = " + " } + { "int" + { "#text" = "0x070F" } + } + { "#text" = " " } + { "#comment" = " SYRIAC ABBREVIATION MARK " } + { "#text" = " + " } + { "int" + { "#text" = "0x115F" } + } + { "#text" = " " } + { "#comment" = " HANGUL CHOSEONG FILLER " } + { "#text" = " + " } + { "int" + { "#text" = "0x1160" } + } + { "#text" = " " } + { "#comment" = " HANGUL JUNGSEONG FILLER " } + { "#text" = " + " } + { "int" + { "#text" = "0x1680" } + } + { "#text" = " " } + { "#comment" = " OGHAM SPACE MARK " } + { "#text" = " + " } + { "int" + { "#text" = "0x17B4" } + } + { "#text" = " " } + { "#comment" = " KHMER VOWEL INHERENT AQ " } + { "#text" = " + " } + { "int" + { "#text" = "0x17B5" } + } + { "#text" = " " } + { "#comment" = " KHMER VOWEL INHERENT AA " } + { "#text" = " + " } + { "int" + { "#text" = "0x180E" } + } + { "#text" = " " } + { "#comment" = " MONGOLIAN VOWEL SEPARATOR " } + { "#text" = " + " } + { "int" + { "#text" = "0x2000" } + } + { "#text" = " " } + { "#comment" = " EN QUAD " } + { "#text" = " + " } + { "int" + { "#text" = "0x2001" } + } + { "#text" = " " } + { "#comment" = " EM QUAD " } + { "#text" = " + " } + { "int" + { "#text" = "0x2002" } + } + { "#text" = " " } + { "#comment" = " EN SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2003" } + } + { "#text" = " " } + { "#comment" = " EM SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2004" } + } + { "#text" = " " } + { "#comment" = " THREE-PER-EM SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2005" } + } + { "#text" = " " } + { "#comment" = " FOUR-PER-EM SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2006" } + } + { "#text" = " " } + { "#comment" = " SIX-PER-EM SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2007" } + } + { "#text" = " " } + { "#comment" = " FIGURE SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2008" } + } + { "#text" = " " } + { "#comment" = " PUNCTUATION SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2009" } + } + { "#text" = " " } + { "#comment" = " THIN SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x200A" } + } + { "#text" = " " } + { "#comment" = " HAIR SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x200B" } + } + { "#text" = " " } + { "#comment" = " ZERO WIDTH SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x200C" } + } + { "#text" = " " } + { "#comment" = " ZERO WIDTH NON-JOINER " } + { "#text" = " + " } + { "int" + { "#text" = "0x200D" } + } + { "#text" = " " } + { "#comment" = " ZERO WIDTH JOINER " } + { "#text" = " + " } + { "int" + { "#text" = "0x200E" } + } + { "#text" = " " } + { "#comment" = " LEFT-TO-RIGHT MARK " } + { "#text" = " + " } + { "int" + { "#text" = "0x200F" } + } + { "#text" = " " } + { "#comment" = " RIGHT-TO-LEFT MARK " } + { "#text" = " + " } + { "int" + { "#text" = "0x2028" } + } + { "#text" = " " } + { "#comment" = " LINE SEPARATOR " } + { "#text" = " + " } + { "int" + { "#text" = "0x2029" } + } + { "#text" = " " } + { "#comment" = " PARAGRAPH SEPARATOR " } + { "#text" = " + " } + { "int" + { "#text" = "0x202A" } + } + { "#text" = " " } + { "#comment" = " LEFT-TO-RIGHT EMBEDDING " } + { "#text" = " + " } + { "int" + { "#text" = "0x202B" } + } + { "#text" = " " } + { "#comment" = " RIGHT-TO-LEFT EMBEDDING " } + { "#text" = " + " } + { "int" + { "#text" = "0x202C" } + } + { "#text" = " " } + { "#comment" = " POP DIRECTIONAL FORMATTING " } + { "#text" = " + " } + { "int" + { "#text" = "0x202D" } + } + { "#text" = " " } + { "#comment" = " LEFT-TO-RIGHT OVERRIDE " } + { "#text" = " + " } + { "int" + { "#text" = "0x202E" } + } + { "#text" = " " } + { "#comment" = " RIGHT-TO-LEFT OVERRIDE " } + { "#text" = " + " } + { "int" + { "#text" = "0x202F" } + } + { "#text" = " " } + { "#comment" = " NARROW NO-BREAK SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x205F" } + } + { "#text" = " " } + { "#comment" = " MEDIUM MATHEMATICAL SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x2060" } + } + { "#text" = " " } + { "#comment" = " WORD JOINER " } + { "#text" = " + " } + { "int" + { "#text" = "0x2061" } + } + { "#text" = " " } + { "#comment" = " FUNCTION APPLICATION " } + { "#text" = " + " } + { "int" + { "#text" = "0x2062" } + } + { "#text" = " " } + { "#comment" = " INVISIBLE TIMES " } + { "#text" = " + " } + { "int" + { "#text" = "0x2063" } + } + { "#text" = " " } + { "#comment" = " INVISIBLE SEPARATOR " } + { "#text" = " + " } + { "int" + { "#text" = "0x206A" } + } + { "#text" = " " } + { "#comment" = " INHIBIT SYMMETRIC SWAPPING " } + { "#text" = " + " } + { "int" + { "#text" = "0x206B" } + } + { "#text" = " " } + { "#comment" = " ACTIVATE SYMMETRIC SWAPPING " } + { "#text" = " + " } + { "int" + { "#text" = "0x206C" } + } + { "#text" = " " } + { "#comment" = " INHIBIT ARABIC FORM SHAPING " } + { "#text" = " + " } + { "int" + { "#text" = "0x206D" } + } + { "#text" = " " } + { "#comment" = " ACTIVATE ARABIC FORM SHAPING " } + { "#text" = " + " } + { "int" + { "#text" = "0x206E" } + } + { "#text" = " " } + { "#comment" = " NATIONAL DIGIT SHAPES " } + { "#text" = " + " } + { "int" + { "#text" = "0x206F" } + } + { "#text" = " " } + { "#comment" = " NOMINAL DIGIT SHAPES " } + { "#text" = " + " } + { "int" + { "#text" = "0x2800" } + } + { "#text" = " " } + { "#comment" = " BRAILLE PATTERN BLANK " } + { "#text" = " + " } + { "int" + { "#text" = "0x3000" } + } + { "#text" = " " } + { "#comment" = " IDEOGRAPHIC SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0x3164" } + } + { "#text" = " " } + { "#comment" = " HANGUL FILLER " } + { "#text" = " + " } + { "int" + { "#text" = "0xFEFF" } + } + { "#text" = " " } + { "#comment" = " ZERO WIDTH NO-BREAK SPACE " } + { "#text" = " + " } + { "int" + { "#text" = "0xFFA0" } + } + { "#text" = " " } + { "#comment" = " HALFWIDTH HANGUL FILLER " } + { "#text" = " + " } + { "int" + { "#text" = "0xFFF9" } + } + { "#text" = " " } + { "#comment" = " INTERLINEAR ANNOTATION ANCHOR " } + { "#text" = " + " } + { "int" + { "#text" = "0xFFFA" } + } + { "#text" = " " } + { "#comment" = " INTERLINEAR ANNOTATION SEPARATOR " } + { "#text" = " + " } + { "int" + { "#text" = "0xFFFB" } + } + { "#text" = " " } + { "#comment" = " INTERLINEAR ANNOTATION TERMINATOR " } + { "#text" = " + " } + } + { "#comment" = " + Rescan configuration every 30 seconds when FcFontSetList is called + " } + { "#text" = " + " } + { "rescan" + { "#text" = " + " } + { "int" + { "#text" = "30" } + } + { "#text" = " " } + } + { "#text" = " " } + } + { "#text" = " +" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_fstab.aug b/Sharp.Augeas.Test/lens/tests/test_fstab.aug new file mode 100644 index 0000000..438f619 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_fstab.aug @@ -0,0 +1,161 @@ +module Test_fstab = + + let simple = "/dev/vg00/lv00\t /\t ext3\t defaults 1 1\n" + + let simple_tree = + { "1" + { "spec" = "/dev/vg00/lv00" } + { "file" = "/" } + { "vfstype" = "ext3" } + { "opt" = "defaults" } + { "dump" = "1" } + { "passno" = "1" } } + + let leading_ws = " /dev/vg00/lv00\t /\t ext3\t defaults 1 1\n" + + let trailing_ws = "/dev/vg00/lv00\t /\t ext3\t defaults 1 1 \t\n" + + let gen_no_passno(passno:string) = + "LABEL=/boot\t /boot\t ext3\t defaults 1" . passno . " \t\n" + let no_passno = gen_no_passno "" + + let no_passno_tree = + { "1" + { "spec" = "LABEL=/boot" } + { "file" = "/boot" } + { "vfstype" = "ext3" } + { "opt" = "defaults" } + { "dump" = "1" } } + + let no_dump = "/dev/vg00/lv00\t /\t ext3\t defaults\n" + + let no_dump_tree = + { "1" + { "spec" = "/dev/vg00/lv00" } + { "file" = "/" } + { "vfstype" = "ext3" } + { "opt" = "defaults" } } + + let no_opts = "/dev/vg00/lv00\t /\t ext3\n" + + let no_opts_tree = + { "1" + { "spec" = "/dev/vg00/lv00" } + { "file" = "/" } + { "vfstype" = "ext3" } } + + let multi_opts = "devpts\t /dev/pts\t devpts gid=5,mode=620,fscontext=system_u:object_r:removable_t 0 0\n" + + let multi_opts_tree = + { "1" + { "spec" = "devpts" } + { "file" = "/dev/pts" } + { "vfstype" = "devpts" } + { "opt" = "gid" + { "value" = "5" } } + { "opt" = "mode" + { "value" = "620" } } + { "opt" = "fscontext" + { "value" = "system_u:object_r:removable_t" } } + { "dump" = "0" } + { "passno" = "0" } } + + test Fstab.lns get simple = simple_tree + + test Fstab.lns get leading_ws = simple_tree + + test Fstab.lns get trailing_ws = simple_tree + + test Fstab.lns get no_passno = no_passno_tree + + test Fstab.lns put no_passno after set "/1/passno" "1" = gen_no_passno " 1" + + test Fstab.lns get no_dump = no_dump_tree + + test Fstab.lns get no_opts = no_opts_tree + + test Fstab.lns get multi_opts = multi_opts_tree + + test Fstab.lns get "/dev/hdc /media/cdrom0 udf,iso9660 user,noauto\t0\t0\n" = + { "1" + { "spec" = "/dev/hdc" } + { "file" = "/media/cdrom0" } + { "vfstype" = "udf" } + { "vfstype" = "iso9660" } + { "opt" = "user" } + { "opt" = "noauto" } + { "dump" = "0" } + { "passno" = "0" } } + + (* Allow # in the spec *) + test Fstab.lns get "sshfs#jon@10.0.0.2:/home /media/server fuse uid=1000,gid=100,port=1022 0 0\n" = + { "1" + { "spec" = "sshfs#jon@10.0.0.2:/home" } + { "file" = "/media/server" } + { "vfstype" = "fuse" } + { "opt" = "uid" + { "value" = "1000" } } + { "opt" = "gid" + { "value" = "100" } } + { "opt" = "port" + { "value" = "1022" } } + { "dump" = "0" } + { "passno" = "0" } } + + (* Bug #191 *) + test Fstab.lns get "tmpfs /dev/shm tmpfs rw,rootcontext=\"system_u:object_r:tmpfs_t:s0\" 0 0\n" = + { "1" + { "spec" = "tmpfs" } + { "file" = "/dev/shm" } + { "vfstype" = "tmpfs" } + { "opt" = "rw" } + { "opt" = "rootcontext" + { "value" = "\"system_u:object_r:tmpfs_t:s0\"" } } + { "dump" = "0" } + { "passno" = "0" } } + + (* BZ https://bugzilla.redhat.com/show_bug.cgi?id=751342 + * Mounting multiple cgroups together results in path with ',' + *) + test Fstab.lns get "spec /path/file1,file2 vfs opts 0 0\n" = + { "1" + { "spec" = "spec" } + { "file" = "/path/file1,file2" } + { "vfstype" = "vfs" } + { "opt" = "opts" } + { "dump" = "0" } + { "passno" = "0" } } + + (* Parse when empty option value given, only equals sign *) + test Fstab.lns get "//host.example.org/a_share /mnt cifs defaults,ro,password= 0 0\n" = + { "1" + { "spec" = "//host.example.org/a_share" } + { "file" = "/mnt" } + { "vfstype" = "cifs" } + { "opt" = "defaults" } + { "opt" = "ro" } + { "opt" = "password" + { "value" } + } + { "dump" = "0" } + { "passno" = "0" } + } + + (* Allow end of line comments *) + test Fstab.lns get "UUID=0314be77-bb1e-47d4-b2a2-e69ae5bc954f / ext4 rw,errors=remount-ro 0 1 # device at install: /dev/sda3\n" = + { "1" + { "spec" = "UUID=0314be77-bb1e-47d4-b2a2-e69ae5bc954f" } + { "file" = "/" } + { "vfstype" = "ext4" } + { "opt" = "rw" } + { "opt" = "errors" + { "value" = "remount-ro" } + } + { "dump" = "0" } + { "passno" = "1" } + { "#comment" = "device at install: /dev/sda3" } + } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_fuse.aug b/Sharp.Augeas.Test/lens/tests/test_fuse.aug new file mode 100644 index 0000000..58ffa3d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_fuse.aug @@ -0,0 +1,22 @@ +(* +Module: Test_Fuse + Provides unit tests and examples for the <Fuse> lens. +*) + +module Test_Fuse = + +(* Variable: conf *) +let conf = "# Set the maximum number of FUSE mounts allowed to non-root users. +mount_max = 1000 + +# Allow non-root users to specify the 'allow_other' or 'allow_root' +user_allow_other +" + +(* Test: Fuse.lns *) +test Fuse.lns get conf = + { "#comment" = "Set the maximum number of FUSE mounts allowed to non-root users." } + { "mount_max" = "1000" } + { } + { "#comment" = "Allow non-root users to specify the 'allow_other' or 'allow_root'" } + { "user_allow_other" } diff --git a/Sharp.Augeas.Test/lens/tests/test_gdm.aug b/Sharp.Augeas.Test/lens/tests/test_gdm.aug new file mode 100644 index 0000000..50b12f3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_gdm.aug @@ -0,0 +1,21 @@ +module Test_gdm = + + let conf = "[daemon] +# Automatic login, if true the first attached screen will automatically logged +# in as user as set with AutomaticLogin key. +AutomaticLoginEnable=false +AutomaticLogin= + +[server] +0=Standard device=/dev/console +" + + test Gdm.lns get conf = + { "daemon" + { "#comment" = "Automatic login, if true the first attached screen will automatically logged" } + { "#comment" = "in as user as set with AutomaticLogin key." } + { "AutomaticLoginEnable" = "false" } + { "AutomaticLogin" } + {} } + { "server" + { "0" = "Standard device=/dev/console" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_getcap.aug b/Sharp.Augeas.Test/lens/tests/test_getcap.aug new file mode 100644 index 0000000..4cd435c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_getcap.aug @@ -0,0 +1,122 @@ +module Test_getcap = + +(* Example from getcap(3) *) +let getcap = "example|an example of binding multiple values to names:\\ + :foo%bar:foo^blah:foo@:\\ + :abc%xyz:abc^frap:abc$@:\\ + :tc=more: +" + +test Getcap.lns get getcap = + { "record" + { "name" = "example" } + { "name" = "an example of binding multiple values to names" } + { "capability" = "foo%bar" } + { "capability" = "foo^blah" } + { "capability" = "foo@" } + { "capability" = "abc%xyz" } + { "capability" = "abc^frap" } + { "capability" = "abc$@" } + { "capability" = "tc=more" } + } + +(* Taken from the standard /etc/login.conf *) +let login_conf = "# Default allowed authentication styles +auth-defaults:auth=passwd,skey: + +# Default allowed authentication styles for authentication type ftp +auth-ftp-defaults:auth-ftp=passwd: + +# +# The default values +# To alter the default authentication types change the line: +# :tc=auth-defaults:\\ +# to be read something like: (enables passwd, \"myauth\", and activ) +# :auth=passwd,myauth,activ:\\ +# Any value changed in the daemon class should be reset in default +# class. +# +default:\\ + :path=/usr/bin /bin /usr/sbin /sbin /usr/X11R6/bin /usr/local/bin /usr/local/sbin:\\ + :umask=022:\\ + :datasize-max=512M:\\ + :datasize-cur=512M:\\ + :maxproc-max=256:\\ + :maxproc-cur=128:\\ + :openfiles-cur=512:\\ + :stacksize-cur=4M:\\ + :localcipher=blowfish,8:\\ + :ypcipher=old:\\ + :tc=auth-defaults:\\ + :tc=auth-ftp-defaults: +" + +test Getcap.lns get login_conf = + { "#comment" = "Default allowed authentication styles" } + { "record" + { "name" = "auth-defaults" } + { "capability" = "auth=passwd,skey" } + } + { } + { "#comment" = "Default allowed authentication styles for authentication type ftp" } + { "record" + { "name" = "auth-ftp-defaults" } + { "capability" = "auth-ftp=passwd" } + } + { } + { } + { "#comment" = "The default values" } + { "#comment" = "To alter the default authentication types change the line:" } + { "#comment" = ":tc=auth-defaults:\\" } + { "#comment" = "to be read something like: (enables passwd, \"myauth\", and activ)" } + { "#comment" = ":auth=passwd,myauth,activ:\\" } + { "#comment" = "Any value changed in the daemon class should be reset in default" } + { "#comment" = "class." } + { } + { "record" + { "name" = "default" } + { "capability" = "path=/usr/bin /bin /usr/sbin /sbin /usr/X11R6/bin /usr/local/bin /usr/local/sbin" } + { "capability" = "umask=022" } + { "capability" = "datasize-max=512M" } + { "capability" = "datasize-cur=512M" } + { "capability" = "maxproc-max=256" } + { "capability" = "maxproc-cur=128" } + { "capability" = "openfiles-cur=512" } + { "capability" = "stacksize-cur=4M" } + { "capability" = "localcipher=blowfish,8" } + { "capability" = "ypcipher=old" } + { "capability" = "tc=auth-defaults" } + { "capability" = "tc=auth-ftp-defaults" } + } + +(* Sample /etc/printcap *) +let printcap = "# $OpenBSD: printcap,v 1.1 2014/07/12 03:52:39 deraadt Exp $ + +lp|local line printer:\\ + :lp=/dev/lp:sd=/var/spool/output:lf=/var/log/lpd-errs: + +rp|remote line printer:\\ + :lp=:rm=printhost:rp=lp:sd=/var/spool/output:lf=/var/log/lpd-errs: +" + +test Getcap.lns get printcap = + { "#comment" = "$OpenBSD: printcap,v 1.1 2014/07/12 03:52:39 deraadt Exp $" } + { } + { "record" + { "name" = "lp" } + { "name" = "local line printer" } + { "capability" = "lp=/dev/lp" } + { "capability" = "sd=/var/spool/output" } + { "capability" = "lf=/var/log/lpd-errs" } + } + { } + { "record" + { "name" = "rp" } + { "name" = "remote line printer" } + { "capability" = "lp=" } + { "capability" = "rm=printhost" } + { "capability" = "rp=lp" } + { "capability" = "sd=/var/spool/output" } + { "capability" = "lf=/var/log/lpd-errs" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_group.aug b/Sharp.Augeas.Test/lens/tests/test_group.aug new file mode 100644 index 0000000..37c27fa --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_group.aug @@ -0,0 +1,54 @@ +module Test_group = + +let conf = "bin:x:2: +audio:x:29:joe +avahi-autoipd:!:113:bill,martha +" + +test Group.lns get conf = + { "bin" + { "password" = "x" } + { "gid" = "2" } } + { "audio" + { "password" = "x" } + { "gid" = "29" } + { "user" = "joe" } } + { "avahi-autoipd" + { "password" = "!" } + { "gid" = "113" } + { "user" = "bill"} + { "user" = "martha"} } + +(* Password field can be empty *) +test Group.lns get "root::0:root\n" = + { "root" + { "password" = "" } + { "gid" = "0" } + { "user" = "root" } } + +(* Password field can be disabled by ! or * *) +test Group.lns get "testgrp:!:0:testusr\n" = + { "testgrp" + { "password" = "!" } + { "gid" = "0" } + { "user" = "testusr" } } + +test Group.lns get "testgrp:*:0:testusr\n" = + { "testgrp" + { "password" = "*" } + { "gid" = "0" } + { "user" = "testusr" } } + +(* NIS defaults *) +test Group.lns get "+\n" = + { "@nisdefault" } + +test Group.lns get "+:::\n" = + { "@nisdefault" + { "password" = "" } + { "gid" = "" } } + +test Group.lns get "+:*::\n" = + { "@nisdefault" + { "password" = "*" } + { "gid" = "" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_grub.aug b/Sharp.Augeas.Test/lens/tests/test_grub.aug new file mode 100644 index 0000000..e50bdc4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_grub.aug @@ -0,0 +1,301 @@ +module Test_grub = + + let conf = "# grub.conf generated by anaconda +# +# Note that you do not have to rerun grub after making changes to this file +# NOTICE: You have a /boot partition. This means that +# all kernel and initrd paths are relative to /boot/, eg. +# root (hd0,0) +# kernel /vmlinuz-version ro root=/dev/vg00/lv00 +# initrd /initrd-version.img +boot=/dev/sda +device (hd0) HD(1,800,64000,9895c137-d4b2-4e3b-a93b-dc9ac4) +password --md5 $1$M9NLj$p2gs87vwNv48BUu.wAfVw0 +default=0 +setkey +setkey less backquote +background 103332 +timeout=5 +splashimage=(hd0,0)/grub/splash.xpm.gz +gfxmenu=(hd0,0)/boot/message +verbose = 0 +hiddenmenu +title Fedora (2.6.24.4-64.fc8) + root (hd0,0) + kernel /vmlinuz-2.6.24.4-64.fc8 ro root=/dev/vg00/lv00 crashkernel= + initrd /initrd-2.6.24.4-64.fc8.img +title=Fedora (2.6.24.3-50.fc8) + root (hd0,0) + kernel /vmlinuz-2.6.24.3-50.fc8 ro root=/dev/vg00/lv00 + initrd /initrd-2.6.24.3-50.fc8.img +title Fedora (2.6.21.7-3.fc8xen) + root (hd0,0) + kernel /xen.gz-2.6.21.7-3.fc8 + module /vmlinuz-2.6.21.7-3.fc8xen ro root=/dev/vg00/lv00 + module /initrd-2.6.21.7-3.fc8xen.img +title Fedora (2.6.24.3-34.fc8) + root (hd0,0) + kernel /vmlinuz-2.6.24.3-34.fc8 ro root=/dev/vg00/lv00 + initrd /initrd-2.6.24.3-34.fc8.img + map (hd0) (hd1) +title othermenu + lock + makeactive + configfile /boot/grub/othergrub.conf +" + + test Grub.lns get conf = + { "#comment" = "grub.conf generated by anaconda" } + {} + { "#comment" = "Note that you do not have to rerun grub after making changes to this file" } + { "#comment" = "NOTICE: You have a /boot partition. This means that" } + { "#comment" = "all kernel and initrd paths are relative to /boot/, eg." } + { "#comment" = "root (hd0,0)" } + { "#comment" = "kernel /vmlinuz-version ro root=/dev/vg00/lv00" } + { "#comment" = "initrd /initrd-version.img" } + { "boot" = "/dev/sda" } + { "device" = "(hd0)" + { "file" = "HD(1,800,64000,9895c137-d4b2-4e3b-a93b-dc9ac4)" } } + { "password" = "$1$M9NLj$p2gs87vwNv48BUu.wAfVw0" + { "md5" } } + { "default" = "0" } + { "setkey" } + { "setkey" + { "to" = "less" } + { "from" = "backquote" } } + { "background" = "103332" } + { "timeout" = "5" } + { "splashimage" = "(hd0,0)/grub/splash.xpm.gz" } + { "gfxmenu" = "(hd0,0)/boot/message" } + { "verbose" = "0" } + { "hiddenmenu" } + { "title" = "Fedora (2.6.24.4-64.fc8)" + { "root" = "(hd0,0)" } + { "kernel" = "/vmlinuz-2.6.24.4-64.fc8" + { "ro" } { "root" = "/dev/vg00/lv00" } {"crashkernel" = ""} } + { "initrd" = "/initrd-2.6.24.4-64.fc8.img" } } + { "title" = "Fedora (2.6.24.3-50.fc8)" + { "root" = "(hd0,0)" } + { "kernel" = "/vmlinuz-2.6.24.3-50.fc8" + { "ro" } { "root" = "/dev/vg00/lv00" } } + { "initrd" = "/initrd-2.6.24.3-50.fc8.img" } } + { "title" = "Fedora (2.6.21.7-3.fc8xen)" + { "root" = "(hd0,0)" } + { "kernel" = "/xen.gz-2.6.21.7-3.fc8" } + { "module" = "/vmlinuz-2.6.21.7-3.fc8xen" + { "ro" } { "root" = "/dev/vg00/lv00" } } + { "module" = "/initrd-2.6.21.7-3.fc8xen.img" } } + { "title" = "Fedora (2.6.24.3-34.fc8)" + { "root" = "(hd0,0)" } + { "kernel" = "/vmlinuz-2.6.24.3-34.fc8" + { "ro" } { "root" = "/dev/vg00/lv00" } } + { "initrd" = "/initrd-2.6.24.3-34.fc8.img" } + { "map" { "from" = "(hd0)" } { "to" = "(hd1)" } } } + { "title" = "othermenu" + { "lock" } + { "makeactive" } + { "configfile" = "/boot/grub/othergrub.conf" } } + + + test Grub.lns put conf after set "default" "0" = conf + + test Grub.lns get "# menu.lst - See: grub(8), info grub, update-grub(8) + +## default num\n" = + { "#comment" = "menu.lst - See: grub(8), info grub, update-grub(8)" } + {} + { "#comment" = "# default num" } + + (* Color directive *) + test Grub.lns get "color cyan/blue white/blue\n" = + { "color" + { "normal" { "foreground" = "cyan" } + { "background" = "blue" } } + { "highlight" { "foreground" = "white" } + { "background" = "blue" } } } + + test Grub.lns get "\tcolor cyan/light-blue\n" = + { "color" + { "normal" { "foreground" = "cyan" } + { "background" = "light-blue" } } } + + test Grub.lns put "color cyan/light-blue\n" after + set "/color/highlight/foreground" "white"; + set "/color/highlight/background" "black" = + "color cyan/light-blue white/black\n" + + (* Boot stanza with savedefault *) + let boot_savedefault = +"title\t\tDebian GNU/Linux, kernel 2.6.18-6-vserver-686 +root\t\t(hd0,0) + kernel\t\t/boot/vmlinuz-2.6.18-6-vserver-686 root=/dev/md0 ro +initrd\t\t/boot/initrd.img-2.6.18-6-vserver-686 +\tsavedefault\n" + + test Grub.lns get boot_savedefault = + { "title" = "Debian GNU/Linux, kernel 2.6.18-6-vserver-686" + { "root" = "(hd0,0)" } + { "kernel" = "/boot/vmlinuz-2.6.18-6-vserver-686" + { "root" = "/dev/md0" } { "ro" } } + { "initrd" = "/boot/initrd.img-2.6.18-6-vserver-686" } + { "savedefault" } } + + test Grub.lns get + "serial --unit=0 --speed=9600 --word=8 --parity=no --stop=1\n" + = + { "serial" + { "unit" = "0" } + { "speed" = "9600" } + { "word" = "8" } + { "parity" = "no" } + { "stop" = "1" } } + + test Grub.lns get + "terminal --timeout=10 serial console\n" = + { "terminal" + { "timeout" = "10" } + { "serial" } + { "console" } } + + test Grub.boot_setting get + "chainloader --force +1 \n" = { "chainloader" = "+1" { "force" } } + + test Grub.savedefault put "savedefault\n" after + set "/savedefault" "3" = "savedefault 3\n" + + test Grub.lns get +"password foo +password foo /boot/grub/custom.lst +password --md5 $1$Ahx/T0$Sgcp7Z0xgGlyANIJCdESi. +password --encrypted ^9^32kwzzX./3WISQ0C +password --encrypted ^9^32kwzzX./3WISQ0C /boot/grub/custom.lst +" = + { "password" = "foo" } + { "password" = "foo" + { "file" = "/boot/grub/custom.lst" } } + { "password" = "$1$Ahx/T0$Sgcp7Z0xgGlyANIJCdESi." + { "md5" } } + { "password" = "^9^32kwzzX./3WISQ0C" + { "encrypted" } } + { "password" = "^9^32kwzzX./3WISQ0C" + { "encrypted" } + { "file" = "/boot/grub/custom.lst" } } + + (* BZ 590067 - handle comments in a title section *) + (* Comments within a boot stanza belong to that boot stanza *) + test Grub.lns get "title Red Hat Enterprise Linux AS (2.4.21-63.ELsmp) + root (hd0,0) + kernel /vmlinuz-2.4.21-63.ELsmp ro root=LABEL=/ + #initrd /initrd-2.4.21-63.ELsmp.img + initrd /initrd-2.4.21-63.EL.img.e1000.8139\n" = + { "title" = "Red Hat Enterprise Linux AS (2.4.21-63.ELsmp)" + { "root" = "(hd0,0)" } + { "kernel" = "/vmlinuz-2.4.21-63.ELsmp" { "ro" } { "root" = "LABEL=/" } } + { "#comment" = "initrd /initrd-2.4.21-63.ELsmp.img" } + { "initrd" = "/initrd-2.4.21-63.EL.img.e1000.8139" } } + + (* Comments at the end of a boot stanza go into the top level *) + test Grub.lns get "title Red Hat Enterprise Linux AS (2.4.21-63.ELsmp) + root (hd0,0) + kernel /vmlinuz-2.4.21-63.ELsmp ro root=LABEL=/ + initrd /initrd-2.4.21-63.EL.img.e1000.8139 + # Now for something completely different\n" = + { "title" = "Red Hat Enterprise Linux AS (2.4.21-63.ELsmp)" + { "root" = "(hd0,0)" } + { "kernel" = "/vmlinuz-2.4.21-63.ELsmp" { "ro" } { "root" = "LABEL=/" } } + { "initrd" = "/initrd-2.4.21-63.EL.img.e1000.8139" } } + { "#comment" = "Now for something completely different" } + + (* Solaris 10 extensions: kernel$ and module$ are permitted and enable *) + (* variable expansion. findroot (similar to root) and bootfs added *) + test Grub.lns get "title Solaris 10 10/09 s10x_u8wos_08a X86 + findroot (pool_rpool,0,a) + bootfs rpool/mybootenv-alt + kernel$ /platform/i86pc/multiboot -B $ZFS-BOOTFS + module$ /platform/i86pc/boot_archive\n" = + { "title" = "Solaris 10 10/09 s10x_u8wos_08a X86" + { "findroot" = "(pool_rpool,0,a)" } + { "bootfs" = "rpool/mybootenv-alt" } + { "kernel$" = "/platform/i86pc/multiboot" { "-B" } { "$ZFS-BOOTFS" } } + { "module$" = "/platform/i86pc/boot_archive" } } + + (* Solaris 10 extension: multiboot kernel may take a path as its first *) + (* argument. *) + test Grub.lns get "title Solaris failsafe + findroot (pool_rpool,0,a) + kernel /boot/multiboot kernel/unix -s + module /boot/x86.miniroot-safe\n" = + { "title" = "Solaris failsafe" + { "findroot" = "(pool_rpool,0,a)" } + { "kernel" = "/boot/multiboot" { "@path" = "kernel/unix" } { "-s" } } + { "module" = "/boot/x86.miniroot-safe" } } + + test Grub.lns get "title SUSE Linux Enterprise Server 11 SP1 - 2.6.32.27-0.2 + kernel (hd0,0)/vmlinuz root=/dev/vg_root/lv_root resume=/dev/vg_root/lv_swap splash=silent showopts + initrd (hd0,0)/initrd\n" = + { "title" = "SUSE Linux Enterprise Server 11 SP1 - 2.6.32.27-0.2" + { "kernel" = "(hd0,0)/vmlinuz" + { "root" = "/dev/vg_root/lv_root" } + { "resume" = "/dev/vg_root/lv_swap" } + { "splash" = "silent" } + { "showopts" } } + { "initrd" = "(hd0,0)/initrd" } } + + (* Password protected kernel, issue #229 *) + test Grub.lns get "title Password Protected Kernel + root (hd0,0) + kernel /vmlinuz ro root=/dev/mapper/root + initrd /initramfs + password --md5 secret\n" = + { "title" = "Password Protected Kernel" + { "root" = "(hd0,0)" } + { "kernel" = "/vmlinuz" + { "ro" } + { "root" = "/dev/mapper/root" } + } + { "initrd" = "/initramfs" } + { "password" = "secret" + { "md5" } + } } + + (* Test kernel options with different special characters. *) + test Grub.lns get "title Fedora (2.6.24.4-64.fc8) + root (hd0,0) + kernel /vmlinuz-2.6.24.4-64.fc8 ro root=/dev/vg00/lv00 with.dot=1 with-dash=1 with_underscore=1 with+plus=1 + initrd /initrd-2.6.24.4-64.fc8.img\n" = + { "title" = "Fedora (2.6.24.4-64.fc8)" + { "root" = "(hd0,0)" } + { "kernel" = "/vmlinuz-2.6.24.4-64.fc8" + { "ro" } + { "root" = "/dev/vg00/lv00" } + { "with.dot" = "1" } + { "with-dash" = "1" } + { "with_underscore" = "1" } + { "with+plus" = "1" } + } + { "initrd" = "/initrd-2.6.24.4-64.fc8.img" } } + + (* Test parsing of invalid entries via menu_error *) + test Grub.lns get "default=0\ncrud=no\n" = + { "default" = "0" } + { "#error" = "crud=no" } + + (* We handle some pretty bizarre bad syntax *) + test Grub.lns get "default=0 +crud no +valid:nope +nonsense = yes +bad arg1 arg2 arg3=v\n" = + { "default" = "0" } + { "#error" = "crud no" } + { "#error" = "valid:nope" } + { "#error" = "nonsense = yes" } + { "#error" = "bad arg1 arg2 arg3=v" } + + (* Test parsing of invalid entries via boot_error *) + test Grub.lns get "title test + root (hd0,0) + crud foo\n" = + { "title" = "test" + { "root" = "(hd0,0)" } + { "#error" = "crud foo" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_grubenv.aug b/Sharp.Augeas.Test/lens/tests/test_grubenv.aug new file mode 100644 index 0000000..2976c16 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_grubenv.aug @@ -0,0 +1,36 @@ +module Test_grubenv = + + let conf = "# GRUB Environment Block +serial=1 +serial_speed=115200 +dummy1=abc\\\\xyz +dummy2=abc\\ +xyz +dummy3=abc\\\\uvw\\ +xyz +######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################## +" + + test GrubEnv.lns get conf = + { "#comment" = "GRUB Environment Block" } + { "1" + { "name" = "serial" } + { "value" = "1" } + } + { "2" + { "name" = "serial_speed" } + { "value" = "115200" } + } + { "3" + { "name" = "dummy1" } + { "value" = "abc\\\\xyz" } + } + { "4" + { "name" = "dummy2" } + { "value" = "abc\\\nxyz" } + } + { "5" + { "name" = "dummy3" } + { "value" = "abc\\\\uvw\\\nxyz" } + } + { "#comment" = "#######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################" } diff --git a/Sharp.Augeas.Test/lens/tests/test_gshadow.aug b/Sharp.Augeas.Test/lens/tests/test_gshadow.aug new file mode 100644 index 0000000..b226a3e --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_gshadow.aug @@ -0,0 +1,18 @@ +module Test_Gshadow = + +let conf = "root:x:: +uucp:x:: +sudo:x:suadmin1,suadmin2:coadmin1,coadmin2 +" + +test Gshadow.lns get conf = + { "root" + { "password" = "x" } } + { "uucp" + { "password" = "x" } } + { "sudo" + { "password" = "x" } + { "admin" = "suadmin1" } + { "admin" = "suadmin2" } + { "member" = "coadmin1" } + { "member" = "coadmin2" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_gtkbookmarks.aug b/Sharp.Augeas.Test/lens/tests/test_gtkbookmarks.aug new file mode 100644 index 0000000..404a4fd --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_gtkbookmarks.aug @@ -0,0 +1,25 @@ +(* +Module: Test_GtkBookmarks + Provides unit tests and examples for the <GtkBookmarks> lens. +*) + +module Test_GtkBookmarks = + +(* Test: GtkBookmarks.lns + Test without label *) +test GtkBookmarks.lns get "ftp://user@myftp.com/somedir\n" = + { "bookmark" = "ftp://user@myftp.com/somedir" } + +(* Test: GtkBookmarks.lns + Test with label *) +test GtkBookmarks.lns get "file:///home/rpinson/Ubuntu%20One Ubuntu One\n" = + { "bookmark" = "file:///home/rpinson/Ubuntu%20One" + { "label" = "Ubuntu One" } } + +(* Test: GtkBookmarks.lns + Empty lines are allowed, not comments *) +test GtkBookmarks.lns get "ftp://user@myftp.com/somedir\n\nfile:///home/rpinson/Ubuntu%20One Ubuntu One\n" = + { "bookmark" = "ftp://user@myftp.com/somedir" } + { } + { "bookmark" = "file:///home/rpinson/Ubuntu%20One" + { "label" = "Ubuntu One" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_host_conf.aug b/Sharp.Augeas.Test/lens/tests/test_host_conf.aug new file mode 100644 index 0000000..f0df5ab --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_host_conf.aug @@ -0,0 +1,36 @@ +module Test_Host_Conf = + +let conf = " +# /etc/host.conf +# We have named running, but no NIS (yet) +order bind, hosts +# Allow multiple addrs +multi on +# Guard against spoof attempts +nospoof on +# Trim local domain (not really necessary). +trim vbrew.com.:fedora.org. +trim augeas.net.,ubuntu.com. +" + +test Host_Conf.lns get conf = + { } + { "#comment" = "/etc/host.conf" } + { "#comment" = "We have named running, but no NIS (yet)" } + { "order" + { "1" = "bind" } + { "2" = "hosts" } + } + { "#comment" = "Allow multiple addrs" } + { "multi" = "on" } + { "#comment" = "Guard against spoof attempts" } + { "nospoof" = "on" } + { "#comment" = "Trim local domain (not really necessary)." } + { "trim" + { "1" = "vbrew.com." } + { "2" = "fedora.org." } + } + { "trim" + { "3" = "augeas.net." } + { "4" = "ubuntu.com." } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_hostname.aug b/Sharp.Augeas.Test/lens/tests/test_hostname.aug new file mode 100644 index 0000000..32d8821 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_hostname.aug @@ -0,0 +1,4 @@ +module Test_Hostname = + +test Hostname.lns get "local.localnet\n" = + { "hostname" = "local.localnet" } diff --git a/Sharp.Augeas.Test/lens/tests/test_hosts.aug b/Sharp.Augeas.Test/lens/tests/test_hosts.aug new file mode 100644 index 0000000..2bc61fb --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_hosts.aug @@ -0,0 +1,64 @@ +(* Tests for the Hosts module *) + +module Test_hosts = + + let two_entries = "127.0.0.1 foo foo.example.com + # \tcomment\t +192.168.0.1 pigiron.example.com pigiron pigiron.example +" + + test Hosts.record get "127.0.0.1 foo\n" = + { "1" { "ipaddr" = "127.0.0.1" } + { "canonical" = "foo" } } + + test Hosts.lns get two_entries = + { "1" { "ipaddr" = "127.0.0.1" } + { "canonical" = "foo" } + { "alias" = "foo.example.com" } + } + { "#comment" = "comment" } + { "2" { "ipaddr" = "192.168.0.1" } + { "canonical" = "pigiron.example.com" } + { "alias" = "pigiron" } + { "alias" = "pigiron.example" } } + + test Hosts.record put "127.0.0.1 foo\n" after + set "/1/canonical" "bar" + = "127.0.0.1 bar\n" + + test Hosts.lns put two_entries after + set "/2/alias[10]" "piggy" ; + rm "/1/alias[1]" ; + rm "/2/alias[2]" + = "127.0.0.1 foo + # \tcomment\t +192.168.0.1 pigiron.example.com pigiron piggy +" + + (* Deleting the 'canonical' node violates the schema; each host entry *) + (* must have one *) + test Hosts.lns put two_entries after + rm "/1/canonical" + = * + + (* Make sure blank and indented lines get through *) + test Hosts.lns get " \t 127.0.0.1\tlocalhost \n \n\n +127.0.1.1\tetch.example.com\tetch\n" = + { "1" { "ipaddr" = "127.0.0.1" } + { "canonical" = "localhost" } } + {} {} {} + { "2" { "ipaddr" = "127.0.1.1" } + { "canonical" = "etch.example.com" } + { "alias" = "etch" } } + + (* Comment at the end of a line *) + test Hosts.lns get "127.0.0.1 localhost # must always be there \n" = + { "1" { "ipaddr" = "127.0.0.1" } + { "canonical" = "localhost" } + { "#comment" = "must always be there" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) + + diff --git a/Sharp.Augeas.Test/lens/tests/test_hosts_access.aug b/Sharp.Augeas.Test/lens/tests/test_hosts_access.aug new file mode 100644 index 0000000..e677078 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_hosts_access.aug @@ -0,0 +1,253 @@ +module Test_Hosts_Access = + +let multi_daemon = "sshd, sendmail : 10.234.\n" + +test Hosts_Access.lns get multi_daemon = + { "1" + { "process" = "sshd" } + { "process" = "sendmail" } + { "client" = "10.234." } + } + +let multi_daemon_spc = "sshd sendmail : 10.234.\n" + +test Hosts_Access.lns get multi_daemon_spc = + { "1" + { "process" = "sshd" } + { "process" = "sendmail" } + { "client" = "10.234." } + } + +let multi_client = "sshd: 10.234. , 192.168.\n" + +test Hosts_Access.lns get multi_client = + { "1" + { "process" = "sshd" } + { "client" = "10.234." } + { "client" = "192.168." } + } + +let multi_client_spc = "sshd: 10.234. 192.168.\n" + +test Hosts_Access.lns get multi_client_spc = + { "1" + { "process" = "sshd" } + { "client" = "10.234." } + { "client" = "192.168." } + } + +let daemon_except = "ALL Except sshd : 10.234.\n" + +test Hosts_Access.lns get daemon_except = + { "1" + { "process" = "ALL" } + { "except" + { "process" = "sshd" } + } + { "client" = "10.234." } + } + +let client_except = "sshd : ALL EXCEPT 192.168\n" + +test Hosts_Access.lns get client_except = + { "1" + { "process" = "sshd" } + { "client" = "ALL" } + { "except" + { "client" = "192.168" } + } + } + +let daemon_host = "sshd@192.168.0.1: 10.234.\n" + +test Hosts_Access.lns get daemon_host = + { "1" + { "process" = "sshd" + { "host" = "192.168.0.1" } + } + { "client" = "10.234." } + } + +let user_client = "sshd: root@.example.tld\n" + +test Hosts_Access.lns get user_client = + { "1" + { "process" = "sshd" } + { "client" = ".example.tld" + { "user" = "root" } + } + } + +let shell_command = "sshd: 192.168. : /usr/bin/my_cmd -t -f some_arg\n" + +test Hosts_Access.lns get shell_command = + { "1" + { "process" = "sshd" } + { "client" = "192.168." } + { "shell_command" = "/usr/bin/my_cmd -t -f some_arg" } + } + +let client_netgroup = "sshd: @hostgroup\n" +test Hosts_Access.lns get client_netgroup = + { "1" + { "process" = "sshd" } + { "client" = "@hostgroup" } + } + +let client_netmask = "sshd: 192.168.0.0/255.255.0.0\n" +test Hosts_Access.lns get client_netmask = + { "1" + { "process" = "sshd" } + { "client" = "192.168.0.0" + { "netmask" = "255.255.0.0" } } + } + +let client_cidr_v4 = "sshd: 192.168.0.0/24\n" +test Hosts_Access.lns get client_cidr_v4 = + { "1" + { "process" = "sshd" } + { "client" = "192.168.0.0" + { "netmask" = "24" } } + } + +let client_cidr_v6 = "sshd: [fe80::%fxp0]/64\n" +test Hosts_Access.lns get client_cidr_v6 = + { "1" + { "process" = "sshd" } + { "client" = "[fe80::%fxp0]" + { "netmask" = "64" } } + } + +let client_file = "sshd: /etc/external_file\n" +test Hosts_Access.lns get client_file = + { "1" + { "process" = "sshd" } + { "file" = "/etc/external_file" } + } + +let client_wildcard = "sshd: 192.168.?.*\n" +test Hosts_Access.lns get client_wildcard = + { "1" + { "process" = "sshd" } + { "client" = "192.168.?.*" } + } + +let sample_hosts_allow = "# hosts.allow This file describes the names of the hosts which are +# allowed to use the local INET services, as decided +# by the '/usr/sbin/tcpd' server. +in.telnetd: 192.168.1. +sshd: 70.16., 207.228. +ipop3d: ALL +sendmail: ALL +" + +test Hosts_Access.lns get sample_hosts_allow = + { "#comment" = "hosts.allow This file describes the names of the hosts which are" } + { "#comment" = "allowed to use the local INET services, as decided" } + { "#comment" = "by the '/usr/sbin/tcpd' server." } + { "1" + { "process" = "in.telnetd" } + { "client" = "192.168.1." } + } + { "2" + { "process" = "sshd" } + { "client" = "70.16." } + { "client" = "207.228." } + } + { "3" + { "process" = "ipop3d" } + { "client" = "ALL" } + } + { "4" + { "process" = "sendmail" } + { "client" = "ALL" } + } + + +let sample_hosts_deny = "# +# hosts.deny This file describes the names of the hosts which are +# *not* allowed to use the local INET services, as decided +# by the '/usr/sbin/tcpd' server. +in.telnetd: all + +sshd: 61., 62., \ + 64.179., 65. +" + +test Hosts_Access.lns get sample_hosts_deny = + { } + { "#comment" = "hosts.deny This file describes the names of the hosts which are" } + { "#comment" = "*not* allowed to use the local INET services, as decided" } + { "#comment" = "by the '/usr/sbin/tcpd' server." } + { "1" + { "process" = "in.telnetd" } + { "client" = "all" } + } + { } + { "2" + { "process" = "sshd" } + { "client" = "61." } + { "client" = "62." } + { "client" = "64.179." } + { "client" = "65." } + } + + +let ip_mask = "sshd: 61./255.255.255.255\n" + +test Hosts_Access.lns get ip_mask = + { "1" + { "process" = "sshd" } + { "client" = "61." { "netmask" = "255.255.255.255" } } } + +(* Support options from hosts_options(5) *) +test Hosts_Access.lns get "sshd: all: keepalive\n" = + { "1" + { "process" = "sshd" } + { "client" = "all" } + { "keepalive" } } + +test Hosts_Access.lns get "sshd: all: severity mail.info\n" = + { "1" + { "process" = "sshd" } + { "client" = "all" } + { "severity" = "mail.info" } } + +test Hosts_Access.lns get "sshd: all: severity mail.info : rfc931 5 : DENY\n" = + { "1" + { "process" = "sshd" } + { "client" = "all" } + { "severity" = "mail.info" } + { "rfc931" = "5" } + { "DENY" } } + +(* Ticket #255, from FreeBSD *) +let host_options_cmds = "# You need to be clever with finger; do _not_ backfinger!! You can easily +# start a \"finger war\". +fingerd : ALL \ + : spawn (echo Finger. | \ + /usr/bin/mail -s \"tcpd\: %u@%h[%a] fingered me!\" root) & \ + : deny + +# The rest of the daemons are protected. +ALL : ALL : \ + severity auth.info \ + : twist /bin/echo \"You are not welcome to use %d from %h.\" +" + +test Hosts_Access.lns get host_options_cmds = + { "#comment" = "You need to be clever with finger; do _not_ backfinger!! You can easily" } + { "#comment" = "start a \"finger war\"." } + { "1" + { "process" = "fingerd" } + { "client" = "ALL" } + { "spawn" = "(echo Finger. | \ + /usr/bin/mail -s \"tcpd\\: %u@%h[%a] fingered me!\" root) &" } + { "deny" } } + { } + { "#comment" = "The rest of the daemons are protected." } + { "2" + { "process" = "ALL" } + { "client" = "ALL" } + { "severity" = "auth.info" } + { "twist" = "/bin/echo \"You are not welcome to use %d from %h.\"" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_htpasswd.aug b/Sharp.Augeas.Test/lens/tests/test_htpasswd.aug new file mode 100644 index 0000000..6b45a87 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_htpasswd.aug @@ -0,0 +1,19 @@ +(* +Module: Test_Htpasswd + Provides unit tests and examples for the <Htpasswd> lens. +*) + +module Test_Htpasswd = + +let htpasswd = "foo-plain:bar +foo-crypt:78YuxG9nnfUCo +foo-md5:$apr1$NqCzyXmd$WLc/Wb35AkC.8tQQB3/Uw/ +foo-sha1:{SHA}Ys23Ag/5IOWqZCw9QGaVDdHwH00= +" + +test Htpasswd.lns get htpasswd = + { "foo-plain" = "bar" } + { "foo-crypt" = "78YuxG9nnfUCo" } + { "foo-md5" = "$apr1$NqCzyXmd$WLc/Wb35AkC.8tQQB3/Uw/" } + { "foo-sha1" = "{SHA}Ys23Ag/5IOWqZCw9QGaVDdHwH00=" } + diff --git a/Sharp.Augeas.Test/lens/tests/test_httpd.aug b/Sharp.Augeas.Test/lens/tests/test_httpd.aug new file mode 100644 index 0000000..9887f7a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_httpd.aug @@ -0,0 +1,648 @@ +module Test_httpd = + +(* Check that we can iterate on directive *) +let _ = Httpd.directive+ + +(* Check that we can do a non iterative section *) +let _ = Httpd.section Httpd.directive + +(* directives testing *) +let d1 = "ServerRoot \"/etc/apache2\"\n" +test Httpd.directive get d1 = + { "directive" = "ServerRoot" + { "arg" = "\"/etc/apache2\"" } + } + +(* simple quotes *) +let d1s = "ServerRoot '/etc/apache2'\n" +test Httpd.directive get d1s = + { "directive" = "ServerRoot" + { "arg" = "'/etc/apache2'" } + } + +let d2 = "ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/\n" +test Httpd.directive get d2 = + { "directive" = "ScriptAlias" + { "arg" = "/cgi-bin/" } + { "arg" = "/usr/lib/cgi-bin/" } + } + +let d3 = "LockFile /var/lock/apache2/accept.lock\n" +test Httpd.directive get d3 = + { "directive" = "LockFile" + { "arg" = "/var/lock/apache2/accept.lock" } + } + +let c1 = " +<IfModule> +</IfModule> +" +let c1_put = +" +<IfModule foo bar> +</IfModule> +" + + +test Httpd.lns get c1 = { }{ "IfModule" } + +test Httpd.lns put c1 after set "/IfModule/arg[1]" "foo"; + set "/IfModule/arg[2]" "bar" = c1_put + +let c2 = " +<IfModule !mpm_winnt.c> + <IfModule !mpm_netware.c> + LockFile /var/lock/apache2/accept.lock + </IfModule> +</IfModule> +" + +test Httpd.lns get c2 = + { } + { "IfModule" + { "arg" = "!mpm_winnt.c" } + { "IfModule" + { "arg" = "!mpm_netware.c" } + { "directive" = "LockFile" + { "arg" = "/var/lock/apache2/accept.lock" } + } + } + } + +(* arguments must be the first child of the section *) +test Httpd.lns put c2 after rm "/IfModule/arg"; + insb "arg" "/IfModule/*[1]"; + set "/IfModule/arg" "foo" = +" +<IfModule foo> + <IfModule !mpm_netware.c> + LockFile /var/lock/apache2/accept.lock + </IfModule> +</IfModule> +" + +let c3 = " +<IfModule mpm_event_module> + StartServers 2 + MaxClients 150 + MinSpareThreads 25 + MaxSpareThreads 75 + ThreadLimit 64 + ThreadsPerChild 25 + MaxRequestsPerChild 0 +</IfModule> +" + +test Httpd.lns get c3 = + { } + { "IfModule" + { "arg" = "mpm_event_module" } + { "directive" = "StartServers" + { "arg" = "2" } + } + { "directive" = "MaxClients" + { "arg" = "150" } + } + { "directive" = "MinSpareThreads" + { "arg" = "25" } + } + { "directive" = "MaxSpareThreads" + { "arg" = "75" } + } + { "directive" = "ThreadLimit" + { "arg" = "64" } + } + { "directive" = "ThreadsPerChild" + { "arg" = "25" } + } + { "directive" = "MaxRequestsPerChild" + { "arg" = "0" } + } + } + + + +let c4 = " +<Files ~ \"^\.ht\"> + Order allow,deny + Deny from all + Satisfy all +</Files> +" + +test Httpd.lns get c4 = + { } + { "Files" + { "arg" = "~" } + { "arg" = "\"^\.ht\"" } + { "directive" = "Order" + { "arg" = "allow,deny" } + } + { "directive" = "Deny" + { "arg" = "from" } + { "arg" = "all" } + } + { "directive" = "Satisfy" + { "arg" = "all" } + } + } + + + +let c5 = "LogFormat \"%{User-agent}i\" agent\n" +test Httpd.lns get c5 = + { "directive" = "LogFormat" + { "arg" = "\"%{User-agent}i\"" } + { "arg" = "agent" } + } + +let c7 = "LogFormat \"%v:%p %h %l %u %t \\\"%r\\\" %>s %O \\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\"\" vhost_combined\n" +test Httpd.lns get c7 = + { "directive" = "LogFormat" + { "arg" = "\"%v:%p %h %l %u %t \\\"%r\\\" %>s %O \\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\"\"" } + { "arg" = "vhost_combined" } + } + +let c8 = "IndexIgnore .??* *~ *# RCS CVS *,v *,t \n" +test Httpd.directive get c8 = + { "directive" = "IndexIgnore" + { "arg" = ".??*" } + { "arg" = "*~" } + { "arg" = "*#" } + { "arg" = "RCS" } + { "arg" = "CVS" } + { "arg" = "*,v" } + { "arg" = "*,t" } + } + +(* FIXME: not yet supported: + * The backslash "\" may be used as the last character on a line to indicate + * that the directive continues onto the next line. There must be no other + * characters or white space between the backslash and the end of the line. + *) +let multiline = "Options Indexes \ +FollowSymLinks MultiViews +" + +test Httpd.directive get multiline = + { "directive" = "Options" + { "arg" = "Indexes" } + { "arg" = "FollowSymLinks" } + { "arg" = "MultiViews" } + } + + +let conf2 = "<VirtualHost *:80> + ServerAdmin webmaster@localhost + + DocumentRoot /var/www + <Directory /> + Options FollowSymLinks + AllowOverride None + </Directory> + <Directory /var/www/> + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + allow from all + </Directory> + + ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ + <Directory \"/usr/lib/cgi-bin\"> + AllowOverride None + Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch + Order allow,deny + Allow from all + </Directory> + + ErrorLog /var/log/apache2/error.log + + # Possible values include: debug, info, notice, warn, error, crit, + # alert, emerg. + LogLevel warn + + CustomLog /var/log/apache2/access.log combined + + SSLRequireSSL + + Alias /doc/ \"/usr/share/doc/\" + <Directory \"/usr/share/doc/\"> + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Order deny,allow + Deny from all + Allow from 127.0.0.0/255.0.0.0 ::1/128 + </Directory> + +</VirtualHost> +" + +test Httpd.lns get conf2 = + { "VirtualHost" + { "arg" = "*:80" } + { "directive" = "ServerAdmin" + { "arg" = "webmaster@localhost" } + } + { } + { "directive" = "DocumentRoot" + { "arg" = "/var/www" } + } + { "Directory" + { "arg" = "/" } + { "directive" = "Options" + { "arg" = "FollowSymLinks" } + } + { "directive" = "AllowOverride" + { "arg" = "None" } + } + } + { "Directory" + { "arg" = "/var/www/" } + { "directive" = "Options" + { "arg" = "Indexes" } + { "arg" = "FollowSymLinks" } + { "arg" = "MultiViews" } + } + { "directive" = "AllowOverride" + { "arg" = "None" } + } + { "directive" = "Order" + { "arg" = "allow,deny" } + } + { "directive" = "allow" + { "arg" = "from" } + { "arg" = "all" } + } + } + { "directive" = "ScriptAlias" + { "arg" = "/cgi-bin/" } + { "arg" = "/usr/lib/cgi-bin/" } + } + { "Directory" + { "arg" = "\"/usr/lib/cgi-bin\"" } + { "directive" = "AllowOverride" + { "arg" = "None" } + } + { "directive" = "Options" + { "arg" = "+ExecCGI" } + { "arg" = "-MultiViews" } + { "arg" = "+SymLinksIfOwnerMatch" } + } + { "directive" = "Order" + { "arg" = "allow,deny" } + } + { "directive" = "Allow" + { "arg" = "from" } + { "arg" = "all" } + } + } + { "directive" = "ErrorLog" + { "arg" = "/var/log/apache2/error.log" } + } + { } + { "#comment" = "Possible values include: debug, info, notice, warn, error, crit," } + { "#comment" = "alert, emerg." } + { "directive" = "LogLevel" + { "arg" = "warn" } + } + { } + { "directive" = "CustomLog" + { "arg" = "/var/log/apache2/access.log" } + { "arg" = "combined" } + } + { } + { "directive" = "SSLRequireSSL" } + { } + { "directive" = "Alias" + { "arg" = "/doc/" } + { "arg" = "\"/usr/share/doc/\"" } + } + { "Directory" + { "arg" = "\"/usr/share/doc/\"" } + { "directive" = "Options" + { "arg" = "Indexes" } + { "arg" = "MultiViews" } + { "arg" = "FollowSymLinks" } + } + { "directive" = "AllowOverride" + { "arg" = "None" } + } + { "directive" = "Order" + { "arg" = "deny,allow" } + } + { "directive" = "Deny" + { "arg" = "from" } + { "arg" = "all" } + } + { "directive" = "Allow" + { "arg" = "from" } + { "arg" = "127.0.0.0/255.0.0.0" } + { "arg" = "::1/128" } + } + } + } + +(* Eol comment *) +test Httpd.lns get "<a> # a comment +MyDirective Foo +</a>\n" = + { "a" + { "#comment" = "a comment" } + { "directive" = "MyDirective" { "arg" = "Foo" } } } + +test Httpd.lns get "<a> +# a comment +</a>\n" = + { "a" { "#comment" = "a comment" } } + +(* Test: Httpd.lns + Newlines inside quoted value (GH issue #104) *) +test Httpd.lns get "Single 'Foo\\ +bar' +Double \"Foo\\ +bar\"\n" = + { "directive" = "Single" + { "arg" = "'Foo\\\nbar'" } } + { "directive" = "Double" + { "arg" = "\"Foo\\\nbar\"" } } + +(* Test: Httpd.lns + Support >= in tags (GH #154) *) +let versioncheck = " +<IfVersion = 2.1> +<IfModule !proxy_ajp_module> +LoadModule proxy_ajp_module modules/mod_proxy_ajp.so +</IfModule> +</IfVersion> + +<IfVersion >= 2.4> +<IfModule !proxy_ajp_module> +LoadModule proxy_ajp_module modules/mod_proxy_ajp.so +</IfModule> +</IfVersion> +" + +test Httpd.lns get versioncheck = + { } + { "IfVersion" + { "arg" = "=" } + { "arg" = "2.1" } + { "IfModule" + { "arg" = "!proxy_ajp_module" } + { "directive" = "LoadModule" + { "arg" = "proxy_ajp_module" } + { "arg" = "modules/mod_proxy_ajp.so" } + } + } + } + { "IfVersion" + { "arg" = ">=" } + { "arg" = "2.4" } + { "IfModule" + { "arg" = "!proxy_ajp_module" } + { "directive" = "LoadModule" + { "arg" = "proxy_ajp_module" } + { "arg" = "modules/mod_proxy_ajp.so" } + } + } + } + + +(* GH #220 *) +let double_comment = "<IfDefine Foo> +## +## Comment +## +</IfDefine>\n" + +test Httpd.lns get double_comment = + { "IfDefine" + { "arg" = "Foo" } + { "#comment" = "#" } + { "#comment" = "# Comment" } + { "#comment" = "#" } + } + +let single_comment = "<IfDefine Foo> +# +## Comment +## +</IfDefine>\n" + +test Httpd.lns get single_comment = + { "IfDefine" + { "arg" = "Foo" } + { "#comment" = "# Comment" } + { "#comment" = "#" } + } + +let single_empty = "<IfDefine Foo> +# + +</IfDefine>\n" +test Httpd.lns get single_empty = + { "IfDefine" + { "arg" = "Foo" } + } + +let eol_empty = "<IfDefine Foo> # +</IfDefine>\n" +test Httpd.lns get eol_empty = + { "IfDefine" + { "arg" = "Foo" } + } + +(* Issue #140 *) +test Httpd.lns get "<IfModule mod_ssl.c> + # one comment + # another comment +</IfModule>\n" = + { "IfModule" + { "arg" = "mod_ssl.c" } + { "#comment" = "one comment" } + { "#comment" = "another comment" } + } + +(* Issue #307: backslashes in regexes *) +test Httpd.lns get "<VirtualHost *:80> + RewriteRule ^/(.*) http\:\/\/example\.com\/$1 [L,R,NE] + RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1] +</VirtualHost>\n" = + { "VirtualHost" + { "arg" = "*:80" } + { "directive" = "RewriteRule" + { "arg" = "^/(.*)" } + { "arg" = "http\:\/\/example\.com\/$1" } + { "arg" = "[L,R,NE]" } } + { "directive" = "RewriteRule" + { "arg" = "\.css\.gz$" } + { "arg" = "-" } + { "arg" = "[T=text/css,E=no-gzip:1]" } } } + +(* https://github.com/letsencrypt/letsencrypt/issues/1294#issuecomment-161805063 *) +test Httpd.lns get "<IfModule> +</ifModule>\n" = + { "IfModule" } + +(* https://github.com/letsencrypt/letsencrypt/issues/1693 *) +test Httpd.lns get "<IfModule mod_ssl.c> + <VirtualHost *:443> + ServerAdmin admin@example.com + </VirtualHost> </IfModule>\n" = + { "IfModule" + { "arg" = "mod_ssl.c" } + { "VirtualHost" + { "arg" = "*:443" } + { "directive" = "ServerAdmin" + { "arg" = "admin@example.com" } } } } + +(* Double quotes inside braces in directive arguments + https://github.com/letsencrypt/letsencrypt/issues/1766 *) +test Httpd.lns get "SSLRequire %{SSL_CLIENT_S_DN_CN} in {\"foo@bar.com\", bar@foo.com}\n" = + { "directive" = "SSLRequire" + { "arg" = "%{SSL_CLIENT_S_DN_CN}" } + { "arg" = "in" } + { "wordlist" + { "arg" = "\"foo@bar.com\"" } + { "arg" = "bar@foo.com" } } } + +(* Issue #330: optional end double quote to directive arg, for messages *) +test Httpd.lns get "SSLCipherSuite \"EECDH+ECDSA+AESGCM EECDH+aRS$\n" = + { "directive" = "SSLCipherSuite" + { "arg" = "\"EECDH+ECDSA+AESGCM EECDH+aRS$" } } + +test Httpd.lns get "ErrorDocument 404 \"The requested file favicon.ico was not found.\n" = + { "directive" = "ErrorDocument" + { "arg" = "404" } + { "arg" = "\"The requested file favicon.ico was not found." } } + +(* Quotes inside a unquoted directive argument + https://github.com/letsencrypt/letsencrypt/issues/1934 *) +test Httpd.lns get "<VirtualHost *:80> + WSGIDaemonProcess _graphite processes=5 threads=5 display-name='%{GROUP}' inactivity-timeout=120 user=_graphite group=_graphite +</VirtualHost>\n" = + { "VirtualHost" + { "arg" = "*:80" } + { "directive" = "WSGIDaemonProcess" + { "arg" = "_graphite" } + { "arg" = "processes=5" } + { "arg" = "threads=5" } + { "arg" = "display-name='%{GROUP}'" } + { "arg" = "inactivity-timeout=120" } + { "arg" = "user=_graphite" } + { "arg" = "group=_graphite" } } } + +(* Issue #327: perl blocks *) +test Httpd.lns get "<Perl> + Apache::AuthDBI->setCacheTime(600); +</Perl>\n" = + { "Perl" = "\n Apache::AuthDBI->setCacheTime(600);\n" } + +(* Line continuations inside VirtualHost blocks *) +test Httpd.lns get "<VirtualHost \\ + 0.0.0.0:7080 \\ + [00000:000:000:0000::2]:7080 \\ + 0.0.0.0:7080 \\ + 127.0.0.1:7080 \\ + > +</VirtualHost>\n" = + { "VirtualHost" + { "arg" = "0.0.0.0:7080" } + { "arg" = "[00000:000:000:0000::2]:7080" } + { "arg" = "0.0.0.0:7080" } + { "arg" = "127.0.0.1:7080" } } + +(* Blank line continuations inside VirtualHost blocks *) +test Httpd.lns get "<VirtualHost \\ + 0.0.0.0:7080 \\ + \\ + 0.0.0.0:7080 \\ + \\ + > +</VirtualHost>\n" = + { "VirtualHost" + { "arg" = "0.0.0.0:7080" } + { "arg" = "0.0.0.0:7080" } } + +(* Non-continuation backslashes inside VirtualHost section headings *) +test Httpd.lns get "<FilesMatch \.php$> + ExpiresActive Off +</FilesMatch>\n" = + { "FilesMatch" + { "arg" = "\.php$" } + { "directive" = "ExpiresActive" + { "arg" = "Off" } } } + +(* Escaped spaces in directive and section arguments *) +test Httpd.lns get "RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC]\n" = + { "directive" = "RewriteCond" + { "arg" = "%{THE_REQUEST}" } + { "arg" = "^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/" } + { "arg" = "[NC]" } } + +test Httpd.lns get "<FilesMatch \ test\.php$></FilesMatch>\n" = + { "FilesMatch" + { "arg" = "\ test\.php$" } } + +(* Continuations in comments cause the comment to be continued without a new comment character *) +test Httpd.lns get "#ServerRoot \\\n /var/www\n" = + { "#comment" = "ServerRoot \\\n /var/www" } + +(* Empty comments can contain continuations, too. Issue #423 *) +test Httpd.lns get "# \\\n\n" = { } +test Httpd.comment get "# a\\\n\n" = { "#comment" = "a" } +test Httpd.comment get "# \\\na\\\n\n" = { "#comment" = "a" } +test Httpd.comment get "# \\\n\\\na \\\n\\\n\n" = { "#comment" = "a" } + +(* Comparison with empty string did not work. Issue #429 *) +test Httpd.dir_args get ">\"a\"" = { "arg" = ">\"a\"" } +test Httpd.dir_args get ">\"\"" = { "arg" = ">\"\"" } +test Httpd.directive get "RewriteCond ${movedPageMap:$1} >\"a\"\n" = + { "directive" = "RewriteCond" + { "arg" = "${movedPageMap:$1}" } + { "arg" = ">\"a\"" }} +test Httpd.directive get "RewriteCond ${movedPageMap:$1} >\"\"\n" = + { "directive" = "RewriteCond" + { "arg" = "${movedPageMap:$1}" } + { "arg" = ">\"\"" }} + +(* Quoted arguments may or may not have space spearating them. Issue #435 *) +test Httpd.directive get + "ProxyPassReverse \"/js\" \"http://127.0.0.1:8123/js\"\n" = + { "directive" = "ProxyPassReverse" + { "arg" = "\"/js\"" } + { "arg" = "\"http://127.0.0.1:8123/js\"" } } + +test Httpd.directive get + "ProxyPassReverse \"/js\"\"http://127.0.0.1:8123/js\"\n" = + { "directive" = "ProxyPassReverse" + { "arg" = "\"/js\"" } + { "arg" = "\"http://127.0.0.1:8123/js\"" } } + +(* Don't get confused by quoted strings inside bare arguments. Issue #470 *) +test Httpd.directive get + "RequestHeader set X-Forwarded-Proto https expr=(%{HTTP:CF-Visitor}='{\"scheme\":\"https\"}')\n" = + { "directive" = "RequestHeader" + { "arg" = "set" } + { "arg" = "X-Forwarded-Proto" } + { "arg" = "https" } + { "arg" = "expr=(%{HTTP:CF-Visitor}='{\"scheme\":\"https\"}')" } } + +(* Issue #577: we make the newline starting a section optional, including + an empty comment at the end of the line. This used to miss empty comments + with whitespace *) +test Httpd.lns get "<If cond>#\n</If>\n" = { "If" { "arg" = "cond" } } + +test Httpd.lns get "<If cond># \n</If>\n" = { "If" { "arg" = "cond" } } + +test Httpd.lns get "<If cond>\n# \n</If>\n" = { "If" { "arg" = "cond" } } + +test Httpd.lns get "<If cond># text\n</If>\n" = + { "If" + { "arg" = "cond" } + { "#comment" = "text" } } + +test Httpd.lns get "<If cond>\n\t# text\n</If>\n" = + { "If" + { "arg" = "cond" } + { "#comment" = "text" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_inetd.aug b/Sharp.Augeas.Test/lens/tests/test_inetd.aug new file mode 100644 index 0000000..93e035b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_inetd.aug @@ -0,0 +1,181 @@ +module Test_inetd = + + (* The standard "parse a bucket of text" test *) + let conf = "# Blah di blah comment + +simplesrv stream tcp nowait fred /usr/bin/simplesrv +arguserve dgram udp wait mary /usr/bin/usenet foo bar wombat + +1234 stream tcp nowait fred /usr/bin/numbersrv + +127.0.0.1:addrsrv stream tcp nowait fred /usr/bin/addrsrv +127.0.0.1,10.0.0.1:multiaddrsrv stream tcp nowait fred /usr/bin/multiaddrsrv +faff.fred.com: +127.0.0.1,faff.fred.com: +*: +[::1]:addrsrv stream tcp nowait fred /usr/bin/addrsrv + +sndbufsrv stream tcp,sndbuf=12k nowait fred /usr/bin/sndbufsrv +rcvbufsrv stream tcp,rcvbuf=24k nowait fred /usr/bin/rcvbufsrv +allbufsrv stream tcp,sndbuf=1m,rcvbuf=24k nowait fred /usr/bin/allbufsrv + +dotgroupsrv stream tcp nowait fred.wilma /usr/bin/dotgroupsrv +colongroupsrv stream tcp nowait fred:wilma /usr/bin/colongroupsrv + +maxsrv stream tcp nowait.20 fred /usr/bin/maxsrv + +dummy/1 tli rpc/circuit_v,udp wait root /tmp/test_svc test_svc +" + + test Inetd.lns get conf = + { "#comment" = "Blah di blah comment" } + {} + { "service" = "simplesrv" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/simplesrv" } + } + { "service" = "arguserve" + { "socket" = "dgram" } + { "protocol" = "udp" } + { "wait" = "wait" } + { "user" = "mary" } + { "command" = "/usr/bin/usenet" } + { "arguments" + { "1" = "foo" } + { "2" = "bar" } + { "3" = "wombat" } + } + } + {} + { "service" = "1234" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/numbersrv" } + } + {} + { "service" = "addrsrv" + { "address" + { "1" = "127.0.0.1" } + } + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/addrsrv" } + } + { "service" = "multiaddrsrv" + { "address" + { "1" = "127.0.0.1" } + { "2" = "10.0.0.1" } + } + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/multiaddrsrv" } + } + { "address" + { "1" = "faff.fred.com" } + } + { "address" + { "1" = "127.0.0.1" } + { "2" = "faff.fred.com" } + } + { "address" + { "1" = "*" } + } + { "service" = "addrsrv" + { "address" + { "1" = "[::1]" } + } + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/addrsrv" } + } + {} + { "service" = "sndbufsrv" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "sndbuf" = "12k" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/sndbufsrv" } + } + { "service" = "rcvbufsrv" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "rcvbuf" = "24k" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/rcvbufsrv" } + } + { "service" = "allbufsrv" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "sndbuf" = "1m" } + { "rcvbuf" = "24k" } + { "wait" = "nowait" } + { "user" = "fred" } + { "command" = "/usr/bin/allbufsrv" } + } + {} + { "service" = "dotgroupsrv" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "user" = "fred" } + { "group" = "wilma" } + { "command" = "/usr/bin/dotgroupsrv" } + } + { "service" = "colongroupsrv" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "user" = "fred" } + { "group" = "wilma" } + { "command" = "/usr/bin/colongroupsrv" } + } + {} + { "service" = "maxsrv" + { "socket" = "stream" } + { "protocol" = "tcp" } + { "wait" = "nowait" } + { "max" = "20" } + { "user" = "fred" } + { "command" = "/usr/bin/maxsrv" } + } + {} + { "rpc_service" = "dummy" + { "version" = "1" } + { "endpoint-type" = "tli" } + { "protocol" = "circuit_v" } + { "protocol" = "udp" } + { "wait" = "wait" } + { "user" = "root" } + { "command" = "/tmp/test_svc" } + { "arguments" + { "1" = "test_svc" } } + } + + +(**************************************************************************) + + (* Test new file creation *) + + test Inetd.lns put "" after + set "/service" "faffsrv"; + set "/service/socket" "stream"; + set "/service/protocol" "tcp"; + set "/service/wait" "nowait"; + set "/service/user" "george"; + set "/service/command" "/sbin/faffsrv" + = "faffsrv stream tcp nowait george /sbin/faffsrv\n" + + diff --git a/Sharp.Augeas.Test/lens/tests/test_inifile.aug b/Sharp.Augeas.Test/lens/tests/test_inifile.aug new file mode 100644 index 0000000..873e1fd --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_inifile.aug @@ -0,0 +1,396 @@ +(* +Module: Test_IniFile + Provides unit tests and examples for the <IniFile> module. + +About: Tests to run + + The tests are run with all combinations of the following + three parameters: + + > separator : (a) default (/[:=]/ "=") ; (b) "=" "=" + > comment : (c) default (/[;#]/ ";") ; (d) ";" ";" + > empty lines : (e) default ; (f) noempty + +*) + +module Test_IniFile = + + (* ALL TESTS TO RUN *) + + + (* Group: TEST a/c/e *) + (* Variable: comment_ace *) + let comment_ace = IniFile.comment IniFile.comment_re IniFile.comment_default + (* Variable: sep_ace *) + let sep_ace = IniFile.sep IniFile.sep_re IniFile.sep_default + (* Variable: entry_ace *) + let entry_ace = IniFile.entry IniFile.entry_re sep_ace comment_ace + (* Variable: title_ace *) + let title_ace = IniFile.title IniFile.record_re + (* Variable: record_ace *) + let record_ace = IniFile.record title_ace entry_ace + (* Variable: lns_ace *) + let lns_ace = IniFile.lns record_ace comment_ace + (* Variable: conf_ace *) + let conf_ace = "# comment with sharp + +[section1] +test_ace = value # end of line comment +test_ace = +test_ace = \"value with spaces\" +; comment with colon + +" + (* Test: lns_ace + Testing the a/c/e combination *) + test lns_ace get conf_ace = + { "#comment" = "comment with sharp" } + {} + { "section1" + { "test_ace" = "value" + { "#comment" = "end of line comment" } } + { "test_ace" } + { "test_ace" = "value with spaces" } + { "#comment" = "comment with colon" } + {} } + + test lns_ace put conf_ace after + set "section1/foo" "yes" = "# comment with sharp + +[section1] +test_ace = value # end of line comment +test_ace = +test_ace = \"value with spaces\" +; comment with colon + +foo=yes +" + + (* Test: lns_ace + Quotes can appear within bare values *) + test lns_ace get "[section]\ntest_ace = value \"with quotes\" inside\n" = + { "section" { "test_ace" = "value \"with quotes\" inside" } } + + (* Group: TEST a/c/f *) + (* Variable: comment_acf *) + let comment_acf = IniFile.comment IniFile.comment_re IniFile.comment_default + (* Variable: sep_acf *) + let sep_acf = IniFile.sep IniFile.sep_re IniFile.sep_default + (* Variable: entry_acf *) + let entry_acf = IniFile.entry IniFile.entry_re sep_acf comment_acf + (* Variable: title_acf *) + let title_acf = IniFile.title IniFile.record_re + (* Variable: record_acf *) + let record_acf = IniFile.record_noempty title_acf entry_acf + (* Variable: lns_acf *) + let lns_acf = IniFile.lns_noempty record_acf comment_acf + (* Variable: conf_acf *) + let conf_acf = "# comment with sharp +[section1] +test_acf = value +test_acf = +test_acf : value2 # end of line comment +; comment with colon +" + (* Test: lns_acf + Testing the a/c/f combination *) + test lns_acf get conf_acf = + { "#comment" = "comment with sharp" } + { "section1" + { "test_acf" = "value" } + { "test_acf" } + { "test_acf" = "value2" + { "#comment" = "end of line comment" } } + { "#comment" = "comment with colon" } } + + + (* Group: TEST a/d/e *) + (* Variable: comment_ade *) + let comment_ade = IniFile.comment ";" ";" + (* Variable: sep_ade *) + let sep_ade = IniFile.sep IniFile.sep_re IniFile.sep_default + (* Variable: entry_ade *) + let entry_ade = IniFile.entry IniFile.entry_re sep_ade comment_ade + (* Variable: title_ade *) + let title_ade = IniFile.title IniFile.record_re + (* Variable: record_ade *) + let record_ade = IniFile.record title_ade entry_ade + (* Variable: lns_ade *) + let lns_ade = IniFile.lns record_ade comment_ade + (* Variable: conf_ade *) + let conf_ade = "; a first comment with colon +[section1] +test_ade = value +test_ade : value2 ; end of line comment +; comment with colon + +test_ade = +" + (* Test: lns_ade + Testing the a/d/e combination *) + test lns_ade get conf_ade = + { "#comment" = "a first comment with colon" } + { "section1" + { "test_ade" = "value" } + { "test_ade" = "value2" + { "#comment" = "end of line comment" } } + { "#comment" = "comment with colon" } + {} + { "test_ade" } } + + + (* Group: TEST a/d/f *) + (* Variable: comment_adf *) + let comment_adf = IniFile.comment ";" ";" + (* Variable: sep_adf *) + let sep_adf = IniFile.sep IniFile.sep_re IniFile.sep_default + (* Variable: entry_adf *) + let entry_adf = IniFile.entry IniFile.entry_re sep_adf comment_adf + (* Variable: title_adf *) + let title_adf = IniFile.title IniFile.record_re + (* Variable: record_adf *) + let record_adf = IniFile.record_noempty title_adf entry_adf + (* Variable: lns_adf *) + let lns_adf = IniFile.lns_noempty record_adf comment_adf + (* Variable: conf_adf *) + let conf_adf = "; a first comment with colon +[section1] +test_adf = value +test_adf : value2 ; end of line comment +; comment with colon +test_adf = +" + (* Test: lns_adf + Testing the a/d/f combination *) + test lns_adf get conf_adf = + { "#comment" = "a first comment with colon" } + { "section1" + { "test_adf" = "value" } + { "test_adf" = "value2" + { "#comment" = "end of line comment" } } + { "#comment" = "comment with colon" } + { "test_adf" } } + + + (* Group: TEST b/c/e *) + (* Variable: comment_bce *) + let comment_bce = IniFile.comment IniFile.comment_re IniFile.comment_default + (* Variable: sep_bce *) + let sep_bce = IniFile.sep "=" "=" + (* Variable: entry_bce *) + let entry_bce = IniFile.entry IniFile.entry_re sep_bce comment_bce + (* Variable: title_bce *) + let title_bce = IniFile.title IniFile.record_re + (* Variable: record_bce *) + let record_bce = IniFile.record title_bce entry_bce + (* Variable: lns_bce *) + let lns_bce = IniFile.lns record_bce comment_bce + (* Variable: conf_bce *) + let conf_bce = "# comment with sharp + +[section1] +test_bce = value # end of line comment +; comment with colon + +test_bce = +" + (* Test: lns_bce + Testing the b/c/e combination *) + test lns_bce get conf_bce = + { "#comment" = "comment with sharp" } + {} + { "section1" + { "test_bce" = "value" + { "#comment" = "end of line comment" } } + { "#comment" = "comment with colon" } + {} + { "test_bce" } } + + + (* Group: TEST b/c/f *) + (* Variable: comment_bcf *) + let comment_bcf = IniFile.comment IniFile.comment_re IniFile.comment_default + (* Variable: sep_bcf *) + let sep_bcf = IniFile.sep "=" "=" + (* Variable: entry_bcf *) + let entry_bcf = IniFile.entry IniFile.entry_re sep_bcf comment_bcf + (* Variable: title_bcf *) + let title_bcf = IniFile.title IniFile.record_re + (* Variable: record_bcf *) + let record_bcf = IniFile.record_noempty title_bce entry_bcf + (* Variable: lns_bcf *) + let lns_bcf = IniFile.lns_noempty record_bce comment_bcf + (* Variable: conf_bcf *) + let conf_bcf = "# conf with sharp +[section1] +test_bcf = value # end of line comment +; comment with colon +test_bcf = +" + (* Test: lns_bcf + Testing the b/c/f combination *) + test lns_bcf get conf_bcf = + { "#comment" = "conf with sharp" } + { "section1" + { "test_bcf" = "value" + { "#comment" = "end of line comment" } } + { "#comment" = "comment with colon" } + { "test_bcf" } } + + + (* Group: TEST b/d/e *) + (* Variable: comment_bde *) + let comment_bde = IniFile.comment ";" ";" + (* Variable: sep_bde *) + let sep_bde = IniFile.sep "=" "=" + (* Variable: entry_bde *) + let entry_bde = IniFile.entry IniFile.entry_re sep_bde comment_bde + (* Variable: title_bde *) + let title_bde = IniFile.title IniFile.record_re + (* Variable: record_bde *) + let record_bde = IniFile.record title_bde entry_bde + (* Variable: lns_bde *) + let lns_bde = IniFile.lns record_bde comment_bde + (* Variable: conf_bde *) + let conf_bde = "; first comment with colon + +[section1] +test_bde = value ; end of line comment +; comment with colon + +test_bde = +" + (* Test: lns_bde + Testing the b/d/e combination *) + test lns_bde get conf_bde = + { "#comment" = "first comment with colon" } + {} + { "section1" + { "test_bde" = "value" + { "#comment" = "end of line comment" } } + { "#comment" = "comment with colon" } + {} + { "test_bde" } } + + + (* Group: TEST b/d/f *) + (* Variable: comment_bdf *) + let comment_bdf = IniFile.comment ";" ";" + (* Variable: sep_bdf *) + let sep_bdf = IniFile.sep "=" "=" + (* Variable: entry_bdf *) + let entry_bdf = IniFile.entry IniFile.entry_re sep_bdf comment_bdf + (* Variable: title_bdf *) + let title_bdf = IniFile.title IniFile.record_re + (* Variable: record_bdf *) + let record_bdf = IniFile.record_noempty title_bdf entry_bdf + (* Variable: lns_bdf *) + let lns_bdf = IniFile.lns_noempty record_bdf comment_bdf + (* Variable: conf_bdf *) + let conf_bdf = "; first comment with colon +[section1] +test_bdf = value ; end of line comment +; comment with colon +test_bdf = +" + (* Test: lns_bdf + Testing the b/d/f combination *) + test lns_bdf get conf_bdf = + { "#comment" = "first comment with colon" } + { "section1" + { "test_bdf" = "value" + { "#comment" = "end of line comment" } } + { "#comment" = "comment with colon" } + { "test_bdf" } } + + + (* Group: TEST multiline values *) + (* Variable: multiline_test *) + let multiline_test = "test_ace = val1\n val2\n val3\n" + (* Variable: multiline_nl *) + let multiline_nl = "test_ace =\n val2\n val3\n" + (* Variable: multiline_ace *) + let multiline_ace = IniFile.entry_multiline IniFile.entry_re sep_ace comment_ace + (* Test: multiline_ace + Testing the a/c/e combination with a multiline entry *) + test multiline_ace get multiline_test = + { "test_ace" = "val1\n val2\n val3" } + (* Test: multiline_nl + Multiline values can begin with a single newline *) + test multiline_ace get multiline_nl = + { "test_ace" = "\n val2\n val3" } + + (* Test: lns_ace + Ticket #243 *) + test lns_ace get "[section1] +ticket_243 = \"value1;value2#value3\" # end of line comment +" = + { "section1" + { "ticket_243" = "value1;value2#value3" + { "#comment" = "end of line comment" } + } + } + + (* Group: TEST list entries *) + (* Variable: list_test *) + let list_test = "test_ace = val1,val2,val3 # a comment\n" + (* Lens: list_ace *) + let list_ace = IniFile.entry_list IniFile.entry_re sep_ace RX.word Sep.comma comment_ace + (* Test: list_ace + Testing the a/c/e combination with a list entry *) + test list_ace get list_test = + { "test_ace" + { "1" = "val1" } + { "2" = "val2" } + { "3" = "val3" } + { "#comment" = "a comment" } + } + + (* Variable: list_nocomment_test *) + let list_nocomment_test = "test_ace = val1,val2,val3 \n" + (* Lens: list_nocomment_ace *) + let list_nocomment_ace = IniFile.entry_list_nocomment IniFile.entry_re sep_ace RX.word Sep.comma + (* Test: list_nocomment_ace + Testing the a/c/e combination with a list entry without end-of-line comment *) + test list_nocomment_ace get list_nocomment_test = + { "test_ace" + { "1" = "val1" } + { "2" = "val2" } + { "3" = "val3" } + } + + (* Test: IniFile.lns_loose *) + test IniFile.lns_loose get conf_ace = + { "section" = ".anon" + { "#comment" = "comment with sharp" } + { } + } + { "section" = "section1" + { "test_ace" = "value" + { "#comment" = "end of line comment" } + } + { "test_ace" } + { "test_ace" = "value with spaces" } + { "#comment" = "comment with colon" } + { } + } + + (* Test: IniFile.lns_loose_multiline *) + test IniFile.lns_loose_multiline get conf_ace = + { "section" = ".anon" + { "#comment" = "comment with sharp" } + { } + } + { "section" = "section1" + { "test_ace" = "value" + { "#comment" = "end of line comment" } + } + { "test_ace" } + { "test_ace" = "value with spaces" } + { "#comment" = "comment with colon" } + { } + } + + test IniFile.lns_loose_multiline get multiline_test = + { "section" = ".anon" { "test_ace" = "val1\n val2\n val3" } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_inittab.aug b/Sharp.Augeas.Test/lens/tests/test_inittab.aug new file mode 100644 index 0000000..2704ff8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_inittab.aug @@ -0,0 +1,69 @@ +module Test_inittab = + + let simple = "id:5:initdefault:\n" + + let inittab = "id:5:initdefault: +# System initialization. +si::sysinit:/etc/rc.d/rc.sysinit + +# Trap CTRL-ALT-DELETE +ca::ctrlaltdel:/sbin/shutdown -t3 -r now + +l0:0:wait:/etc/rc.d/rc 0 +" + + test Inittab.lns get inittab = + { "id" + { "runlevels" = "5" } + { "action" = "initdefault" } + { "process" = "" } } + { "#comment" = "System initialization." } + { "si" + { "runlevels" = "" } + { "action" = "sysinit" } + { "process" = "/etc/rc.d/rc.sysinit" } } + { } + { "#comment" = "Trap CTRL-ALT-DELETE" } + { "ca" + { "runlevels" = "" } + { "action" = "ctrlaltdel" } + { "process" = "/sbin/shutdown -t3 -r now" } } + { } + { "l0" + { "runlevels" = "0" } + { "action" = "wait" } + { "process" = "/etc/rc.d/rc 0" } } + + test Inittab.lns put simple after rm "/id/process" = * + + test Inittab.lns put simple after set "/id/runlevels" "3" = + "id:3:initdefault:\n" + + test Inittab.lns get + "co:2345:respawn:/usr/bin/command # End of line comment\n" = + { "co" + { "runlevels" = "2345" } + { "action" = "respawn" } + { "process" = "/usr/bin/command " } + { "#comment" = "End of line comment" } } + + test Inittab.lns get + "co:2345:respawn:/usr/bin/blank_comment # \t \n" = + { "co" + { "runlevels" = "2345" } + { "action" = "respawn" } + { "process" = "/usr/bin/blank_comment " } + { "#comment" = "" } } + + (* Bug 108: allow ':' in the process field *) + test Inittab.record get + "co:234:respawn:ttymon -p \"console login: \"\n" = + { "co" + { "runlevels" = "234" } + { "action" = "respawn" } + { "process" = "ttymon -p \"console login: \"" } } + + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_inputrc.aug b/Sharp.Augeas.Test/lens/tests/test_inputrc.aug new file mode 100644 index 0000000..1535697 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_inputrc.aug @@ -0,0 +1,178 @@ +(* +Module: Test_Inputrc + Provides unit tests and examples for the <Inputrc> lens. +*) + +module Test_Inputrc = + +(* Variable: conf *) +let conf = "# /etc/inputrc - global inputrc for libreadline +# See readline(3readline) and `info rluserman' for more information. + +# Be 8 bit clean. +set input-meta on +set output-meta on + +# To allow the use of 8bit-characters like the german umlauts, uncomment +# the line below. However this makes the meta key not work as a meta key, +# which is annoying to those which don't need to type in 8-bit characters. + +# set convert-meta off + +# try to enable the application keypad when it is called. Some systems +# need this to enable the arrow keys. +# set enable-keypad on + +# see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys + +# do not bell on tab-completion +# set bell-style none +# set bell-style visible + +# some defaults / modifications for the emacs mode +$if mode=emacs + +# allow the use of the Home/End keys +\"\\e[1~\": beginning-of-line +\"\\e[4~\": end-of-line + +# allow the use of the Delete/Insert keys +\"\\e[3~\": delete-char +\"\\e[2~\": quoted-insert + +# mappings for \"page up\" and \"page down\" to step to the beginning/end +# of the history +# \"\\e[5~\": beginning-of-history +# \"\\e[6~\": end-of-history + +# alternate mappings for \"page up\" and \"page down\" to search the history +# \"\\e[5~\": history-search-backward +# \"\\e[6~\": history-search-forward + +# mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving +\"\\e[1;5C\": forward-word +\"\\e[1;5D\": backward-word +\"\\e[5C\": forward-word +\"\\e[5D\": backward-word +\"\\e\\e[C\": forward-word +\"\\e\\e[D\": backward-word + +$if term=rxvt +\"\\e[8~\": end-of-line +\"\\eOc\": forward-word +\"\\eOd\": backward-word +$else +\"\\e[G\": \",\" +$endif + +# for non RH/Debian xterm, can't hurt for RH/Debian xterm +# \"\\eOH\": beginning-of-line +# \"\\eOF\": end-of-line + +# for freebsd console +# \"\\e[H\": beginning-of-line +# \"\\e[F\": end-of-line + +$endif +" + +(* Test: Inputrc.lns *) +test Inputrc.lns get conf = + { "#comment" = "/etc/inputrc - global inputrc for libreadline" } + { "#comment" = "See readline(3readline) and `info rluserman' for more information." } + { } + { "#comment" = "Be 8 bit clean." } + { "input-meta" = "on" } + { "output-meta" = "on" } + { } + { "#comment" = "To allow the use of 8bit-characters like the german umlauts, uncomment" } + { "#comment" = "the line below. However this makes the meta key not work as a meta key," } + { "#comment" = "which is annoying to those which don't need to type in 8-bit characters." } + { } + { "#comment" = "set convert-meta off" } + { } + { "#comment" = "try to enable the application keypad when it is called. Some systems" } + { "#comment" = "need this to enable the arrow keys." } + { "#comment" = "set enable-keypad on" } + { } + { "#comment" = "see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys" } + { } + { "#comment" = "do not bell on tab-completion" } + { "#comment" = "set bell-style none" } + { "#comment" = "set bell-style visible" } + { } + { "#comment" = "some defaults / modifications for the emacs mode" } + { "@if" = "mode=emacs" + { } + { "#comment" = "allow the use of the Home/End keys" } + { "entry" = "\\e[1~" + { "mapping" = "beginning-of-line" } + } + { "entry" = "\\e[4~" + { "mapping" = "end-of-line" } + } + { } + { "#comment" = "allow the use of the Delete/Insert keys" } + { "entry" = "\\e[3~" + { "mapping" = "delete-char" } + } + { "entry" = "\\e[2~" + { "mapping" = "quoted-insert" } + } + { } + { "#comment" = "mappings for \"page up\" and \"page down\" to step to the beginning/end" } + { "#comment" = "of the history" } + { "#comment" = "\"\\e[5~\": beginning-of-history" } + { "#comment" = "\"\\e[6~\": end-of-history" } + { } + { "#comment" = "alternate mappings for \"page up\" and \"page down\" to search the history" } + { "#comment" = "\"\\e[5~\": history-search-backward" } + { "#comment" = "\"\\e[6~\": history-search-forward" } + { } + { "#comment" = "mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving" } + { "entry" = "\\e[1;5C" + { "mapping" = "forward-word" } + } + { "entry" = "\\e[1;5D" + { "mapping" = "backward-word" } + } + { "entry" = "\\e[5C" + { "mapping" = "forward-word" } + } + { "entry" = "\\e[5D" + { "mapping" = "backward-word" } + } + { "entry" = "\\e\\e[C" + { "mapping" = "forward-word" } + } + { "entry" = "\\e\\e[D" + { "mapping" = "backward-word" } + } + { } + { "@if" = "term=rxvt" + { "entry" = "\\e[8~" + { "mapping" = "end-of-line" } + } + { "entry" = "\\eOc" + { "mapping" = "forward-word" } + } + { "entry" = "\\eOd" + { "mapping" = "backward-word" } + } + { "@else" + { "entry" = "\\e[G" + { "mapping" = "\",\"" } + } + } + } + { } + { "#comment" = "for non RH/Debian xterm, can't hurt for RH/Debian xterm" } + { "#comment" = "\"\\eOH\": beginning-of-line" } + { "#comment" = "\"\\eOF\": end-of-line" } + { } + { "#comment" = "for freebsd console" } + { "#comment" = "\"\\e[H\": beginning-of-line" } + { "#comment" = "\"\\e[F\": end-of-line" } + { } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_interfaces.aug b/Sharp.Augeas.Test/lens/tests/test_interfaces.aug new file mode 100644 index 0000000..271d8d8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_interfaces.aug @@ -0,0 +1,141 @@ +module Test_interfaces = + + let conf ="# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). +# The loopback network interface + +source /etc/network/interfaces.d/*.conf + +auto lo eth0 #foo +allow-hotplug eth1 + +iface lo inet \ + loopback + +mapping eth0 + script /usr/local/sbin/map-scheme +map HOME eth0-home + map \ + WORK eth0-work + +iface eth0-home inet static + +address 192.168.1.1 + netmask 255.255.255.0 + bridge_maxwait 0 +# up flush-mail + down Mambo #5 + + iface eth0-work inet dhcp + +allow-auto eth1 +iface eth1 inet dhcp + +iface tap0 inet static + vde2-switch - + +mapping eth1 + # I like mapping ... + # ... and I like comments + + script\ + /usr/local/sbin/map-scheme + +iface bond0 inet dhcp + bridge-ports eth2 eth3 eth4 + +iface br0 inet static + bond-slaves eth5 eth6 + address 10.0.0.1 + netmask 255.0.0.0 + +source /etc/network.d/*.net.conf +" + + test Interfaces.lns get conf = + { "#comment" = "This file describes the network interfaces available on your system"} + { "#comment" = "and how to activate them. For more information, see interfaces(5)." } + { "#comment" = "The loopback network interface" } + {} + {"source" = "/etc/network/interfaces.d/*.conf"} + {} + { "auto" + { "1" = "lo" } + { "2" = "eth0" } + { "3" = "#foo" } } + { "allow-hotplug" { "1" = "eth1" } } + { } + { "iface" = "lo" + { "family" = "inet"} + { "method" = "loopback"} {} } + { "mapping" = "eth0" + { "script" = "/usr/local/sbin/map-scheme"} + { "map" = "HOME eth0-home"} + { "map" = "WORK eth0-work"} + {} } + { "iface" = "eth0-home" + { "family" = "inet"} + { "method" = "static"} + {} + { "address" = "192.168.1.1" } + { "netmask" = "255.255.255.0" } + { "bridge_maxwait" = "0" } + { "#comment" = "up flush-mail" } + { "down" = "Mambo #5" } + {} } + { "iface" = "eth0-work" + { "family" = "inet"} + { "method" = "dhcp"} + {} } + { "auto" + { "1" = "eth1" } } + { "iface" = "eth1" + { "family" = "inet"} + { "method" = "dhcp"} + {} } + { "iface" = "tap0" + { "family" = "inet" } + { "method" = "static" } + { "vde2-switch" = "-" } + {} } + { "mapping" = "eth1" + { "#comment" = "I like mapping ..." } + { "#comment" = "... and I like comments" } + {} + { "script" = "/usr/local/sbin/map-scheme"} + {} } + { "iface" = "bond0" + { "family" = "inet" } + { "method" = "dhcp" } + { "bridge-ports" + { "1" = "eth2" } + { "2" = "eth3" } + { "3" = "eth4" } + } + {} } + { "iface" = "br0" + { "family" = "inet" } + { "method" = "static" } + { "bond-slaves" + { "1" = "eth5" } + { "2" = "eth6" } + } + { "address" = "10.0.0.1" } + { "netmask" = "255.0.0.0" } + {} } + {"source" = "/etc/network.d/*.net.conf"} + +test Interfaces.lns put "" after + set "/iface[1]" "eth0"; + set "/iface[1]/family" "inet"; + set "/iface[1]/method" "dhcp" += "iface eth0 inet dhcp\n" + +test Interfaces.lns put "" after + set "/source[0]" "/etc/network/conf.d/*.conf" += "source /etc/network/conf.d/*.conf\n" + +(* Test: Interfaces.lns + source-directory (Issue #306) *) +test Interfaces.lns get "source-directory interfaces.d\n" = + { "source-directory" = "interfaces.d" } diff --git a/Sharp.Augeas.Test/lens/tests/test_iproute2.aug b/Sharp.Augeas.Test/lens/tests/test_iproute2.aug new file mode 100644 index 0000000..2acd367 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_iproute2.aug @@ -0,0 +1,63 @@ +module Test_IPRoute2 = + +let conf = " +# /etc/iproute2/rt_tables +# +# reserved values +# +255 local +254 main +253 default +0 unspec +# +# local +# +#1 inr.ruhep +200 h3g0 +201 adsl1 +202 adsl2 +203 adsl3 +204 adsl4 +205 wifi0 +# +# From rt_dsfield +# +0x00 default +0x80 flash-override + +# From rt_protos +# +254 gated/aggr +253 gated/bgp +" + +test IPRoute2.lns get conf = + { } + { "#comment" = "/etc/iproute2/rt_tables" } + { } + { "#comment" = "reserved values" } + { } + { "255" = "local" } + { "254" = "main" } + { "253" = "default" } + { "0" = "unspec" } + { } + { "#comment" = "local" } + { } + { "#comment" = "1 inr.ruhep" } + { "200" = "h3g0" } + { "201" = "adsl1" } + { "202" = "adsl2" } + { "203" = "adsl3" } + { "204" = "adsl4" } + { "205" = "wifi0" } + { } + { "#comment" = "From rt_dsfield" } + { } + { "0x00" = "default" } + { "0x80" = "flash-override" } + { } + { "#comment" = "From rt_protos" } + { } + { "254" = "gated/aggr" } + { "253" = "gated/bgp" } diff --git a/Sharp.Augeas.Test/lens/tests/test_iptables.aug b/Sharp.Augeas.Test/lens/tests/test_iptables.aug new file mode 100644 index 0000000..5be9afc --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_iptables.aug @@ -0,0 +1,240 @@ +module Test_iptables = + +let add_rule = Iptables.table_rule +let ipt_match = Iptables.ipt_match + +test add_rule get +"-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT\n" = + { "append" = "INPUT" + { "match" = "state" } + { "state" = "ESTABLISHED,RELATED" } + { "jump" = "ACCEPT" } } + +test add_rule get +"-A INPUT -p icmp -j \tACCEPT \n" = + { "append" = "INPUT" + { "protocol" = "icmp" } + { "jump" = "ACCEPT" } } + +test add_rule get +"-A INPUT -i lo -j ACCEPT\n" = + { "append" = "INPUT" + { "in-interface" = "lo" } + { "jump" = "ACCEPT" } } + +test ipt_match get " -m tcp -p tcp --dport 53" = + { "match" = "tcp" } { "protocol" = "tcp" } { "dport" = "53" } + +let arule = " -m state --state NEW -m tcp -p tcp --dport 53 -j ACCEPT" + +test add_rule get ("--append INPUT" . arule . "\n") = + { "append" = "INPUT" + { "match" = "state" } + { "state" = "NEW" } + { "match" = "tcp" } + { "protocol" = "tcp" } + { "dport" = "53" } + { "jump" = "ACCEPT" } } + +test ipt_match get arule = + { "match" = "state" } { "state" = "NEW" } { "match" = "tcp" } + { "protocol" = "tcp" } { "dport" = "53" } { "jump" = "ACCEPT" } + +test ipt_match get ("-A INPUT" . arule) = * + +test ipt_match get " -p esp -j ACCEPT" = + { "protocol" = "esp" } { "jump" = "ACCEPT" } + +test ipt_match get + " -m state --state NEW -m udp -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT" + = + { "match" = "state" } { "state" = "NEW" } { "match" = "udp" } + { "protocol" = "udp" } { "dport" = "5353" } + { "destination" = "224.0.0.251" } { "jump" = "ACCEPT" } + +test add_rule get + "-I FORWARD -m physdev --physdev-is-bridged -j ACCEPT\n" = + { "insert" = "FORWARD" + { "match" = "physdev" } { "physdev-is-bridged" } { "jump" = "ACCEPT" } } + +test add_rule get + "-A INPUT -j REJECT --reject-with icmp-host-prohibited\n" = + { "append" = "INPUT" + { "jump" = "REJECT" } { "reject-with" = "icmp-host-prohibited" } } + +test add_rule get + "-A RH-Firewall-1-INPUT -p icmp --icmp-type any -j ACCEPT\n" = + { "append" = "RH-Firewall-1-INPUT" + { "protocol" = "icmp" } + { "icmp-type" = "any" } + { "jump" = "ACCEPT" } } + +test Iptables.table get "*filter +:RH-Firewall-1-INPUT - [0:0] +-A FORWARD -j RH-Firewall-1-INPUT +-A RH-Firewall-1-INPUT -i lo -j ACCEPT +COMMIT\n" = + { "table" = "filter" + { "chain" = "RH-Firewall-1-INPUT" + { "policy" = "-" } } + { "append" = "FORWARD" + { "jump" = "RH-Firewall-1-INPUT" } } + { "append" = "RH-Firewall-1-INPUT" + { "in-interface" = "lo" } + { "jump" = "ACCEPT" } } } + +test Iptables.table get "*filter + +:RH-Firewall-1-INPUT - [0:0] + +-A FORWARD -j RH-Firewall-1-INPUT + +COMMIT\n" = + { "table" = "filter" + { } + { "chain" = "RH-Firewall-1-INPUT" + { "policy" = "-" } } + { } + { "append" = "FORWARD" + { "jump" = "RH-Firewall-1-INPUT" } } + { } } + +let conf = "# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002 +*filter +:INPUT DROP [1:229] +:FORWARD DROP [0:0] +:OUTPUT DROP [0:0] +-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT + +-I FORWARD -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT + +# comments and blank lines are allow between rules + +-A FORWARD -i eth1 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT +--append OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT +COMMIT +# Completed on Wed Apr 24 10:19:55 2002 +# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002 +*mangle +:PREROUTING ACCEPT [658:32445] + +:INPUT ACCEPT [658:32445] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [891:68234] +:POSTROUTING ACCEPT [891:68234] +COMMIT +# Completed on Wed Apr 24 10:19:55 2002 +# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002 +*nat +:PREROUTING ACCEPT [1:229] +:POSTROUTING ACCEPT [3:450] +# The output chain +:OUTPUT ACCEPT [3:450] +# insert something +--insert POSTROUTING -o eth0 -j SNAT --to-source 195.233.192.1 \t +# and now commit +COMMIT +# Completed on Wed Apr 24 10:19:55 2002\n" + +test Iptables.lns get conf = + { "#comment" = + "Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002" } + { "table" = "filter" + { "chain" = "INPUT" { "policy" = "DROP" } } + { "chain" = "FORWARD" { "policy" = "DROP" } } + { "chain" = "OUTPUT" { "policy" = "DROP" } } + { "append" = "INPUT" + { "match" = "state" } + { "state" = "RELATED,ESTABLISHED" } + { "jump" = "ACCEPT" } } + {} + { "insert" = "FORWARD" + { "in-interface" = "eth0" } + { "match" = "state" } + { "state" = "RELATED,ESTABLISHED" } + { "jump" = "ACCEPT" } } + {} + { "#comment" = "comments and blank lines are allow between rules" } + {} + { "append" = "FORWARD" + { "in-interface" = "eth1" } + { "match" = "state" } + { "state" = "NEW,RELATED,ESTABLISHED" } + { "jump" = "ACCEPT" } } + { "append" = "OUTPUT" + { "match" = "state" } + { "state" = "NEW,RELATED,ESTABLISHED" } + { "jump" = "ACCEPT" } } } + { "#comment" = "Completed on Wed Apr 24 10:19:55 2002" } + { "#comment" = + "Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002" } + { "table" = "mangle" + { "chain" = "PREROUTING" { "policy" = "ACCEPT" } } + {} + { "chain" = "INPUT" { "policy" = "ACCEPT" } } + { "chain" = "FORWARD" { "policy" = "ACCEPT" } } + { "chain" = "OUTPUT" { "policy" = "ACCEPT" } } + { "chain" = "POSTROUTING" { "policy" = "ACCEPT" } } } + { "#comment" = "Completed on Wed Apr 24 10:19:55 2002" } + { "#comment" = + "Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002" } + { "table" = "nat" + { "chain" = "PREROUTING" { "policy" = "ACCEPT" } } + { "chain" = "POSTROUTING" { "policy" = "ACCEPT" } } + { "#comment" = "The output chain" } + { "chain" = "OUTPUT" { "policy" = "ACCEPT" } } + { "#comment" = "insert something" } + { "insert" = "POSTROUTING" + { "out-interface" = "eth0" } + { "jump" = "SNAT" } + { "to-source" = "195.233.192.1" } } + { "#comment" = "and now commit" } } + { "#comment" = "Completed on Wed Apr 24 10:19:55 2002" } + +test ipt_match get " -m comment --comment \"A comment\"" = + { "match" = "comment" } + { "comment" = "\"A comment\"" } + +(* + * Test the various schemes for negation that iptables supports + * + * Note that the two ways in which a parameter can be negated lead to + * two different trees that mean the same. + *) +test add_rule get "-I POSTROUTING ! -d 192.168.122.0/24 -j MASQUERADE\n" = + { "insert" = "POSTROUTING" + { "destination" = "192.168.122.0/24" + { "not" } } + { "jump" = "MASQUERADE" } } + +test add_rule get "-I POSTROUTING -d ! 192.168.122.0/24 -j MASQUERADE\n" = + { "insert" = "POSTROUTING" + { "destination" = "! 192.168.122.0/24" } + { "jump" = "MASQUERADE" } } + +test add_rule put "-I POSTROUTING ! -d 192.168.122.0/24 -j MASQUERADE\n" + after rm "/insert/destination/not" = + "-I POSTROUTING -d 192.168.122.0/24 -j MASQUERADE\n" + +(* I have no idea if iptables will accept double negations, but we + * allow it syntactically *) +test add_rule put "-I POSTROUTING -d ! 192.168.122.0/24 -j MASQUERADE\n" + after clear "/insert/destination/not" = + "-I POSTROUTING ! -d ! 192.168.122.0/24 -j MASQUERADE\n" + +test Iptables.chain get ":tcp_packets - [0:0] +" = + { "chain" = "tcp_packets" { "policy" = "-" } } + +(* Bug #157 *) +test ipt_match get " --tcp-flags SYN,RST,ACK,FIN SYN" = + { "tcp-flags" + { "mask" = "SYN" } + { "mask" = "RST" } + { "mask" = "ACK" } + { "mask" = "FIN" } + { "set" = "SYN" } } + +(* Bug #224 *) +test ipt_match get " --icmpv6-type neighbor-solicitation" = + { "icmpv6-type" = "neighbor-solicitation" } diff --git a/Sharp.Augeas.Test/lens/tests/test_iscsid.aug b/Sharp.Augeas.Test/lens/tests/test_iscsid.aug new file mode 100644 index 0000000..2a8a532 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_iscsid.aug @@ -0,0 +1,69 @@ +(* +Module: Test_Iscsid + Provides unit tests and examples for the <Iscsid> lens. +*) + +module Test_Iscsid = + +(* Variable: conf + A full configuration *) +let conf = "################ +# iSNS settings +################ +# Address of iSNS server +isns.address = 127.0.0.1 +isns.port = 3260 + +# ************* +# CHAP Settings +# ************* + +# To enable CHAP authentication set node.session.auth.authmethod +# to CHAP. The default is None. +node.session.auth.authmethod = CHAP + +# To set a CHAP username and password for initiator +# authentication by the target(s), uncomment the following lines: +node.session.auth.username = someuser1 +node.session.auth.password = somep$31#$^&7! + +# To enable CHAP authentication for a discovery session to the target +# set discovery.sendtargets.auth.authmethod to CHAP. The default is None. +discovery.sendtargets.auth.authmethod = CHAP + +# To set a discovery session CHAP username and password for the initiator +# authentication by the target(s), uncomment the following lines: +discovery.sendtargets.auth.username = someuser3 +discovery.sendtargets.auth.password = _09+7)(,./?;'p[] +" + +(* Test: Iscsid.lns + Test the full <conf> *) +test Iscsid.lns get conf = { "#comment" = "###############" } + { "#comment" = "iSNS settings" } + { "#comment" = "###############" } + { "#comment" = "Address of iSNS server" } + { "isns.address" = "127.0.0.1" } + { "isns.port" = "3260" } + { } + { "#comment" = "*************" } + { "#comment" = "CHAP Settings" } + { "#comment" = "*************" } + { } + { "#comment" = "To enable CHAP authentication set node.session.auth.authmethod" } + { "#comment" = "to CHAP. The default is None." } + { "node.session.auth.authmethod" = "CHAP" } + { } + { "#comment" = "To set a CHAP username and password for initiator" } + { "#comment" = "authentication by the target(s), uncomment the following lines:" } + { "node.session.auth.username" = "someuser1" } + { "node.session.auth.password" = "somep$31#$^&7!" } + { } + { "#comment" = "To enable CHAP authentication for a discovery session to the target" } + { "#comment" = "set discovery.sendtargets.auth.authmethod to CHAP. The default is None." } + { "discovery.sendtargets.auth.authmethod" = "CHAP" } + { } + { "#comment" = "To set a discovery session CHAP username and password for the initiator" } + { "#comment" = "authentication by the target(s), uncomment the following lines:" } + { "discovery.sendtargets.auth.username" = "someuser3" } + { "discovery.sendtargets.auth.password" = "_09+7)(,./?;'p[]" } diff --git a/Sharp.Augeas.Test/lens/tests/test_jaas.aug b/Sharp.Augeas.Test/lens/tests/test_jaas.aug new file mode 100644 index 0000000..5f2bfb1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_jaas.aug @@ -0,0 +1,144 @@ +(* Module Jaas *) +(* Author: Simon Vocella <voxsim@gmail.com> *) +module Test_jaas = + +let conf = " +/* + This is the JAAS configuration file used by the Shibboleth IdP. + + A JAAS configuration file is a grouping of LoginModules defined in the following manner: + <LoginModuleClass> <Flag> <ModuleOptions>; + + LoginModuleClass - fully qualified class name of the LoginModule class + Flag - indicates whether the requirement level for the modules; + allowed values: required, requisite, sufficient, optional + ModuleOptions - a space delimited list of name=\"value\" options + + For complete documentation on the format of this file see: + http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html + + For LoginModules available within the Sun JVM see: + http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tutorials/LoginConfigFile.html + + Warning: Do NOT use Sun's JNDI LoginModule to authentication against an LDAP directory, + Use the LdapLoginModule that ships with Shibboleth and is demonstrated below. + + Note, the application identifier MUST be ShibUserPassAuth +*/ + + +ShibUserPassAuth { + +// Example LDAP authentication +// See: https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPass +/* + edu.vt.middleware.ldap.jaas.LdapLoginModule required + ldapUrl=\"ldap://ldap.example.org\" + baseDn=\"ou=people,dc=example,dc=org\" + ssl=\"true\" + userFilter=\"uid={0}\"; +*/ + +// Example Kerberos authentication, requires Sun's JVM +// See: https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPass +/* + com.sun.security.auth.module.Krb5LoginModule required + useKeyTab=\"true\" + keyTab=\"/path/to/idp/keytab/file\"; +*/ + + edu.vt.middleware.ldap.jaas.LdapLoginModule required + host = \"ldap://127.0.0.1:389\" + base = \"dc=example,dc=com\" + serviceUser = \"cn=admin,dc=example,dc=com\" + serviceCredential = \"ldappassword\" + ssl = \"false\" + userField = \"uid\" + // Example comment within definition + subtreeSearch = \"true\"; +}; + +NetAccountAuth { + // Test of optionless flag + nz.ac.auckland.jaas.Krb5LoginModule required; +}; + +com.sun.security.jgss.krb5.initiate { + // Test of omitted linebreaks and naked boolean + com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true; +};" + +test Jaas.lns get conf = + { } + { "#mcomment" + { "1" = "This is the JAAS configuration file used by the Shibboleth IdP." } + { "2" = "A JAAS configuration file is a grouping of LoginModules defined in the following manner:" } + { "3" = "<LoginModuleClass> <Flag> <ModuleOptions>;" } + { "4" = "LoginModuleClass - fully qualified class name of the LoginModule class" } + { "5" = "Flag - indicates whether the requirement level for the modules;" } + { "6" = "allowed values: required, requisite, sufficient, optional" } + { "7" = "ModuleOptions - a space delimited list of name=\"value\" options" } + { "8" = "For complete documentation on the format of this file see:" } + { "9" = "http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html" } + { "10" = "For LoginModules available within the Sun JVM see:" } + { "11" = "http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/tutorials/LoginConfigFile.html" } + { "12" = "Warning: Do NOT use Sun's JNDI LoginModule to authentication against an LDAP directory," } + { "13" = "Use the LdapLoginModule that ships with Shibboleth and is demonstrated below." } + { "14" = "Note, the application identifier MUST be ShibUserPassAuth" } + } + { } + { } + { "login" = "ShibUserPassAuth" + { } + { "#comment" = "Example LDAP authentication" } + { "#comment" = "See: https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPass" } + { "#mcomment" + { "1" = "edu.vt.middleware.ldap.jaas.LdapLoginModule required" } + { "2" = "ldapUrl=\"ldap://ldap.example.org\"" } + { "3" = "baseDn=\"ou=people,dc=example,dc=org\"" } + { "4" = "ssl=\"true\"" } + { "5" = "userFilter=\"uid={0}\";" } + } + { } + { "#comment" = "Example Kerberos authentication, requires Sun's JVM" } + { "#comment" = "See: https://wiki.shibboleth.net/confluence/display/SHIB2/IdPAuthUserPass" } + { "#mcomment" + { "1" = "com.sun.security.auth.module.Krb5LoginModule required" } + { "2" = "useKeyTab=\"true\"" } + { "3" = "keyTab=\"/path/to/idp/keytab/file\";" } + } + { } + { "loginModuleClass" = "edu.vt.middleware.ldap.jaas.LdapLoginModule" + { "flag" = "required" + { "host" = "\"ldap://127.0.0.1:389\"" } + { "base" = "\"dc=example,dc=com\"" } + { "serviceUser" = "\"cn=admin,dc=example,dc=com\"" } + { "serviceCredential" = "\"ldappassword\"" } + { "ssl" = "\"false\"" } + { "userField" = "\"uid\"" } + { "#comment" = "Example comment within definition" } + { "subtreeSearch" = "\"true\"" } + } + } + { } + } + { } + { } + { "login" = "NetAccountAuth" + { "#comment" = "Test of optionless flag" } + { "loginModuleClass" = "nz.ac.auckland.jaas.Krb5LoginModule" + { "flag" = "required" } + } + { } + } + { } + { } + { "login" = "com.sun.security.jgss.krb5.initiate" + { "#comment" = "Test of omitted linebreaks and naked boolean" } + { "loginModuleClass" = "com.sun.security.auth.module.Krb5LoginModule" + { "flag" = "required" + { "useTicketCache" = "true" } + } + } + { } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_jettyrealm.aug b/Sharp.Augeas.Test/lens/tests/test_jettyrealm.aug new file mode 100644 index 0000000..620ffa3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_jettyrealm.aug @@ -0,0 +1,51 @@ +(* +Module: Test_JettyRealm + Provides unit tests and examples for the <JettyRealm> lens. +*) + +module Test_JettyRealm = + +(* Variable: conf *) +let conf = "### Comment +admin: admin, admin +" + +(* Variable: conf_norealm *) +let conf_norealm = "### Comment +admin: admin +" + +(* Variable: new_conf *) +let new_conf = "### Comment +admin: password, admin +" + +let lns = JettyRealm.lns + +(* Test: JettyRealm.lns + * Get test against tree structure +*) +test lns get conf = + { "#comment" = "## Comment" } + { "user" + { "username" = "admin" } + { "password" = "admin" } + { "realm" = "admin" } + } + +(* Test: JettyRealm.lns + * Get test against tree structure without a realm +*) +test lns get conf_norealm = + { "#comment" = "## Comment" } + { "user" + { "username" = "admin" } + { "password" = "admin" } + } + +(* Test: JettyRealm.lns + * Put test changing password to password +*) +test lns put conf after set "/user/password" "password" = new_conf + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_jmxaccess.aug b/Sharp.Augeas.Test/lens/tests/test_jmxaccess.aug new file mode 100644 index 0000000..14e095e --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_jmxaccess.aug @@ -0,0 +1,35 @@ +(* +Module: Test_JMXAccess + Provides unit tests and examples for the <JMXAccess> lens. +*) + +module Test_JMXAccess = + +(* Variable: conf *) +let conf = "# Comment +admin readwrite +" + +(* Variable: new_conf *) +let new_conf = "# Comment +admin readonly +" + +let lns = JMXAccess.lns + +(* Test: JMXAccess.lns + * Get test against tree structure +*) +test lns get conf = + { "#comment" = "Comment" } + { "user" + { "username" = "admin" } + { "access" = "readwrite" } + } + +(* Test: JMXAccess.lns + * Put test changing access to readonly +*) +test lns put conf after set "/user/access" "readonly" = new_conf + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_jmxpassword.aug b/Sharp.Augeas.Test/lens/tests/test_jmxpassword.aug new file mode 100644 index 0000000..5365162 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_jmxpassword.aug @@ -0,0 +1,35 @@ +(* +Module: Test_JMXPassword + Provides unit tests and examples for the <JMXPassword> lens. +*) + +module Test_JMXPassword = + +(* Variable: conf *) +let conf = "# Comment +admin activemq +" + +(* Variable: new_conf *) +let new_conf = "# Comment +admin password +" + +let lns = JMXPassword.lns + +(* Test: JMXPassword.lns + * Get test against tree structure +*) +test lns get conf = + { "#comment" = "Comment" } + { "user" + { "username" = "admin" } + { "password" = "activemq" } + } + +(* Test: JMXPassword.lns + * Put test changing password to password +*) +test lns put conf after set "/user/password" "password" = new_conf + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_json.aug b/Sharp.Augeas.Test/lens/tests/test_json.aug new file mode 100644 index 0000000..1ad0624 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_json.aug @@ -0,0 +1,512 @@ +module Test_json = + +let lns = Json.lns + +(* Non recursive checks *) + +(* Typecheck finitely deep nesting *) +let value0 = Json.str | Json.number | Json.const /true|false|null/ +let value1 = Json.fix_value value0 +(* This test is usually too heavy, activate at will +let value2 = Json.fix_value value1 +*) + +test lns get "\"menu\"" = { "string" = "menu" } + +test lns get "true" = { "const" = "true" } + +test lns get "3.141" = { "number" = "3.141" } + +test lns get "{ \"key\" : 666 }" = + { "dict" { "entry" = "key" { "number" = "666" } } } + +test lns get "[true, 0, \"yo\"]" = + { "array" { "const" = "true" } { "number" = "0" } { "string" = "yo" } } + +test lns get "{\"a\" : true}" = + { "dict" { "entry" = "a" { "const" = "true" } } } + +test lns get "{ \"0\":true, \"1\":false }" = + { "dict" { "entry" = "0" { "const" = "true" } } + { "entry" = "1" { "const" = "false" } } } + + +test lns get "{ \"0\": true, \"1\":false }" = + { "dict" + { "entry" = "0" { "const" = "true" } } + { "entry" = "1" { "const" = "false" } } } + +test lns get "{\"menu\": \"entry one\"}" = + { "dict" { "entry" = "menu" { "string" = "entry one" } } } + +test lns get "[ ]" = + { "array" } + +test lns get "{}" = + { "dict" } + +let s = "{\"menu\": { + \"id\": \"file\", + \"value\": \"File\", + \"popup\": { + \"menuitem\": [ + {\"value\": \"New\", \"onclick\": \"CreateNewDoc()\"}, + {\"value\": \"Open\", \"onclick\": \"OpenDoc()\"}, + {\"value\": \"Close\", \"onclick\": \"CloseDoc()\"} + ] + } +}}" + +test lns get s = + { "dict" + { "entry" = "menu" + { "dict" + { } + { "entry" = "id" { "string" = "file" } } + { } + { "entry" = "value" { "string" = "File" } } + { } + { "entry" = "popup" + { "dict" + { } + { "entry" = "menuitem" + { "array" + { } + { "dict" + { "entry" = "value" { "string" = "New" } } + { "entry" = "onclick" + { "string" = "CreateNewDoc()" } } } + { } + { "dict" + { "entry" = "value" { "string" = "Open" } } + { "entry" = "onclick" { "string" = "OpenDoc()" } } } + { } + { "dict" + { "entry" = "value" { "string" = "Close" } } + { "entry" = "onclick" { "string" = "CloseDoc()" } } + { } + } + { } } } { } } } } } } + +let t = " +{\"web-app\": { + \"servlet\": [ + { + \"servlet-name\": \"cofaxCDS\", + \"servlet-class\": \"org.cofax.cds.CDSServlet\", + \"init-param\": { + \"configGlossary:installationAt\": \"Philadelphia, PA\", + \"configGlossary:adminEmail\": \"ksm@pobox.com\", + \"configGlossary:poweredBy\": \"Cofax\", + \"configGlossary:poweredByIcon\": \"/images/cofax.gif\", + \"configGlossary:staticPath\": \"/content/static\", + \"templateProcessorClass\": \"org.cofax.WysiwygTemplate\", + \"templateLoaderClass\": \"org.cofax.FilesTemplateLoader\", + \"templatePath\": \"templates\", + \"templateOverridePath\": \"\", + \"defaultListTemplate\": \"listTemplate.htm\", + \"defaultFileTemplate\": \"articleTemplate.htm\", + \"useJSP\": false, + \"jspListTemplate\": \"listTemplate.jsp\", + \"jspFileTemplate\": \"articleTemplate.jsp\", + \"cachePackageTagsTrack\": 200, + \"cachePackageTagsStore\": 200, + \"cachePackageTagsRefresh\": 60, + \"cacheTemplatesTrack\": 100, + \"cacheTemplatesStore\": 50, + \"cacheTemplatesRefresh\": 15, + \"cachePagesTrack\": 200, + \"cachePagesStore\": 100, + \"cachePagesRefresh\": 10, + \"cachePagesDirtyRead\": 10, + \"searchEngineListTemplate\": \"forSearchEnginesList.htm\", + \"searchEngineFileTemplate\": \"forSearchEngines.htm\", + \"searchEngineRobotsDb\": \"WEB-INF/robots.db\", + \"useDataStore\": true, + \"dataStoreClass\": \"org.cofax.SqlDataStore\", + \"redirectionClass\": \"org.cofax.SqlRedirection\", + \"dataStoreName\": \"cofax\", + \"dataStoreDriver\": \"com.microsoft.jdbc.sqlserver.SQLServerDriver\", + \"dataStoreUrl\": \"jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon\", + \"dataStoreUser\": \"sa\", + \"dataStorePassword\": \"dataStoreTestQuery\", + \"dataStoreTestQuery\": \"SET NOCOUNT ON;select test='test';\", + \"dataStoreLogFile\": \"/usr/local/tomcat/logs/datastore.log\", + \"dataStoreInitConns\": 10, + \"dataStoreMaxConns\": 100, + \"dataStoreConnUsageLimit\": 100, + \"dataStoreLogLevel\": \"debug\", + \"maxUrlLength\": 500}}, + { + \"servlet-name\": \"cofaxEmail\", + \"servlet-class\": \"org.cofax.cds.EmailServlet\", + \"init-param\": { + \"mailHost\": \"mail1\", + \"mailHostOverride\": \"mail2\"}}, + { + \"servlet-name\": \"cofaxAdmin\", + \"servlet-class\": \"org.cofax.cds.AdminServlet\"}, + + { + \"servlet-name\": \"fileServlet\", + \"servlet-class\": \"org.cofax.cds.FileServlet\"}, + { + \"servlet-name\": \"cofaxTools\", + \"servlet-class\": \"org.cofax.cms.CofaxToolsServlet\", + \"init-param\": { + \"templatePath\": \"toolstemplates/\", + \"log\": 1, + \"logLocation\": \"/usr/local/tomcat/logs/CofaxTools.log\", + \"logMaxSize\": \"\", + \"dataLog\": 1, + \"dataLogLocation\": \"/usr/local/tomcat/logs/dataLog.log\", + \"dataLogMaxSize\": \"\", + \"removePageCache\": \"/content/admin/remove?cache=pages&id=\", + \"removeTemplateCache\": \"/content/admin/remove?cache=templates&id=\", + \"fileTransferFolder\": \"/usr/local/tomcat/webapps/content/fileTransferFolder\", + \"lookInContext\": 1, + \"adminGroupID\": 4, + \"betaServer\": true}}], + \"servlet-mapping\": { + \"cofaxCDS\": \"/\", + \"cofaxEmail\": \"/cofaxutil/aemail/*\", + \"cofaxAdmin\": \"/admin/*\", + \"fileServlet\": \"/static/*\", + \"cofaxTools\": \"/tools/*\"}, + + \"taglib\": { + \"taglib-uri\": \"cofax.tld\", + \"taglib-location\": \"/WEB-INF/tlds/cofax.tld\"}}}" + +test lns get t = + { } + { "dict" + { "entry" = "web-app" + { "dict" + { } + { "entry" = "servlet" + { "array" + { } + { "dict" + { } + { "entry" = "servlet-name" { "string" = "cofaxCDS" } } + { } + { "entry" = "servlet-class" + { "string" = "org.cofax.cds.CDSServlet" } } + { } + { "entry" = "init-param" + { "dict" + { } + { "entry" = "configGlossary:installationAt" + { "string" = "Philadelphia, PA" } } + { } + { "entry" = "configGlossary:adminEmail" + { "string" = "ksm@pobox.com" } } + { } + { "entry" = "configGlossary:poweredBy" + { "string" = "Cofax" } } + { } + { "entry" = "configGlossary:poweredByIcon" + { "string" = "/images/cofax.gif" } } + { } + { "entry" = "configGlossary:staticPath" + { "string" = "/content/static" } } + { } + { "entry" = "templateProcessorClass" + { "string" = "org.cofax.WysiwygTemplate" } } + { } + { "entry" = "templateLoaderClass" + { "string" = "org.cofax.FilesTemplateLoader" } } + { } + { "entry" = "templatePath" + { "string" = "templates" } } + { } + { "entry" = "templateOverridePath" + { "string" = "" } } + { } + { "entry" = "defaultListTemplate" + { "string" = "listTemplate.htm" } } + { } + { "entry" = "defaultFileTemplate" + { "string" = "articleTemplate.htm" } } + { } + { "entry" = "useJSP" + { "const" = "false" } } + { } + { "entry" = "jspListTemplate" + { "string" = "listTemplate.jsp" } } + { } + { "entry" = "jspFileTemplate" + { "string" = "articleTemplate.jsp" } } + { } + { "entry" = "cachePackageTagsTrack" + { "number" = "200" } } + { } + { "entry" = "cachePackageTagsStore" + { "number" = "200" } } + { } + { "entry" = "cachePackageTagsRefresh" + { "number" = "60" } } + { } + { "entry" = "cacheTemplatesTrack" + { "number" = "100" } } + { } + { "entry" = "cacheTemplatesStore" + { "number" = "50" } } + { } + { "entry" = "cacheTemplatesRefresh" + { "number" = "15" } } + { } + { "entry" = "cachePagesTrack" + { "number" = "200" } } + { } + { "entry" = "cachePagesStore" + { "number" = "100" } } + { } + { "entry" = "cachePagesRefresh" + { "number" = "10" } } + { } + { "entry" = "cachePagesDirtyRead" + { "number" = "10" } } + { } + { "entry" = "searchEngineListTemplate" + { "string" = "forSearchEnginesList.htm" } } + { } + { "entry" = "searchEngineFileTemplate" + { "string" = "forSearchEngines.htm" } } + { } + { "entry" = "searchEngineRobotsDb" + { "string" = "WEB-INF/robots.db" } } + { } + { "entry" = "useDataStore" + { "const" = "true" } } + { } + { "entry" = "dataStoreClass" + { "string" = "org.cofax.SqlDataStore" } } + { } + { "entry" = "redirectionClass" + { "string" = "org.cofax.SqlRedirection" } } + { } + { "entry" = "dataStoreName" + { "string" = "cofax" } } + { } + { "entry" = "dataStoreDriver" + { "string" = "com.microsoft.jdbc.sqlserver.SQLServerDriver" } } + { } + { "entry" = "dataStoreUrl" + { "string" = "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon" } } + { } + { "entry" = "dataStoreUser" + { "string" = "sa" } } + { } + { "entry" = "dataStorePassword" + { "string" = "dataStoreTestQuery" } } + { } + { "entry" = "dataStoreTestQuery" + { "string" = "SET NOCOUNT ON;select test='test';" } } + { } + { "entry" = "dataStoreLogFile" + { "string" = "/usr/local/tomcat/logs/datastore.log" } } + { } + { "entry" = "dataStoreInitConns" + { "number" = "10" } } + { } + { "entry" = "dataStoreMaxConns" + { "number" = "100" } } + { } + { "entry" = "dataStoreConnUsageLimit" + { "number" = "100" } } + { } + { "entry" = "dataStoreLogLevel" + { "string" = "debug" } } + { } + { "entry" = "maxUrlLength" + { "number" = "500" } } } } } + { } + { "dict" + { } + { "entry" = "servlet-name" + { "string" = "cofaxEmail" } } + { } + { "entry" = "servlet-class" + { "string" = "org.cofax.cds.EmailServlet" } } + { } + { "entry" = "init-param" + { "dict" + { } + { "entry" = "mailHost" + { "string" = "mail1" } } + { } + { "entry" = "mailHostOverride" + { "string" = "mail2" } } } } } + { } + { "dict" + { } + { "entry" = "servlet-name" + { "string" = "cofaxAdmin" } } + { } + { "entry" = "servlet-class" + { "string" = "org.cofax.cds.AdminServlet" } } } + { } + { } + { "dict" + { } + { "entry" = "servlet-name" + { "string" = "fileServlet" } } + { } + { "entry" = "servlet-class" + { "string" = "org.cofax.cds.FileServlet" } } } + { } + { "dict" + { } + { "entry" = "servlet-name" + { "string" = "cofaxTools" } } + { } + { "entry" = "servlet-class" + { "string" = "org.cofax.cms.CofaxToolsServlet" } } + { } + { "entry" = "init-param" + { "dict" + { } + { "entry" = "templatePath" + { "string" = "toolstemplates/" } } + { } + { "entry" = "log" + { "number" = "1" } } + { } + { "entry" = "logLocation" + { "string" = "/usr/local/tomcat/logs/CofaxTools.log" } } + { } + { "entry" = "logMaxSize" + { "string" = "" } } + { } + { "entry" = "dataLog" + { "number" = "1" } } + { } + { "entry" = "dataLogLocation" + { "string" = "/usr/local/tomcat/logs/dataLog.log" } } + { } + { "entry" = "dataLogMaxSize" + { "string" = "" } } + { } + { "entry" = "removePageCache" + { "string" = "/content/admin/remove?cache=pages&id=" } } + { } + { "entry" = "removeTemplateCache" + { "string" = "/content/admin/remove?cache=templates&id=" } } + { } + { "entry" = "fileTransferFolder" + { "string" = "/usr/local/tomcat/webapps/content/fileTransferFolder" } } + { } + { "entry" = "lookInContext" + { "number" = "1" } } + { } + { "entry" = "adminGroupID" + { "number" = "4" } } + { } + { "entry" = "betaServer" + { "const" = "true" } } } } } } } + { } + { "entry" = "servlet-mapping" + { "dict" + { } + { "entry" = "cofaxCDS" + { "string" = "/" } } + { } + { "entry" = "cofaxEmail" + { "string" = "/cofaxutil/aemail/*" } } + { } + { "entry" = "cofaxAdmin" + { "string" = "/admin/*" } } + { } + { "entry" = "fileServlet" + { "string" = "/static/*" } } + { } + { "entry" = "cofaxTools" + { "string" = "/tools/*" } } } } + { } + { } + { "entry" = "taglib" + { "dict" + { } + { "entry" = "taglib-uri" + { "string" = "cofax.tld" } } + { } + { "entry" = "taglib-location" + { "string" = "/WEB-INF/tlds/cofax.tld" } } } } } } } + +(* Comments *) +test lns get "// A comment +// +{\"menu\": 1 } +// +/* +This is a multiline comment +*/\n" = + { "#comment" = "A comment" } + { } + { "dict" + { "entry" = "menu" + { "number" = "1" } } + { } + { } + { "#mcomment" + { "1" = "This is a multiline comment" } } } + + +let s_commented = "/* before */ +{ // before all values +\"key\": // my key + \"value\" // my value + , // after value +\"key2\": [ // before array values + \"val21\", + \"val22\" + // after value 22 +] +// after all values +} +" +test lns get s_commented = + { "#mcomment" { "1" = "before" } } + { "dict" + { "#comment" = "before all values" } + { "entry" = "key" + { "#comment" = "my key" } + { "string" = "value" { "#comment" = "my value" } } } + { "#comment" = "after value" } + { "entry" = "key2" + { "array" + { "#comment" = "before array values" } + { "string" = "val21" } + { } + { "string" = "val22" + { } + { "#comment" = "after value 22" } } + { } + { "#comment" = "after all values" } } } + { } } + +(* Test lns + Allow escaped quotes, backslashes and tabs/newlines *) +test lns get "{ \"filesystem\": \"ext3\\\" \\\\ \t \r\n SEC_TYPE=\\\"ext2\" }\n" = + { "dict" + { "entry" = "filesystem" + { "string" = "ext3\\\" \\\\ \t \r\n SEC_TYPE=\\\"ext2" } } + { } } + +test Json.str get "\"\\\"\"" = { "string" = "\\\"" } + +test Json.str get "\"\\\"" = * + +test Json.str get "\"\"\"" = * + +test Json.str get "\"\\u1234\"" = { "string" = "\u1234" } + +(* Allow spurious backslashes; Issue #557 *) +test Json.str get "\"\\/\"" = { "string" = "\\/" } + +test lns get "{ \"download-dir\": \"\\/var\\/tmp\\/\" }" = + { "dict" + { "entry" = "download-dir" + { "string" = "\/var\/tmp\/" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_kdump.aug b/Sharp.Augeas.Test/lens/tests/test_kdump.aug new file mode 100644 index 0000000..51c79a3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_kdump.aug @@ -0,0 +1,102 @@ +(* +Module: Test_Kdump + Provides unit tests and examples for the <Kdump> lens. +*) + +module Test_Kdump = + + let conf = "# this is a comment +#another commented line + +#comment after empty line +# +#comment after empty comment +path /var/crash #comment after entry +core_collector makedumpfile -c +default poweroff +raw /dev/sda5 +ext3 /dev/sda3 +net my.server.com:/export/tmp +nfs my.server.com:/export/tmp +net user@my.server.com +ssh user@my.server.com +link_delay 60 +kdump_pre /var/crash/scripts/kdump-pre.sh +kdump_post /var/crash/scripts/kdump-post.sh +#extra_bins /usr/bin/lftp /a/b/c +extra_bins /usr/bin/lftp /a/b/c # comment +disk_timeout 30 +extra_modules gfs2 extra modules more +options babla labl kbak df=dfg +options babla labl kbak df=dfg +options babla labl kbak df=dfg # comment +sshkey /root/.ssh/kdump_id_rsa +force_rebuild 1 +override_resettable 1 +dracut_args --omit-drivers \"cfg80211 snd\" --add-drivers \"ext2 ext3\" +fence_kdump_args -p 7410 -f auto +fence_kdump_nodes 192.168.1.10 10.34.63.155 +debug_mem_level 3 +blacklist gfs2 +" + + (* Test: Kdump.lns + Check whole config file *) + test Kdump.lns get conf = + { "#comment" = "this is a comment" } + { "#comment" = "another commented line" } + { } + { "#comment" = "comment after empty line" } + { } + { "#comment" = "comment after empty comment" } + { "path" = "/var/crash" + { "#comment" = "comment after entry" } } + { "core_collector" = "makedumpfile -c" } + { "default" = "poweroff" } + { "raw" = "/dev/sda5" } + { "ext3" = "/dev/sda3" } + { "net" = "my.server.com:/export/tmp" } + { "nfs" = "my.server.com:/export/tmp" } + { "net" = "user@my.server.com" } + { "ssh" = "user@my.server.com" } + { "link_delay" = "60" } + { "kdump_pre" = "/var/crash/scripts/kdump-pre.sh" } + { "kdump_post" = "/var/crash/scripts/kdump-post.sh" } + { "#comment" = "extra_bins /usr/bin/lftp /a/b/c" } + { "extra_bins" + { "1" = "/usr/bin/lftp" } + { "2" = "/a/b/c" } + { "#comment" = "comment" } } + { "disk_timeout" = "30" } + { "extra_modules" + { "1" = "gfs2" } + { "2" = "extra" } + { "3" = "modules" } + { "4" = "more" } } + { "options" + { "babla" + { "labl" } + { "kbak" } + { "df" = "dfg" } } } + { "options" + { "babla" + { "labl" } + { "kbak" } + { "df" = "dfg" } } } + { "options" + { "babla" + { "labl" } + { "kbak" } + { "df" = "dfg" } } + { "#comment" = "comment" } } + { "sshkey" = "/root/.ssh/kdump_id_rsa" } + { "force_rebuild" = "1" } + { "override_resettable" = "1" } + { "dracut_args" = "--omit-drivers \"cfg80211 snd\" --add-drivers \"ext2 ext3\"" } + { "fence_kdump_args" = "-p 7410 -f auto" } + { "fence_kdump_nodes" + { "1" = "192.168.1.10" } + { "2" = "10.34.63.155" } } + { "debug_mem_level" = "3" } + { "blacklist" + { "1" = "gfs2" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_keepalived.aug b/Sharp.Augeas.Test/lens/tests/test_keepalived.aug new file mode 100644 index 0000000..6886357 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_keepalived.aug @@ -0,0 +1,493 @@ +(* +Module: Test_Keepalived + Provides unit tests and examples for the <Keepalived> lens. +*) + +module Test_Keepalived = + +(* Variable: conf + A full configuration file *) + let conf = "! This is a comment +! Configuration File for keepalived + +global_defs { + ! this is who emails will go to on alerts + notification_email { + admins@example.com + fakepager@example.com + ! add a few more email addresses here if you would like + } + notification_email_from admins@example.com + + smtp_server 127.0.0.1 ! I use the local machine to relay mail + smtp_connect_timeout 30 + + ! each load balancer should have a different ID + ! this will be used in SMTP alerts, so you should make + ! each router easily identifiable + lvs_id LVS_EXAMPLE_01 + + vrrp_mcast_group4 224.0.0.18 + vrrp_mcast_group6 ff02::12 +} + +vrrp_sync_group VG1 { + group { + inside_network # name of vrrp_instance (below) + outside_network # One for each moveable IP. + } + notify /usr/bin/foo + notify_master /usr/bin/foo + smtp_alert +} + +vrrp_instance VI_1 { + state MASTER + interface eth0 + + track_interface { + eth0 # Back + eth1 # DMZ + } + track_script { + check_apache2 # weight = +2 si ok, 0 si nok + } + garp_master_delay 5 + garp_master_repeat 5 + garp_master_refresh 5 + garp_master_refresh_repeat 5 + priority 50 + advert_int 2 + authentication { + auth_type PASS + auth_pass mypass + } + virtual_ipaddress { + 10.234.66.146/32 dev eth0 + } + + lvs_sync_daemon_interface eth0 + ha_suspend + + notify_master \"/svr/scripts/notify_master.sh\" + notify_backup \"/svr/scripts/notify_backup.sh\" + notify_fault \"/svr/scripts/notify_fault.sh\" + notify \"/svr/scripts/notify.sh\" + + ! each virtual router id must be unique per instance name! + virtual_router_id 51 + + ! MASTER and BACKUP state are determined by the priority + ! even if you specify MASTER as the state, the state will + ! be voted on by priority (so if your state is MASTER but your + ! priority is lower than the router with BACKUP, you will lose + ! the MASTER state) + ! I make it a habit to set priorities at least 50 points apart + ! note that a lower number is lesser priority - lower gets less vote + priority 150 + + ! how often should we vote, in seconds? + advert_int 1 + + ! send an alert when this instance changes state from MASTER to BACKUP + smtp_alert + + ! this authentication is for syncing between failover servers + ! keepalived supports PASS, which is simple password + ! authentication + ! or AH, which is the IPSec authentication header. + ! I don't use AH + ! yet as many people have reported problems with it + authentication { + auth_type PASS + auth_pass example + } + + ! these are the IP addresses that keepalived will setup on this + ! machine. Later in the config we will specify which real + ! servers are behind these IPs + ! without this block, keepalived will not setup and takedown the + ! any IP addresses + + virtual_ipaddress { + 192.168.1.11 + 10.234.66.146/32 dev vlan933 # parse it well + ! and more if you want them + } + + use_vmac + vmac_xmit_base + native_ipv6 + dont_track_primary + preempt_delay + + mcast_src_ip 192.168.1.1 + unicast_src_ip 192.168.1.1 + + unicast_peer { + 192.168.1.2 + 192.168.1.3 + } +} + +virtual_server 192.168.1.11 22 { + delay_loop 6 + + ! use round-robin as a load balancing algorithm + lb_algo rr + + ! we are doing NAT + lb_kind NAT + nat_mask 255.255.255.0 + + protocol TCP + + sorry_server 10.20.40.30 22 + + ! there can be as many real_server blocks as you need + + real_server 10.20.40.10 22 { + + ! if we used weighted round-robin or a similar lb algo, + ! we include the weight of this server + + weight 1 + + ! here is a health checker for this server. + ! we could use a custom script here (see the keepalived docs) + ! but we will just make sure we can do a vanilla tcp connect() + ! on port 22 + ! if it fails, we will pull this realserver out of the pool + ! and send email about the removal + TCP_CHECK { + connect_timeout 3 + connect_port 22 + } + } +} + +virtual_server_group DNS_1 { + 192.168.0.1 22 + 10.234.55.22-25 36 + 10.45.58.59/32 27 +} + +vrrp_script chk_apache2 { # Requires keepalived-1.1.13 + script \"killall -0 apache2\" # faster + interval 2 # check every 2 seconds + weight 2 # add 2 points of prio if OK + fall 5 + raise 5 +} + +! that's all +" + + +(* Test: Keepalived.lns + Test the full <conf> *) + test Keepalived.lns get conf = + { "#comment" = "This is a comment" } + { "#comment" = "Configuration File for keepalived" } + {} + { "global_defs" + { "#comment" = "this is who emails will go to on alerts" } + { "notification_email" + { "email" = "admins@example.com" } + { "email" = "fakepager@example.com" } + { "#comment" = "add a few more email addresses here if you would like" } } + { "notification_email_from" = "admins@example.com" } + { } + { "smtp_server" = "127.0.0.1" + { "#comment" = "I use the local machine to relay mail" } } + { "smtp_connect_timeout" = "30" } + {} + { "#comment" = "each load balancer should have a different ID" } + { "#comment" = "this will be used in SMTP alerts, so you should make" } + { "#comment" = "each router easily identifiable" } + { "lvs_id" = "LVS_EXAMPLE_01" } + {} + { "vrrp_mcast_group4" = "224.0.0.18" } + { "vrrp_mcast_group6" = "ff02::12" } } + {} + { "vrrp_sync_group" = "VG1" + { "group" + { "inside_network" + { "#comment" = "name of vrrp_instance (below)" } } + { "outside_network" + { "#comment" = "One for each moveable IP." } } } + { "notify" = "/usr/bin/foo" } + { "notify_master" = "/usr/bin/foo" } + { "smtp_alert" } } + {} + { "vrrp_instance" = "VI_1" + { "state" = "MASTER" } + { "interface" = "eth0" } + { } + { "track_interface" + { "eth0" { "#comment" = "Back" } } + { "eth1" { "#comment" = "DMZ" } } } + { "track_script" + { "check_apache2" { "#comment" = "weight = +2 si ok, 0 si nok" } } } + { "garp_master_delay" = "5" } + { "garp_master_repeat" = "5" } + { "garp_master_refresh" = "5" } + { "garp_master_refresh_repeat" = "5" } + { "priority" = "50" } + { "advert_int" = "2" } + { "authentication" + { "auth_type" = "PASS" } + { "auth_pass" = "mypass" } } + { "virtual_ipaddress" + { "ipaddr" = "10.234.66.146" + { "prefixlen" = "32" } + { "dev" = "eth0" } } } + { } + { "lvs_sync_daemon_interface" = "eth0" } + { "ha_suspend" } + { } + { "notify_master" = "\"/svr/scripts/notify_master.sh\"" } + { "notify_backup" = "\"/svr/scripts/notify_backup.sh\"" } + { "notify_fault" = "\"/svr/scripts/notify_fault.sh\"" } + { "notify" = "\"/svr/scripts/notify.sh\"" } + { } + { "#comment" = "each virtual router id must be unique per instance name!" } + { "virtual_router_id" = "51" } + { } + { "#comment" = "MASTER and BACKUP state are determined by the priority" } + { "#comment" = "even if you specify MASTER as the state, the state will" } + { "#comment" = "be voted on by priority (so if your state is MASTER but your" } + { "#comment" = "priority is lower than the router with BACKUP, you will lose" } + { "#comment" = "the MASTER state)" } + { "#comment" = "I make it a habit to set priorities at least 50 points apart" } + { "#comment" = "note that a lower number is lesser priority - lower gets less vote" } + { "priority" = "150" } + { } + { "#comment" = "how often should we vote, in seconds?" } + { "advert_int" = "1" } + { } + { "#comment" = "send an alert when this instance changes state from MASTER to BACKUP" } + { "smtp_alert" } + { } + { "#comment" = "this authentication is for syncing between failover servers" } + { "#comment" = "keepalived supports PASS, which is simple password" } + { "#comment" = "authentication" } + { "#comment" = "or AH, which is the IPSec authentication header." } + { "#comment" = "I don't use AH" } + { "#comment" = "yet as many people have reported problems with it" } + { "authentication" + { "auth_type" = "PASS" } + { "auth_pass" = "example" } } + { } + { "#comment" = "these are the IP addresses that keepalived will setup on this" } + { "#comment" = "machine. Later in the config we will specify which real" } + { "#comment" = "servers are behind these IPs" } + { "#comment" = "without this block, keepalived will not setup and takedown the" } + { "#comment" = "any IP addresses" } + { } + { "virtual_ipaddress" + { "ipaddr" = "192.168.1.11" } + { "ipaddr" = "10.234.66.146" + { "prefixlen" = "32" } + { "dev" = "vlan933" } + { "#comment" = "parse it well" } } + { "#comment" = "and more if you want them" } } + { } + { "use_vmac" } + { "vmac_xmit_base" } + { "native_ipv6" } + { "dont_track_primary" } + { "preempt_delay" } + { } + { "mcast_src_ip" = "192.168.1.1" } + { "unicast_src_ip" = "192.168.1.1" } + { } + { "unicast_peer" + { "ipaddr" = "192.168.1.2" } + { "ipaddr" = "192.168.1.3" } } } + { } + { "virtual_server" + { "ip" = "192.168.1.11" } + { "port" = "22" } + { "delay_loop" = "6" } + { } + { "#comment" = "use round-robin as a load balancing algorithm" } + { "lb_algo" = "rr" } + { } + { "#comment" = "we are doing NAT" } + { "lb_kind" = "NAT" } + { "nat_mask" = "255.255.255.0" } + { } + { "protocol" = "TCP" } + { } + { "sorry_server" + { "ip" = "10.20.40.30" } + { "port" = "22" } } + { } + { "#comment" = "there can be as many real_server blocks as you need" } + { } + { "real_server" + { "ip" = "10.20.40.10" } + { "port" = "22" } + { "#comment" = "if we used weighted round-robin or a similar lb algo," } + { "#comment" = "we include the weight of this server" } + { } + { "weight" = "1" } + { } + { "#comment" = "here is a health checker for this server." } + { "#comment" = "we could use a custom script here (see the keepalived docs)" } + { "#comment" = "but we will just make sure we can do a vanilla tcp connect()" } + { "#comment" = "on port 22" } + { "#comment" = "if it fails, we will pull this realserver out of the pool" } + { "#comment" = "and send email about the removal" } + { "TCP_CHECK" + { "connect_timeout" = "3" } + { "connect_port" = "22" } } } } + { } + { "virtual_server_group" = "DNS_1" + { "vip" + { "ipaddr" = "192.168.0.1" } + { "port" = "22" } } + { "vip" + { "ipaddr" = "10.234.55.22-25" } + { "port" = "36" } } + { "vip" + { "ipaddr" = "10.45.58.59" + { "prefixlen" = "32" } } + { "port" = "27" } } } + { } + { "vrrp_script" = "chk_apache2" + { "#comment" = "Requires keepalived-1.1.13" } + { "script" = "\"killall -0 apache2\"" + { "#comment" = "faster" } } + { "interval" = "2" + { "#comment" = "check every 2 seconds" } } + { "weight" = "2" + { "#comment" = "add 2 points of prio if OK" } } + { "fall" = "5" } + { "raise" = "5" } } + { } + { "#comment" = "that's all" } + +(* Variable: tcp_check + An example of a TCP health checker *) +let tcp_check = "virtual_server 192.168.1.11 22 { + real_server 10.20.40.10 22 { + TCP_CHECK { + connect_timeout 3 + connect_port 22 + bindto 192.168.1.1 + } + } +} +" +test Keepalived.lns get tcp_check = + { "virtual_server" + { "ip" = "192.168.1.11" } + { "port" = "22" } + { "real_server" + { "ip" = "10.20.40.10" } + { "port" = "22" } + { "TCP_CHECK" + { "connect_timeout" = "3" } + { "connect_port" = "22" } + { "bindto" = "192.168.1.1" } } } } + +(* Variable: misc_check + An example of a MISC health checker *) +let misc_check = "virtual_server 192.168.1.11 22 { + real_server 10.20.40.10 22 { + MISC_CHECK { + misc_path /usr/local/bin/server_test + misc_timeout 3 + misc_dynamic + } + } +} +" +test Keepalived.lns get misc_check = + { "virtual_server" + { "ip" = "192.168.1.11" } + { "port" = "22" } + { "real_server" + { "ip" = "10.20.40.10" } + { "port" = "22" } + { "MISC_CHECK" + { "misc_path" = "/usr/local/bin/server_test" } + { "misc_timeout" = "3" } + { "misc_dynamic" } } } } + +(* Variable: smtp_check + An example of an SMTP health checker *) +let smtp_check = "virtual_server 192.168.1.11 22 { + real_server 10.20.40.10 22 { + SMTP_CHECK { + host { + connect_ip 10.20.40.11 + connect_port 587 + bindto 192.168.1.1 + } + connect_timeout 3 + retry 5 + delay_before_retry 10 + helo_name \"Testing Augeas\" + } + } +} +" +test Keepalived.lns get smtp_check = + { "virtual_server" + { "ip" = "192.168.1.11" } + { "port" = "22" } + { "real_server" + { "ip" = "10.20.40.10" } + { "port" = "22" } + { "SMTP_CHECK" + { "host" + { "connect_ip" = "10.20.40.11" } + { "connect_port" = "587" } + { "bindto" = "192.168.1.1" } } + { "connect_timeout" = "3" } + { "retry" = "5" } + { "delay_before_retry" = "10" } + { "helo_name" = "\"Testing Augeas\"" } } } } + +(* Variable: http_check + An example of an HTTP health checker *) +let http_check = "virtual_server 192.168.1.11 22 { + real_server 10.20.40.10 22 { + HTTP_GET { + url { + path /mrtg2/ + digest 9b3a0c85a887a256d6939da88aabd8cd + status_code 200 + } + connect_timeout 3 + connect_port 8080 + nb_get_retry 5 + delay_before_retry 10 + } + SSL_GET { + connect_port 8443 + } + } +} +" +test Keepalived.lns get http_check = + { "virtual_server" + { "ip" = "192.168.1.11" } + { "port" = "22" } + { "real_server" + { "ip" = "10.20.40.10" } + { "port" = "22" } + { "HTTP_GET" + { "url" + { "path" = "/mrtg2/" } + { "digest" = "9b3a0c85a887a256d6939da88aabd8cd" } + { "status_code" = "200" } } + { "connect_timeout" = "3" } + { "connect_port" = "8080" } + { "nb_get_retry" = "5" } + { "delay_before_retry" = "10" } } + { "SSL_GET" + { "connect_port" = "8443" } } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_known_hosts.aug b/Sharp.Augeas.Test/lens/tests/test_known_hosts.aug new file mode 100644 index 0000000..1b987e3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_known_hosts.aug @@ -0,0 +1,48 @@ +(* +Module: Test_Known_Hosts + Provides unit tests and examples for the <Known_Hosts> lens. +*) + +module Test_Known_Hosts = + +(* Test: Known_Hosts.lns + Simple get test *) +test Known_Hosts.lns get "# A comment +foo.example.com,foo ecdsa-sha2-nistp256 AAABBBDKDFX= +bar.example.com,bar ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9NJSjDZh4+K6WBS16iX7ZndnwbGsaEbLwHlCEhZmef +|1|FhUqf1kMlRWNfK6InQSAmXiNiSY=|jwbKFwD4ipl6D0k6OoshmW7xOao= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIvNOU8OedkWalFmoFcJWP3nasnCLx6M78F9y0rzTQtplggNd0dvR0A4SQOBfHInmk5dH6YGGcpT3PM3cJBR7rI=\n" = + { "#comment" = "A comment" } + { "1" = "foo.example.com" + { "alias" = "foo" } + { "type" = "ecdsa-sha2-nistp256" } + { "key" = "AAABBBDKDFX=" } } + { "2" = "bar.example.com" + { "alias" = "bar" } + { "type" = "ssh-ed25519" } + { "key" = "AAAAC3NzaC1lZDI1NTE5AAAAIN9NJSjDZh4+K6WBS16iX7ZndnwbGsaEbLwHlCEhZmef" } } + { "3" = "|1|FhUqf1kMlRWNfK6InQSAmXiNiSY=|jwbKFwD4ipl6D0k6OoshmW7xOao=" + { "type" = "ecdsa-sha2-nistp256" } + { "key" = "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIvNOU8OedkWalFmoFcJWP3nasnCLx6M78F9y0rzTQtplggNd0dvR0A4SQOBfHInmk5dH6YGGcpT3PM3cJBR7rI=" } } + +(* Test: Known_Hosts.lns + Markers *) +test Known_Hosts.lns get "@revoked * ssh-rsa AAAAB5W +@cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W\n" = + { "1" = "*" + { "@revoked" } + { "type" = "ssh-rsa" } + { "key" = "AAAAB5W" } } + { "2" = "*.mydomain.org" + { "@cert-authority" } + { "alias" = "*.mydomain.com" } + { "type" = "ssh-rsa" } + { "key" = "AAAAB5W" } } + +(* Test: Known_Hosts.lns + Eol comment *) +test Known_Hosts.lns get "@revoked * ssh-rsa AAAAB5W # this is revoked\n" = + { "1" = "*" + { "@revoked" } + { "type" = "ssh-rsa" } + { "key" = "AAAAB5W" } + { "#comment" = "this is revoked" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_koji.aug b/Sharp.Augeas.Test/lens/tests/test_koji.aug new file mode 100644 index 0000000..729e07f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_koji.aug @@ -0,0 +1,65 @@ +(* +Module: Test_Koji + Provides unit tests and examples for the <Koji> lens. +*) + +module Test_koji = + + (* Variable: conf + A full koji.conf *) + let conf = "[koji] + +;configuration for koji cli tool + +;url of XMLRPC server +server = http://localhost/kojihub + +;url of web interface +weburl = http://localhost/koji + +;url of package download site +pkgurl = http://localhost/packages + +;path to the koji top directory +topdir = /mnt/koji + +;configuration for SSL athentication + +;client certificate +cert = /etc/pki/koji/kojiadm.pem + +;certificate of the CA that issued the client certificate +ca = /etc/pki/koji/koji_ca_cert.crt + +;certificate of the CA that issued the HTTP server certificate +serverca = /etc/pki/koji/koji_ca_cert.crt +" + + test Koji.lns get conf = + { "section" = "koji" + { } + { "#comment" = "configuration for koji cli tool" } + { } + { "#comment" = "url of XMLRPC server" } + { "server" = "http://localhost/kojihub" } + { } + { "#comment" = "url of web interface" } + { "weburl" = "http://localhost/koji" } + { } + { "#comment" = "url of package download site" } + { "pkgurl" = "http://localhost/packages" } + { } + { "#comment" = "path to the koji top directory" } + { "topdir" = "/mnt/koji" } + { } + { "#comment" = "configuration for SSL athentication" } + { } + { "#comment" = "client certificate" } + { "cert" = "/etc/pki/koji/kojiadm.pem" } + { } + { "#comment" = "certificate of the CA that issued the client certificate" } + { "ca" = "/etc/pki/koji/koji_ca_cert.crt" } + { } + { "#comment" = "certificate of the CA that issued the HTTP server certificate" } + { "serverca" = "/etc/pki/koji/koji_ca_cert.crt" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_krb5.aug b/Sharp.Augeas.Test/lens/tests/test_krb5.aug new file mode 100644 index 0000000..d4a11b6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_krb5.aug @@ -0,0 +1,1107 @@ +module Test_krb5 = + + (* Krb5.conf from Fermilab *) + let fermi_str = "### +### This krb5.conf template is intended for use with Fermi +### Kerberos v1_2 and later. Earlier versions may choke on the +### \"auth_to_local = \" lines unless they are commented out. +### The installation process should do all the right things in +### any case, but if you are reading this and haven't updated +### your kerberos product to v1_2 or later, you really should! +### +[libdefaults] + ticket_lifetime = 1560m + default_realm = FNAL.GOV + ccache_type = 4 + default_tgs_enCtypes = des-cbc-crc + default_tkt_enctypes = des-cbc-crc + permitted_enctypes = des-cbc-crc des3-cbc-sha1 + default_lifetime = 7d + renew_lifetime = 7d + autologin = true + forward = true + forwardable = true + renewable = true + encrypt = true + v4_name_convert = { + host = { + rcmd = host + } + } + +[realms] + FNAL.GOV = { + kdc = krb-fnal-1.fnal.gov:88 + kdc = krb-fnal-2.fnal.gov:88 + kdc = krb-fnal-3.fnal.gov:88 + kdc = krb-fnal-4.fnal.gov:88 + kdc = krb-fnal-5.fnal.gov:88 + kdc = krb-fnal-6.fnal.gov:88 + kdc = krb-fnal-7.fnal.gov:88 + master_kdc = krb-fnal-admin.fnal.gov:88 + admin_server = krb-fnal-admin.fnal.gov + default_domain = fnal.gov + } + WIN.FNAL.GOV = { + kdc = littlebird.win.fnal.gov:88 + kdc = bigbird.win.fnal.gov:88 + default_domain = fnal.gov + } + FERMI.WIN.FNAL.GOV = { + kdc = sully.fermi.win.fnal.gov:88 + kdc = elmo.fermi.win.fnal.gov:88 + kdc = grover.fermi.win.fnal.gov:88 + kdc = oscar.fermi.win.fnal.gov:88 + kdc = cookie.fermi.win.fnal.gov:88 + kdc = herry.fermi.win.fnal.gov:88 + default_domain = fnal.gov + } + UCHICAGO.EDU = { + kdc = kerberos-0.uchicago.edu + kdc = kerberos-1.uchicago.edu + kdc = kerberos-2.uchicago.edu + admin_server = kerberos.uchicago.edu + default_domain = uchicago.edu + } + PILOT.FNAL.GOV = { + kdc = i-krb-2.fnal.gov:88 + master_kdc = i-krb-2.fnal.gov:88 + admin_server = i-krb-2.fnal.gov + default_domain = fnal.gov + } + WINBETA.FNAL.GOV = { + kdc = wbdc1.winbeta.fnal.gov:88 + kdc = wbdc2.winbeta.fnal.gov:88 + default_domain = fnal.gov + } + FERMIBETA.WINBETA.FNAL.GOV = { + kdc = fbdc1.fermibeta.winbeta.fnal.gov:88 + kdc = fbdc2.fermibeta.winbeta.fnal.gov:88 + default_domain = fnal.gov + } + CERN.CH = { + kdc = afsdb2.cern.ch + kdc = afsdb3.cern.ch + kdc = afsdb1.cern.ch + default_domain = cern.ch + kpasswd_server = afskrb5m.cern.ch + admin_server = afskrb5m.cern.ch + v4_name_convert = { + host = { + rcmd = host + } + } + } + 1TS.ORG = { + kdc = kerberos.1ts.org + admin_server = kerberos.1ts.org + } + stanford.edu = { + kdc = krb5auth1.stanford.edu + kdc = krb5auth2.stanford.edu + kdc = krb5auth3.stanford.edu + master_kdc = krb5auth1.stanford.edu + admin_server = krb5-admin.stanford.edu + default_domain = stanford.edu + krb524_server = krb524.stanford.edu + } + +[instancemapping] + afs = { + cron/* = \"\" + cms/* = \"\" + afs/* = \"\" + e898/* = \"\" + } + +[capaths] + +# FNAL.GOV and PILOT.FNAL.GOV are the MIT Kerberos Domains +# FNAL.GOV is production and PILOT is for testing +# The FERMI Windows domain uses the WIN.FNAL.GOV root realm +# with the FERMI.WIN.FNAL.GOV sub-realm where machines and users +# reside. The WINBETA and FERMIBETA domains are the equivalent +# testing realms for the FERMIBETA domain. The 2-way transitive +# trust structure of this complex is as follows: +# +# FNAL.GOV <=> PILOT.FNAL.GOV +# FNAL.GOV <=> WIN.FERMI.GOV <=> FERMI.WIN.FERMI.GOV +# PILOT.FNAL.GOV <=> WINBETA.FNAL.GOV <=> FERMIBETA.WINBETA.FNAL.GOV + +FNAL.GOV = { + PILOT.FNAL.GOV = . + FERMI.WIN.FNAL.GOV = WIN.FNAL.GOV + WIN.FNAL.GOV = . + FERMIBETA.WINBETA.FNAL.GOV = WINBETA.FNAL.GOV + WINBETA.FNAL.GOV = PILOT.FNAL.GOV +} +PILOT.FNAL.GOV = { + FNAL.GOV = . + FERMI.WIN.FNAL.GOV = WIN.FNAL.GOV + WIN.FNAL.GOV = FNAL.GOV + FERMIBETA.WINBETA.FNAL.GOV = WINBETA.FNAL.GOV + WINBETA.FNAL.GOV = . +} +WIN.FNAL.GOV = { + FNAL.GOV = . + PILOT.FNAL.GOV = FNAL.GOV + FERMI.WIN.FNAL.GOV = . + FERMIBETA.WINBETA.FNAL.GOV = WINBETA.FNAL.GOV + WINBETA.FNAL.GOV = PILOT.FNAL.GOV +} +WINBETA.FNAL.GOV = { + PILOT.FNAL.GOV = . + FERMIBETA.WINBETA.FNAL.GOV = . + FNAL.GOV = PILOT.FNAL.GOV + FERMI.WIN.FNAL.GOV = WIN.FNAL.GOV + WIN.FNAL.GOV = PILOT.FNAL.GOV +} + +[logging] + kdc = SYSLOG:info:local1 + admin_server = SYSLOG:info:local2 + default = SYSLOG:err:auth + +[domain_realm] +# Fermilab's (non-windows-centric) domains + .fnal.gov = FNAL.GOV + .cdms-soudan.org = FNAL.GOV + .deemz.net = FNAL.GOV + .dhcp.fnal.gov = FNAL.GOV + .minos-soudan.org = FNAL.GOV + i-krb-2.fnal.gov = PILOT.FNAL.GOV + .win.fnal.gov = WIN.FNAL.GOV + .fermi.win.fnal.gov = FERMI.WIN.FNAL.GOV + .winbeta.fnal.gov = WINBETA.FNAL.GOV + .fermibeta.winbeta.fnal.gov = FERMIBETA.WINBETA.FNAL.GOV +# Fermilab's KCA servers so FERMI.WIN principals work in FNAL.GOV realm +# winserver.fnal.gov = FERMI.WIN.FNAL.GOV +# winserver2.fnal.gov = FERMI.WIN.FNAL.GOVA +# Accelerator nodes to FERMI.WIN for Linux/OS X users + adgroups.fnal.gov = FERMI.WIN.FNAL.GOV + adusers.fnal.gov = FERMI.WIN.FNAL.GOV + webad.fnal.gov = FERMI.WIN.FNAL.GOV +# Friends and family (by request) + .cs.ttu.edu = FNAL.GOV + .geol.uniovi.es = FNAL.GOV + .harvard.edu = FNAL.GOV + .hpcc.ttu.edu = FNAL.GOV + .infn.it = FNAL.GOV + .knu.ac.kr = FNAL.GOV + .lns.mit.edu = FNAL.GOV + .ph.liv.ac.uk = FNAL.GOV + .pha.jhu.edu = FNAL.GOV + .phys.ttu.edu = FNAL.GOV + .phys.ualberta.ca = FNAL.GOV + .physics.lsa.umich.edu = FNAL.GOV + .physics.ucla.edu = FNAL.GOV + .physics.ucsb.edu = FNAL.GOV + .physics.utoronto.ca = FNAL.GOV + .rl.ac.uk = FNAL.GOV + .rockefeller.edu = FNAL.GOV + .rutgers.edu = FNAL.GOV + .sdsc.edu = FNAL.GOV + .sinica.edu.tw = FNAL.GOV + .tsukuba.jp.hep.net = FNAL.GOV + .ucsd.edu = FNAL.GOV + .unl.edu = FNAL.GOV + .in2p3.fr = FNAL.GOV + .wisc.edu = FNAL.GOV + .pic.org.es = FNAL.GOV + .kisti.re.kr = FNAL.GOV + +# The whole \"top half\" is replaced during \"ups installAsRoot krb5conf\", so: +# It would probably be a bad idea to change anything on or above this line + +# If you need to add any .domains or hosts, put them here +[domain_realm] + mojo.lunet.edu = FNAL.GOV + +[appdefaults] + default_lifetime = 7d + retain_ccache = false + autologin = true + forward = true + forwardable = true + renewable = true + encrypt = true + krb5_aklog_path = /usr/bin/aklog + + telnet = { + } + + rcp = { + forward = true + encrypt = false + allow_fallback = true + } + + rsh = { + allow_fallback = true + } + + rlogin = { + allow_fallback = false + } + + + login = { + forwardable = true + krb5_run_aklog = false + krb5_get_tickets = true + krb4_get_tickets = false + krb4_convert = false + } + + kinit = { + forwardable = true + krb5_run_aklog = false + } + + kadmin = { + forwardable = false + } + + rshd = { + krb5_run_aklog = false + } + + ftpd = { + krb5_run_aklog = false + default_lifetime = 10h + } + + pam = { + debug = false + forwardable = true + renew_lifetime = 7d + ticket_lifetime = 1560m + krb4_convert = true + afs_cells = fnal.gov + krb5_run_aklog = false + } +" + +test Krb5.lns get fermi_str = + { "#comment" = "##" } + { "#comment" = "## This krb5.conf template is intended for use with Fermi" } + { "#comment" = "## Kerberos v1_2 and later. Earlier versions may choke on the" } + { "#comment" = "## \"auth_to_local = \" lines unless they are commented out." } + { "#comment" = "## The installation process should do all the right things in" } + { "#comment" = "## any case, but if you are reading this and haven't updated" } + { "#comment" = "## your kerberos product to v1_2 or later, you really should!" } + { "#comment" = "##" } + { "libdefaults" + { "ticket_lifetime" = "1560m" } + { "default_realm" = "FNAL.GOV" } + { "ccache_type" = "4" } + { "default_tgs_enctypes" = "des-cbc-crc" } + { "#eol" } + { "default_tkt_enctypes" = "des-cbc-crc" } + { "#eol" } + { "permitted_enctypes" = "des-cbc-crc" } + { "permitted_enctypes" = "des3-cbc-sha1" } + { "#eol" } + { "default_lifetime" = "7d" } + { "renew_lifetime" = "7d" } + { "autologin" = "true" } + { "forward" = "true" } + { "forwardable" = "true" } + { "renewable" = "true" } + { "encrypt" = "true" } + { "v4_name_convert" + { "host" + { "rcmd" = "host" } + } + } + { } } + { "realms" + { "realm" = "FNAL.GOV" + { "kdc" = "krb-fnal-1.fnal.gov:88" } + { "kdc" = "krb-fnal-2.fnal.gov:88" } + { "kdc" = "krb-fnal-3.fnal.gov:88" } + { "kdc" = "krb-fnal-4.fnal.gov:88" } + { "kdc" = "krb-fnal-5.fnal.gov:88" } + { "kdc" = "krb-fnal-6.fnal.gov:88" } + { "kdc" = "krb-fnal-7.fnal.gov:88" } + { "master_kdc" = "krb-fnal-admin.fnal.gov:88" } + { "admin_server" = "krb-fnal-admin.fnal.gov" } + { "default_domain" = "fnal.gov" } } + { "realm" = "WIN.FNAL.GOV" + { "kdc" = "littlebird.win.fnal.gov:88" } + { "kdc" = "bigbird.win.fnal.gov:88" } + { "default_domain" = "fnal.gov" } } + { "realm" = "FERMI.WIN.FNAL.GOV" + { "kdc" = "sully.fermi.win.fnal.gov:88" } + { "kdc" = "elmo.fermi.win.fnal.gov:88" } + { "kdc" = "grover.fermi.win.fnal.gov:88" } + { "kdc" = "oscar.fermi.win.fnal.gov:88" } + { "kdc" = "cookie.fermi.win.fnal.gov:88" } + { "kdc" = "herry.fermi.win.fnal.gov:88" } + { "default_domain" = "fnal.gov" } } + { "realm" = "UCHICAGO.EDU" + { "kdc" = "kerberos-0.uchicago.edu" } + { "kdc" = "kerberos-1.uchicago.edu" } + { "kdc" = "kerberos-2.uchicago.edu" } + { "admin_server" = "kerberos.uchicago.edu" } + { "default_domain" = "uchicago.edu" } } + { "realm" = "PILOT.FNAL.GOV" + { "kdc" = "i-krb-2.fnal.gov:88" } + { "master_kdc" = "i-krb-2.fnal.gov:88" } + { "admin_server" = "i-krb-2.fnal.gov" } + { "default_domain" = "fnal.gov" } } + { "realm" = "WINBETA.FNAL.GOV" + { "kdc" = "wbdc1.winbeta.fnal.gov:88" } + { "kdc" = "wbdc2.winbeta.fnal.gov:88" } + { "default_domain" = "fnal.gov" } } + { "realm" = "FERMIBETA.WINBETA.FNAL.GOV" + { "kdc" = "fbdc1.fermibeta.winbeta.fnal.gov:88" } + { "kdc" = "fbdc2.fermibeta.winbeta.fnal.gov:88" } + { "default_domain" = "fnal.gov" } } + { "realm" = "CERN.CH" + { "kdc" = "afsdb2.cern.ch" } + { "kdc" = "afsdb3.cern.ch" } + { "kdc" = "afsdb1.cern.ch" } + { "default_domain" = "cern.ch" } + { "kpasswd_server" = "afskrb5m.cern.ch" } + { "admin_server" = "afskrb5m.cern.ch" } + { "v4_name_convert" + { "host" + { "rcmd" = "host" } + } + } + } + { "realm" = "1TS.ORG" + { "kdc" = "kerberos.1ts.org" } + { "admin_server" = "kerberos.1ts.org" } + } + { "realm" = "stanford.edu" + { "kdc" = "krb5auth1.stanford.edu" } + { "kdc" = "krb5auth2.stanford.edu" } + { "kdc" = "krb5auth3.stanford.edu" } + { "master_kdc" = "krb5auth1.stanford.edu" } + { "admin_server" = "krb5-admin.stanford.edu" } + { "default_domain" = "stanford.edu" } + { "krb524_server" = "krb524.stanford.edu" } + } + { } } + { "instancemapping" + { "afs" + { "mapping" = "cron/*" { "value" = "" } } + { "mapping" = "cms/*" { "value" = "" } } + { "mapping" = "afs/*" { "value" = "" } } + { "mapping" = "e898/*" { "value" = "" } } } + { } } + { "capaths" + { } + { "#comment" = "FNAL.GOV and PILOT.FNAL.GOV are the MIT Kerberos Domains" } + { "#comment" = "FNAL.GOV is production and PILOT is for testing" } + { "#comment" = "The FERMI Windows domain uses the WIN.FNAL.GOV root realm" } + { "#comment" = "with the FERMI.WIN.FNAL.GOV sub-realm where machines and users" } + { "#comment" = "reside. The WINBETA and FERMIBETA domains are the equivalent" } + { "#comment" = "testing realms for the FERMIBETA domain. The 2-way transitive" } + { "#comment" = "trust structure of this complex is as follows:" } + {} + { "#comment" = "FNAL.GOV <=> PILOT.FNAL.GOV" } + { "#comment" = "FNAL.GOV <=> WIN.FERMI.GOV <=> FERMI.WIN.FERMI.GOV" } + { "#comment" = "PILOT.FNAL.GOV <=> WINBETA.FNAL.GOV <=> FERMIBETA.WINBETA.FNAL.GOV" } + { } + { "FNAL.GOV" + { "PILOT.FNAL.GOV" = "." } + { "FERMI.WIN.FNAL.GOV" = "WIN.FNAL.GOV" } + { "WIN.FNAL.GOV" = "." } + { "FERMIBETA.WINBETA.FNAL.GOV" = "WINBETA.FNAL.GOV" } + { "WINBETA.FNAL.GOV" = "PILOT.FNAL.GOV" } } + { "PILOT.FNAL.GOV" + { "FNAL.GOV" = "." } + { "FERMI.WIN.FNAL.GOV" = "WIN.FNAL.GOV" } + { "WIN.FNAL.GOV" = "FNAL.GOV" } + { "FERMIBETA.WINBETA.FNAL.GOV" = "WINBETA.FNAL.GOV" } + { "WINBETA.FNAL.GOV" = "." } } + { "WIN.FNAL.GOV" + { "FNAL.GOV" = "." } + { "PILOT.FNAL.GOV" = "FNAL.GOV" } + { "FERMI.WIN.FNAL.GOV" = "." } + { "FERMIBETA.WINBETA.FNAL.GOV" = "WINBETA.FNAL.GOV" } + { "WINBETA.FNAL.GOV" = "PILOT.FNAL.GOV" } } + { "WINBETA.FNAL.GOV" + { "PILOT.FNAL.GOV" = "." } + { "FERMIBETA.WINBETA.FNAL.GOV" = "." } + { "FNAL.GOV" = "PILOT.FNAL.GOV" } + { "FERMI.WIN.FNAL.GOV" = "WIN.FNAL.GOV" } + { "WIN.FNAL.GOV" = "PILOT.FNAL.GOV" } } + { } } + { "logging" + { "kdc" + { "syslog" + { "severity" = "info" } + { "facility" = "local1" } } } + { "admin_server" + { "syslog" + { "severity" = "info" } + { "facility" = "local2" } } } + { "default" + { "syslog" + { "severity" = "err" } + { "facility" = "auth" } } } + { } } + { "domain_realm" + { "#comment" = "Fermilab's (non-windows-centric) domains" } + { ".fnal.gov" = "FNAL.GOV" } + { ".cdms-soudan.org" = "FNAL.GOV" } + { ".deemz.net" = "FNAL.GOV" } + { ".dhcp.fnal.gov" = "FNAL.GOV" } + { ".minos-soudan.org" = "FNAL.GOV" } + { "i-krb-2.fnal.gov" = "PILOT.FNAL.GOV" } + { ".win.fnal.gov" = "WIN.FNAL.GOV" } + { ".fermi.win.fnal.gov" = "FERMI.WIN.FNAL.GOV" } + { ".winbeta.fnal.gov" = "WINBETA.FNAL.GOV" } + { ".fermibeta.winbeta.fnal.gov" = "FERMIBETA.WINBETA.FNAL.GOV" } + { "#comment" = "Fermilab's KCA servers so FERMI.WIN principals work in FNAL.GOV realm" } + { "#comment" = "winserver.fnal.gov = FERMI.WIN.FNAL.GOV" } + { "#comment" = "winserver2.fnal.gov = FERMI.WIN.FNAL.GOVA" } + { "#comment" = "Accelerator nodes to FERMI.WIN for Linux/OS X users" } + { "adgroups.fnal.gov" = "FERMI.WIN.FNAL.GOV" } + { "adusers.fnal.gov" = "FERMI.WIN.FNAL.GOV" } + { "webad.fnal.gov" = "FERMI.WIN.FNAL.GOV" } + { "#comment" = "Friends and family (by request)" } + { ".cs.ttu.edu" = "FNAL.GOV" } + { ".geol.uniovi.es" = "FNAL.GOV" } + { ".harvard.edu" = "FNAL.GOV" } + { ".hpcc.ttu.edu" = "FNAL.GOV" } + { ".infn.it" = "FNAL.GOV" } + { ".knu.ac.kr" = "FNAL.GOV" } + { ".lns.mit.edu" = "FNAL.GOV" } + { ".ph.liv.ac.uk" = "FNAL.GOV" } + { ".pha.jhu.edu" = "FNAL.GOV" } + { ".phys.ttu.edu" = "FNAL.GOV" } + { ".phys.ualberta.ca" = "FNAL.GOV" } + { ".physics.lsa.umich.edu" = "FNAL.GOV" } + { ".physics.ucla.edu" = "FNAL.GOV" } + { ".physics.ucsb.edu" = "FNAL.GOV" } + { ".physics.utoronto.ca" = "FNAL.GOV" } + { ".rl.ac.uk" = "FNAL.GOV" } + { ".rockefeller.edu" = "FNAL.GOV" } + { ".rutgers.edu" = "FNAL.GOV" } + { ".sdsc.edu" = "FNAL.GOV" } + { ".sinica.edu.tw" = "FNAL.GOV" } + { ".tsukuba.jp.hep.net" = "FNAL.GOV" } + { ".ucsd.edu" = "FNAL.GOV" } + { ".unl.edu" = "FNAL.GOV" } + { ".in2p3.fr" = "FNAL.GOV" } + { ".wisc.edu" = "FNAL.GOV" } + { ".pic.org.es" = "FNAL.GOV" } + { ".kisti.re.kr" = "FNAL.GOV" } + { } + { "#comment" = "The whole \"top half\" is replaced during \"ups installAsRoot krb5conf\", so:" } + { "#comment" = "It would probably be a bad idea to change anything on or above this line" } + { } + { "#comment" = "If you need to add any .domains or hosts, put them here" } } + { "domain_realm" + { "mojo.lunet.edu" = "FNAL.GOV" } + { } } + { "appdefaults" + { "default_lifetime" = "7d" } + { "retain_ccache" = "false" } + { "autologin" = "true" } + { "forward" = "true" } + { "forwardable" = "true" } + { "renewable" = "true" } + { "encrypt" = "true" } + { "krb5_aklog_path" = "/usr/bin/aklog" } + { } + { "application" = "telnet" } + { } + { "application" = "rcp" + { "forward" = "true" } + { "encrypt" = "false" } + { "allow_fallback" = "true" } } + { } + { "application" = "rsh" + { "allow_fallback" = "true" } } + { } + { "application" = "rlogin" + { "allow_fallback" = "false" } } + { } + { } + { "application" = "login" + { "forwardable" = "true" } + { "krb5_run_aklog" = "false" } + { "krb5_get_tickets" = "true" } + { "krb4_get_tickets" = "false" } + { "krb4_convert" = "false" } } + { } + { "application" = "kinit" + { "forwardable" = "true" } + { "krb5_run_aklog" = "false" } } + { } + { "application" = "kadmin" + { "forwardable" = "false" } } + { } + { "application" = "rshd" + { "krb5_run_aklog" = "false" } } + { } + { "application" = "ftpd" + { "krb5_run_aklog" = "false" } + { "default_lifetime" = "10h" } } + { } + { "application" = "pam" + { "debug" = "false" } + { "forwardable" = "true" } + { "renew_lifetime" = "7d" } + { "ticket_lifetime" = "1560m" } + { "krb4_convert" = "true" } + { "afs_cells" = "fnal.gov" } + { "krb5_run_aklog" = "false" } } } + + +(* Example from the krb5 distrubution *) +let dist_str = "[libdefaults] + default_realm = ATHENA.MIT.EDU + krb4_config = /usr/kerberos/lib/krb.conf + krb4_realms = /usr/kerberos/lib/krb.realms + +[realms] + ATHENA.MIT.EDU = { + admin_server = KERBEROS.MIT.EDU + default_domain = MIT.EDU + v4_instance_convert = { + mit = mit.edu + lithium = lithium.lcs.mit.edu + } + } + ANDREW.CMU.EDU = { + admin_server = vice28.fs.andrew.cmu.edu + } +# use \"kdc =\" if realm admins haven't put SRV records into DNS + GNU.ORG = { + kdc = kerberos.gnu.org + kdc = kerberos-2.gnu.org + admin_server = kerberos.gnu.org + } + +[domain_realm] + .mit.edu = ATHENA.MIT.EDU + mit.edu = ATHENA.MIT.EDU + .media.mit.edu = MEDIA-LAB.MIT.EDU + media.mit.edu = MEDIA-LAB.MIT.EDU + .ucsc.edu = CATS.UCSC.EDU + +[logging] +# kdc = CONSOLE +" + +test Krb5.lns get dist_str = + { "libdefaults" + { "default_realm" = "ATHENA.MIT.EDU" } + { "krb4_config" = "/usr/kerberos/lib/krb.conf" } + { "krb4_realms" = "/usr/kerberos/lib/krb.realms" } + { } } + { "realms" + { "realm" = "ATHENA.MIT.EDU" + { "admin_server" = "KERBEROS.MIT.EDU" } + { "default_domain" = "MIT.EDU" } + { "v4_instance_convert" + { "mit" = "mit.edu" } + { "lithium" = "lithium.lcs.mit.edu" } } } + { "realm" = "ANDREW.CMU.EDU" + { "admin_server" = "vice28.fs.andrew.cmu.edu" } } + { "#comment" = "use \"kdc =\" if realm admins haven't put SRV records into DNS" } + { "realm" = "GNU.ORG" + { "kdc" = "kerberos.gnu.org" } + { "kdc" = "kerberos-2.gnu.org" } + { "admin_server" = "kerberos.gnu.org" } } + { } } + { "domain_realm" + { ".mit.edu" = "ATHENA.MIT.EDU" } + { "mit.edu" = "ATHENA.MIT.EDU" } + { ".media.mit.edu" = "MEDIA-LAB.MIT.EDU" } + { "media.mit.edu" = "MEDIA-LAB.MIT.EDU" } + { ".ucsc.edu" = "CATS.UCSC.EDU" } + { } } + { "logging" + { "#comment" = "kdc = CONSOLE" } } + +(* Test for [libdefaults] *) +test Krb5.libdefaults get "[libdefaults] + default_realm = ATHENA.MIT.EDU + krb4_config = /usr/kerberos/lib/krb.conf + krb4_realms = /usr/kerberos/lib/krb.realms\n\n" = + { "libdefaults" + { "default_realm" = "ATHENA.MIT.EDU" } + { "krb4_config" = "/usr/kerberos/lib/krb.conf" } + { "krb4_realms" = "/usr/kerberos/lib/krb.realms" } + { } } + +(* Test for [appfdefaults] *) +test Krb5.appdefaults get "[appdefaults]\n\tdefault_lifetime = 7d\n" = + { "appdefaults" { "default_lifetime" = "7d" } } + +test Krb5.appdefaults get + "[appdefaults]\nrcp = { \n forward = true\n encrypt = false\n }\n" = + { "appdefaults" + { "application" = "rcp" + { "forward" = "true" } + { "encrypt" = "false" } } } + +test Krb5.appdefaults get "[appdefaults]\ntelnet = {\n\t}\n" = + { "appdefaults" { "application" = "telnet" } } + +test Krb5.appdefaults get "[appdefaults] + rcp = { + forward = true + ATHENA.MIT.EDU = { + encrypt = false + } + MEDIA-LAB.MIT.EDU = { + encrypt = true + } + forwardable = true + }\n" = + { "appdefaults" + { "application" = "rcp" + { "forward" = "true" } + { "realm" = "ATHENA.MIT.EDU" + { "encrypt" = "false" } } + { "realm" = "MEDIA-LAB.MIT.EDU" + { "encrypt" = "true" } } + { "forwardable" = "true" } } } + +let appdef = "[appdefaults] + default_lifetime = 7d + retain_ccache = false + autologin = true + forward = true + forwardable = true + renewable = true + encrypt = true + krb5_aklog_path = /usr/bin/aklog + + telnet = { + } + + rcp = { + forward = true + encrypt = false + allow_fallback = true + } + + rsh = { + allow_fallback = true + } + + rlogin = { + allow_fallback = false + } + + + login = { + forwardable = true + krb5_run_aklog = false + krb5_get_tickets = true + krb4_get_tickets = false + krb4_convert = false + } + + kinit = { + forwardable = true + krb5_run_aklog = false + } + + kadmin = { + forwardable = false + } + + rshd = { + krb5_run_aklog = false + } + + ftpd = { + krb5_run_aklog = false + default_lifetime = 10h + } + + pam = { + debug = false + forwardable = true + renew_lifetime = 7d + ticket_lifetime = 1560m + krb4_convert = true + afs_cells = fnal.gov + krb5_run_aklog = false + }\n" + +let appdef_tree = + { "appdefaults" + { "default_lifetime" = "7d" } + { "retain_ccache" = "false" } + { "autologin" = "true" } + { "forward" = "true" } + { "forwardable" = "true" } + { "renewable" = "true" } + { "encrypt" = "true" } + { "krb5_aklog_path" = "/usr/bin/aklog" } + { } + { "application" = "telnet" } + { } + { "application" = "rcp" + { "forward" = "true" } + { "encrypt" = "false" } + { "allow_fallback" = "true" } + } + { } + { "application" = "rsh" + { "allow_fallback" = "true" } + } + { } + { "application" = "rlogin" + { "allow_fallback" = "false" } + } + { } + { } + { "application" = "login" + { "forwardable" = "true" } + { "krb5_run_aklog" = "false" } + { "krb5_get_tickets" = "true" } + { "krb4_get_tickets" = "false" } + { "krb4_convert" = "false" } + } + { } + { "application" = "kinit" + { "forwardable" = "true" } + { "krb5_run_aklog" = "false" } + } + { } + { "application" = "kadmin" + { "forwardable" = "false" } + } + { } + { "application" = "rshd" + { "krb5_run_aklog" = "false" } + } + { } + { "application" = "ftpd" + { "krb5_run_aklog" = "false" } + { "default_lifetime" = "10h" } + } + { } + { "application" = "pam" + { "debug" = "false" } + { "forwardable" = "true" } + { "renew_lifetime" = "7d" } + { "ticket_lifetime" = "1560m" } + { "krb4_convert" = "true" } + { "afs_cells" = "fnal.gov" } + { "krb5_run_aklog" = "false" } + } + } + + +test Krb5.appdefaults get appdef = appdef_tree +test Krb5.lns get appdef = appdef_tree + + +(* Test realms section *) +let realms_str = "[realms] + ATHENA.MIT.EDU = { + admin_server = KERBEROS.MIT.EDU + default_domain = MIT.EDU + database_module = ldapconf + + # test + v4_instance_convert = { + mit = mit.edu + lithium = lithium.lcs.mit.edu + } + v4_realm = LCS.MIT.EDU + }\n" + +test Krb5.lns get realms_str = + { "realms" + { "realm" = "ATHENA.MIT.EDU" + { "admin_server" = "KERBEROS.MIT.EDU" } + { "default_domain" = "MIT.EDU" } + { "database_module" = "ldapconf" } + { } + { "#comment" = "test" } + { "v4_instance_convert" + { "mit" = "mit.edu" } + { "lithium" = "lithium.lcs.mit.edu" } } + { "v4_realm" = "LCS.MIT.EDU" } } } + +(* Test dpmain_realm section *) +let domain_realm_str = "[domain_realm] + .mit.edu = ATHENA.MIT.EDU + mit.edu = ATHENA.MIT.EDU + dodo.mit.edu = SMS_TEST.MIT.EDU + .ucsc.edu = CATS.UCSC.EDU\n" + +test Krb5.lns get domain_realm_str = + { "domain_realm" + { ".mit.edu" = "ATHENA.MIT.EDU" } + { "mit.edu" = "ATHENA.MIT.EDU" } + { "dodo.mit.edu" = "SMS_TEST.MIT.EDU" } + { ".ucsc.edu" = "CATS.UCSC.EDU" } } + +(* Test logging section *) +let logging_str = "[logging] + kdc = CONSOLE + kdc = SYSLOG:INFO:DAEMON + admin_server = FILE:/var/adm/kadmin.log + admin_server = DEVICE=/dev/tty04\n" + +test Krb5.lns get logging_str = + { "logging" + { "kdc" + { "console" } } + { "kdc" + { "syslog" + { "severity" = "INFO" } + { "facility" = "DAEMON" } } } + { "admin_server" + { "file" = "/var/adm/kadmin.log" } } + { "admin_server" + { "device" = "/dev/tty04" } } } + +(* Test capaths section *) +let capaths_str = "[capaths] + ANL.GOV = { + TEST.ANL.GOV = . + PNL.GOV = ES.NET + NERSC.GOV = ES.NET + ES.NET = . + } + TEST.ANL.GOV = { + ANL.GOV = . + } + PNL.GOV = { + ANL.GOV = ES.NET + } + NERSC.GOV = { + ANL.GOV = ES.NET + } + ES.NET = { + ANL.GOV = . + }\n" + +test Krb5.lns get capaths_str = + { "capaths" + { "ANL.GOV" + { "TEST.ANL.GOV" = "." } + { "PNL.GOV" = "ES.NET" } + { "NERSC.GOV" = "ES.NET" } + { "ES.NET" = "." } } + { "TEST.ANL.GOV" + { "ANL.GOV" = "." } } + { "PNL.GOV" + { "ANL.GOV" = "ES.NET" } } + { "NERSC.GOV" + { "ANL.GOV" = "ES.NET" } } + { "ES.NET" + { "ANL.GOV" = "." } } } + +(* Test instancemapping *) + +test Krb5.instance_mapping get "[instancemapping] + afs = { + cron/* = \"\" + cms/* = \"\" + afs/* = \"\" + e898/* = \"\" + }\n" = + { "instancemapping" + { "afs" + { "mapping" = "cron/*" + { "value" = "" } } + { "mapping" = "cms/*" + { "value" = "" } } + { "mapping" = "afs/*" + { "value" = "" } } + { "mapping" = "e898/*" + { "value" = "" } } } } + +test Krb5.kdc get "[kdc] + profile = /var/kerberos/krb5kdc/kdc.conf\n" = + { "kdc" + { "profile" = "/var/kerberos/krb5kdc/kdc.conf" } } + +(* v4_name_convert in libdefaults *) +test Krb5.libdefaults get "[libdefaults] + default_realm = MY.REALM + clockskew = 300 + v4_instance_resolve = false + v4_name_convert = { + host = { + rcmd = host + ftp = ftp + } + plain = { + something = something-else + } + }\n" = + + { "libdefaults" + { "default_realm" = "MY.REALM" } + { "clockskew" = "300" } + { "v4_instance_resolve" = "false" } + { "v4_name_convert" + { "host" { "rcmd" = "host" } { "ftp" = "ftp" } } + { "plain" { "something" = "something-else" } } } } + +(* Test pam section *) +let pam_str = "[pam] + debug = false + ticket_lifetime = 36000 + renew_lifetime = 36000 + forwardable = true + krb4_convert = false +" + +test Krb5.lns get pam_str = + { "pam" + { "debug" = "false" } + { "ticket_lifetime" = "36000" } + { "renew_lifetime" = "36000" } + { "forwardable" = "true" } + { "krb4_convert" = "false" } } + +(* Ticket #274 - multiple *enctypes values *) +let multiple_enctypes = "[libdefaults] +permitted_enctypes = arcfour-hmac-md5 arcfour-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc aes128-cts +default_tgs_enctypes = des3-cbc-sha1 des-cbc-md5 +default_tkt_enctypes = des-cbc-md5 +" + +test Krb5.lns get multiple_enctypes = + { "libdefaults" + { "permitted_enctypes" = "arcfour-hmac-md5" } + { "permitted_enctypes" = "arcfour-hmac" } + { "permitted_enctypes" = "des3-cbc-sha1" } + { "permitted_enctypes" = "des-cbc-md5" } + { "permitted_enctypes" = "des-cbc-crc" } + { "permitted_enctypes" = "aes128-cts" } + { "#eol" } + { "default_tgs_enctypes" = "des3-cbc-sha1" } + { "default_tgs_enctypes" = "des-cbc-md5" } + { "#eol" } + { "default_tkt_enctypes" = "des-cbc-md5" } + { "#eol" } + } + +(* Ticket #274 - v4_name_convert subsection *) +let v4_name_convert = "[realms] + EXAMPLE.COM = { + kdc = kerberos.example.com:88 + admin_server = kerberos.example.com:749 + default_domain = example.com + ticket_lifetime = 12h + v4_name_convert = { + host = { + rcmd = host + } + } + } +" + +test Krb5.lns get v4_name_convert = + { "realms" + { "realm" = "EXAMPLE.COM" + { "kdc" = "kerberos.example.com:88" } + { "admin_server" = "kerberos.example.com:749" } + { "default_domain" = "example.com" } + { "ticket_lifetime" = "12h" } + { "v4_name_convert" + { "host" + { "rcmd" = "host" } + } + } + } + } + +(* Ticket #288: semicolons for comments *) +test Krb5.lns get "; AD : This Kerberos configuration is for CERN's Active Directory realm.\n" = + { "#comment" = "AD : This Kerberos configuration is for CERN's Active Directory realm." } + +(* RHBZ#1066419: braces in values *) +test Krb5.lns get "[libdefaults]\n +default_ccache_name = KEYRING:persistent:%{uid}\n" = + { "libdefaults" + { } + { "default_ccache_name" = "KEYRING:persistent:%{uid}" } } + +(* Include(dir) tests *) +let include_test = "include /etc/krb5.other_conf.d/other.conf +includedir /etc/krb5.conf.d/ +" + +test Krb5.lns get include_test = + { "include" = "/etc/krb5.other_conf.d/other.conf" } + { "includedir" = "/etc/krb5.conf.d/" } + +let include2_test = "[logging] + default = FILE:/var/log/krb5libs.log + +include /etc/krb5.other_conf.d/other.conf + +includedir /etc/krb5.conf.d/ +" + +test Krb5.lns get include2_test = + { "logging" + { "default" + { "file" = "/var/log/krb5libs.log" } } + { } + } + { "include" = "/etc/krb5.other_conf.d/other.conf" } + { } + { "includedir" = "/etc/krb5.conf.d/" } + +(* [dbmodules] test *) +let dbmodules_test = "[dbmodules] + ATHENA.MIT.EDU = { + disable_last_success = true + } + db_module_dir = /some/path +" + +test Krb5.lns get dbmodules_test = + { "dbmodules" + { "realm" = "ATHENA.MIT.EDU" + { "disable_last_success" = "true" } + } + { "db_module_dir" = "/some/path" } + } + +(* [plugins] test *) +let plugins_test = "[plugins] + clpreauth = { + module = mypreauth:/path/to/mypreauth.so + } + ccselect = { + disable = k5identity + } + pwqual = { + module = mymodule:/path/to/mymodule.so + module = mymodule2:/path/to/mymodule2.so + enable_only = mymodule + } + kadm5_hook = { + } +" + +test Krb5.lns get plugins_test = + { "plugins" + { "clpreauth" + { "module" = "mypreauth:/path/to/mypreauth.so" } + } + { "ccselect" + { "disable" = "k5identity" } + } + { "pwqual" + { "module" = "mymodule:/path/to/mymodule.so" } + { "module" = "mymodule2:/path/to/mymodule2.so" } + { "enable_only" = "mymodule" } + } + { "kadm5_hook" + } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_ldap.aug b/Sharp.Augeas.Test/lens/tests/test_ldap.aug new file mode 100644 index 0000000..a284204 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ldap.aug @@ -0,0 +1,20 @@ +module Test_ldap = + +let conf = "host 127.0.0.1 + +# The distinguished name of the search base. +base dc=example,dc=com +#tls_key +ssl no +pam_password md5 +" + +test Spacevars.simple_lns get conf = + { "host" = "127.0.0.1" } + {} + { "#comment" = "The distinguished name of the search base." } + { "base" = "dc=example,dc=com" } + { "#comment" = "tls_key" } + { "ssl" = "no" } + { "pam_password" = "md5" } + diff --git a/Sharp.Augeas.Test/lens/tests/test_ldif.aug b/Sharp.Augeas.Test/lens/tests/test_ldif.aug new file mode 100644 index 0000000..e7c220b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ldif.aug @@ -0,0 +1,150 @@ +(* Test for LDIF lens *) +module Test_ldif = + + (* Test LDIF content only *) + let content = "version: 1 +dn: cn=foo bar,dc=example,dc=com +# test +ou: example value +cn:: Zm9vIGJhcg== +# test +telephoneNumber;foo;bar: +1 123 456 789 +binary;foo:< file:///file/something +# test + +dn: cn=simple,dc=example,dc=com +cn: simple +test: split line starts with + :colon + +dn:: Y249c2ltcGxlLGRjPWV4YW1wbGUsZGM9Y29t +# test +cn: simple + +dn: cn=simple,dc=exam + ple,dc=com +cn: simple +telephoneNumber:: KzEgMTIzIDQ1 + NiA3ODk= + +# test +" + + test Ldif.lns get content = + { "@content" + { "version" = "1" } + { "1" = "cn=foo bar,dc=example,dc=com" + { "#comment" = "test" } + { "ou" = "example value" } + { "cn" + { "@base64" = "Zm9vIGJhcg==" } } + { "#comment" = "test" } + { "telephoneNumber" = "+1 123 456 789" + { "@option" = "foo" } + { "@option" = "bar" } } + { "binary" + { "@option" = "foo" } + { "@url" = "file:///file/something" } } } + { "#comment" = "test" } + {} + { "2" = "cn=simple,dc=example,dc=com" + { "cn" = "simple" } + { "test" = "split line starts with + :colon" } } + {} + { "3" + { "@base64" = "Y249c2ltcGxlLGRjPWV4YW1wbGUsZGM9Y29t" } + { "#comment" = "test" } + { "cn" = "simple" } } + {} + { "4" = "cn=simple,dc=exam + ple,dc=com" + { "cn" = "simple" } + { "telephoneNumber" + { "@base64" = "KzEgMTIzIDQ1 + NiA3ODk=" } } } + {} + { "#comment" = "test" } + } + + (* Test LDIF changes *) + let changes = "version: 1 +dn: cn=foo,dc=example,dc=com +changetype: delete + +dn: cn=simple,dc=example,dc=com +control: 1.2.3.4 +control: 1.2.3.4 true +# test +control: 1.2.3.4 true: foo bar +control: 1.2.3.4 true:: Zm9vIGJhcg== +changetype: add +cn: simple + +dn: cn=foo bar,dc=example,dc=com +changeType: modify +add: telephoneNumber +telephoneNumber: +1 123 456 789 +- +replace: homePostalAddress;lang-fr +homePostalAddress;lang-fr: 34 rue de Seine +# test +- +delete: telephoneNumber +- +replace: telephoneNumber +telephoneNumber:: KzEgMTIzIDQ1NiA3ODk= +- + +dn: cn=foo,dc=example,dc=com +changetype: moddn +newrdn: cn=bar +deleteoldrdn: 0 +newsuperior: dc=example,dc=net +" + + test Ldif.lns get changes = + { "@changes" + { "version" = "1" } + { "1" = "cn=foo,dc=example,dc=com" + { "changetype" = "delete" } } + {} + { "2" = "cn=simple,dc=example,dc=com" + { "control" = "1.2.3.4" } + { "control" = "1.2.3.4" + { "criticality" = "true" } } + { "#comment" = "test" } + { "control" = "1.2.3.4" + { "criticality" = "true" } + { "value" = "foo bar" } } + { "control" = "1.2.3.4" + { "criticality" = "true" } + { "value" + { "@base64" = "Zm9vIGJhcg==" } } } + { "changetype" = "add" } + { "cn" = "simple" } } + {} + { "3" = "cn=foo bar,dc=example,dc=com" + { "changeType" = "modify" } + { "add" = "telephoneNumber" + { "telephoneNumber" = "+1 123 456 789" } } + { "replace" = "homePostalAddress" + { "@option" = "lang-fr" } + { "homePostalAddress" = "34 rue de Seine" + { "@option" = "lang-fr" } } + { "#comment" = "test" } } + { "delete" = "telephoneNumber" } + { "replace" = "telephoneNumber" + { "telephoneNumber" + { "@base64" = "KzEgMTIzIDQ1NiA3ODk=" } } } } + {} + { "4" = "cn=foo,dc=example,dc=com" + { "changetype" = "moddn" } + { "newrdn" = "cn=bar" } + { "deleteoldrdn" = "0" } + { "newsuperior" = "dc=example,dc=net" } } + } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_ldso.aug b/Sharp.Augeas.Test/lens/tests/test_ldso.aug new file mode 100644 index 0000000..70ee07d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ldso.aug @@ -0,0 +1,26 @@ +(* +Module: Test_Ldso + Provides unit tests and examples for the <Ldso> lens. +*) + +module Test_Ldso = + +(* Variable: conf *) +let conf = "include /etc/ld.so.conf.d/*.conf + +# libc default configuration +/usr/local/lib + +hwcap 1 nosegneg +" + +(* Test: Ldso.lns *) +test Ldso.lns get conf = + { "include" = "/etc/ld.so.conf.d/*.conf" } + { } + { "#comment" = "libc default configuration" } + { "path" = "/usr/local/lib" } + { } + { "hwcap" + { "bit" = "1" } + { "name" = "nosegneg" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_lightdm.aug b/Sharp.Augeas.Test/lens/tests/test_lightdm.aug new file mode 100644 index 0000000..90f3b47 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_lightdm.aug @@ -0,0 +1,125 @@ +(* +Module: Test_Lightdm + Module to test Lightdm module for Augeas + +Author: David Salmen <dsalmen@dsalmen.com> + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. +*) + +module Test_lightdm = + + let conf_lightdm = " +[SeatDefaults] +greeter-session=unity-greeter +user-session=ubuntu +" + + test Lightdm.lns get conf_lightdm = + {} + { "SeatDefaults" + { "greeter-session" = "unity-greeter" } + { "user-session" = "ubuntu" } + } + + test Lightdm.lns put conf_lightdm after + set "SeatDefaults/allow-guest" "false" + = " +[SeatDefaults] +greeter-session=unity-greeter +user-session=ubuntu +allow-guest=false +" + + test Lightdm.lns put conf_lightdm after + set "SeatDefaults/allow-guest" "true" + = " +[SeatDefaults] +greeter-session=unity-greeter +user-session=ubuntu +allow-guest=true +" + + let conf_unity_greeter = " +# +# background = Background file to use, either an image path or a color (e.g. #772953) +# logo = Logo file to use +# theme-name = GTK+ theme to use +# font-name = Font to use +# xft-antialias = Whether to antialias Xft fonts (true or false) +# xft-dpi = Resolution for Xft in dots per inch (e.g. 96) +# xft-hintstyle = What degree of hinting to use (hintnone, hintslight, hintmedium, or hintfull) +# xft-rgba = Type of subpixel antialiasing (none, rgb, bgr, vrgb or vbgr) +# +[greeter] +background=/usr/share/backgrounds/warty-final-ubuntu.png +logo=/usr/share/unity-greeter/logo.png +theme-name=Ambiance +icon-theme-name=ubuntu-mono-dark +font-name=Ubuntu 11 +xft-antialias=true +xft-dpi=96 +xft-hintstyle=hintslight +xft-rgba=rgb +" + + test Lightdm.lns get conf_unity_greeter = + {} + {} + { "#comment" = "background = Background file to use, either an image path or a color (e.g. #772953)" } + { "#comment" = "logo = Logo file to use" } + { "#comment" = "theme-name = GTK+ theme to use" } + { "#comment" = "font-name = Font to use" } + { "#comment" = "xft-antialias = Whether to antialias Xft fonts (true or false)" } + { "#comment" = "xft-dpi = Resolution for Xft in dots per inch (e.g. 96)" } + { "#comment" = "xft-hintstyle = What degree of hinting to use (hintnone, hintslight, hintmedium, or hintfull)" } + { "#comment" = "xft-rgba = Type of subpixel antialiasing (none, rgb, bgr, vrgb or vbgr)" } + {} + { "greeter" + { "background" = "/usr/share/backgrounds/warty-final-ubuntu.png" } + { "logo" = "/usr/share/unity-greeter/logo.png" } + { "theme-name" = "Ambiance" } + { "icon-theme-name" = "ubuntu-mono-dark" } + { "font-name" = "Ubuntu 11" } + { "xft-antialias" = "true" } + { "xft-dpi" = "96" } + { "xft-hintstyle" = "hintslight" } + { "xft-rgba" = "rgb" } + } + + let conf_users = " +# +# User accounts configuration +# +# NOTE: If you have AccountsService installed on your system, then LightDM will +# use this instead and these settings will be ignored +# +# minimum-uid = Minimum UID required to be shown in greeter +# hidden-users = Users that are not shown to the user +# hidden-shells = Shells that indicate a user cannot login +# +[UserAccounts] +minimum-uid=500 +hidden-users=nobody nobody4 noaccess +hidden-shells=/bin/false /usr/sbin/nologin +" + + test Lightdm.lns get conf_users = + {} + {} + { "#comment" = "User accounts configuration" } + {} + { "#comment" = "NOTE: If you have AccountsService installed on your system, then LightDM will" } + { "#comment" = "use this instead and these settings will be ignored" } + {} + { "#comment" = "minimum-uid = Minimum UID required to be shown in greeter" } + { "#comment" = "hidden-users = Users that are not shown to the user" } + { "#comment" = "hidden-shells = Shells that indicate a user cannot login" } + {} + { "UserAccounts" + { "minimum-uid" = "500" } + { "hidden-users" = "nobody nobody4 noaccess" } + { "hidden-shells" = "/bin/false /usr/sbin/nologin" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_limits.aug b/Sharp.Augeas.Test/lens/tests/test_limits.aug new file mode 100644 index 0000000..dd96ec5 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_limits.aug @@ -0,0 +1,44 @@ +module Test_limits = + + let conf = "@audio - rtprio 99 +ftp hard nproc /ftp +1200:2000 - as 1024 +* soft core 0 +" + + test Limits.lns get conf = + { "domain" = "@audio" + { "type" = "-" } + { "item" = "rtprio" } + { "value" = "99" } } + { "domain" = "ftp" + { "type" = "hard" } + { "item" = "nproc" } + { "value" = "/ftp" } } + { "domain" = "1200:2000" + { "type" = "-" } + { "item" = "as" } + { "value" = "1024" } } + { "domain" = "*" + { "type" = "soft" } + { "item" = "core" } + { "value" = "0" } } + + test Limits.lns put conf after + insa "domain" "domain[last()]" ; + set "domain[last()]" "*" ; + set "domain[last()]/type" "-" ; + set "domain[last()]/item" "nofile" ; + set "domain[last()]/value" "4096" + = "@audio - rtprio 99 +ftp hard nproc /ftp +1200:2000 - as 1024 +* soft core 0 +* - nofile 4096\n" + + test Limits.lns get "* soft core 0 # clever comment\n" = + { "domain" = "*" + { "type" = "soft" } + { "item" = "core" } + { "value" = "0" } + { "#comment" = "clever comment" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_login_defs.aug b/Sharp.Augeas.Test/lens/tests/test_login_defs.aug new file mode 100644 index 0000000..00d7ce8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_login_defs.aug @@ -0,0 +1,26 @@ +(* +Module: Test_login_defs + Test cases for the login_defs lense + +Author: Erinn Looney-Triggs + +About: License + This file is licensed under the LGPLv2+, like the rest of Augeas. +*) +module Test_login_defs = + +let record = "MAIL_DIR /var/spool/mail +ENCRYPT_METHOD SHA512 +UMASK 077 +" + +test Login_defs.lns get record = + { "MAIL_DIR" = "/var/spool/mail" } + { "ENCRYPT_METHOD" = "SHA512" } + { "UMASK" = "077" } + +let comment ="# *REQUIRED* +" + +test Login_defs.lns get comment = + {"#comment" = "*REQUIRED*"} diff --git a/Sharp.Augeas.Test/lens/tests/test_logrotate.aug b/Sharp.Augeas.Test/lens/tests/test_logrotate.aug new file mode 100644 index 0000000..00ba23b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_logrotate.aug @@ -0,0 +1,290 @@ +module Test_logrotate = + +test Logrotate.body get "\n{\n monthly\n}" = + { "schedule" = "monthly" } + +test Logrotate.rule get "/var/log/foo\n{\n monthly\n}\n" = + { "rule" + { "file" = "/var/log/foo" } + { "schedule" = "monthly" } } + +test Logrotate.rule get "/var/log/foo /var/log/bar\n{\n monthly\n}\n" = + { "rule" + { "file" = "/var/log/foo" } + { "file" = "/var/log/bar" } + { "schedule" = "monthly" } } + +test Logrotate.rule get "\"/var/log/foo\"\n{\n monthly\n}\n" = + { "rule" + { "file" = "/var/log/foo" } + { "schedule" = "monthly" } } + +let conf = "# see man logrotate for details +# rotate log files weekly +weekly + +# keep 4 weeks worth of backlogs +rotate 4 + +# create new (empty) log files after rotating old ones +create + +# uncomment this if you want your log files compressed +#compress + +tabooext + .old .orig .ignore + +# packages drop log rotation information into this directory +include /etc/logrotate.d + +# no packages own wtmp, or btmp -- we'll rotate them here +/var/log/wtmp +/var/log/wtmp2 +{ + missingok + monthly + create 0664 root utmp + rotate 1 +} + +/var/log/btmp /var/log/btmp* { + missingok + # ftpd doesn't handle SIGHUP properly + monthly + create 0664 root utmp + rotate 1 +} +/var/log/vsftpd.log { + # ftpd doesn't handle SIGHUP properly + nocompress + missingok + notifempty + rotate 4 + weekly +} + +/var/log/apache2/*.log { + weekly + missingok + rotate 52 + compress + delaycompress + notifempty + create 640 root adm + sharedscripts + prerotate + if [ -f /var/run/apache2.pid ]; then + /etc/init.d/apache2 restart > /dev/null + fi + endscript +} +/var/log/mailman/digest { + su root list + monthly + missingok + create 0664 list list + rotate 4 + compress + delaycompress + sharedscripts + postrotate + [ -f '/var/run/mailman/mailman.pid' ] && /usr/lib/mailman/bin/mailmanctl -q reopen || exit 0 + endscript +} +/var/log/ntp { + compress + dateext + maxage 365 + rotate 99 + size=+2048k + notifempty + missingok + copytruncate + postrotate + chmod 644 /var/log/ntp + endscript +} +" + +test Logrotate.lns get conf = + { "#comment" = "see man logrotate for details" } + { "#comment" = "rotate log files weekly" } + { "schedule" = "weekly" } + {} + { "#comment" = "keep 4 weeks worth of backlogs" } + { "rotate" = "4" } + {} + { "#comment" = "create new (empty) log files after rotating old ones" } + { "create" } + {} + { "#comment" = "uncomment this if you want your log files compressed" } + { "#comment" = "compress" } + {} + { "tabooext" = "+" { ".old" } { ".orig" } { ".ignore" } } + {} + { "#comment" = "packages drop log rotation information into this directory" } + { "include" = "/etc/logrotate.d" } + {} + { "#comment" = "no packages own wtmp, or btmp -- we'll rotate them here" } + { "rule" + { "file" = "/var/log/wtmp" } + { "file" = "/var/log/wtmp2" } + { "missingok" = "missingok" } + { "schedule" = "monthly" } + { "create" + { "mode" = "0664" } + { "owner" = "root" } + { "group" = "utmp" } } + { "rotate" = "1" } } + {} + { "rule" + { "file" = "/var/log/btmp" } + { "file" = "/var/log/btmp*" } + { "missingok" = "missingok" } + { "#comment" = "ftpd doesn't handle SIGHUP properly" } + { "schedule" = "monthly" } + { "create" + { "mode" = "0664" } + { "owner" = "root" } + { "group" = "utmp" } } + { "rotate" = "1" } } + { "rule" + { "file" = "/var/log/vsftpd.log" } + { "#comment" = "ftpd doesn't handle SIGHUP properly" } + { "compress" = "nocompress" } + { "missingok" = "missingok" } + { "ifempty" = "notifempty" } + { "rotate" = "4" } + { "schedule" = "weekly" } } + {} + { "rule" + { "file" = "/var/log/apache2/*.log" } + { "schedule" = "weekly" } + { "missingok" = "missingok" } + { "rotate" = "52" } + { "compress" = "compress" } + { "delaycompress" = "delaycompress" } + { "ifempty" = "notifempty" } + { "create" + { "mode" = "640" } + { "owner" = "root" } + { "group" = "adm" } } + { "sharedscripts" = "sharedscripts" } + { "prerotate" = " if [ -f /var/run/apache2.pid ]; then + /etc/init.d/apache2 restart > /dev/null + fi" } } + { "rule" + { "file" = "/var/log/mailman/digest" } + { "su" + { "owner" = "root" } + { "group" = "list" } } + { "schedule" = "monthly" } + { "missingok" = "missingok" } + { "create" + { "mode" = "0664" } + { "owner" = "list" } + { "group" = "list" } } + { "rotate" = "4" } + { "compress" = "compress" } + { "delaycompress" = "delaycompress" } + { "sharedscripts" = "sharedscripts" } + { "postrotate" = " [ -f '/var/run/mailman/mailman.pid' ] && /usr/lib/mailman/bin/mailmanctl -q reopen || exit 0" } } + { "rule" + { "file" = "/var/log/ntp" } + { "compress" = "compress" } + { "dateext" = "dateext" } + { "maxage" = "365" } + { "rotate" = "99" } + { "size" = "+2048k" } + { "ifempty" = "notifempty" } + { "missingok" = "missingok" } + { "copytruncate" = "copytruncate" } + { "postrotate" = " chmod 644 /var/log/ntp" } } + +test Logrotate.lns get "/var/log/file {\n dateext\n}\n" = + { "rule" + { "file" = "/var/log/file" } + { "dateext" = "dateext" } } + + (* Make sure 'minsize 1M' works *) +test Logrotate.lns get "/avr/log/wtmp {\n minsize 1M\n}\n" = + { "rule" + { "file" = "/avr/log/wtmp" } + { "minsize" = "1M" } } + + (* '=' is a legal separator, file names can be indented *) +test Logrotate.lns get " \t /file {\n size=5M\n}\n" = + { "rule" + { "file" = "/file" } + { "size" = "5M" } } + + (* Can leave owner/group off a create statement *) +test Logrotate.lns get "/file { + create 600\n}\n" = + { "rule" + { "file" = "/file" } + { "create" + { "mode" = "600" } } } + +test Logrotate.lns put "/file {\n create 600\n}\n" after + set "/rule/create/owner" "user" + = "/file {\n create 600 user\n}\n" + + (* The newline at the end of a script is optional *) +test Logrotate.lns put "/file {\n size=5M\n}\n" after + set "/rule/prerotate" "\tfoobar" + = +"/file { + size=5M +\tprerotate +\tfoobar +\tendscript\n}\n" + +test Logrotate.lns put "/file {\n size=5M\n}\n" after + set "/rule/prerotate" "\tfoobar\n" + = +"/file { + size=5M +\tprerotate +\tfoobar\n +\tendscript\n}\n" + +(* Bug #101: whitespace at the end of the line *) +test Logrotate.lns get "/file {\n missingok \t\n}\n" = + { "rule" + { "file" = "/file" } + { "missingok" = "missingok" } } + +(* Bug #104: file names can be separated by newlines *) +let conf2 = "/var/log/mail.info +/var/log/mail.warn +/var/log/mail.err +{ + weekly +} +" +test Logrotate.lns get conf2 = + { "rule" + { "file" = "/var/log/mail.info" } + { "file" = "/var/log/mail.warn" } + { "file" = "/var/log/mail.err" } + { "schedule" = "weekly" } } + +(* Issue #217: support for dateformat *) +let dateformat = "dateformat -%Y%m%d\n" + +test Logrotate.lns get dateformat = + { "dateformat" = "-%Y%m%d" } + +(* Issue #123: no space before '{' *) +test Logrotate.lns get "/file{\n missingok \t\n}\n" = + { "rule" + { "file" = "/file" } + { "missingok" = "missingok" } } + +(* RHBZ#1213292: maxsize 30k *) +test Logrotate.lns get "/var/log/yum.log {\n maxsize 30k\n}\n" = + { "rule" + { "file" = "/var/log/yum.log" } + { "maxsize" = "30k" } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_logwatch.aug b/Sharp.Augeas.Test/lens/tests/test_logwatch.aug new file mode 100644 index 0000000..f2ba806 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_logwatch.aug @@ -0,0 +1,15 @@ +module Test_logwatch = + +let conf = "# Configuration file for logwatch. +# +#Mailto_host1 = user@example.com + +MailFrom = root@example.com +" + +test Logwatch.lns get conf = + { "#comment" = "Configuration file for logwatch." } + {} + { "#comment" = "Mailto_host1 = user@example.com" } + {} + { "MailFrom" = "root@example.com" } diff --git a/Sharp.Augeas.Test/lens/tests/test_lokkit.aug b/Sharp.Augeas.Test/lens/tests/test_lokkit.aug new file mode 100644 index 0000000..c197687 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_lokkit.aug @@ -0,0 +1,88 @@ +module Test_lokkit = + +let conf = "# Configuration file for system-config-firewall + +--enabled +--port=111:tcp +-p 111:udp +-p 2020-2049:tcp +--port=5900-5910:tcp +--custom-rules=ipv4:filter:/var/lib/misc/iptables-forward-bridged +-s dns +--service=ssh +--trust=trust1 +--masq=eth42 +--block-icmp=5 +-t trust0 +--addmodule=fancy +--removemodule=broken +--forward-port=if=forw0:port=42:proto=tcp:toport=42:toaddr=192.168.0.42 +--selinux=permissive +" + +test Lokkit.lns get conf = + { "#comment" = "Configuration file for system-config-firewall" } + { } + { "enabled" } + { "port" + { "start" = "111" } + { "protocol" = "tcp" } } + { "port" + { "start" = "111" } + { "protocol" = "udp" } } + { "port" + { "start" = "2020" } + { "end" = "2049" } + { "protocol" = "tcp" } } + { "port" + { "start" = "5900" } + { "end" = "5910" } + { "protocol" = "tcp" } } + { "custom-rules" = "/var/lib/misc/iptables-forward-bridged" + { "type" = "ipv4" } + { "table" = "filter" } } + { "service" = "dns" } + { "service" = "ssh" } + { "trust" = "trust1" } + { "masq" = "eth42" } + { "block-icmp" = "5" } + { "trust" = "trust0" } + { "addmodule" = "fancy" } + { "removemodule" = "broken" } + { "forward-port" + { "if" = "forw0" } + { "port" = "42" } + { "proto" = "tcp" } + { "toport" = "42" } + { "toaddr" = "192.168.0.42" } } + { "selinux" = "permissive" } + +test Lokkit.custom_rules get +"--custom-rules=ipv4:filter:/some/file\n" = + { "custom-rules" = "/some/file" + { "type" = "ipv4" } + { "table" = "filter" } } + +test Lokkit.custom_rules get +"--custom-rules=filter:/some/file\n" = + { "custom-rules" = "/some/file" + { "table" = "filter" } } + +test Lokkit.custom_rules get +"--custom-rules=ipv4:/some/file\n" = + { "custom-rules" = "/some/file" + { "type" = "ipv4" } } + +test Lokkit.custom_rules get +"--custom-rules=/some/file\n" = + { "custom-rules" = "/some/file" } + +test Lokkit.lns get +"--trust=tun+\n--trust=eth0.42\n--trust=eth0:1\n" = + { "trust" = "tun+" } + { "trust" = "eth0.42" } + { "trust" = "eth0:1" } + +(* We didn't allow '-' in the service name *) +test Lokkit.lns get "--service=samba-client\n" = + { "service" = "samba-client" } diff --git a/Sharp.Augeas.Test/lens/tests/test_lvm.aug b/Sharp.Augeas.Test/lens/tests/test_lvm.aug new file mode 100644 index 0000000..8ee2377 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_lvm.aug @@ -0,0 +1,253 @@ +(* +Module: Test_LVM + Provides unit tests and examples for the <LVM> lens. +*) + +module Test_LVM = + +(* Variable: conf + A full configuration file *) +let conf = "# Generated by LVM2: date + +contents = \"Text Format Volume Group\" +version = 1 + +description = \"Created *after* executing 'eek'\" + +creation_host = \"eek\" # Linux eek +creation_time = 6666666666 # eeeek + +VG1 { + id = \"uuid-uuid-uuid-uuid\" + seqno = 2 + status = [\"RESIZEABLE\", \"READ\", \"WRITE\"] + extent_size = 8192 # 4 Megabytes + max_lv = 0 + max_pv = 0 + process_priority = -18 + + physical_volumes { + pv0 { + id = \"uuid-uuid-uuid-uuid\" + device = \"/dev/sda6\" # Hint only + + status = [\"ALLOCATABLE\"] + pe_start = 123 + pe_count = 123456 # many Gigabytes + } + } + + logical_volumes { + LogicalEek { + id = \"uuid-uuid-uuid-uuid\" + status = [\"READ\", \"WRITE\", \"VISIBLE\"] + segment_count = 1 + + segment1 { + start_extent = 0 + extent_count = 123456 # beaucoup Gigabytes + + type = \"striped\" + stripe_count = 1 # linear + + stripes = [ + \"pv0\", 0 + ] + } + } + } +} +" + +test LVM.int get "5" = { "int" = "5" } +test LVM.str get "\"abc\"" = { "str" = "abc"} +test LVM.lns get "\n" = {} +test LVM.lns get "#foo\n" = { "#comment" = "foo"} + +test LVM.lns get "# Generated by LVM2: date + +contents = \"Text Format Volume Group\" +version = 1 + +description = \"Created *after* executing 'eek'\" + +creation_host = \"eek\" # Linux eek +creation_time = 6666666666 # eeeek\n" = + { "#comment" = "Generated by LVM2: date" } + {} + { "contents" + { "str" = "Text Format Volume Group" } + } + { "version" + { "int" = "1" } + } + {} + { "description" + { "str" = "Created *after* executing 'eek'" } + } + {} + { "creation_host" + { "str" = "eek" } + { "#comment" = "Linux eek" } + } + { "creation_time" + { "int" = "6666666666" } + { "#comment" = "eeeek" } + } + +(* Test: LVM.lns + Test the full <conf> *) +test LVM.lns get conf = + { "#comment" = "Generated by LVM2: date" } + {} + { "contents" + { "str" = "Text Format Volume Group" } + } + { "version" + { "int" = "1" } + } + {} + { "description" + { "str" = "Created *after* executing 'eek'" } + } + {} + { "creation_host" + { "str" = "eek" } + { "#comment" = "Linux eek" } + } + { "creation_time" + { "int" = "6666666666" } + { "#comment" = "eeeek" } + } + {} + { "VG1" + { "dict" + { "id" + { "str" = "uuid-uuid-uuid-uuid" } + } + { "seqno" + { "int" = "2" } + } + { "status" + { "list" + { "1" + { "str" = "RESIZEABLE" } + } + { "2" + { "str" = "READ" } + } + { "3" + { "str" = "WRITE" } + } + } + } + { "extent_size" + { "int" = "8192" } + { "#comment" = "4 Megabytes" } + } + { "max_lv" + { "int" = "0" } + } + { "max_pv" + { "int" = "0" } + } + { "process_priority" + { "int" = "-18" } + } + {} + { "physical_volumes" + { "dict" + { "pv0" + { "dict" + { "id" + { "str" = "uuid-uuid-uuid-uuid" } + } + { "device" + { "str" = "/dev/sda6" } + { "#comment" = "Hint only" } + } + {} + { "status" + { "list" + { "1" + { "str" = "ALLOCATABLE" } + } + } + } + { "pe_start" + { "int" = "123" } + } + { "pe_count" + { "int" = "123456" } + { "#comment" = "many Gigabytes" } + } + } + } + } + } + {} + { "logical_volumes" + { "dict" + { "LogicalEek" + { "dict" + { "id" + { "str" = "uuid-uuid-uuid-uuid" } + } + { "status" + { "list" + { "1" + { "str" = "READ" } + } + { "2" + { "str" = "WRITE" } + } + { "3" + { "str" = "VISIBLE" } + } + } + } + { "segment_count" + { "int" = "1" } + } + {} + { "segment1" + { "dict" + { "start_extent" + { "int" = "0" } + } + { "extent_count" + { "int" = "123456" } + { "#comment" = "beaucoup Gigabytes" } + } + {} + { "type" + { "str" = "striped" } + } + { "stripe_count" + { "int" = "1" } + { "#comment" = "linear" } + } + {} + { "stripes" + { "list" + { "1" + { "str" = "pv0" } + } + { "2" + { "int" = "0" } + } + } + } + } + } + } + } + } + } + } + } + +(* Parse description from RHEL 6 *) +let descr="\"Created *before* executing '/sbin/vgs --noheadings -o name --config 'log{command_names=0 prefix=\\\" \\\"}''\"" +test LVM.str get descr = + { "str" = "Created *before* executing '/sbin/vgs --noheadings -o name --config 'log{command_names=0 prefix=\\\" \\\"}''" } diff --git a/Sharp.Augeas.Test/lens/tests/test_mailscanner.aug b/Sharp.Augeas.Test/lens/tests/test_mailscanner.aug new file mode 100644 index 0000000..4c60e31 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_mailscanner.aug @@ -0,0 +1,745 @@ +module Test_Mailscanner = + +let conf = "# Main configuration file for the MailScanner E-Mail Virus Scanner +%org-name% = BARUWA +%org-long-name% = BARUWA MAILFW +%web-site% = www.baruwa.com +%etc-dir% = /etc/MailScanner +%reports-base% = /etc/MailScanner/reports +%report-dir% = /etc/MailScanner/reports/en +%rules-dir% = /etc/MailScanner/rules +%mcp-dir% = /etc/MailScanner/mcp +%spool-dir% = /var/spool/MailScanner +%signature-dir% = /etc/MailScanner/baruwa/signatures +%brules-dir% = /etc/MailScanner/baruwa/rules +Max Children = 5 +Run As User = exim +Run As Group = exim +Queue Scan Interval = 6 +Incoming Queue Dir = /var/spool/exim.in/input +Outgoing Queue Dir = /var/spool/exim/input +Incoming Work Dir = %spool-dir%/incoming +Quarantine Dir = %spool-dir%/quarantine +PID file = /var/run/MailScanner/MailScanner.pid +Restart Every = 7200 +MTA = exim +Sendmail = /usr/sbin/exim -C /etc/exim/exim_out.conf +Sendmail2 = /usr/sbin/exim -C /etc/exim/exim_out.conf +Incoming Work User = exim +Incoming Work Group = clam +Incoming Work Permissions = 0640 +Quarantine User = exim +Quarantine Group = baruwa +Quarantine Permissions = 0660 +Max Unscanned Bytes Per Scan = 100m +Max Unsafe Bytes Per Scan = 50m +Max Unscanned Messages Per Scan = 30 +Max Unsafe Messages Per Scan = 30 +Max Normal Queue Size = 800 +Scan Messages = %rules-dir%/scan.messages.rules +Reject Message = no +Maximum Processing Attempts = 6 +Processing Attempts Database = %spool-dir%/incoming/Processing.db +Maximum Attachments Per Message = 200 +Expand TNEF = yes +Use TNEF Contents = replace +Deliver Unparsable TNEF = no +TNEF Expander = /usr/bin/tnef --maxsize=100000000 +TNEF Timeout = 120 +File Command = /usr/sbin/file-wrapper +File Timeout = 20 +Gunzip Command = /bin/gunzip +Gunzip Timeout = 50 +Unrar Command = /usr/bin/unrar +Unrar Timeout = 50 +Find UU-Encoded Files = no +Maximum Message Size = %brules-dir%/message.size.rules +Maximum Attachment Size = -1 +Minimum Attachment Size = -1 +Maximum Archive Depth = 4 +Find Archives By Content = yes +Unpack Microsoft Documents = yes +Zip Attachments = no +Attachments Zip Filename = MessageAttachments.zip +Attachments Min Total Size To Zip = 100k +Attachment Extensions Not To Zip = .zip .rar .gz .tgz .jpg .jpeg .mpg .mpe .mpeg .mp3 .rpm .htm .html .eml +Add Text Of Doc = no +Antiword = /usr/bin/antiword -f +Antiword Timeout = 50 +Unzip Maximum Files Per Archive = 0 +Unzip Maximum File Size = 50k +Unzip Filenames = *.txt *.ini *.log *.csv +Unzip MimeType = text/plain +Virus Scanning = %brules-dir%/virus.checks.rules +Virus Scanners = auto +Virus Scanner Timeout = 300 +Deliver Disinfected Files = no +Silent Viruses = HTML-IFrame All-Viruses +Still Deliver Silent Viruses = no +Non-Forging Viruses = Joke/ OF97/ WM97/ W97M/ eicar +Spam-Virus Header = X-%org-name%-BaruwaFW-SpamVirus-Report: +Virus Names Which Are Spam = Sanesecurity.Spam*UNOFFICIAL HTML/* *Phish* *Suspected-phishing_safebrowsing* +Block Encrypted Messages = no +Block Unencrypted Messages = no +Allow Password-Protected Archives = yes +Check Filenames In Password-Protected Archives = yes +Allowed Sophos Error Messages = +Sophos IDE Dir = /opt/sophos-av/lib/sav +Sophos Lib Dir = /opt/sophos-av/lib +Monitors For Sophos Updates = /opt/sophos-av/lib/sav/*.ide +Monitors for ClamAV Updates = /var/lib/clamav/*.cvd +ClamAVmodule Maximum Recursion Level = 8 +ClamAVmodule Maximum Files = 1000 +ClamAVmodule Maximum File Size = 10000000 +ClamAVmodule Maximum Compression Ratio = 250 +Clamd Port = 3310 +Clamd Socket = /var/run/clamav/clamd.sock +Clamd Lock File = +Clamd Use Threads = no +ClamAV Full Message Scan = yes +Fpscand Port = 10200 +Dangerous Content Scanning = %rules-dir%/content.scanning.rules +Allow Partial Messages = no +Allow External Message Bodies = no +Find Phishing Fraud = yes +Also Find Numeric Phishing = yes +Use Stricter Phishing Net = yes +Highlight Phishing Fraud = yes +Phishing Safe Sites File = %etc-dir%/phishing.safe.sites.conf +Phishing Bad Sites File = %etc-dir%/phishing.bad.sites.conf +Country Sub-Domains List = %etc-dir%/country.domains.conf +Allow IFrame Tags = disarm +Allow Form Tags = disarm +Allow Script Tags = disarm +Allow WebBugs = disarm +Ignored Web Bug Filenames = spacer pixel.gif pixel.png gap +Known Web Bug Servers = msgtag.com +Web Bug Replacement = https://datafeeds.baruwa.com/1x1spacer.gif +Allow Object Codebase Tags = disarm +Convert Dangerous HTML To Text = no +Convert HTML To Text = no +Archives Are = zip rar ole +Allow Filenames = +Deny Filenames = +Filename Rules = %rules-dir%/filename.rules +Allow Filetypes = +Allow File MIME Types = +Deny Filetypes = +Deny File MIME Types = +Filetype Rules = %rules-dir%/filetype.rules +Archives: Allow Filenames = +Archives: Deny Filenames = +Archives: Filename Rules = %etc-dir%/archives.filename.rules.conf +Archives: Allow Filetypes = +Archives: Allow File MIME Types = +Archives: Deny Filetypes = +Archives: Deny File MIME Types = +Archives: Filetype Rules = %etc-dir%/archives.filetype.rules.conf +Default Rename Pattern = __FILENAME__.disarmed +Quarantine Infections = yes +Quarantine Silent Viruses = no +Quarantine Modified Body = no +Quarantine Whole Message = yes +Quarantine Whole Messages As Queue Files = no +Keep Spam And MCP Archive Clean = yes +Language Strings = %brules-dir%/languages.rules +Rejection Report = %brules-dir%/rejectionreport.rules +Deleted Bad Content Message Report = %brules-dir%/deletedcontentmessage.rules +Deleted Bad Filename Message Report = %brules-dir%/deletedfilenamemessage.rules +Deleted Virus Message Report = %brules-dir%/deletedvirusmessage.rules +Deleted Size Message Report = %brules-dir%/deletedsizemessage.rules +Stored Bad Content Message Report = %brules-dir%/storedcontentmessage.rules +Stored Bad Filename Message Report = %brules-dir%/storedfilenamemessage.rules +Stored Virus Message Report = %brules-dir%/storedvirusmessage.rules +Stored Size Message Report = %brules-dir%/storedsizemessage.rules +Disinfected Report = %brules-dir%/disinfectedreport.rules +Inline HTML Signature = %brules-dir%/html.sigs.rules +Inline Text Signature = %brules-dir%/text.sigs.rules +Signature Image Filename = %brules-dir%/sig.imgs.names.rules +Signature Image <img> Filename = %brules-dir%/sig.imgs.rules +Inline HTML Warning = %brules-dir%/inlinewarninghtml.rules +Inline Text Warning = %brules-dir%/inlinewarningtxt.rules +Sender Content Report = %brules-dir%/sendercontentreport.rules +Sender Error Report = %brules-dir%/sendererrorreport.rules +Sender Bad Filename Report = %brules-dir%/senderfilenamereport.rules +Sender Virus Report = %brules-dir%/sendervirusreport.rules +Sender Size Report = %brules-dir%/sendersizereport.rules +Hide Incoming Work Dir = yes +Include Scanner Name In Reports = yes +Mail Header = X-%org-name%-BaruwaFW: +Spam Header = X-%org-name%-BaruwaFW-SpamCheck: +Spam Score Header = X-%org-name%-BaruwaFW-SpamScore: +Information Header = X-%org-name%-BaruwaFW-Information: +Add Envelope From Header = yes +Add Envelope To Header = no +Envelope From Header = X-BARUWA-BaruwaFW-From: +Envelope To Header = X-%org-name%-BaruwaFW-To: +ID Header = X-%org-name%-BaruwaFW-ID: +IP Protocol Version Header = +Spam Score Character = s +SpamScore Number Instead Of Stars = no +Minimum Stars If On Spam List = 0 +Clean Header Value = Found to be clean +Infected Header Value = Found to be infected +Disinfected Header Value = Disinfected +Information Header Value = Please contact %org-long-name% for more information +Detailed Spam Report = yes +Include Scores In SpamAssassin Report = yes +Always Include SpamAssassin Report = no +Multiple Headers = add +Place New Headers At Top Of Message = yes +Hostname = the %org-name% ($HOSTNAME) Baruwa +Sign Messages Already Processed = no +Sign Clean Messages = %brules-dir%/sign.clean.msgs.rules +Attach Image To Signature = yes +Attach Image To HTML Message Only = yes +Allow Multiple HTML Signatures = no +Dont Sign HTML If Headers Exist = +Mark Infected Messages = yes +Mark Unscanned Messages = no +Unscanned Header Value = Not scanned: please contact %org-long-name% for details +Remove These Headers = X-Mozilla-Status: X-Mozilla-Status2: +Deliver Cleaned Messages = yes +Notify Senders = no +Notify Senders Of Viruses = no +Notify Senders Of Blocked Filenames Or Filetypes = no +Notify Senders Of Blocked Size Attachments = no +Notify Senders Of Other Blocked Content = no +Never Notify Senders Of Precedence = list bulk +Scanned Modify Subject = no +Scanned Subject Text = {Scanned} +Virus Modify Subject = no +Virus Subject Text = {Virus?} +Filename Modify Subject = no +Filename Subject Text = {Filename?} +Content Modify Subject = no +Content Subject Text = {Dangerous Content?} +Size Modify Subject = no +Size Subject Text = {Size} +Disarmed Modify Subject = no +Disarmed Subject Text = {Disarmed} +Phishing Modify Subject = yes +Phishing Subject Text = {Suspected Phishing?} +Spam Modify Subject = no +Spam Subject Text = {Spam?} +High Scoring Spam Modify Subject = no +High Scoring Spam Subject Text = {Spam?} +Warning Is Attachment = yes +Attachment Warning Filename = %org-name%-Attachment-Warning.txt +Attachment Encoding Charset = ISO-8859-1 +Archive Mail = +Missing Mail Archive Is = file +Send Notices = no +Notices Include Full Headers = yes +Hide Incoming Work Dir in Notices = yes +Notice Signature = -- \\n%org-name%\\nEmail Security\\n%website% +Notices From = Baruwa +Notices To = postmaster +Local Postmaster = postmaster +Spam List Definitions = %etc-dir%/spam.lists.conf +Virus Scanner Definitions = %etc-dir%/virus.scanners.conf +Spam Checks = %brules-dir%/spam.checks.rules +Spam List = +Spam Domain List = +Spam Lists To Be Spam = 1 +Spam Lists To Reach High Score = 3 +Spam List Timeout = 10 +Max Spam List Timeouts = 7 +Spam List Timeouts History = 10 +Is Definitely Not Spam = %brules-dir%/approved.senders.rules +Is Definitely Spam = %brules-dir%/banned.senders.rules +Definite Spam Is High Scoring = yes +Ignore Spam Whitelist If Recipients Exceed = 20 +Max Spam Check Size = 4000k +Use Watermarking = no +Add Watermark = yes +Check Watermarks With No Sender = yes +Treat Invalid Watermarks With No Sender as Spam = nothing +Check Watermarks To Skip Spam Checks = yes +Watermark Secret = %org-name%-BaruwaFW-Secret +Watermark Lifetime = 604800 +Watermark Header = X-%org-name%-BaruwaFW-Watermark: +Use SpamAssassin = yes +Max SpamAssassin Size = 800k +Required SpamAssassin Score = %brules-dir%/spam.score.rules +High SpamAssassin Score = %brules-dir%/highspam.score.rules +SpamAssassin Auto Whitelist = yes +SpamAssassin Timeout = 75 +Max SpamAssassin Timeouts = 10 +SpamAssassin Timeouts History = 30 +Check SpamAssassin If On Spam List = yes +Include Binary Attachments In SpamAssassin = no +Spam Score = yes +Cache SpamAssassin Results = yes +SpamAssassin Cache Database File = %spool-dir%/incoming/SpamAssassin.cache.db +Rebuild Bayes Every = 0 +Wait During Bayes Rebuild = no +Use Custom Spam Scanner = no +Max Custom Spam Scanner Size = 20k +Custom Spam Scanner Timeout = 20 +Max Custom Spam Scanner Timeouts = 10 +Custom Spam Scanner Timeout History = 20 +Spam Actions = %brules-dir%/spam.actions.rules +High Scoring Spam Actions = %brules-dir%/highspam.actions.rules +Non Spam Actions = %rules-dir%/nonspam.actions.rules +SpamAssassin Rule Actions = +Sender Spam Report = %brules-dir%/senderspamreport.rules +Sender Spam List Report = %brules-dir%/senderspamrblreport.rules +Sender SpamAssassin Report = %brules-dir%/senderspamsareport.rules +Inline Spam Warning = %brules-dir%/inlinespamwarning.rules +Recipient Spam Report = %brules-dir%/recipientspamreport.rules +Enable Spam Bounce = %rules-dir%/bounce.rules +Bounce Spam As Attachment = no +Syslog Facility = mail +Log Speed = no +Log Spam = no +Log Non Spam = no +Log Delivery And Non-Delivery = no +Log Permitted Filenames = no +Log Permitted Filetypes = no +Log Permitted File MIME Types = no +Log Silent Viruses = no +Log Dangerous HTML Tags = no +Log SpamAssassin Rule Actions = no +SpamAssassin Temporary Dir = /var/spool/MailScanner/incoming/SpamAssassin-Temp +SpamAssassin User State Dir = +SpamAssassin Install Prefix = +SpamAssassin Site Rules Dir = /etc/mail/spamassassin +SpamAssassin Local Rules Dir = +SpamAssassin Local State Dir = +SpamAssassin Default Rules Dir = +DB DSN = DBI:Pg:database=baruwa +DB Username = baruwa +DB Password = password +SQL Serial Number = SELECT MAX(value) AS confserialnumber FROM configurations WHERE internal='confserialnumber' +SQL Quick Peek = SELECT dbvalue(value) AS value FROM quickpeek WHERE external = ? AND (hostname = ? OR hostname='default') LIMIT 1 +SQL Config = SELECT internal, dbvalue(value) AS value, hostname FROM quickpeek WHERE hostname=? OR hostname='default' +SQL Ruleset = SELECT row_number, ruleset AS rule FROM msrulesets WHERE name=? +SQL SpamAssassin Config = +SQL Debug = no +Sphinx Host = 127.0.0.1 +Sphinx Port = 9306 +MCP Checks = no +First Check = spam +MCP Required SpamAssassin Score = 1 +MCP High SpamAssassin Score = 10 +MCP Error Score = 1 +MCP Header = X-%org-name%-BaruwaFW-MCPCheck: +Non MCP Actions = deliver +MCP Actions = deliver +High Scoring MCP Actions = deliver +Bounce MCP As Attachment = no +MCP Modify Subject = start +MCP Subject Text = {MCP?} +High Scoring MCP Modify Subject = start +High Scoring MCP Subject Text = {MCP?} +Is Definitely MCP = no +Is Definitely Not MCP = no +Definite MCP Is High Scoring = no +Always Include MCP Report = no +Detailed MCP Report = yes +Include Scores In MCP Report = no +Log MCP = no +MCP Max SpamAssassin Timeouts = 20 +MCP Max SpamAssassin Size = 100k +MCP SpamAssassin Timeout = 10 +MCP SpamAssassin Prefs File = %mcp-dir%/mcp.spam.assassin.prefs.conf +MCP SpamAssassin User State Dir = +MCP SpamAssassin Local Rules Dir = %mcp-dir% +MCP SpamAssassin Default Rules Dir = %mcp-dir% +MCP SpamAssassin Install Prefix = %mcp-dir% +Recipient MCP Report = %report-dir%/recipient.mcp.report.txt +Sender MCP Report = %report-dir%/sender.mcp.report.txt +Use Default Rules With Multiple Recipients = no +Read IP Address From Received Header = no +Spam Score Number Format = %d.1f +MailScanner Version Number = 4.85.5 +SpamAssassin Cache Timings = 1800,300,10800,172800,600 +Debug = no +Debug SpamAssassin = no +Run In Foreground = no +Always Looked Up Last = &BaruwaLog +Always Looked Up Last After Batch = no +Deliver In Background = yes +Delivery Method = batch +Split Exim Spool = no +Lockfile Dir = %spool-dir%/incoming/Locks +Custom Functions Dir = /usr/share/baruwa/CustomFunctions +Lock Type = +Syslog Socket Type = +Automatic Syntax Check = yes +Minimum Code Status = supported +include /etc/MailScanner/conf.d/*.conf +" + +test Mailscanner.lns get conf = + { "#comment" = "Main configuration file for the MailScanner E-Mail Virus Scanner"} + { "%org-name%" = "BARUWA" } + { "%org-long-name%" = "BARUWA MAILFW" } + { "%web-site%" = "www.baruwa.com" } + { "%etc-dir%" = "/etc/MailScanner" } + { "%reports-base%" = "/etc/MailScanner/reports" } + { "%report-dir%" = "/etc/MailScanner/reports/en" } + { "%rules-dir%" = "/etc/MailScanner/rules" } + { "%mcp-dir%" = "/etc/MailScanner/mcp" } + { "%spool-dir%" = "/var/spool/MailScanner" } + { "%signature-dir%" = "/etc/MailScanner/baruwa/signatures" } + { "%brules-dir%" = "/etc/MailScanner/baruwa/rules" } + { "Max Children" = "5" } + { "Run As User" = "exim" } + { "Run As Group" = "exim" } + { "Queue Scan Interval" = "6" } + { "Incoming Queue Dir" = "/var/spool/exim.in/input" } + { "Outgoing Queue Dir" = "/var/spool/exim/input" } + { "Incoming Work Dir" = "%spool-dir%/incoming" } + { "Quarantine Dir" = "%spool-dir%/quarantine" } + { "PID file" = "/var/run/MailScanner/MailScanner.pid" } + { "Restart Every" = "7200" } + { "MTA" = "exim" } + { "Sendmail" = "/usr/sbin/exim -C /etc/exim/exim_out.conf" } + { "Sendmail2" = "/usr/sbin/exim -C /etc/exim/exim_out.conf" } + { "Incoming Work User" = "exim" } + { "Incoming Work Group" = "clam" } + { "Incoming Work Permissions" = "0640" } + { "Quarantine User" = "exim" } + { "Quarantine Group" = "baruwa" } + { "Quarantine Permissions" = "0660" } + { "Max Unscanned Bytes Per Scan" = "100m" } + { "Max Unsafe Bytes Per Scan" = "50m" } + { "Max Unscanned Messages Per Scan" = "30" } + { "Max Unsafe Messages Per Scan" = "30" } + { "Max Normal Queue Size" = "800" } + { "Scan Messages" = "%rules-dir%/scan.messages.rules" } + { "Reject Message" = "no" } + { "Maximum Processing Attempts" = "6" } + { "Processing Attempts Database" = "%spool-dir%/incoming/Processing.db" } + { "Maximum Attachments Per Message" = "200" } + { "Expand TNEF" = "yes" } + { "Use TNEF Contents" = "replace" } + { "Deliver Unparsable TNEF" = "no" } + { "TNEF Expander" = "/usr/bin/tnef --maxsize=100000000" } + { "TNEF Timeout" = "120" } + { "File Command" = "/usr/sbin/file-wrapper" } + { "File Timeout" = "20" } + { "Gunzip Command" = "/bin/gunzip" } + { "Gunzip Timeout" = "50" } + { "Unrar Command" = "/usr/bin/unrar" } + { "Unrar Timeout" = "50" } + { "Find UU-Encoded Files" = "no" } + { "Maximum Message Size" = "%brules-dir%/message.size.rules" } + { "Maximum Attachment Size" = "-1" } + { "Minimum Attachment Size" = "-1" } + { "Maximum Archive Depth" = "4" } + { "Find Archives By Content" = "yes" } + { "Unpack Microsoft Documents" = "yes" } + { "Zip Attachments" = "no" } + { "Attachments Zip Filename" = "MessageAttachments.zip" } + { "Attachments Min Total Size To Zip" = "100k" } + { "Attachment Extensions Not To Zip" = ".zip .rar .gz .tgz .jpg .jpeg .mpg .mpe .mpeg .mp3 .rpm .htm .html .eml" } + { "Add Text Of Doc" = "no" } + { "Antiword" = "/usr/bin/antiword -f" } + { "Antiword Timeout" = "50" } + { "Unzip Maximum Files Per Archive" = "0" } + { "Unzip Maximum File Size" = "50k" } + { "Unzip Filenames" = "*.txt *.ini *.log *.csv" } + { "Unzip MimeType" = "text/plain" } + { "Virus Scanning" = "%brules-dir%/virus.checks.rules" } + { "Virus Scanners" = "auto" } + { "Virus Scanner Timeout" = "300" } + { "Deliver Disinfected Files" = "no" } + { "Silent Viruses" = "HTML-IFrame All-Viruses" } + { "Still Deliver Silent Viruses" = "no" } + { "Non-Forging Viruses" = "Joke/ OF97/ WM97/ W97M/ eicar" } + { "Spam-Virus Header" = "X-%org-name%-BaruwaFW-SpamVirus-Report:" } + { "Virus Names Which Are Spam" = "Sanesecurity.Spam*UNOFFICIAL HTML/* *Phish* *Suspected-phishing_safebrowsing*" } + { "Block Encrypted Messages" = "no" } + { "Block Unencrypted Messages" = "no" } + { "Allow Password-Protected Archives" = "yes" } + { "Check Filenames In Password-Protected Archives" = "yes" } + { "Allowed Sophos Error Messages" } + { "Sophos IDE Dir" = "/opt/sophos-av/lib/sav" } + { "Sophos Lib Dir" = "/opt/sophos-av/lib" } + { "Monitors For Sophos Updates" = "/opt/sophos-av/lib/sav/*.ide" } + { "Monitors for ClamAV Updates" = "/var/lib/clamav/*.cvd" } + { "ClamAVmodule Maximum Recursion Level" = "8" } + { "ClamAVmodule Maximum Files" = "1000" } + { "ClamAVmodule Maximum File Size" = "10000000" } + { "ClamAVmodule Maximum Compression Ratio" = "250" } + { "Clamd Port" = "3310" } + { "Clamd Socket" = "/var/run/clamav/clamd.sock" } + { "Clamd Lock File" } + { "Clamd Use Threads" = "no" } + { "ClamAV Full Message Scan" = "yes" } + { "Fpscand Port" = "10200" } + { "Dangerous Content Scanning" = "%rules-dir%/content.scanning.rules" } + { "Allow Partial Messages" = "no" } + { "Allow External Message Bodies" = "no" } + { "Find Phishing Fraud" = "yes" } + { "Also Find Numeric Phishing" = "yes" } + { "Use Stricter Phishing Net" = "yes" } + { "Highlight Phishing Fraud" = "yes" } + { "Phishing Safe Sites File" = "%etc-dir%/phishing.safe.sites.conf" } + { "Phishing Bad Sites File" = "%etc-dir%/phishing.bad.sites.conf" } + { "Country Sub-Domains List" = "%etc-dir%/country.domains.conf" } + { "Allow IFrame Tags" = "disarm" } + { "Allow Form Tags" = "disarm" } + { "Allow Script Tags" = "disarm" } + { "Allow WebBugs" = "disarm" } + { "Ignored Web Bug Filenames" = "spacer pixel.gif pixel.png gap" } + { "Known Web Bug Servers" = "msgtag.com" } + { "Web Bug Replacement" = "https://datafeeds.baruwa.com/1x1spacer.gif" } + { "Allow Object Codebase Tags" = "disarm" } + { "Convert Dangerous HTML To Text" = "no" } + { "Convert HTML To Text" = "no" } + { "Archives Are" = "zip rar ole" } + { "Allow Filenames" } + { "Deny Filenames" } + { "Filename Rules" = "%rules-dir%/filename.rules" } + { "Allow Filetypes" } + { "Allow File MIME Types" } + { "Deny Filetypes" } + { "Deny File MIME Types" } + { "Filetype Rules" = "%rules-dir%/filetype.rules" } + { "Archives: Allow Filenames" } + { "Archives: Deny Filenames" } + { "Archives: Filename Rules" = "%etc-dir%/archives.filename.rules.conf" } + { "Archives: Allow Filetypes" } + { "Archives: Allow File MIME Types" } + { "Archives: Deny Filetypes" } + { "Archives: Deny File MIME Types" } + { "Archives: Filetype Rules" = "%etc-dir%/archives.filetype.rules.conf" } + { "Default Rename Pattern" = "__FILENAME__.disarmed" } + { "Quarantine Infections" = "yes" } + { "Quarantine Silent Viruses" = "no" } + { "Quarantine Modified Body" = "no" } + { "Quarantine Whole Message" = "yes" } + { "Quarantine Whole Messages As Queue Files" = "no" } + { "Keep Spam And MCP Archive Clean" = "yes" } + { "Language Strings" = "%brules-dir%/languages.rules" } + { "Rejection Report" = "%brules-dir%/rejectionreport.rules" } + { "Deleted Bad Content Message Report" = "%brules-dir%/deletedcontentmessage.rules" } + { "Deleted Bad Filename Message Report" = "%brules-dir%/deletedfilenamemessage.rules" } + { "Deleted Virus Message Report" = "%brules-dir%/deletedvirusmessage.rules" } + { "Deleted Size Message Report" = "%brules-dir%/deletedsizemessage.rules" } + { "Stored Bad Content Message Report" = "%brules-dir%/storedcontentmessage.rules" } + { "Stored Bad Filename Message Report" = "%brules-dir%/storedfilenamemessage.rules" } + { "Stored Virus Message Report" = "%brules-dir%/storedvirusmessage.rules" } + { "Stored Size Message Report" = "%brules-dir%/storedsizemessage.rules" } + { "Disinfected Report" = "%brules-dir%/disinfectedreport.rules" } + { "Inline HTML Signature" = "%brules-dir%/html.sigs.rules" } + { "Inline Text Signature" = "%brules-dir%/text.sigs.rules" } + { "Signature Image Filename" = "%brules-dir%/sig.imgs.names.rules" } + { "Signature Image <img> Filename" = "%brules-dir%/sig.imgs.rules" } + { "Inline HTML Warning" = "%brules-dir%/inlinewarninghtml.rules" } + { "Inline Text Warning" = "%brules-dir%/inlinewarningtxt.rules" } + { "Sender Content Report" = "%brules-dir%/sendercontentreport.rules" } + { "Sender Error Report" = "%brules-dir%/sendererrorreport.rules" } + { "Sender Bad Filename Report" = "%brules-dir%/senderfilenamereport.rules" } + { "Sender Virus Report" = "%brules-dir%/sendervirusreport.rules" } + { "Sender Size Report" = "%brules-dir%/sendersizereport.rules" } + { "Hide Incoming Work Dir" = "yes" } + { "Include Scanner Name In Reports" = "yes" } + { "Mail Header" = "X-%org-name%-BaruwaFW:" } + { "Spam Header" = "X-%org-name%-BaruwaFW-SpamCheck:" } + { "Spam Score Header" = "X-%org-name%-BaruwaFW-SpamScore:" } + { "Information Header" = "X-%org-name%-BaruwaFW-Information:" } + { "Add Envelope From Header" = "yes" } + { "Add Envelope To Header" = "no" } + { "Envelope From Header" = "X-BARUWA-BaruwaFW-From:" } + { "Envelope To Header" = "X-%org-name%-BaruwaFW-To:" } + { "ID Header" = "X-%org-name%-BaruwaFW-ID:" } + { "IP Protocol Version Header" } + { "Spam Score Character" = "s" } + { "SpamScore Number Instead Of Stars" = "no" } + { "Minimum Stars If On Spam List" = "0" } + { "Clean Header Value" = "Found to be clean" } + { "Infected Header Value" = "Found to be infected" } + { "Disinfected Header Value" = "Disinfected" } + { "Information Header Value" = "Please contact %org-long-name% for more information" } + { "Detailed Spam Report" = "yes" } + { "Include Scores In SpamAssassin Report" = "yes" } + { "Always Include SpamAssassin Report" = "no" } + { "Multiple Headers" = "add" } + { "Place New Headers At Top Of Message" = "yes" } + { "Hostname" = "the %org-name% ($HOSTNAME) Baruwa" } + { "Sign Messages Already Processed" = "no" } + { "Sign Clean Messages" = "%brules-dir%/sign.clean.msgs.rules" } + { "Attach Image To Signature" = "yes" } + { "Attach Image To HTML Message Only" = "yes" } + { "Allow Multiple HTML Signatures" = "no" } + { "Dont Sign HTML If Headers Exist" } + { "Mark Infected Messages" = "yes" } + { "Mark Unscanned Messages" = "no" } + { "Unscanned Header Value" = "Not scanned: please contact %org-long-name% for details" } + { "Remove These Headers" = "X-Mozilla-Status: X-Mozilla-Status2:" } + { "Deliver Cleaned Messages" = "yes" } + { "Notify Senders" = "no" } + { "Notify Senders Of Viruses" = "no" } + { "Notify Senders Of Blocked Filenames Or Filetypes" = "no" } + { "Notify Senders Of Blocked Size Attachments" = "no" } + { "Notify Senders Of Other Blocked Content" = "no" } + { "Never Notify Senders Of Precedence" = "list bulk" } + { "Scanned Modify Subject" = "no" } + { "Scanned Subject Text" = "{Scanned}" } + { "Virus Modify Subject" = "no" } + { "Virus Subject Text" = "{Virus?}" } + { "Filename Modify Subject" = "no" } + { "Filename Subject Text" = "{Filename?}" } + { "Content Modify Subject" = "no" } + { "Content Subject Text" = "{Dangerous Content?}" } + { "Size Modify Subject" = "no" } + { "Size Subject Text" = "{Size}" } + { "Disarmed Modify Subject" = "no" } + { "Disarmed Subject Text" = "{Disarmed}" } + { "Phishing Modify Subject" = "yes" } + { "Phishing Subject Text" = "{Suspected Phishing?}" } + { "Spam Modify Subject" = "no" } + { "Spam Subject Text" = "{Spam?}" } + { "High Scoring Spam Modify Subject" = "no" } + { "High Scoring Spam Subject Text" = "{Spam?}" } + { "Warning Is Attachment" = "yes" } + { "Attachment Warning Filename" = "%org-name%-Attachment-Warning.txt" } + { "Attachment Encoding Charset" = "ISO-8859-1" } + { "Archive Mail" } + { "Missing Mail Archive Is" = "file" } + { "Send Notices" = "no" } + { "Notices Include Full Headers" = "yes" } + { "Hide Incoming Work Dir in Notices" = "yes" } + { "Notice Signature" = "-- \\n%org-name%\\nEmail Security\\n%website%" } + { "Notices From" = "Baruwa" } + { "Notices To" = "postmaster" } + { "Local Postmaster" = "postmaster" } + { "Spam List Definitions" = "%etc-dir%/spam.lists.conf" } + { "Virus Scanner Definitions" = "%etc-dir%/virus.scanners.conf" } + { "Spam Checks" = "%brules-dir%/spam.checks.rules" } + { "Spam List" } + { "Spam Domain List" } + { "Spam Lists To Be Spam" = "1" } + { "Spam Lists To Reach High Score" = "3" } + { "Spam List Timeout" = "10" } + { "Max Spam List Timeouts" = "7" } + { "Spam List Timeouts History" = "10" } + { "Is Definitely Not Spam" = "%brules-dir%/approved.senders.rules" } + { "Is Definitely Spam" = "%brules-dir%/banned.senders.rules" } + { "Definite Spam Is High Scoring" = "yes" } + { "Ignore Spam Whitelist If Recipients Exceed" = "20" } + { "Max Spam Check Size" = "4000k" } + { "Use Watermarking" = "no" } + { "Add Watermark" = "yes" } + { "Check Watermarks With No Sender" = "yes" } + { "Treat Invalid Watermarks With No Sender as Spam" = "nothing" } + { "Check Watermarks To Skip Spam Checks" = "yes" } + { "Watermark Secret" = "%org-name%-BaruwaFW-Secret" } + { "Watermark Lifetime" = "604800" } + { "Watermark Header" = "X-%org-name%-BaruwaFW-Watermark:" } + { "Use SpamAssassin" = "yes" } + { "Max SpamAssassin Size" = "800k" } + { "Required SpamAssassin Score" = "%brules-dir%/spam.score.rules" } + { "High SpamAssassin Score" = "%brules-dir%/highspam.score.rules" } + { "SpamAssassin Auto Whitelist" = "yes" } + { "SpamAssassin Timeout" = "75" } + { "Max SpamAssassin Timeouts" = "10" } + { "SpamAssassin Timeouts History" = "30" } + { "Check SpamAssassin If On Spam List" = "yes" } + { "Include Binary Attachments In SpamAssassin" = "no" } + { "Spam Score" = "yes" } + { "Cache SpamAssassin Results" = "yes" } + { "SpamAssassin Cache Database File" = "%spool-dir%/incoming/SpamAssassin.cache.db" } + { "Rebuild Bayes Every" = "0" } + { "Wait During Bayes Rebuild" = "no" } + { "Use Custom Spam Scanner" = "no" } + { "Max Custom Spam Scanner Size" = "20k" } + { "Custom Spam Scanner Timeout" = "20" } + { "Max Custom Spam Scanner Timeouts" = "10" } + { "Custom Spam Scanner Timeout History" = "20" } + { "Spam Actions" = "%brules-dir%/spam.actions.rules" } + { "High Scoring Spam Actions" = "%brules-dir%/highspam.actions.rules" } + { "Non Spam Actions" = "%rules-dir%/nonspam.actions.rules" } + { "SpamAssassin Rule Actions" } + { "Sender Spam Report" = "%brules-dir%/senderspamreport.rules" } + { "Sender Spam List Report" = "%brules-dir%/senderspamrblreport.rules" } + { "Sender SpamAssassin Report" = "%brules-dir%/senderspamsareport.rules" } + { "Inline Spam Warning" = "%brules-dir%/inlinespamwarning.rules" } + { "Recipient Spam Report" = "%brules-dir%/recipientspamreport.rules" } + { "Enable Spam Bounce" = "%rules-dir%/bounce.rules" } + { "Bounce Spam As Attachment" = "no" } + { "Syslog Facility" = "mail" } + { "Log Speed" = "no" } + { "Log Spam" = "no" } + { "Log Non Spam" = "no" } + { "Log Delivery And Non-Delivery" = "no" } + { "Log Permitted Filenames" = "no" } + { "Log Permitted Filetypes" = "no" } + { "Log Permitted File MIME Types" = "no" } + { "Log Silent Viruses" = "no" } + { "Log Dangerous HTML Tags" = "no" } + { "Log SpamAssassin Rule Actions" = "no" } + { "SpamAssassin Temporary Dir" = "/var/spool/MailScanner/incoming/SpamAssassin-Temp" } + { "SpamAssassin User State Dir" } + { "SpamAssassin Install Prefix" } + { "SpamAssassin Site Rules Dir" = "/etc/mail/spamassassin" } + { "SpamAssassin Local Rules Dir" } + { "SpamAssassin Local State Dir" } + { "SpamAssassin Default Rules Dir" } + { "DB DSN" = "DBI:Pg:database=baruwa" } + { "DB Username" = "baruwa" } + { "DB Password" = "password" } + { "SQL Serial Number" = "SELECT MAX(value) AS confserialnumber FROM configurations WHERE internal='confserialnumber'" } + { "SQL Quick Peek" = "SELECT dbvalue(value) AS value FROM quickpeek WHERE external = ? AND (hostname = ? OR hostname='default') LIMIT 1" } + { "SQL Config" = "SELECT internal, dbvalue(value) AS value, hostname FROM quickpeek WHERE hostname=? OR hostname='default'" } + { "SQL Ruleset" = "SELECT row_number, ruleset AS rule FROM msrulesets WHERE name=?" } + { "SQL SpamAssassin Config" } + { "SQL Debug" = "no" } + { "Sphinx Host" = "127.0.0.1" } + { "Sphinx Port" = "9306" } + { "MCP Checks" = "no" } + { "First Check" = "spam" } + { "MCP Required SpamAssassin Score" = "1" } + { "MCP High SpamAssassin Score" = "10" } + { "MCP Error Score" = "1" } + { "MCP Header" = "X-%org-name%-BaruwaFW-MCPCheck:" } + { "Non MCP Actions" = "deliver" } + { "MCP Actions" = "deliver" } + { "High Scoring MCP Actions" = "deliver" } + { "Bounce MCP As Attachment" = "no" } + { "MCP Modify Subject" = "start" } + { "MCP Subject Text" = "{MCP?}" } + { "High Scoring MCP Modify Subject" = "start" } + { "High Scoring MCP Subject Text" = "{MCP?}" } + { "Is Definitely MCP" = "no" } + { "Is Definitely Not MCP" = "no" } + { "Definite MCP Is High Scoring" = "no" } + { "Always Include MCP Report" = "no" } + { "Detailed MCP Report" = "yes" } + { "Include Scores In MCP Report" = "no" } + { "Log MCP" = "no" } + { "MCP Max SpamAssassin Timeouts" = "20" } + { "MCP Max SpamAssassin Size" = "100k" } + { "MCP SpamAssassin Timeout" = "10" } + { "MCP SpamAssassin Prefs File" = "%mcp-dir%/mcp.spam.assassin.prefs.conf" } + { "MCP SpamAssassin User State Dir" } + { "MCP SpamAssassin Local Rules Dir" = "%mcp-dir%" } + { "MCP SpamAssassin Default Rules Dir" = "%mcp-dir%" } + { "MCP SpamAssassin Install Prefix" = "%mcp-dir%" } + { "Recipient MCP Report" = "%report-dir%/recipient.mcp.report.txt" } + { "Sender MCP Report" = "%report-dir%/sender.mcp.report.txt" } + { "Use Default Rules With Multiple Recipients" = "no" } + { "Read IP Address From Received Header" = "no" } + { "Spam Score Number Format" = "%d.1f" } + { "MailScanner Version Number" = "4.85.5" } + { "SpamAssassin Cache Timings" = "1800,300,10800,172800,600" } + { "Debug" = "no" } + { "Debug SpamAssassin" = "no" } + { "Run In Foreground" = "no" } + { "Always Looked Up Last" = "&BaruwaLog" } + { "Always Looked Up Last After Batch" = "no" } + { "Deliver In Background" = "yes" } + { "Delivery Method" = "batch" } + { "Split Exim Spool" = "no" } + { "Lockfile Dir" = "%spool-dir%/incoming/Locks" } + { "Custom Functions Dir" = "/usr/share/baruwa/CustomFunctions" } + { "Lock Type" } + { "Syslog Socket Type" } + { "Automatic Syntax Check" = "yes" } + { "Minimum Code Status" = "supported" } + { "include" = "/etc/MailScanner/conf.d/*.conf"} \ No newline at end of file diff --git a/Sharp.Augeas.Test/lens/tests/test_mailscanner_rules.aug b/Sharp.Augeas.Test/lens/tests/test_mailscanner_rules.aug new file mode 100644 index 0000000..c8acf7a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_mailscanner_rules.aug @@ -0,0 +1,59 @@ +module Test_Mailscanner_Rules = +let conf = "# JKF 10/08/2007 Adobe Acrobat nastiness +rename \.fdf$ Dangerous Adobe Acrobat data-file Opening this file can cause auto-loading of any file from the internet + +# JKF 04/01/2005 More Microsoft security vulnerabilities +deny \.ico$ Windows icon file security vulnerability Possible buffer overflow in Windows +allow \.(jan|feb|mar|apr|may|jun|june|jul|july|aug|sep|sept|oct|nov|dec)\.[a-z0-9]{3}$ - - +deny+delete \.cur$ Windows cursor file security vulnerability Possible buffer overflow in Windows +andrew@baruwa.com,andrew@baruwa.net \.reg$ Possible Windows registry attack Windows registry entries are very dangerous in email +andrew@baruwa.com andrew@baruwa.net \.chm$ Possible compiled Help file-based virus Compiled help files are very dangerous in email +rename to .ppt \.pps$ Renamed .pps to .ppt Renamed .pps to .ppt +" + +test Mailscanner_Rules.lns get conf = + { "#comment" = "JKF 10/08/2007 Adobe Acrobat nastiness" } + { "1" + { "action" = "rename" } + { "regex" = "\.fdf$" } + { "log-text" = "Dangerous Adobe Acrobat data-file" } + { "user-report" = "Opening this file can cause auto-loading of any file from the internet" } + } + {} + { "#comment" = "JKF 04/01/2005 More Microsoft security vulnerabilities" } + { "2" + { "action" = "deny" } + { "regex" = "\.ico$" } + { "log-text" = "Windows icon file security vulnerability" } + { "user-report" = "Possible buffer overflow in Windows" } + } + { "3" + { "action" = "allow" } + { "regex" = "\.(jan|feb|mar|apr|may|jun|june|jul|july|aug|sep|sept|oct|nov|dec)\.[a-z0-9]{3}$" } + { "log-text" = "-" } + { "user-report" = "-" } + } + { "4" + { "action" = "deny+delete" } + { "regex" = "\.cur$" } + { "log-text" = "Windows cursor file security vulnerability" } + { "user-report" = "Possible buffer overflow in Windows" } + } + { "5" + { "action" = "andrew@baruwa.com,andrew@baruwa.net" } + { "regex" = "\.reg$" } + { "log-text" = "Possible Windows registry attack" } + { "user-report" = "Windows registry entries are very dangerous in email" } + } + { "6" + { "action" = "andrew@baruwa.com andrew@baruwa.net" } + { "regex" = "\.chm$" } + { "log-text" = "Possible compiled Help file-based virus" } + { "user-report" = "Compiled help files are very dangerous in email" } + } + { "7" + { "action" = "rename to .ppt" } + { "regex" = "\.pps$" } + { "log-text" = "Renamed .pps to .ppt" } + { "user-report" = "Renamed .pps to .ppt" } + } \ No newline at end of file diff --git a/Sharp.Augeas.Test/lens/tests/test_masterpasswd.aug b/Sharp.Augeas.Test/lens/tests/test_masterpasswd.aug new file mode 100644 index 0000000..838b7bd --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_masterpasswd.aug @@ -0,0 +1,125 @@ +module Test_MasterPasswd = + +let conf = "root:*:0:0:daemon:0:0:Charlie &:/root:/bin/ksh +sshd:*:27:27::0:0:sshd privsep:/var/empty:/sbin/nologin +_portmap:*:28:28::0:0:portmap:/var/empty:/sbin/nologin +test:x:1000:1000:ldap:1434329080:1434933880:Test User,,,:/home/test:/bin/bash +" + +test MasterPasswd.lns get conf = + { "root" + { "password" = "*" } + { "uid" = "0" } + { "gid" = "0" } + { "class" = "daemon" } + { "change_date" = "0" } + { "expire_date" = "0" } + { "name" = "Charlie &" } + { "home" = "/root" } + { "shell" = "/bin/ksh" } } + { "sshd" + { "password" = "*" } + { "uid" = "27" } + { "gid" = "27" } + { "class" } + { "change_date" = "0" } + { "expire_date" = "0" } + { "name" = "sshd privsep" } + { "home" = "/var/empty" } + { "shell" = "/sbin/nologin" } } + { "_portmap" + { "password" = "*" } + { "uid" = "28" } + { "gid" = "28" } + { "class" } + { "change_date" = "0" } + { "expire_date" = "0" } + { "name" = "portmap" } + { "home" = "/var/empty" } + { "shell" = "/sbin/nologin" } } + { "test" + { "password" = "x" } + { "uid" = "1000" } + { "gid" = "1000" } + { "class" = "ldap" } + { "change_date" = "1434329080" } + { "expire_date" = "1434933880" } + { "name" = "Test User,,," } + { "home" = "/home/test" } + { "shell" = "/bin/bash" } } + +(* Popular on Solaris *) +test MasterPasswd.lns get "+@some-nis-group:::::::::\n" = + { "@nis" = "some-nis-group" } + +test MasterPasswd.lns get "+\n" = + { "@nisdefault" } + +test MasterPasswd.lns get "+:::::::::\n" = + { "@nisdefault" + { "password" = "" } + { "uid" = "" } + { "gid" = "" } + { "class" } + { "change_date" = "" } + { "expire_date" = "" } + { "name" } + { "home" } + { "shell" } } + +test MasterPasswd.lns get "+:::::::::/sbin/nologin\n" = + { "@nisdefault" + { "password" = "" } + { "uid" = "" } + { "gid" = "" } + { "class" } + { "change_date" = "" } + { "expire_date" = "" } + { "name" } + { "home" } + { "shell" = "/sbin/nologin" } } + +test MasterPasswd.lns get "+:*:::ldap:::::\n" = + { "@nisdefault" + { "password" = "*" } + { "uid" = "" } + { "gid" = "" } + { "class" = "ldap" } + { "change_date" = "" } + { "expire_date" = "" } + { "name" } + { "home" } + { "shell" } } + +(* NIS entries with overrides, ticket #339 *) +test MasterPasswd.lns get "+@bob::::::::/home/bob:/bin/bash\n" = + { "@nis" = "bob" + { "home" = "/home/bob" } + { "shell" = "/bin/bash" } } + +(* NIS user entries *) +test MasterPasswd.lns get "+bob:::::::::\n" = + { "@+nisuser" = "bob" } + +test MasterPasswd.lns get "+bob:::::::User Comment:/home/bob:/bin/bash\n" = + { "@+nisuser" = "bob" + { "name" = "User Comment" } + { "home" = "/home/bob" } + { "shell" = "/bin/bash" } } + +test MasterPasswd.lns put "+bob:::::::::\n" after + set "@+nisuser" "alice" += "+alice:::::::::\n" + +test MasterPasswd.lns put "+bob:::::::::\n" after + set "@+nisuser/name" "User Comment"; + set "@+nisuser/home" "/home/bob"; + set "@+nisuser/shell" "/bin/bash" += "+bob:::::::User Comment:/home/bob:/bin/bash\n" + +test MasterPasswd.lns get "-bob:::::::::\n" = + { "@-nisuser" = "bob" } + +test MasterPasswd.lns put "-bob:::::::::\n" after + set "@-nisuser" "alice" += "-alice:::::::::\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_mcollective.aug b/Sharp.Augeas.Test/lens/tests/test_mcollective.aug new file mode 100644 index 0000000..e71a85d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_mcollective.aug @@ -0,0 +1,53 @@ +(* +Module: Test_MCollective + Provides unit tests and examples for the <MCollective> lens. +*) + +module Test_MCollective = + +let conf = "topicprefix = /topic/ +main_collective = mcollective +collectives = mcollective +libdir = /usr/libexec/mcollective +logger_type = console +loglevel = warn + +# Plugins +securityprovider = psk +plugin.psk = unset + +connector = stomp +plugin.stomp.host = localhost +plugin.stomp.port = 61613 +plugin.stomp.user = mcollective +plugin.stomp.password = secret + +# Facts +factsource = yaml # bla +plugin.yaml=/etc/mcollective/facts.yaml +" + +test MCollective.lns get conf = + { "topicprefix" = "/topic/" } + { "main_collective" = "mcollective" } + { "collectives" = "mcollective" } + { "libdir" = "/usr/libexec/mcollective" } + { "logger_type" = "console" } + { "loglevel" = "warn" } + { } + { "#comment" = "Plugins" } + { "securityprovider" = "psk" } + { "plugin.psk" = "unset" } + { } + { "connector" = "stomp" } + { "plugin.stomp.host" = "localhost" } + { "plugin.stomp.port" = "61613" } + { "plugin.stomp.user" = "mcollective" } + { "plugin.stomp.password" = "secret" } + { } + { "#comment" = "Facts" } + { "factsource" = "yaml" + { "#comment" = "bla" } + } + { "plugin.yaml" = "/etc/mcollective/facts.yaml" } + diff --git a/Sharp.Augeas.Test/lens/tests/test_mdadm_conf.aug b/Sharp.Augeas.Test/lens/tests/test_mdadm_conf.aug new file mode 100644 index 0000000..a7622cd --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_mdadm_conf.aug @@ -0,0 +1,94 @@ +module Test_mdadm_conf = + +let conf = " +# Comment +device containers + # Comment +DEVICE partitions \ndev + /dev/hda* \n /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@example.com # End of line comment +MAILF user@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@example.com" } + { "#comment" = "End of line comment" } + } + { "mailfrom" + { "value" = "user@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" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_memcached.aug b/Sharp.Augeas.Test/lens/tests/test_memcached.aug new file mode 100644 index 0000000..2a287c2 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_memcached.aug @@ -0,0 +1,43 @@ +(* +Module: Test_Memcached + Provides unit tests and examples for the <Memcached> lens. +*) + +module Test_Memcached = + +let conf = "# memcached default config file + +# Run memcached as a daemon. This command is implied, and is not needed for the +# daemon to run. See the README.Debian that comes with this package for more +# information. +-d +-l 127.0.0.1 + +# Log memcached's output to /var/log/memcached +logfile /var/log/memcached.log + +# Default connection port is 11211 +-p 11211 +-m 64 # Start with a cap of 64 megs of memory. +-M +" + +test Memcached.lns get conf = + { "#comment" = "memcached default config file" } + { } + { "#comment" = "Run memcached as a daemon. This command is implied, and is not needed for the" } + { "#comment" = "daemon to run. See the README.Debian that comes with this package for more" } + { "#comment" = "information." } + { "d" } + { "l" = "127.0.0.1" } + { } + { "#comment" = "Log memcached's output to /var/log/memcached" } + { "logfile" = "/var/log/memcached.log" } + { } + { "#comment" = "Default connection port is 11211" } + { "p" = "11211" } + { "m" = "64" + { "#comment" = "Start with a cap of 64 megs of memory." } + } + { "M" } + diff --git a/Sharp.Augeas.Test/lens/tests/test_mke2fs.aug b/Sharp.Augeas.Test/lens/tests/test_mke2fs.aug new file mode 100644 index 0000000..bcf2fe6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_mke2fs.aug @@ -0,0 +1,126 @@ +(* Test for keepalived lens *) + +module Test_mke2fs = + + let conf = "# This is a comment +; and another comment + +[defaults] + base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr + default_mntopts = acl,user_xattr + enable_periodic_fsck = 0 + blocksize = 4096 + inode_size = 256 + ; here goes inode_ratio + inode_ratio = 16384 + +[fs_types] + ; here we have fs_types + ext4dev = { + # this is ext4dev conf + + features = has_journal,^extent + auto_64-bit_support = 1 + inode_size = 256 + options = test_fs=1 + } + small = { + blocksize = 1024 + inode_size = 128 + inode_ratio = 4096 + } + largefile = { + inode_ratio = 1048576 + blocksize = -1 + } + +[options] + proceed_delay = 1 + sync_kludge = 1 +" + + test Mke2fs.lns get conf = + { "#comment" = "This is a comment" } + { "#comment" = "and another comment" } + {} + { "defaults" + { "base_features" + { "sparse_super" } + { "filetype" } + { "resize_inode" } + { "dir_index" } + { "ext_attr" } } + { "default_mntopts" + { "acl" } + { "user_xattr" } } + { "enable_periodic_fsck" = "0" } + { "blocksize" = "4096" } + { "inode_size" = "256" } + { "#comment" = "here goes inode_ratio" } + { "inode_ratio" = "16384" } + {} } + { "fs_types" + { "#comment" = "here we have fs_types" } + { "filesystem" = "ext4dev" + { "#comment" = "this is ext4dev conf" } + {} + { "features" + { "has_journal" } + { "extent" + { "disable" } } } + { "auto_64-bit_support" = "1" } + { "inode_size" = "256" } + { "options" + { "test_fs" = "1" } } } + { "filesystem" = "small" + { "blocksize" = "1024" } + { "inode_size" = "128" } + { "inode_ratio" = "4096" } } + { "filesystem" = "largefile" + { "inode_ratio" = "1048576" } + { "blocksize" = "-1" } } + {} } + { "options" + { "proceed_delay" = "1" } + { "sync_kludge" = "1" } } + + + let quoted_conf = "[defaults] + base_features = \"sparse_super,filetype,resize_inode,dir_index,ext_attr\" + +[fs_types] + ext4dev = { + features = \"has_journal,^extent\" + default_mntopts = \"user_xattr\" + encoding = \"utf8\" + encoding = \"\" + } +" + + test Mke2fs.lns get quoted_conf = + { "defaults" + { "base_features" + { "sparse_super" } + { "filetype" } + { "resize_inode" } + { "dir_index" } + { "ext_attr" } } + {} } + { "fs_types" + { "filesystem" = "ext4dev" + { "features" + { "has_journal" } + { "extent" + { "disable" } } } + { "default_mntopts" + { "user_xattr" } } + { "encoding" = "utf8" } + { "encoding" } + } } + + +test Mke2fs.common_entry + put "features = has_journal,^extent\n" + after set "/features/has_journal/disable" ""; + rm "/features/extent/disable" = "features = ^has_journal,extent\n" + diff --git a/Sharp.Augeas.Test/lens/tests/test_modprobe.aug b/Sharp.Augeas.Test/lens/tests/test_modprobe.aug new file mode 100644 index 0000000..30a7bce --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_modprobe.aug @@ -0,0 +1,147 @@ +module Test_modprobe = + +(* Based on 04config.sh from module-init-tools *) + +let conf = "# Various aliases +alias alias_to_foo foo +alias alias_to_bar bar +alias alias_to_export_dep-$BITNESS export_dep-$BITNESS + +# Various options, including options to aliases. +options alias_to_export_dep-$BITNESS I am alias to export_dep +options alias_to_noexport_nodep-$BITNESS_with_tabbed_options index=0 id=\"Thinkpad\" isapnp=0 \\ +\tport=0x530 cport=0x538 fm_port=0x388 \\ +\tmpu_port=-1 mpu_irq=-1 \\ +\tirq=9 dma1=1 dma2=3 \\ +\tenable=1 isapnp=0 + +# Blacklist +blacklist watchdog_drivers \t + +# Install commands +install bar echo Installing bar +install foo echo Installing foo +install export_nodep-$BITNESS echo Installing export_nodep + +# Remove commands +remove bar echo Removing bar +remove foo echo Removing foo +remove export_nodep-$BITNESS echo Removing export_nodep + +# Softdep +softdep uhci-hcd post: foo +softdep uhci-hcd pre: ehci-hcd foo +softdep uhci-hcd pre: ehci-hcd foo post: foo +" + +test Modprobe.lns get conf = + { "#comment" = "Various aliases" } + { "alias" = "alias_to_foo" + { "modulename" = "foo" } + } + { "alias" = "alias_to_bar" + { "modulename" = "bar" } + } + { "alias" = "alias_to_export_dep-$BITNESS" + { "modulename" = "export_dep-$BITNESS" } + } + { } + { "#comment" = "Various options, including options to aliases." } + { "options" = "alias_to_export_dep-$BITNESS" + { "I" } + { "am" } + { "alias" } + { "to" } + { "export_dep" } + } + { "options" = "alias_to_noexport_nodep-$BITNESS_with_tabbed_options" + { "index" = "0" } + { "id" = "\"Thinkpad\"" } + { "isapnp" = "0" } + { "port" = "0x530" } + { "cport" = "0x538" } + { "fm_port" = "0x388" } + { "mpu_port" = "-1" } + { "mpu_irq" = "-1" } + { "irq" = "9" } + { "dma1" = "1" } + { "dma2" = "3" } + { "enable" = "1" } + { "isapnp" = "0" } + } + { } + { "#comment" = "Blacklist" } + { "blacklist" = "watchdog_drivers" } + { } + { "#comment" = "Install commands" } + { "install" = "bar" + { "command" = "echo Installing bar" } + } + { "install" = "foo" + { "command" = "echo Installing foo" } + } + { "install" = "export_nodep-$BITNESS" + { "command" = "echo Installing export_nodep" } + } + { } + { "#comment" = "Remove commands" } + { "remove" = "bar" + { "command" = "echo Removing bar" } + } + { "remove" = "foo" + { "command" = "echo Removing foo" } + } + { "remove" = "export_nodep-$BITNESS" + { "command" = "echo Removing export_nodep" } + } + { } + { "#comment" = "Softdep" } + { "softdep" = "uhci-hcd" + { "post" = "foo" } + } + { "softdep" = "uhci-hcd" + { "pre" = "ehci-hcd" } + { "pre" = "foo" } + } + { "softdep" = "uhci-hcd" + { "pre" = "ehci-hcd" } + { "pre" = "foo" } + { "post" = "foo" } + } + + +(* eol-comments *) +test Modprobe.lns get "blacklist brokenmodule # never worked\n" = + { "blacklist" = "brokenmodule" + { "#comment" = "never worked" } } + + +(* Ticket 108 *) +let options_space_quote = "options name attr1=\"val\" attr2=\"val2 val3\"\n" + +test Modprobe.entry get options_space_quote = + { "options" = "name" + { "attr1" = "\"val\"" } + { "attr2" = "\"val2 val3\"" } + } + +(* Allow spaces around the '=', BZ 826752 *) +test Modprobe.entry get "options ipv6 disable = 1\n" = + { "options" = "ipv6" + { "disable" = "1" } } + +(* Support multiline split commands, Ubuntu bug #1054306 *) +test Modprobe.lns get "# /etc/modprobe.d/iwlwifi.conf +# iwlwifi will dyamically load either iwldvm or iwlmvm depending on the +# microcode file installed on the system. When removing iwlwifi, first +# remove the iwl?vm module and then iwlwifi. +remove iwlwifi \ +(/sbin/lsmod | grep -o -e ^iwlmvm -e ^iwldvm -e ^iwlwifi | xargs /sbin/rmmod) \ +&& /sbin/modprobe -r mac80211\n" = + { "#comment" = "/etc/modprobe.d/iwlwifi.conf" } + { "#comment" = "iwlwifi will dyamically load either iwldvm or iwlmvm depending on the" } + { "#comment" = "microcode file installed on the system. When removing iwlwifi, first" } + { "#comment" = "remove the iwl?vm module and then iwlwifi." } + { "remove" = "iwlwifi" + { "command" = "(/sbin/lsmod | grep -o -e ^iwlmvm -e ^iwldvm -e ^iwlwifi | xargs /sbin/rmmod) \\\n&& /sbin/modprobe -r mac80211" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_modules.aug b/Sharp.Augeas.Test/lens/tests/test_modules.aug new file mode 100644 index 0000000..f024aca --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_modules.aug @@ -0,0 +1,13 @@ +module Test_Modules = + +let conf = "# /etc/modules: kernel modules to load at boot time. + +lp +rtc +" + +test Modules.lns get conf = + { "#comment" = "/etc/modules: kernel modules to load at boot time." } + { } + { "lp" } + { "rtc" } diff --git a/Sharp.Augeas.Test/lens/tests/test_modules_conf.aug b/Sharp.Augeas.Test/lens/tests/test_modules_conf.aug new file mode 100644 index 0000000..264bbb9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_modules_conf.aug @@ -0,0 +1,120 @@ +module Test_modules_conf = + +(* Based on 04config.sh from module-init-tools *) + +let conf = "# Various aliases +alias alias_to_foo foo +alias alias_to_bar bar +alias alias_to_export_dep-$BITNESS export_dep-$BITNESS + +# Various options, including options to aliases. +options alias_to_export_dep-$BITNESS I am alias to export_dep +options alias_to_noexport_nodep-$BITNESS_with_tabbed_options index=0 id=\"Thinkpad\" isapnp=0 \\ +\tport=0x530 cport=0x538 fm_port=0x388 \\ +\tmpu_port=-1 mpu_irq=-1 \\ +\tirq=9 dma1=1 dma2=3 \\ +\tenable=1 isapnp=0 + +# Install commands +install bar echo Installing bar +install foo echo Installing foo +install export_nodep-$BITNESS echo Installing export_nodep + +# Pre- and post- install something +pre-install ide-scsi modprobe ide-cd # load ide-cd before ide-scsi +post-install serial /etc/init.d/setserial modload > /dev/null 2> /dev/null + +# Remove commands +remove bar echo Removing bar +remove foo echo Removing foo +remove export_nodep-$BITNESS echo Removing export_nodep + +#Pre- and post- remove something +pre-remove serial /etc/init.d/setserial modsave > /dev/null 2> /dev/null +post-remove bttv rmmod tuner + +# Misc other directives +probeall /dev/cdroms +keep +path=/lib/modules/`uname -r`/alsa +" + +test Modules_conf.lns get conf = + { "#comment" = "Various aliases" } + { "alias" = "alias_to_foo" + { "modulename" = "foo" } + } + { "alias" = "alias_to_bar" + { "modulename" = "bar" } + } + { "alias" = "alias_to_export_dep-$BITNESS" + { "modulename" = "export_dep-$BITNESS" } + } + { } + { "#comment" = "Various options, including options to aliases." } + { "options" = "alias_to_export_dep-$BITNESS" + { "I" } + { "am" } + { "alias" } + { "to" } + { "export_dep" } + } + { "options" = "alias_to_noexport_nodep-$BITNESS_with_tabbed_options" + { "index" = "0" } + { "id" = "\"Thinkpad\"" } + { "isapnp" = "0" } + { "port" = "0x530" } + { "cport" = "0x538" } + { "fm_port" = "0x388" } + { "mpu_port" = "-1" } + { "mpu_irq" = "-1" } + { "irq" = "9" } + { "dma1" = "1" } + { "dma2" = "3" } + { "enable" = "1" } + { "isapnp" = "0" } + } + { } + { "#comment" = "Install commands" } + { "install" = "bar" + { "command" = "echo Installing bar" } + } + { "install" = "foo" + { "command" = "echo Installing foo" } + } + { "install" = "export_nodep-$BITNESS" + { "command" = "echo Installing export_nodep" } + } + { } + { "#comment" = "Pre- and post- install something" } + { "pre-install" = "ide-scsi" + { "command" = "modprobe ide-cd" } + { "#comment" = "load ide-cd before ide-scsi" } + } + { "post-install" = "serial" + { "command" = "/etc/init.d/setserial modload > /dev/null 2> /dev/null" } + } + { } + { "#comment" = "Remove commands" } + { "remove" = "bar" + { "command" = "echo Removing bar" } + } + { "remove" = "foo" + { "command" = "echo Removing foo" } + } + { "remove" = "export_nodep-$BITNESS" + { "command" = "echo Removing export_nodep" } + } + { } + { "#comment" = "Pre- and post- remove something" } + { "pre-remove" = "serial" + { "command" = "/etc/init.d/setserial modsave > /dev/null 2> /dev/null" } + } + { "post-remove" = "bttv" + { "command" = "rmmod tuner" } + } + { } + { "#comment" = "Misc other directives" } + { "probeall" = "/dev/cdroms" } + { "keep" } + { "path" = "/lib/modules/`uname -r`/alsa" } diff --git a/Sharp.Augeas.Test/lens/tests/test_mongodbserver.aug b/Sharp.Augeas.Test/lens/tests/test_mongodbserver.aug new file mode 100644 index 0000000..8363d7b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_mongodbserver.aug @@ -0,0 +1,31 @@ +(* +Module: Test_MongoDBServer + Provides unit tests and examples for the <MongoDBServer> lens. +*) + +module Test_MongoDBServer = + +(* Variable: conf *) +let conf = "port = 27017 +fork = true +pidfilepath = /var/run/mongodb/mongodb.pid +logpath = /var/log/mongodb/mongodb.log +dbpath =/var/lib/mongodb +journal = true +nohttpinterface = true +" + +(* Test: MongoDBServer.lns *) +test MongoDBServer.lns get conf = + { "port" = "27017" } + { "fork" = "true" } + { "pidfilepath" = "/var/run/mongodb/mongodb.pid" } + { "logpath" = "/var/log/mongodb/mongodb.log" } + { "dbpath" = "/var/lib/mongodb" } + { "journal" = "true" } + { "nohttpinterface" = "true" } + +(* Test: MongoDBServer.lns + Values have to be without quotes *) +test MongoDBServer.lns get "port = 27017\n" = + { "port" = "27017" } diff --git a/Sharp.Augeas.Test/lens/tests/test_monit.aug b/Sharp.Augeas.Test/lens/tests/test_monit.aug new file mode 100644 index 0000000..e27974d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_monit.aug @@ -0,0 +1,35 @@ +module Test_monit = + +let conf = "# Configuration file for monit. +# +set alert root@localhost +include /my/monit/conf + +check process sshd + start program \"/etc/init.d/ssh start\" + if failed port 22 protocol ssh then restart + +check process httpd with pidfile /usr/local/apache2/logs/httpd.pid + group www-data + start program \"/usr/local/apache2/bin/apachectl start\" + stop program \"/usr/local/apache2/bin/apachectl stop\" +" + +test Monit.lns get conf = + { "#comment" = "Configuration file for monit." } + {} + { "set" + {"alert" = "root@localhost" } } + { "include" = "/my/monit/conf" } + {} + { "check" + { "process" = "sshd" } + { "start" = "program \"/etc/init.d/ssh start\"" } + { "if" = "failed port 22 protocol ssh then restart" } } + {} + { "check" + { "process" = "httpd with pidfile /usr/local/apache2/logs/httpd.pid" } + { "group" = "www-data" } + { "start" = "program \"/usr/local/apache2/bin/apachectl start\"" } + { "stop" = "program \"/usr/local/apache2/bin/apachectl stop\"" } +} diff --git a/Sharp.Augeas.Test/lens/tests/test_multipath.aug b/Sharp.Augeas.Test/lens/tests/test_multipath.aug new file mode 100644 index 0000000..c32f1d4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_multipath.aug @@ -0,0 +1,247 @@ +module Test_multipath = + + let conf = "# Blacklist all devices by default. +blacklist { + devnode \"*\" + wwid * +} + +# By default, devices with vendor = \"IBM\" and product = \"S/390.*\" are +# blacklisted. To enable mulitpathing on these devies, uncomment the +# following lines. +blacklist_exceptions { + device { + vendor \"IBM\" + product \"S/390.*\" + } +} + +# +# Here is an example of how to configure some standard options. +# + +defaults { + udev_dir /dev + polling_interval 10 + selector \"round-robin 0\" + path_grouping_policy multibus + getuid_callout \"/sbin/scsi_id --whitelisted /dev/%n\" + prio alua + path_checker readsector0 + rr_min_io 100 + max_fds 8192 + rr_weight priorities + failback immediate + no_path_retry fail + user_friendly_names yes + dev_loss_tmo 30 + max_polling_interval 300 + verbosity 2 + reassign_maps yes + fast_io_fail_tmo 5 + async_timeout 5 + flush_on_last_del no + delay_watch_checks no + delay_wait_checks no + find_multipaths yes + checker_timeout 10 + hwtable_regex_match yes + reload_readwrite no + force_sync yes + config_dir /etc/multipath/conf.d +} + +# Sections without empty lines in between +blacklist { + wwid 26353900f02796769 + devnode \"^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*\" + + # Comments and blank lines inside a section + devnode \"^hd[a-z]\" + +} +multipaths { + multipath { + wwid 3600508b4000156d700012000000b0000 + alias yellow + path_grouping_policy multibus + path_checker readsector0 + path_selector \"round-robin 0\" + failback manual + rr_weight priorities + no_path_retry 5 + flush_on_last_del yes + } + multipath { + wwid 1DEC_____321816758474 + alias red + } +} +devices { + device { + vendor \"COMPAQ \" + product \"HSV110 (C)COMPAQ\" + path_grouping_policy multibus + getuid_callout \"/sbin/scsi_id --whitelisted /dev/%n\" + path_checker readsector0 + path_selector \"round-robin 0\" + hardware_handler \"0\" + failback 15 + rr_weight priorities + rr_min_io_rq 75 + no_path_retry queue + reservation_key a12345 + } + device { + vendor \"COMPAQ \" + product \"MSA1000 \" + path_grouping_policy multibus + polling_interval 9 + delay_watch_checks 10 + delay_wait_checks 10 + } +}\n" + +test Multipath.lns get conf = + { "#comment" = "Blacklist all devices by default." } + { "blacklist" + { "devnode" = "*" } + { "wwid" = "*" } } + { } + { "#comment" = "By default, devices with vendor = \"IBM\" and product = \"S/390.*\" are" } + { "#comment" = "blacklisted. To enable mulitpathing on these devies, uncomment the" } + { "#comment" = "following lines." } + { "blacklist_exceptions" + { "device" + { "vendor" = "IBM" } + { "product" = "S/390.*" } } } + { } + { } + { "#comment" = "Here is an example of how to configure some standard options." } + { } + { } + { "defaults" + { "udev_dir" = "/dev" } + { "polling_interval" = "10" } + { "selector" = "round-robin 0" } + { "path_grouping_policy" = "multibus" } + { "getuid_callout" = "/sbin/scsi_id --whitelisted /dev/%n" } + { "prio" = "alua" } + { "path_checker" = "readsector0" } + { "rr_min_io" = "100" } + { "max_fds" = "8192" } + { "rr_weight" = "priorities" } + { "failback" = "immediate" } + { "no_path_retry" = "fail" } + { "user_friendly_names" = "yes" } + { "dev_loss_tmo" = "30" } + { "max_polling_interval" = "300" } + { "verbosity" = "2" } + { "reassign_maps" = "yes" } + { "fast_io_fail_tmo" = "5" } + { "async_timeout" = "5" } + { "flush_on_last_del" = "no" } + { "delay_watch_checks" = "no" } + { "delay_wait_checks" = "no" } + { "find_multipaths" = "yes" } + { "checker_timeout" = "10" } + { "hwtable_regex_match" = "yes" } + { "reload_readwrite" = "no" } + { "force_sync" = "yes" } + { "config_dir" = "/etc/multipath/conf.d" } } + { } + { "#comment" = "Sections without empty lines in between" } + { "blacklist" + { "wwid" = "26353900f02796769" } + { "devnode" = "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" } + { } + { "#comment" = "Comments and blank lines inside a section" } + { "devnode" = "^hd[a-z]" } + { } } + { "multipaths" + { "multipath" + { "wwid" = "3600508b4000156d700012000000b0000" } + { "alias" = "yellow" } + { "path_grouping_policy" = "multibus" } + { "path_checker" = "readsector0" } + { "path_selector" = "round-robin 0" } + { "failback" = "manual" } + { "rr_weight" = "priorities" } + { "no_path_retry" = "5" } + { "flush_on_last_del" = "yes" } } + { "multipath" + { "wwid" = "1DEC_____321816758474" } + { "alias" = "red" } } } + { "devices" + { "device" + { "vendor" = "COMPAQ " } + { "product" = "HSV110 (C)COMPAQ" } + { "path_grouping_policy" = "multibus" } + { "getuid_callout" = "/sbin/scsi_id --whitelisted /dev/%n" } + { "path_checker" = "readsector0" } + { "path_selector" = "round-robin 0" } + { "hardware_handler" = "0" } + { "failback" = "15" } + { "rr_weight" = "priorities" } + { "rr_min_io_rq" = "75" } + { "no_path_retry" = "queue" } + { "reservation_key" = "a12345" } } + { "device" + { "vendor" = "COMPAQ " } + { "product" = "MSA1000 " } + { "path_grouping_policy" = "multibus" } + { "polling_interval" = "9" } + { "delay_watch_checks" = "10" } + { "delay_wait_checks" = "10" } } } + +test Multipath.lns get "blacklist { + devnode \".*\" + wwid \"([a-z]+|ab?c).*\" +}\n" = + { "blacklist" + { "devnode" = ".*" } + { "wwid" = "([a-z]+|ab?c).*" } } + +test Multipath.lns get "blacklist {\n property \"[a-z]+\"\n}\n" = + { "blacklist" + { "property" = "[a-z]+" } } + +(* Check that '""' inside a string works *) +test Multipath.lns get "blacklist { + device { + vendor SomeCorp + product \"2.5\"\" SSD\" + } +}\n" = + { "blacklist" + { "device" + { "vendor" = "SomeCorp" } + { "product" = "2.5\"\" SSD" } } } + +(* Issue #583 - allow optional quotes around values and strip them *) +test Multipath.lns get "devices { + device { + vendor \"COMPELNT\" + product \"Compellent Vol\" + path_grouping_policy \"multibus\" + path_checker \"tur\" + features \"0\" + hardware_handler \"0\" + prio \"const\" + failback \"immediate\" + rr_weight \"uniform\" + no_path_retry \"queue\" + } +}\n" = + { "devices" + { "device" + { "vendor" = "COMPELNT" } + { "product" = "Compellent Vol" } + { "path_grouping_policy" = "multibus" } + { "path_checker" = "tur" } + { "features" = "0" } + { "hardware_handler" = "0" } + { "prio" = "const" } + { "failback" = "immediate" } + { "rr_weight" = "uniform" } + { "no_path_retry" = "queue" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_mysql.aug b/Sharp.Augeas.Test/lens/tests/test_mysql.aug new file mode 100644 index 0000000..9356204 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_mysql.aug @@ -0,0 +1,283 @@ +module Test_mysql = + + let conf = "# The MySQL database server configuration file. +# +# You can copy this to one of: +# +# One can use all long options that the program supports. +# Run program with --help to get a list of available options and with +# --print-defaults to see which it would actually understand and use. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +# This will be passed to all mysql clients +# It has been reported that passwords should be enclosed with ticks/quotes +# Remember to edit /etc/mysql/debian.cnf when changing the socket location. + [client] + port = 3306 +socket = /var/run/mysqld/mysqld.sock + +# Here is entries for some specific programs +# The following values assume you have at least 32M ram + +# This was formally known as [safe_mysqld]. Both versions are currently parsed. + [mysqld_safe] +socket = /var/run/mysqld/mysqld.sock +nice = 0 + +[mysqld] +# +# * Basic Settings +# +user = mysql +pid-file = /var/run/mysqld/mysqld.pid +socket = /var/run/mysqld/mysqld.sock +port = 3306 +basedir = /usr +datadir = /var/lib/mysql +tmpdir = /tmp +language = /usr/share/mysql/english + skip-external-locking +# +# Instead of skip-networking the default is now to listen only on +# localhost which is more compatible and is not less secure. +bind-address = 127.0.0.1 +# +# * Fine Tuning +# +key_buffer = 16M +max_allowed_packet = 16M +thread_stack = 128K +thread_cache_size = 8 +#max_connections = 100 +#table_cache = 64 +#thread_concurrency = 10 +# +# * Query Cache Configuration +# +query_cache_limit = 1M +query_cache_size = 16M +# +# * Logging and Replication +# +# Both location gets rotated by the cronjob. +# Be aware that this log type is a performance killer. +#log = /var/log/mysql/mysql.log +# +# Error logging goes to syslog. This is a Debian improvement :) +# +# Here you can see queries with especially long duration +#log_slow_queries = /var/log/mysql/mysql-slow.log +#long_query_time = 2 +#log-queries-not-using-indexes +# +# The following can be used as easy to replay backup logs or for replication. +#server-id = 1 +#log_bin = /var/log/mysql/mysql-bin.log +# WARNING: Using expire_logs_days without bin_log crashes the server! See README.Debian! +#expire_logs_days = 10 +#max_binlog_size = 100M +#binlog_do_db = include_database_name +#binlog_ignore_db = include_database_name +# +# * BerkeleyDB +# +# Using BerkeleyDB is now discouraged as its support will cease in 5.1.12. +skip-bdb +# +# * InnoDB +# +# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. +# Read the manual for more InnoDB related options. There are many! +# You might want to disable InnoDB to shrink the mysqld process by circa 100MB. +#skip-innodb +# +# * Security Features +# +# Read the manual, too, if you want chroot! +# chroot = /var/lib/mysql/ +# +# +# ssl-ca=/etc/mysql/cacert.pem +# ssl-cert=/etc/mysql/server-cert.pem +# ssl-key=/etc/mysql/server-key.pem + + + +[mysqldump] +quick +quote-names +max_allowed_packet = 16M + +[mysql] +#no-auto-rehash # faster start of mysql but no tab completition + +[isamchk] +key_buffer = 16M + +# +# * NDB Cluster +# +# See /usr/share/doc/mysql-server-*/README.Debian for more information. +# +# The following configuration is read by the NDB Data Nodes (ndbd processes) +# not from the NDB Management Nodes (ndb_mgmd processes). +# +# [MYSQL_CLUSTER] +# ndb-connectstring=127.0.0.1 + + +# +# * IMPORTANT: Additional settings that can override those from this file! +# +!includedir /etc/mysql/conf.d/ +!include /etc/mysql/other_conf.d/someconf.cnf +# Another comment + +" + + + test MySQL.lns get conf = { "#comment" = "The MySQL database server configuration file." } + {} + { "#comment" = "You can copy this to one of:" } + {} + { "#comment" = "One can use all long options that the program supports." } + { "#comment" = "Run program with --help to get a list of available options and with" } + { "#comment" = "--print-defaults to see which it would actually understand and use." } + {} + { "#comment" = "For explanations see" } + { "#comment" = "http://dev.mysql.com/doc/mysql/en/server-system-variables.html" } + { } + { "#comment" = "This will be passed to all mysql clients" } + { "#comment" = "It has been reported that passwords should be enclosed with ticks/quotes" } + { "#comment" = "Remember to edit /etc/mysql/debian.cnf when changing the socket location." } + { "target" = "client" + { "port" = "3306" } + { "socket" = "/var/run/mysqld/mysqld.sock" } + { } + { "#comment" = "Here is entries for some specific programs" } + { "#comment" = "The following values assume you have at least 32M ram" } + { } + { "#comment" = "This was formally known as [safe_mysqld]. Both versions are currently parsed." } + } + { "target" = "mysqld_safe" + { "socket" = "/var/run/mysqld/mysqld.sock" } + { "nice" = "0" } + { } + } + { "target" = "mysqld" + {} + { "#comment" = "* Basic Settings" } + {} + { "user" = "mysql" } + { "pid-file" = "/var/run/mysqld/mysqld.pid" } + { "socket" = "/var/run/mysqld/mysqld.sock" } + { "port" = "3306" } + { "basedir" = "/usr" } + { "datadir" = "/var/lib/mysql" } + { "tmpdir" = "/tmp" } + { "language" = "/usr/share/mysql/english" } + { "skip-external-locking" = "" } + {} + { "#comment" = "Instead of skip-networking the default is now to listen only on" } + { "#comment" = "localhost which is more compatible and is not less secure." } + { "bind-address" = "127.0.0.1" } + {} + { "#comment" = "* Fine Tuning" } + {} + { "key_buffer" = "16M" } + { "max_allowed_packet" = "16M" } + { "thread_stack" = "128K" } + { "thread_cache_size" = "8" } + { "#comment" = "max_connections = 100" } + { "#comment" = "table_cache = 64" } + { "#comment" = "thread_concurrency = 10" } + {} + { "#comment" = "* Query Cache Configuration" } + {} + { "query_cache_limit" = "1M" } + { "query_cache_size" = "16M" } + {} + { "#comment" = "* Logging and Replication" } + {} + { "#comment" = "Both location gets rotated by the cronjob." } + { "#comment" = "Be aware that this log type is a performance killer." } + { "#comment" = "log = /var/log/mysql/mysql.log" } + {} + { "#comment" = "Error logging goes to syslog. This is a Debian improvement :)" } + {} + { "#comment" = "Here you can see queries with especially long duration" } + { "#comment" = "log_slow_queries = /var/log/mysql/mysql-slow.log" } + { "#comment" = "long_query_time = 2" } + { "#comment" = "log-queries-not-using-indexes" } + {} + { "#comment" = "The following can be used as easy to replay backup logs or for replication." } + { "#comment" = "server-id = 1" } + { "#comment" = "log_bin = /var/log/mysql/mysql-bin.log" } + { "#comment" = "WARNING: Using expire_logs_days without bin_log crashes the server! See README.Debian!" } + { "#comment" = "expire_logs_days = 10" } + { "#comment" = "max_binlog_size = 100M" } + { "#comment" = "binlog_do_db = include_database_name" } + { "#comment" = "binlog_ignore_db = include_database_name" } + {} + { "#comment" = "* BerkeleyDB" } + {} + { "#comment" = "Using BerkeleyDB is now discouraged as its support will cease in 5.1.12." } + { "skip-bdb" = "" } + {} + { "#comment" = "* InnoDB" } + {} + { "#comment" = "InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/." } + { "#comment" = "Read the manual for more InnoDB related options. There are many!" } + { "#comment" = "You might want to disable InnoDB to shrink the mysqld process by circa 100MB." } + { "#comment" = "skip-innodb" } + {} + { "#comment" = "* Security Features" } + {} + { "#comment" = "Read the manual, too, if you want chroot!" } + { "#comment" = "chroot = /var/lib/mysql/" } + {} + {} + { "#comment" = "ssl-ca=/etc/mysql/cacert.pem" } + { "#comment" = "ssl-cert=/etc/mysql/server-cert.pem" } + { "#comment" = "ssl-key=/etc/mysql/server-key.pem" } + { } + { } + { } + } + { "target" = "mysqldump" + { "quick" = "" } + { "quote-names" = "" } + { "max_allowed_packet" = "16M" } + { } + } + { "target" = "mysql" + { "#comment" = "no-auto-rehash # faster start of mysql but no tab completition" } + { } + } + { "target" = "isamchk" + { "key_buffer" = "16M" } + { } + {} + { "#comment" = "* NDB Cluster" } + {} + { "#comment" = "See /usr/share/doc/mysql-server-*/README.Debian for more information." } + {} + { "#comment" = "The following configuration is read by the NDB Data Nodes (ndbd processes)" } + { "#comment" = "not from the NDB Management Nodes (ndb_mgmd processes)." } + {} + { "#comment" = "[MYSQL_CLUSTER]" } + { "#comment" = "ndb-connectstring=127.0.0.1" } + { } + { } + {} + { "#comment" = "* IMPORTANT: Additional settings that can override those from this file!" } + {} + } + { "!includedir" = "/etc/mysql/conf.d/" } + { "!include" = "/etc/mysql/other_conf.d/someconf.cnf" } + { "#comment" = "Another comment" } + { } + + diff --git a/Sharp.Augeas.Test/lens/tests/test_nagioscfg.aug b/Sharp.Augeas.Test/lens/tests/test_nagioscfg.aug new file mode 100644 index 0000000..5552341 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_nagioscfg.aug @@ -0,0 +1,89 @@ +(* +Module: Test_NagiosCfg + Provides unit tests and examples for the <NagiosCfg> lens. +*) + +module Test_NagiosCfg = + let conf=" +# LOG FILE +log_file=/var/log/nagios3/nagios.log + +# OBJECT CONFIGURATION FILE(S) +cfg_file=/etc/nagios3/objects/check_commands.cfg +cfg_file=/etc/nagios3/objects/contact_groups.cfg +cfg_file=/etc/nagios3/objects/contacts.cfg +cfg_file=/etc/nagios3/objects/hostgroups.cfg +cfg_file=/etc/nagios3/objects/hosts.cfg +cfg_file=/etc/nagios3/objects/services.cfg + +# NAGIOS USER +nagios_user=nagios + +# NAGIOS GROUP +nagios_group=nagios + +# DATE FORMAT +date_format=iso8601 + +# ILLEGAL OBJECT NAME CHARS +illegal_object_name_chars=`~!$%^&*|'\"<>?,()'= + +# ILLEGAL MACRO OUTPUT CHARS +illegal_macro_output_chars=`~$&|'\"<> + +# MISC DIRECTIVES +p1_file=/usr/lib/nagios3/p1.pl +event_broker_options=-1 +use_large_installation_tweaks=1 +broker_module=/usr/lib/nagios3/libNagiosCluster-1.0.so.4.0.0 +broker_module=/usr/sbin/ndomod.o config_file=/etc/nagios3/ndomod.cfg +" + + test NagiosCfg.lns get conf = + {} + { "#comment" = "LOG FILE" } + { "log_file" = "/var/log/nagios3/nagios.log" } + {} + { "#comment" = "OBJECT CONFIGURATION FILE(S)" } + { "cfg_file" = "/etc/nagios3/objects/check_commands.cfg" } + { "cfg_file" = "/etc/nagios3/objects/contact_groups.cfg" } + { "cfg_file" = "/etc/nagios3/objects/contacts.cfg" } + { "cfg_file" = "/etc/nagios3/objects/hostgroups.cfg" } + { "cfg_file" = "/etc/nagios3/objects/hosts.cfg" } + { "cfg_file" = "/etc/nagios3/objects/services.cfg" } + {} + { "#comment" = "NAGIOS USER" } + { "nagios_user" = "nagios" } + {} + { "#comment" = "NAGIOS GROUP" } + { "nagios_group"= "nagios" } + {} + { "#comment" = "DATE FORMAT" } + { "date_format" = "iso8601" } + {} + { "#comment" = "ILLEGAL OBJECT NAME CHARS" } + { "illegal_object_name_chars" = "`~!$%^&*|'\"<>?,()'=" } + {} + { "#comment" = "ILLEGAL MACRO OUTPUT CHARS" } + { "illegal_macro_output_chars" = "`~$&|'\"<>" } + {} + { "#comment" = "MISC DIRECTIVES" } + { "p1_file" = "/usr/lib/nagios3/p1.pl" } + { "event_broker_options" = "-1" } + { "use_large_installation_tweaks" = "1" } + { "broker_module" = "/usr/lib/nagios3/libNagiosCluster-1.0.so.4.0.0" } + { "broker_module" = "/usr/sbin/ndomod.o" + { "config_file" = "/etc/nagios3/ndomod.cfg" } } + + +(* Spaces are fine in values *) +let space_in = "nagios_check_command=/usr/lib/nagios/plugins/check_nagios /var/cache/nagios3/status.dat 5 '/usr/sbin/nagios3'\n" + +test NagiosCfg.lns get space_in = + { "nagios_check_command" = "/usr/lib/nagios/plugins/check_nagios /var/cache/nagios3/status.dat 5 '/usr/sbin/nagios3'" } + +test NagiosCfg.lns get "$USER1$=/usr/local/libexec/nagios\n" = + { "$USER1$" = "/usr/local/libexec/nagios" } + +test NagiosCfg.lns get "$USER3$=somepassword\n" = + { "$USER3$" = "somepassword" } diff --git a/Sharp.Augeas.Test/lens/tests/test_nagiosobjects.aug b/Sharp.Augeas.Test/lens/tests/test_nagiosobjects.aug new file mode 100644 index 0000000..20b02d8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_nagiosobjects.aug @@ -0,0 +1,61 @@ +module Test_NagiosObjects = + let conf=" +# +# Nagios Objects definitions file +# + +define host { + host_name plonk + alias plonk + address plonk + use generic_template + contact_groups Monitoring-Team,admins +} + +define service { + service_description gen + use generic_template_passive + host_name plonk + check_command nopassivecheckreceived + contact_groups admins +} + +; This is a semicolon comment + +define service{ + service_description gen2 + use generic_template_passive + host_name plonk + } +" + + test NagiosObjects.lns get conf = + {} + {} + { "#comment" = "Nagios Objects definitions file" } + {} + {} + { "host" + { "host_name" = "plonk" } + { "alias" = "plonk" } + { "address" = "plonk" } + { "use" = "generic_template" } + { "contact_groups" = "Monitoring-Team,admins" } + } + {} + { "service" + { "service_description" = "gen" } + { "use" = "generic_template_passive" } + { "host_name" = "plonk" } + { "check_command" = "nopassivecheckreceived" } + { "contact_groups" = "admins" } + } + {} + { "#comment" = "This is a semicolon comment" } + {} + { "service" + { "service_description" = "gen2" } + { "use" = "generic_template_passive" } + { "host_name" = "plonk" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_netmasks.aug b/Sharp.Augeas.Test/lens/tests/test_netmasks.aug new file mode 100644 index 0000000..57a9edc --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_netmasks.aug @@ -0,0 +1,26 @@ +(* Test for netmasks lens *) +module Test_netmasks = + + let conf = "# The netmasks file associates Internet Protocol (IP) address +# masks with IP network numbers. +# + +192.168.1.0 255.255.255.0 +10.0.0.0 255.0.0.0 +" + + test Netmasks.lns get conf = + { "#comment" = "The netmasks file associates Internet Protocol (IP) address" } + { "#comment" = "masks with IP network numbers." } + { } + { } + { "1" + { "network" = "192.168.1.0" } + { "netmask" = "255.255.255.0" } } + { "2" + { "network" = "10.0.0.0" } + { "netmask" = "255.0.0.0" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_networkmanager.aug b/Sharp.Augeas.Test/lens/tests/test_networkmanager.aug new file mode 100644 index 0000000..cda2e67 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_networkmanager.aug @@ -0,0 +1,98 @@ +(* +Module: Test_NetworkManager + Provides unit tests and examples for the <NetworkManager> lens. +*) + +module Test_NetworkManager = + +(* Variable: conf *) +let conf = "[connection] +id=wifoobar +uuid=16fa8830-cf15-4523-8c1f-c6c635246855 +permissions=user:foo:; +type=802-11-wireless + +[802-11-wireless] +ssid=wifoobar +mode=infrastructure +mac-address=11:00:99:33:33:AA +security=802-11-wireless-security + +[802-11-wireless-security] +key-mgmt=none +wep-key0=123abc123abc + +[ipv4] +method=auto + +[ipv6] +method=auto + +[vpn] +NAT Traversal Mode=natt +DPD idle timeout (our side)=0\n" + +let conf_psk = "[wifi] +ssid=TEST +mode=infrastructure + +[wifi-security] +key-mgmt=wpa-psk +auth-alg=open +psk=\"#weird but valid psk!\"\n" + +let conf_empty = "" + +(* Test: NetworkManager.lns *) +test NetworkManager.lns get conf = + { "connection" + { "id" = "wifoobar" } + { "uuid" = "16fa8830-cf15-4523-8c1f-c6c635246855" } + { "permissions" = "user:foo:;" } + { "type" = "802-11-wireless" } + { } + } + { "802-11-wireless" + { "ssid" = "wifoobar" } + { "mode" = "infrastructure" } + { "mac-address" = "11:00:99:33:33:AA" } + { "security" = "802-11-wireless-security" } + { } + } + { "802-11-wireless-security" + { "key-mgmt" = "none" } + { "wep-key0" = "123abc123abc" } + { } + } + { "ipv4" + { "method" = "auto" } + { } + } + { "ipv6" + { "method" = "auto" } + { } + } + { "vpn" + { "NAT Traversal Mode" = "natt" } + { "DPD idle timeout (our side)" = "0" } + } + +(* Test: NetworkManager.lns - nontrivial WPA-PSK *) +test NetworkManager.lns get conf_psk = + { "wifi" + { "ssid" = "TEST" } + { "mode" = "infrastructure" } + { } + } + { "wifi-security" + { "key-mgmt" = "wpa-psk" } + { "auth-alg" = "open" } + { "psk" = "\"#weird but valid psk!\"" } + } + +(* Test: NetworkManager.lns - write new values unquoted *) +test NetworkManager.lns put conf_empty after + insa "wifi-security" "/"; + set "wifi-security/psk" "#the key" + = "[wifi-security] +psk=#the key\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_networks.aug b/Sharp.Augeas.Test/lens/tests/test_networks.aug new file mode 100644 index 0000000..d5caf10 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_networks.aug @@ -0,0 +1,50 @@ +module Test_Networks = + +let conf = "# Sample networks +default 0.0.0.0 # default route - mandatory +loopnet 127.0.0.0 loopnet_alias loopnet_alias2 # loopback network - mandatory +mynet 128.253.154 # Modify for your own network address + +loopback 127 +arpanet 10 arpa # Historical +localnet 192.168.25.192 +" + +test Networks.lns get conf = + { "#comment" = "Sample networks" } + { "1" + { "name" = "default" } + { "number" = "0.0.0.0" } + { "#comment" = "default route - mandatory" } + } + { "2" + { "name" = "loopnet" } + { "number" = "127.0.0.0" } + { "aliases" + { "1" = "loopnet_alias" } + { "2" = "loopnet_alias2" } + } + { "#comment" = "loopback network - mandatory" } + } + { "3" + { "name" = "mynet" } + { "number" = "128.253.154" } + { "#comment" = "Modify for your own network address" } + } + {} + { "4" + { "name" = "loopback" } + { "number" = "127" } + } + { "5" + { "name" = "arpanet" } + { "number" = "10" } + { "aliases" + { "1" = "arpa" } + } + { "#comment" = "Historical" } + } + { "6" + { "name" = "localnet" } + { "number" = "192.168.25.192" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_nginx.aug b/Sharp.Augeas.Test/lens/tests/test_nginx.aug new file mode 100644 index 0000000..38336b0 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_nginx.aug @@ -0,0 +1,299 @@ +(* +Module: Test_Nginx + Provides unit tests and examples for the <Nginx> lens. +*) +module Test_nginx = + +(* Check for non-recursive ambiguities *) +let directive = Nginx.simple + | Nginx.block ( + Nginx.simple + | Nginx.block Nginx.simple + ) + +(* Do some limited typechecking on the recursive lens; note that + unrolling once more leads to a typecheck error that seems to + be spurious, though it's not clear why + + Unrolling once more amounts to adding the clause + Nginx.block (Nginx.block Nginx.simple) + to unrolled and results in an error + overlapping lenses in union.get + Example matched by both: 'upstream{}\n' +*) +let unrolled = Nginx.simple | Nginx.block Nginx.simple + +let lns_unrolled = (Util.comment | Util.empty | unrolled) + +(* Normal unit tests *) +let lns = Nginx.lns + +let conf ="user nginx nginx; +worker_processes 1; +error_log /var/log/nginx/error_log info; + +events { + worker_connections 1024; + use epoll; +} + +# comment1 +# comment2 + +http { + # comment3 + include /etc/nginx/mime.types; + default_type application/octet-stream; + log_format main + '$remote_addr - $remote_user [$time_local] ' + '\"$request\" $status $bytes_sent ' + '\"$http_referer\" \"$http_user_agent\" ' + '\"$gzip_ratio\"'; + client_header_timeout 10m; + client_body_timeout 10m; + send_timeout 10m; + connection_pool_size 256; + client_header_buffer_size 2k; + large_client_header_buffers 4 8k; + request_pool_size 4k; + gzip on; + gzip_min_length 1000; + gzip_buffers 4 8k; + gzip_types text/plain application/json; + output_buffers 1 32k; + postpone_output 1460; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 75 20; + ignore_invalid_headers on; + index index.html index.php; + include vhosts/*.conf; +} +" + +test lns get conf = + { "user" = "nginx nginx" } + { "worker_processes" = "1" } + { "error_log" = "/var/log/nginx/error_log info" } + {} + { "events" + { "worker_connections" = "1024" } + { "use" = "epoll" } } + {} + { "#comment" = "comment1" } + { "#comment" = "comment2" } + {} + { "http" + { "#comment" = "comment3" } + { "include" = "/etc/nginx/mime.types" } + { "default_type" = "application/octet-stream" } + { "log_format" = "main + '$remote_addr - $remote_user [$time_local] ' + '\"$request\" $status $bytes_sent ' + '\"$http_referer\" \"$http_user_agent\" ' + '\"$gzip_ratio\"'" } + { "client_header_timeout" = "10m" } + { "client_body_timeout" = "10m" } + { "send_timeout" = "10m" } + { "connection_pool_size" = "256" } + { "client_header_buffer_size" = "2k" } + { "large_client_header_buffers" = "4 8k" } + { "request_pool_size" = "4k" } + { "gzip" = "on" } + { "gzip_min_length" = "1000" } + { "gzip_buffers" = "4 8k" } + { "gzip_types" = "text/plain application/json" } + { "output_buffers" = "1 32k" } + { "postpone_output" = "1460" } + { "sendfile" = "on" } + { "tcp_nopush" = "on" } + { "tcp_nodelay" = "on" } + { "keepalive_timeout" = "75 20" } + { "ignore_invalid_headers" = "on" } + { "index" = "index.html index.php" } + { "include" = "vhosts/*.conf" } } + +(* location blocks *) +test lns get "location / { }\n" = + { "location" + { "#uri" = "/" } } + +test lns get "location = / { }\n" = + { "location" + { "#comp" = "=" } + { "#uri" = "/" } } + +test lns get "location /documents/ { }\n" = + { "location" + { "#uri" = "/documents/" } } + +test lns get "location ^~ /images/ { }\n" = + { "location" + { "#comp" = "^~" } + { "#uri" = "/images/" } } + +test lns get "location ~* \.(gif|jpg|jpeg)$ { }\n" = + { "location" + { "#comp" = "~*" } + { "#uri" = "\.(gif|jpg|jpeg)$" } } + +test lns get "location @fallback { }\n" = + { "location" + { "#uri" = "@fallback" } } + +(* if blocks *) +test lns get "if ($slow) { + tcp_nodelay on; +}\n" = + { "if" + { "#cond" = "($slow)" } + { "tcp_nodelay" = "on" } } + +test lns get "if ($request_method = POST) { }\n" = + { "if" + { "#cond" = "($request_method = POST)" } } + + +test lns get "if ($http_cookie ~* \"id=([^;]+)(?:;|$)\") { }\n" = + { "if" + { "#cond" = "($http_cookie ~* \"id=([^;]+)(?:;|$)\")" } } + +(* geo blocks *) +test lns get "geo $geo { }\n" = + { "geo" + { "#geo" = "$geo" } } + +test lns get "geo $address $geo { }\n" = + { "geo" + { "#address" = "$address" } + { "#geo" = "$geo" } } + +(* map blocks *) +test lns get "map $http_host $name { }\n" = + { "map" + { "#source" = "$http_host" } + { "#variable" = "$name" } } + +(* split_clients block *) +test lns get "split_clients \"${remote_addr}AAA\" $variable { }\n" = + { "split_clients" + { "#string" = "\"${remote_addr}AAA\"" } + { "#variable" = "$variable" } } + +(* upstream block *) +test lns get "upstream backend { }\n" = + { "upstream" + { "#name" = "backend" } } + +(* GH #179 - recursive blocks *) +let http = "http { + server { + listen 80; + location / { + root\thtml; + } + } + gzip on; +}\n" + +test lns get http = + { "http" + { "server" + { "listen" = "80" } + { "location" + { "#uri" = "/" } + { "root" = "html" } } } + { "gzip" = "on" } } + + +(* GH #335 - server single line entries *) +let http_server_single_line_entries = "http { + upstream big_server_com { + server 127.0.0.3:8000 weight=5; + server 127.0.0.3:8001 weight=5; + server 192.168.0.1:8000; + server 192.168.0.1:8001; + server backend2.example.com:8080 fail_timeout=5s slow_start=30s; + server backend3.example.com resolve; + } +}\n" + +test lns get http_server_single_line_entries = + { "http" + { "upstream" + { "#name" = "big_server_com" } + { "@server" { "@address" = "127.0.0.3:8000" } { "weight" = "5" } } + { "@server" { "@address" = "127.0.0.3:8001" } { "weight" = "5" } } + { "@server" { "@address" = "192.168.0.1:8000" } } + { "@server" { "@address" = "192.168.0.1:8001" } } + { "@server" + { "@address" = "backend2.example.com:8080" } + { "fail_timeout" = "5s" } + { "slow_start" = "30s" } } + { "@server" + { "@address" = "backend3.example.com" } + { "resolve" } } } } + +(* Make sure we do not screw up the indentation of the file *) +test lns put http after set "/http/gzip" "off" = +"http { + server { + listen 80; + location / { + root\thtml; + } + } + gzip off; +}\n" + +(* Test lns + GH #260 *) +test lns get "http { + geo $geo { + default 0; + + 127.0.0.1 2; + 192.168.1.0/24 1; + 10.1.0.0/16 1; + + ::1 2; + 2001:0db8::/32 1; + } +}\n" = + { "http" + { "geo" + { "#geo" = "$geo" } + { "default" = "0" } + { } + { "127.0.0.1" = "2" } + { "192.168.1.0" = "1" + { "mask" = "24" } } + { "10.1.0.0" = "1" + { "mask" = "16" } } + { } + { "::1" = "2" } + { "2001:0db8::" = "1" + { "mask" = "32" } } } } + +test lns get "add_header X-XSS-Protection \"1; mode=block\" always;\n" = + { "add_header" = "X-XSS-Protection \"1; mode=block\" always" } + +test lns get "location /foo { + root /var/www/html; + internal; # only valid in location blocks +}\n" = + { "location" + { "#uri" = "/foo" } + { "root" = "/var/www/html" } + { "internal" + { "#comment" = "only valid in location blocks" } } } + +test lns get "upstream php-handler { + server unix:/var/run/php/php7.3-fpm.sock; +}\n" = + { "upstream" + { "#name" = "php-handler" } + { "@server" + { "@address" = "unix:/var/run/php/php7.3-fpm.sock" } } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_nrpe.aug b/Sharp.Augeas.Test/lens/tests/test_nrpe.aug new file mode 100644 index 0000000..e86a241 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_nrpe.aug @@ -0,0 +1,101 @@ +module Test_nrpe = + + let command = "command[foo]=bar\n" + + test Nrpe.command get command = + { "command" + { "foo" = "bar" } + } + + + let item = "nrpe_user=nagios\n" + + test Nrpe.item get item = + { "nrpe_user" = "nagios" } + + + let include = "include=/path/to/file.cfg\n" + + test Nrpe.include get include = + { "include" + { "file" = "/path/to/file.cfg" } + } + + + let comment = "# a comment\n" + + test Nrpe.comment get comment = + { "#comment" = "a comment" } + + + let empty = "# \n" + + test Nrpe.empty get empty = + { } + + + (* Debian bug #749919 *) + let allowed_hosts_1 = "allowed_hosts=127.0.0.1\n" + + test Nrpe.item get allowed_hosts_1 = + { "allowed_hosts" = "127.0.0.1" } + + + let allowed_hosts_2 = "allowed_hosts=127.0.0.1, 127.0.0.2\n" + + test Nrpe.item get allowed_hosts_2 = + { "allowed_hosts" = "127.0.0.1, 127.0.0.2" } + + + let lns = " +# +# server address: +server_address=127.0.0.1 + +nrpe_user=nagios +nrpe_group=nagios + +include=/etc/nrpe_local.cfg + +command[check_users]=/usr/lib/nagios/check_users -w 5 -c 10 +command[check_load]=/usr/lib/nagios/check_load -w 15,10,5 -c 30,25,20 +command[check_mongoscl_proc]=/usr/lib64/nagios/plugins/check_procs -c 1:1 --ereg-argument-array=mongosCL +command[test_command]= foo bar \n +include=/etc/nrpe/nrpe.cfg +include_dir=/etc/nrpe/cfgdir/ \n +# trailing whitespaces \n" + + test Nrpe.lns get lns = + { } + { } + { "#comment" = "server address:" } + { "server_address" = "127.0.0.1" } + { } + { "nrpe_user" = "nagios" } + { "nrpe_group" = "nagios" } + { } + { "include" + { "file" = "/etc/nrpe_local.cfg" } + } + { } + { "command" + { "check_users" = "/usr/lib/nagios/check_users -w 5 -c 10" } + } + { "command" + { "check_load" = "/usr/lib/nagios/check_load -w 15,10,5 -c 30,25,20" } + } + { "command" + { "check_mongoscl_proc" = "/usr/lib64/nagios/plugins/check_procs -c 1:1 --ereg-argument-array=mongosCL" } + } + { "command" + { "test_command" = " foo bar " } + } + { } + { "include" + { "file" = "/etc/nrpe/nrpe.cfg" } + } + { "include_dir" + { "dir" = "/etc/nrpe/cfgdir/" } + } + { } + { "#comment" = "trailing whitespaces" } diff --git a/Sharp.Augeas.Test/lens/tests/test_nslcd.aug b/Sharp.Augeas.Test/lens/tests/test_nslcd.aug new file mode 100644 index 0000000..7d3d4e4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_nslcd.aug @@ -0,0 +1,415 @@ +(* +Module: Test_Nslcd + Provides unit tests and examples for the <Nslcd> lens. +*) + +module Test_nslcd = + +let real_file = "# /etc/nslcd.conf +# nslcd configuration file. See nslcd.conf(5) +# for details. + +# Specifies the number of threads to start that can handle requests and perform LDAP queries. +threads 5 + +# The user and group nslcd should run as. +uid nslcd +gid nslcd + +# This option controls the way logging is done. +log syslog info + +# The location at which the LDAP server(s) should be reachable. +uri ldaps://XXX.XXX.XXX ldaps://YYY.YYY.YYY + +# The search base that will be used for all queries. +base dc=XXX,dc=XXX + +# The LDAP protocol version to use. +ldap_version 3 + +# The DN to bind with for normal lookups. +binddn cn=annonymous,dc=example,dc=net +bindpw secret + + +# The DN used for password modifications by root. +rootpwmoddn cn=admin,dc=example,dc=com + +# The password used for password modifications by root. +rootpwmodpw XXXXXX + + +# SASL authentication options +sasl_mech OTP +sasl_realm realm +sasl_authcid authcid +sasl_authzid dn:cn=annonymous,dc=example,dc=net +sasl_secprops noanonymous,noplain,minssf=0,maxssf=2,maxbufsize=65535 +sasl_canonicalize yes + +# Kerberos authentication options +krb5_ccname ccname + +# Search/mapping options + +# Specifies the base distinguished name (DN) to use as search base. +base dc=people,dc=example,dc=com +base dc=morepeople,dc=example,dc=com +base alias dc=aliases,dc=example,dc=com +base alias dc=morealiases,dc=example,dc=com +base group dc=group,dc=example,dc=com +base group dc=moregroup,dc=example,dc=com +base passwd dc=users,dc=example,dc=com + +# Specifies the search scope (subtree, onelevel, base or children). +scope sub +scope passwd sub +scope aliases sub + +# Specifies the policy for dereferencing aliases. +deref never + +# Specifies whether automatic referral chasing should be enabled. +referrals yes + +# The FILTER is an LDAP search filter to use for a specific map. +filter group (objectClass=posixGroup) + +# This option allows for custom attributes to be looked up instead of the default RFC 2307 attributes. +map passwd homeDirectory \"${homeDirectory:-/home/$uid}\" +map passwd loginShell \"${loginShell:-/bin/bash}\" +map shadow userPassword myPassword + +# Timing/reconnect options + +# Specifies the time limit (in seconds) to use when connecting to the directory server. +bind_timelimit 30 + +# Specifies the time limit (in seconds) to wait for a response from the LDAP server. +timelimit 5 + +# Specifies the period if inactivity (in seconds) after which the connection to the LDAP server will be closed. +idle_timelimit 10 + +# Specifies the number of seconds to sleep when connecting to all LDAP servers fails. +reconnect_sleeptime 10 + +# Specifies the time after which the LDAP server is considered to be permanently unavailable. +reconnect_retrytime 10 + +# SSL/TLS options + +# Specifies whether to use SSL/TLS or not (the default is not to). +ssl start_tls +# Specifies what checks to perform on a server-supplied certificate. +tls_reqcert never +# Specifies the directory containing X.509 certificates for peer authentication. +tls_cacertdir /etc/ssl/ca +# Specifies the path to the X.509 certificate for peer authentication. +tls_cacertfile /etc/ssl/certs/ca-certificates.crt +# Specifies the path to an entropy source. +tls_randfile /dev/random +# Specifies the ciphers to use for TLS. +tls_ciphers TLSv1 +# Specifies the path to the file containing the local certificate for client TLS authentication. +tls_cert /etc/ssl/certs/cert.pem +# Specifies the path to the file containing the private key for client TLS authentication. +tls_key /etc/ssl/private/cert.pem + +# Other options +pagesize 100 +nss_initgroups_ignoreusers user1,user2,user3 +nss_min_uid 1000 +nss_nested_groups yes +nss_getgrent_skipmembers yes +nss_disable_enumeration yes +validnames /^[a-z0-9._@$()]([a-z0-9._@$() \\~-]*[a-z0-9._@$()~-])?$/i +ignorecase yes +pam_authc_ppolicy yes +pam_authz_search (&(objectClass=posixAccount)(uid=$username)(|(authorizedService=$service)(!(authorizedService=*)))) +pam_password_prohibit_message \"MESSAGE LONG AND WITH SPACES\" +reconnect_invalidate nfsidmap,db2,db3 +cache dn2uid 1s 2h + +" + +test Nslcd.lns get real_file = + { "#comment" = "/etc/nslcd.conf" } + { "#comment" = "nslcd configuration file. See nslcd.conf(5)" } + { "#comment" = "for details." } + { } + { "#comment" = "Specifies the number of threads to start that can handle requests and perform LDAP queries." } + { "threads" = "5" } + { } + { "#comment" = "The user and group nslcd should run as." } + { "uid" = "nslcd" } + { "gid" = "nslcd" } + { } + { "#comment" = "This option controls the way logging is done." } + { "log" = "syslog info" } + { } + { "#comment" = "The location at which the LDAP server(s) should be reachable." } + { "uri" + { "1" = "ldaps://XXX.XXX.XXX" } + { "2" = "ldaps://YYY.YYY.YYY" } + } + { } + { "#comment" = "The search base that will be used for all queries." } + { "base" = "dc=XXX,dc=XXX" } + { } + { "#comment" = "The LDAP protocol version to use." } + { "ldap_version" = "3" } + { } + { "#comment" = "The DN to bind with for normal lookups." } + { "binddn" = "cn=annonymous,dc=example,dc=net" } + { "bindpw" = "secret" } + { } + { } + { "#comment" = "The DN used for password modifications by root." } + { "rootpwmoddn" = "cn=admin,dc=example,dc=com" } + { } + { "#comment" = "The password used for password modifications by root." } + { "rootpwmodpw" = "XXXXXX" } + { } + { } + { "#comment" = "SASL authentication options" } + { "sasl_mech" = "OTP" } + { "sasl_realm" = "realm" } + { "sasl_authcid" = "authcid" } + { "sasl_authzid" = "dn:cn=annonymous,dc=example,dc=net" } + { "sasl_secprops" = "noanonymous,noplain,minssf=0,maxssf=2,maxbufsize=65535" } + { "sasl_canonicalize" = "yes" } + { } + { "#comment" = "Kerberos authentication options" } + { "krb5_ccname" = "ccname" } + { } + { "#comment" = "Search/mapping options" } + { } + { "#comment" = "Specifies the base distinguished name (DN) to use as search base." } + { "base" = "dc=people,dc=example,dc=com" } + { "base" = "dc=morepeople,dc=example,dc=com" } + { "base" + { "alias" = "dc=aliases,dc=example,dc=com" } + } + { "base" + { "alias" = "dc=morealiases,dc=example,dc=com" } + } + { "base" + { "group" = "dc=group,dc=example,dc=com" } + } + { "base" + { "group" = "dc=moregroup,dc=example,dc=com" } + } + { "base" + { "passwd" = "dc=users,dc=example,dc=com" } + } + { } + { "#comment" = "Specifies the search scope (subtree, onelevel, base or children)." } + { "scope" = "sub" } + { "scope" + { "passwd" = "sub" } + } + { "scope" + { "aliases" = "sub" } + } + { } + { "#comment" = "Specifies the policy for dereferencing aliases." } + { "deref" = "never" } + { } + { "#comment" = "Specifies whether automatic referral chasing should be enabled." } + { "referrals" = "yes" } + { } + { "#comment" = "The FILTER is an LDAP search filter to use for a specific map." } + { "filter" + { "group" = "(objectClass=posixGroup)" } + } + { } + { "#comment" = "This option allows for custom attributes to be looked up instead of the default RFC 2307 attributes." } + { "map" + { "passwd" + { "homeDirectory" = "\"${homeDirectory:-/home/$uid}\"" } + } + } + { "map" + { "passwd" + { "loginShell" = "\"${loginShell:-/bin/bash}\"" } + } + } + { "map" + { "shadow" + { "userPassword" = "myPassword" } + } + } + { } + { "#comment" = "Timing/reconnect options" } + { } + { "#comment" = "Specifies the time limit (in seconds) to use when connecting to the directory server." } + { "bind_timelimit" = "30" } + { } + { "#comment" = "Specifies the time limit (in seconds) to wait for a response from the LDAP server." } + { "timelimit" = "5" } + { } + { "#comment" = "Specifies the period if inactivity (in seconds) after which the connection to the LDAP server will be closed." } + { "idle_timelimit" = "10" } + { } + { "#comment" = "Specifies the number of seconds to sleep when connecting to all LDAP servers fails." } + { "reconnect_sleeptime" = "10" } + { } + { "#comment" = "Specifies the time after which the LDAP server is considered to be permanently unavailable." } + { "reconnect_retrytime" = "10" } + { } + { "#comment" = "SSL/TLS options" } + { } + { "#comment" = "Specifies whether to use SSL/TLS or not (the default is not to)." } + { "ssl" = "start_tls" } + { "#comment" = "Specifies what checks to perform on a server-supplied certificate." } + { "tls_reqcert" = "never" } + { "#comment" = "Specifies the directory containing X.509 certificates for peer authentication." } + { "tls_cacertdir" = "/etc/ssl/ca" } + { "#comment" = "Specifies the path to the X.509 certificate for peer authentication." } + { "tls_cacertfile" = "/etc/ssl/certs/ca-certificates.crt" } + { "#comment" = "Specifies the path to an entropy source." } + { "tls_randfile" = "/dev/random" } + { "#comment" = "Specifies the ciphers to use for TLS." } + { "tls_ciphers" = "TLSv1" } + { "#comment" = "Specifies the path to the file containing the local certificate for client TLS authentication." } + { "tls_cert" = "/etc/ssl/certs/cert.pem" } + { "#comment" = "Specifies the path to the file containing the private key for client TLS authentication." } + { "tls_key" = "/etc/ssl/private/cert.pem" } + { } + { "#comment" = "Other options" } + { "pagesize" = "100" } + { "nss_initgroups_ignoreusers" + { "1" = "user1" } + { "2" = "user2" } + { "3" = "user3" } + } + { "nss_min_uid" = "1000" } + { "nss_nested_groups" = "yes" } + { "nss_getgrent_skipmembers" = "yes" } + { "nss_disable_enumeration" = "yes" } + { "validnames" = "/^[a-z0-9._@$()]([a-z0-9._@$() \~-]*[a-z0-9._@$()~-])?$/i" } + { "ignorecase" = "yes" } + { "pam_authc_ppolicy" = "yes" } + { "pam_authz_search" = "(&(objectClass=posixAccount)(uid=$username)(|(authorizedService=$service)(!(authorizedService=*))))" } + { "pam_password_prohibit_message" = "MESSAGE LONG AND WITH SPACES" } + { "reconnect_invalidate" = "nfsidmap,db2,db3" } + { "cache" = "dn2uid 1s 2h" } + { } +(* Test writes *) + +(* Test a simple parameter *) +test Nslcd.lns put "pagesize 9999\n" after + set "/pagesize" "1000" = + "pagesize 1000\n" + +(* Test base parameter *) +test Nslcd.lns put "\n" after + set "/base" "dc=example,dc=com" = + "\nbase dc=example,dc=com\n" + +test Nslcd.lns put "base dc=change,dc=me\n" after + set "/base" "dc=example,dc=com" = + "base dc=example,dc=com\n" + +test Nslcd.lns put "\n" after + set "/base/passwd" "dc=example,dc=com" = + "\nbase passwd dc=example,dc=com\n" + +test Nslcd.lns put "base passwd dc=change,dc=me\n" after + set "/base[passwd]/passwd" "dc=example,dc=com"; + set "/base[shadow]/shadow" "dc=example,dc=com" = + "base passwd dc=example,dc=com\nbase shadow dc=example,dc=com\n" + +(* Test scope entry *) +test Nslcd.lns put "\n" after + set "/scope" "sub" = + "\nscope sub\n" + +test Nslcd.lns put "scope one\n" after + set "/scope" "subtree" = + "scope subtree\n" + +test Nslcd.lns put "\n" after + set "/scope/passwd" "base" = + "\nscope passwd base\n" + +test Nslcd.lns put "scope shadow onelevel\n" after + set "/scope[passwd]/passwd" "subtree"; + set "/scope[shadow]/shadow" "base" = + "scope shadow base\nscope passwd subtree\n" + +(* Test filter entry *) +test Nslcd.lns put "\n" after + set "/filter/passwd" "(objectClass=posixAccount)" = + "\nfilter passwd (objectClass=posixAccount)\n" + +test Nslcd.lns put "filter shadow (objectClass=posixAccount)\n" after + set "/filter[passwd]/passwd" "(objectClass=Account)"; + set "/filter[shadow]/shadow" "(objectClass=Account)" = + "filter shadow (objectClass=Account)\nfilter passwd (objectClass=Account)\n" + +(* Test map entry *) +test Nslcd.lns put "map passwd loginShell ab\n" after + set "/map/passwd/loginShell" "bc" = + "map passwd loginShell bc\n" + +test Nslcd.lns put "map passwd loginShell ab\n" after + set "/map[2]/passwd/homeDirectory" "bc" = + "map passwd loginShell ab\nmap passwd homeDirectory bc\n" + +test Nslcd.lns put "map passwd loginShell ab\n" after + set "/map[passwd/homeDirectory]/passwd/homeDirectory" "bc" = + "map passwd loginShell ab\nmap passwd homeDirectory bc\n" + +test Nslcd.lns put "map passwd loginShell ab\nmap passwd homeDirectory ab\n" after + set "/map[passwd/homeDirectory]/passwd/homeDirectory" "bc" = + "map passwd loginShell ab\nmap passwd homeDirectory bc\n" + + +(* Test simple entries *) +let simple = "uid nslcd\n" + +test Nslcd.lns get simple = +{ "uid" = "nslcd" } + +(* Test simple entries with spaces at the end *) +let simple_spaces = "uid nslcd \n" + +test Nslcd.lns get simple_spaces = +{ "uid" = "nslcd" } + +(* Test multi valued entries *) + +let multi_valued = "cache 1 2 \n" + +test Nslcd.lns get multi_valued = +{ "cache" = "1 2" } + +let multi_valued_real = "map passwd homeDirectory ${homeDirectory:-/home/$uid}\n" + +test Nslcd.lns get multi_valued_real = +{ "map" + { "passwd" + { "homeDirectory" = "${homeDirectory:-/home/$uid}" } + } +} + +(* Test multiline *) + +let simple_multiline = "uid nslcd\ngid nslcd\n" + +test Nslcd.lns get simple_multiline = +{"uid" = "nslcd"} +{"gid" = "nslcd"} + + +let multiline_separators = "\n\n \nuid nslcd \ngid nslcd \n" + +test Nslcd.lns get multiline_separators = +{} +{} +{} +{"uid" = "nslcd"} +{"gid" = "nslcd"} diff --git a/Sharp.Augeas.Test/lens/tests/test_nsswitch.aug b/Sharp.Augeas.Test/lens/tests/test_nsswitch.aug new file mode 100644 index 0000000..b467cf7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_nsswitch.aug @@ -0,0 +1,54 @@ +module Test_nsswitch = + + let conf = "# Sample nsswitch.conf +passwd: compat + +hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4 +networks: nis [!UNAVAIL=return success=continue] files +protocols: db files +netgroup: nis +bootparams: nisplus [NOTFOUND=return] files +aliases: files # uses by mail +sudoers: files ldap +" + +test Nsswitch.lns get conf = + { "#comment" = "Sample nsswitch.conf" } + { "database" = "passwd" + { "service" = "compat" } } + {} + { "database" = "hosts" + { "service" = "files" } + { "service" = "mdns4_minimal" } + { "reaction" + { "status" = "NOTFOUND" + { "action" = "return" } } } + { "service" = "dns" } + { "service" = "mdns4" } } + { "database" = "networks" + { "service" = "nis" } + { "reaction" + { "status" = "UNAVAIL" + { "negate" } + { "action" = "return" } } + { "status" = "success" + { "action" = "continue" } } } + { "service" = "files" } } + { "database" = "protocols" + { "service" = "db" } + { "service" = "files" } } + { "database" = "netgroup" + { "service" = "nis" } } + { "database" = "bootparams" + { "service" = "nisplus" } + { "reaction" + { "status" = "NOTFOUND" + { "action" = "return" } } } + { "service" = "files" } } + { "database" = "aliases" + { "service" = "files" } + { "#comment" = "uses by mail" } } + { "database" = "sudoers" + { "service" = "files" } + { "service" = "ldap" } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_ntp.aug b/Sharp.Augeas.Test/lens/tests/test_ntp.aug new file mode 100644 index 0000000..2eea1d8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ntp.aug @@ -0,0 +1,185 @@ +module Test_ntp = + + let conf = "# +# Fichier genere par puppet +# Environnement: development + +server dns01.echo-net.net version 3 +server dns02.echo-net.net version 4 + +driftfile /var/lib/ntp/ntp.drift + +restrict default ignore + +#server dns01.echo-net.net +restrict 192.168.0.150 nomodify + +# allow everything from localhost +restrict 127.0.0.1 + +logfile /var/log/ntpd +statsdir /var/log/ntpstats/ +ntpsigndsocket /var/lib/samba/ntp_signd + +statistics loopstats peerstats clockstats +filegen loopstats file loopstats type day enable link +filegen peerstats file peerstats type day disable +filegen clockstats file clockstats type day enable nolink + +interface ignore wildcard +interface listen 127.0.0.1 +" + + test Ntp.lns get conf = + { "#comment" = "" } + { "#comment" = "Fichier genere par puppet" } + { "#comment" = "Environnement: development" } + {} + { "server" = "dns01.echo-net.net" + { "version" = "3" } } + { "server" = "dns02.echo-net.net" + { "version" = "4" } } + {} + { "driftfile" = "/var/lib/ntp/ntp.drift" } + {} + { "restrict" = "default" + { "action" = "ignore" } } + {} + { "#comment" = "server dns01.echo-net.net" } + { "restrict" = "192.168.0.150" + { "action" = "nomodify" } } + {} + { "#comment" = "allow everything from localhost" } + { "restrict" = "127.0.0.1" } + {} + { "logfile" = "/var/log/ntpd" } + { "statsdir" = "/var/log/ntpstats/" } + { "ntpsigndsocket" = "/var/lib/samba/ntp_signd" } + {} + { "statistics" + { "loopstats" } + { "peerstats" } + { "clockstats" } } + { "filegen" = "loopstats" + { "file" = "loopstats" } + { "type" = "day" } + { "enable" = "enable" } + { "link" = "link" } } + { "filegen" = "peerstats" + { "file" = "peerstats" } + { "type" = "day" } + { "enable" = "disable" } } + { "filegen" = "clockstats" + { "file" = "clockstats" } + { "type" = "day" } + { "enable" = "enable" } + { "link" = "nolink" } } + { } + { "interface" + { "action" = "ignore" } + { "addresses" = "wildcard" } } + { "interface" + { "action" = "listen" } + { "addresses" = "127.0.0.1" } } + + (* Some things needed to process the default ntp.conf on Fedora *) + test Ntp.lns get + "server 66.187.233.4 # added by /sbin/dhclient-script\n" = + { "server" = "66.187.233.4" + { "#comment" = "# added by /sbin/dhclient-script" } } + + test Ntp.lns get + "server 0.fedora.pool.ntp.org iburst dynamic\n" = + { "server" = "0.fedora.pool.ntp.org" { "iburst" } { "dynamic" } } + + test Ntp.lns get + "restrict 127.0.0.1 \n" = + { "restrict" = "127.0.0.1" } + + test Ntp.lns get + "restrict default kod nomodify notrap nopeer noquery\n" = + { "restrict" = "default" + { "action" = "kod" } + { "action" = "nomodify" } + { "action" = "notrap" } + { "action" = "nopeer" } + { "action" = "noquery" } } + + test Ntp.lns put + "restrict default kod nomodify notrap nopeer noquery\n" + after + insb "ipv6" "restrict/action[1]" = + "restrict -6 default kod nomodify notrap nopeer noquery\n" + + test Ntp.lns get + "restrict -6 default kod nomodify notrap nopeer noquery\n" = + { "restrict" = "default" + { "ipv6" } + { "action" = "kod" } + { "action" = "nomodify" } + { "action" = "notrap" } + { "action" = "nopeer" } + { "action" = "noquery" } } + + test Ntp.lns put + "restrict default kod nomodify notrap nopeer noquery\n" + after + insb "ipv4" "restrict/action[1]" = + "restrict -4 default kod nomodify notrap nopeer noquery\n" + + test Ntp.lns get + "restrict -4 default notrap nomodify nopeer noquery\n" = + { "restrict" = "default" + { "ipv4" } + { "action" = "notrap" } + { "action" = "nomodify" } + { "action" = "nopeer" } + { "action" = "noquery" } } + + test Ntp.lns get + "includefile /etc/ntp/crypto/pw\n" = + { "includefile" = "/etc/ntp/crypto/pw" } + + test Ntp.lns get "fudge 127.127.1.0 stratum 10\n" = + { "fudge" = "127.127.1.0" { "stratum" = "10" } } + + test Ntp.lns get "broadcast 192.168.1.255 key 42\n" = + { "broadcast" = "192.168.1.255" { "key" = "42" } } + + + test Ntp.lns get "multicastclient 224.0.1.1\n" = + { "multicastclient" = "224.0.1.1" } + + test Ntp.lns put "broadcastclient\tnovolley # broadcast\n" + after rm "/*/novolley" = "broadcastclient # broadcast\n" + + test Ntp.auth_command get "trustedkey 4 8 42\n" = + { "trustedkey" + { "key" = "4" } + { "key" = "8" } + { "key" = "42" } } + + test Ntp.auth_command get "trustedkey 42\n" = + { "trustedkey" { "key" = "42" } } + + test Ntp.lns get "broadcastdelay 0.008\n" = + { "broadcastdelay" = "0.008" } + + test Ntp.lns get "enable auth calibrate\ndisable kernel stats\n" = + { "enable" + { "flag" = "auth" } + { "flag" = "calibrate" } } + { "disable" + { "flag" = "kernel" } + { "flag" = "stats" } } + +(* Bug #103: tinker directive *) +test Ntp.tinker get "tinker panic 0 huffpuff 3.14\n" = + { "tinker" + { "panic" = "0" } + { "huffpuff" = "3.14" } } + +(* Bug #297: tos directive *) +test Ntp.tos get "tos maxdist 16\n" = + { "tos" + { "maxdist" = "16" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_ntpd.aug b/Sharp.Augeas.Test/lens/tests/test_ntpd.aug new file mode 100644 index 0000000..1d0e41c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ntpd.aug @@ -0,0 +1,80 @@ +(* +Module: Test_Ntpd + Provides unit tests for the <Ntpd> lens. +*) + +module Test_ntpd = + +test Ntpd.listen get "listen on *\n" = + { "listen on" + { "address" = "*" } } + +test Ntpd.listen get "listen on 127.0.0.1\n" = + { "listen on" + { "address" = "127.0.0.1" } } + +test Ntpd.listen get "listen on ::1\n" = + { "listen on" + { "address" = "::1" } } + +test Ntpd.listen get "listen on ::1 rtable 4\n" = + { "listen on" + { "address" = "::1" } + { "rtable" = "4" } } + +test Ntpd.server get "server ntp.example.org\n" = + { "server" + { "address" = "ntp.example.org" } } + +test Ntpd.server get "server ntp.example.org rtable 42\n" = + { "server" + { "address" = "ntp.example.org" } + { "rtable" = "42" } } + +test Ntpd.server get "server ntp.example.org weight 1 rtable 42\n" = + { "server" + { "address" = "ntp.example.org" } + { "weight" = "1" } + { "rtable" = "42" } } + +test Ntpd.server get "server ntp.example.org weight 10\n" = + { "server" + { "address" = "ntp.example.org" } + { "weight" = "10" } } + + +test Ntpd.sensor get "sensor *\n" = + { "sensor" + { "device" = "*" } } + +test Ntpd.sensor get "sensor nmea0\n" = + { "sensor" + { "device" = "nmea0" } } + +test Ntpd.sensor get "sensor nmea0 correction 42\n" = + { "sensor" + { "device" = "nmea0" } + { "correction" = "42" } } + +test Ntpd.sensor get "sensor nmea0 correction -42\n" = + { "sensor" + { "device" = "nmea0" } + { "correction" = "-42" } } + +test Ntpd.sensor get "sensor nmea0 correction 42 weight 2\n" = + { "sensor" + { "device" = "nmea0" } + { "correction" = "42" } + { "weight" = "2" } } + +test Ntpd.sensor get "sensor nmea0 correction 42 refid Puffy\n" = + { "sensor" + { "device" = "nmea0" } + { "correction" = "42" } + { "refid" = "Puffy" } } + +test Ntpd.sensor get "sensor nmea0 correction 42 stratum 2\n" = + { "sensor" + { "device" = "nmea0" } + { "correction" = "42" } + { "stratum" = "2" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_odbc.aug b/Sharp.Augeas.Test/lens/tests/test_odbc.aug new file mode 100644 index 0000000..b20edce --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_odbc.aug @@ -0,0 +1,69 @@ +module Test_odbc = + + let conf = " +# Example driver definitinions +# +# + +# Included in the unixODBC package +[PostgreSQL] +Description = ODBC for PostgreSQL +Driver = /usr/lib/libodbcpsql.so +Setup = /usr/lib/libodbcpsqlS.so +FileUsage = 1 + +[MySQL] +# Driver from the MyODBC package +# Setup from the unixODBC package +Description = ODBC for MySQL +Driver = /usr/lib/libmyodbc.so +Setup = /usr/lib/libodbcmyS.so +FileUsage = 1 +" + +test Odbc.lns get conf = + { } + { "#comment" = "Example driver definitinions" } + {} + {} + { } + { "#comment" = "Included in the unixODBC package" } + + { "PostgreSQL" + { "Description" = "ODBC for PostgreSQL" } + { "Driver" = "/usr/lib/libodbcpsql.so" } + { "Setup" = "/usr/lib/libodbcpsqlS.so" } + { "FileUsage" = "1" } + {} + } + { "MySQL" + { "#comment" = "Driver from the MyODBC package" } + { "#comment" = "Setup from the unixODBC package" } + { "Description" = "ODBC for MySQL" } + { "Driver" = "/usr/lib/libmyodbc.so" } + { "Setup" = "/usr/lib/libodbcmyS.so" } + { "FileUsage" = "1" } + } + +test Odbc.lns put conf after + set "MySQL/Driver" "/usr/lib64/libmyodbc3.so"; + set "MySQL/Driver/#comment" "note the path" = " +# Example driver definitinions +# +# + +# Included in the unixODBC package +[PostgreSQL] +Description = ODBC for PostgreSQL +Driver = /usr/lib/libodbcpsql.so +Setup = /usr/lib/libodbcpsqlS.so +FileUsage = 1 + +[MySQL] +# Driver from the MyODBC package +# Setup from the unixODBC package +Description = ODBC for MySQL +Driver = /usr/lib64/libmyodbc3.so#note the path +Setup = /usr/lib/libodbcmyS.so +FileUsage = 1 +" diff --git a/Sharp.Augeas.Test/lens/tests/test_opendkim.aug b/Sharp.Augeas.Test/lens/tests/test_opendkim.aug new file mode 100644 index 0000000..a91c41e --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_opendkim.aug @@ -0,0 +1,183 @@ +module Test_Opendkim = + + let simple_string_value = "ADSPAction discard\n" + test Opendkim.lns get simple_string_value = + { "ADSPAction" = "discard" } + test Opendkim.lns put simple_string_value after + set "ADSPAction" "discard" = simple_string_value + + let simple_integer_value = "AutoRestartCount 1\n" + test Opendkim.lns get simple_integer_value = + { "AutoRestartCount" = "1" } + test Opendkim.lns put simple_integer_value after + set "AutoRestartCount" "1" = simple_integer_value + + let simple_boolean_value = "AddAllSignatureResults true\n" + test Opendkim.lns get simple_boolean_value = + { "AddAllSignatureResults" = "true" } + test Opendkim.lns put simple_boolean_value after + set "AddAllSignatureResults" "true" = simple_boolean_value + + let yes_boolean_value= "AddAllSignatureResults yes\n" + test Opendkim.lns get yes_boolean_value = + { "AddAllSignatureResults" = "yes" } + test Opendkim.lns put yes_boolean_value after + set "AddAllSignatureResults" "yes" = yes_boolean_value + + let one_boolean_value= "AddAllSignatureResults 1\n" + test Opendkim.lns get one_boolean_value = + { "AddAllSignatureResults" = "1" } + test Opendkim.lns put one_boolean_value after + set "AddAllSignatureResults" "1" = one_boolean_value + + let one_boolean_value_uppercase_yes = "AutoRestart Yes\n" + test Opendkim.lns get one_boolean_value_uppercase_yes = + { "AutoRestart" = "Yes" } + test Opendkim.lns put one_boolean_value_uppercase_yes after + set "AutoRestart" "Yes" = one_boolean_value_uppercase_yes + + let one_boolean_value_uppercase_no = "AutoRestart No\n" + test Opendkim.lns get one_boolean_value_uppercase_no = + { "AutoRestart" = "No" } + test Opendkim.lns put one_boolean_value_uppercase_no after + set "AutoRestart" "No" = one_boolean_value_uppercase_no + + let one_boolean_value_uppercase_true = "AutoRestart True\n" + test Opendkim.lns get one_boolean_value_uppercase_true = + { "AutoRestart" = "True" } + test Opendkim.lns put one_boolean_value_uppercase_true after + set "AutoRestart" "True" = one_boolean_value_uppercase_true + + let one_boolean_value_uppercase_false = "AutoRestart False\n" + test Opendkim.lns get one_boolean_value_uppercase_false = + { "AutoRestart" = "False" } + test Opendkim.lns put one_boolean_value_uppercase_false after + set "AutoRestart" "False" = one_boolean_value_uppercase_false + + let string_value_starting_with_number = "AutoRestartRate 10/1h\n" + test Opendkim.lns get string_value_starting_with_number = + { "AutoRestartRate" = "10/1h" } + test Opendkim.lns put string_value_starting_with_number after + set "AutoRestartRate" "10/1h" = string_value_starting_with_number + + let string_value_containing_slash = "TrustAnchorFile /usr/share/dns/root.key\n" + test Opendkim.lns get string_value_containing_slash = + { "TrustAnchorFile" = "/usr/share/dns/root.key" } + test Opendkim.lns put string_value_containing_slash after + set "TrustAnchorFile" "/usr/share/dns/root.key" = string_value_containing_slash + + let logwhy_keyword_boolean = "LogWhy Yes\n" + test Opendkim.lns get logwhy_keyword_boolean = + { "LogWhy" = "Yes" } + test Opendkim.lns put logwhy_keyword_boolean after + set "LogWhy" "Yes" = logwhy_keyword_boolean + + let three_type_value = "AddAllSignatureResults false\nADSPAction discard\nAutoRestartCount 2\n" + test Opendkim.lns get three_type_value = + { "AddAllSignatureResults" = "false" } + { "ADSPAction" = "discard" } + { "AutoRestartCount" = "2" } + + test Opendkim.lns put "" after + set "AddAllSignatureResults" "false"; + set "ADSPAction" "discard"; + set "AutoRestartCount" "2" = three_type_value + + let two_boolean_value = "AddAllSignatureResults false\nADSPNoSuchDomain true\n" + test Opendkim.lns get two_boolean_value = + { "AddAllSignatureResults" = "false" } + { "ADSPNoSuchDomain" = "true" } + + test Opendkim.lns put "" after + set "AddAllSignatureResults" "false"; + set "ADSPNoSuchDomain" "true" = two_boolean_value + + let blank_line_between= "AddAllSignatureResults false\n\nADSPNoSuchDomain true\n" + test Opendkim.lns get blank_line_between = + { "AddAllSignatureResults" = "false" } + { } + { "ADSPNoSuchDomain" = "true" } + + test Opendkim.lns put "" after + set "AddAllSignatureResults" "false"; + set "ADSPNoSuchDomain" "true" = "AddAllSignatureResults false\nADSPNoSuchDomain true\n" + + let include_comment_line= "AddAllSignatureResults false\n#A comment\nADSPNoSuchDomain true\n" + test Opendkim.lns get include_comment_line = + { "AddAllSignatureResults" = "false" } + { "#comment" = "A comment" } + { "ADSPNoSuchDomain" = "true" } + + test Opendkim.lns put "" after + set "AddAllSignatureResults" "false"; + set "#comment" "A comment"; + set "ADSPNoSuchDomain" "true" = include_comment_line + + let default_config_file = "# This is a basic configuration that can easily be adapted to suit a standard +# installation. For more advanced options, see opendkim.conf(5) and/or +# /usr/share/doc/opendkim/examples/opendkim.conf.sample. + +# Log to syslog +Syslog yes +# Required to use local socket with MTAs that access the socket as a non- +# privileged user (e.g. Postfix) +UMask 002 + +# Sign for example.com with key in /etc/mail/dkim.key using +# selector '2007' (e.g. 2007._domainkey.example.com) +#Domain example.com +#KeyFile /etc/mail/dkim.key +#Selector 2007 + +# Commonly-used options; the commented-out versions show the defaults. +#Canonicalization simple +#Mode sv +#SubDomains no +#ADSPAction continue + +# Always oversign From (sign using actual From and a null From to prevent +# malicious signatures header fields (From and/or others) between the signer +# and the verifier. From is oversigned by default in the Debian package +# because it is often the identity key used by reputation systems and thus +# somewhat security sensitive. +OversignHeaders From + +# List domains to use for RFC 6541 DKIM Authorized Third-Party Signatures +# (ATPS) (experimental) + +#ATPSDomains example.com +" + test Opendkim.lns get default_config_file = + { "#comment" = "This is a basic configuration that can easily be adapted to suit a standard" } + { "#comment" = "installation. For more advanced options, see opendkim.conf(5) and/or" } + { "#comment" = "/usr/share/doc/opendkim/examples/opendkim.conf.sample." } + { } + { "#comment" = "Log to syslog" } + { "Syslog" = "yes" } + { "#comment" = "Required to use local socket with MTAs that access the socket as a non-" } + { "#comment" = "privileged user (e.g. Postfix)" } + { "UMask" = "002" } + { } + { "#comment" = "Sign for example.com with key in /etc/mail/dkim.key using" } + { "#comment" = "selector '2007' (e.g. 2007._domainkey.example.com)" } + { "#comment" = "Domain example.com" } + { "#comment" = "KeyFile /etc/mail/dkim.key" } + { "#comment" = "Selector 2007" } + { } + { "#comment" = "Commonly-used options; the commented-out versions show the defaults." } + { "#comment" = "Canonicalization simple" } + { "#comment" = "Mode sv" } + { "#comment" = "SubDomains no" } + { "#comment" = "ADSPAction continue" } + { } + { "#comment" = "Always oversign From (sign using actual From and a null From to prevent" } + { "#comment" = "malicious signatures header fields (From and/or others) between the signer" } + { "#comment" = "and the verifier. From is oversigned by default in the Debian package" } + { "#comment" = "because it is often the identity key used by reputation systems and thus" } + { "#comment" = "somewhat security sensitive." } + { "OversignHeaders" = "From" } + { } + { "#comment" = "List domains to use for RFC 6541 DKIM Authorized Third-Party Signatures" } + { "#comment" = "(ATPS) (experimental)" } + { } + { "#comment" = "ATPSDomains example.com" } diff --git a/Sharp.Augeas.Test/lens/tests/test_openshift_config.aug b/Sharp.Augeas.Test/lens/tests/test_openshift_config.aug new file mode 100644 index 0000000..451e32f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_openshift_config.aug @@ -0,0 +1,101 @@ +(* +Module: Test_OpenShift_Config + Provides unit tests and examples for the <OpenShift_Config> lens. +*) + +module Test_OpenShift_Config = + +(* Variable: conf *) +let conf = "CLOUD_DOMAIN=\"example.com\" +VALID_GEAR_SIZES=\"small,medium\" +DEFAULT_MAX_GEARS=\"100\" +DEFAULT_GEAR_CAPABILITIES=\"small\" +DEFAULT_GEAR_SIZE=\"small\" +MONGO_HOST_PORT=\"localhost:27017\" +MONGO_USER=\"openshift\" +MONGO_PASSWORD=\"mooo\" +MONGO_DB=\"openshift_broker_dev\" +MONGO_SSL=\"false\" +ENABLE_USAGE_TRACKING_DATASTORE=\"false\" +ENABLE_USAGE_TRACKING_AUDIT_LOG=\"false\" +USAGE_TRACKING_AUDIT_LOG_FILE=\"/var/log/openshift/broker/usage.log\" +ENABLE_ANALYTICS=\"false\" +ENABLE_USER_ACTION_LOG=\"true\" +USER_ACTION_LOG_FILE=\"/var/log/openshift/broker/user_action.log\" +AUTH_PRIVKEYFILE=\"/etc/openshift/server_priv.pem\" +AUTH_PRIVKEYPASS=\"\" +AUTH_PUBKEYFILE=\"/etc/openshift/server_pub.pem\" +AUTH_RSYNC_KEY_FILE=\"/etc/openshift/rsync_id_rsa\" +AUTH_SCOPE_TIMEOUTS=\"session=1.days|7.days, *=1.months|6.months\" +ENABLE_MAINTENANCE_MODE=\"false\" +MAINTENANCE_NOTIFICATION_FILE=\"/etc/openshift/outage_notification.txt\" +DOWNLOAD_CARTRIDGES_ENABLED=\"false\" +" + +(* Variable: new_conf *) +let new_conf = "CLOUD_DOMAIN=\"rhcloud.com\" +VALID_GEAR_SIZES=\"small,medium\" +DEFAULT_MAX_GEARS=\"100\" +DEFAULT_GEAR_CAPABILITIES=\"small\" +DEFAULT_GEAR_SIZE=\"small\" +MONGO_HOST_PORT=\"localhost:27017\" +MONGO_USER=\"openshift\" +MONGO_PASSWORD=\"mooo\" +MONGO_DB=\"openshift_broker_dev\" +MONGO_SSL=\"false\" +ENABLE_USAGE_TRACKING_DATASTORE=\"false\" +ENABLE_USAGE_TRACKING_AUDIT_LOG=\"false\" +USAGE_TRACKING_AUDIT_LOG_FILE=\"/var/log/openshift/broker/usage.log\" +ENABLE_ANALYTICS=\"false\" +ENABLE_USER_ACTION_LOG=\"true\" +USER_ACTION_LOG_FILE=\"/var/log/openshift/broker/user_action.log\" +AUTH_PRIVKEYFILE=\"/etc/openshift/server_priv.pem\" +AUTH_PRIVKEYPASS=\"\" +AUTH_PUBKEYFILE=\"/etc/openshift/server_pub.pem\" +AUTH_RSYNC_KEY_FILE=\"/etc/openshift/rsync_id_rsa\" +AUTH_SCOPE_TIMEOUTS=\"session=1.days|7.days, *=1.months|6.months\" +ENABLE_MAINTENANCE_MODE=\"false\" +MAINTENANCE_NOTIFICATION_FILE=\"/etc/openshift/outage_notification.txt\" +DOWNLOAD_CARTRIDGES_ENABLED=\"false\" +" + +(* Test: OpenShift_Config.lns *) +test OpenShift_Config.lns get conf = + { "CLOUD_DOMAIN" = "example.com" } + { "VALID_GEAR_SIZES" = "small,medium" } + { "DEFAULT_MAX_GEARS" = "100" } + { "DEFAULT_GEAR_CAPABILITIES" = "small" } + { "DEFAULT_GEAR_SIZE" = "small" } + { "MONGO_HOST_PORT" = "localhost:27017" } + { "MONGO_USER" = "openshift" } + { "MONGO_PASSWORD" = "mooo" } + { "MONGO_DB" = "openshift_broker_dev" } + { "MONGO_SSL" = "false" } + { "ENABLE_USAGE_TRACKING_DATASTORE" = "false" } + { "ENABLE_USAGE_TRACKING_AUDIT_LOG" = "false" } + { "USAGE_TRACKING_AUDIT_LOG_FILE" = "/var/log/openshift/broker/usage.log" } + { "ENABLE_ANALYTICS" = "false" } + { "ENABLE_USER_ACTION_LOG" = "true" } + { "USER_ACTION_LOG_FILE" = "/var/log/openshift/broker/user_action.log" } + { "AUTH_PRIVKEYFILE" = "/etc/openshift/server_priv.pem" } + { "AUTH_PRIVKEYPASS" } + { "AUTH_PUBKEYFILE" = "/etc/openshift/server_pub.pem" } + { "AUTH_RSYNC_KEY_FILE" = "/etc/openshift/rsync_id_rsa" } + { "AUTH_SCOPE_TIMEOUTS" = "session=1.days|7.days, *=1.months|6.months" } + { "ENABLE_MAINTENANCE_MODE" = "false" } + { "MAINTENANCE_NOTIFICATION_FILE" = "/etc/openshift/outage_notification.txt" } + { "DOWNLOAD_CARTRIDGES_ENABLED" = "false" } + +(* Test: OpenShift_Config.lns + * Second get test against OpenShift configs +*) +test OpenShift_Config.lns get "MONGO_SSL=\"false\"\n" = + { "MONGO_SSL" = "false" } + +(* Test: OpenShift_Config.lns + * Put test changing CLOUD_DOMAIN to rhcloud.com +*) +test OpenShift_Config.lns put conf after set "CLOUD_DOMAIN" "rhcloud.com" + = new_conf + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_openshift_http.aug b/Sharp.Augeas.Test/lens/tests/test_openshift_http.aug new file mode 100644 index 0000000..bc0fc53 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_openshift_http.aug @@ -0,0 +1,71 @@ +(* +Module: Test_OpenShift_Http + Provides unit tests and examples for the <OpenShift_Http> lens. +*) + +module Test_OpenShift_Http = + +(* Variable: conf *) +let conf = "Listen 127.0.0.1:8080 +User apache +Group apache +include /etc/httpd/conf.d/ruby193-passenger.conf +PassengerUser apache +PassengerMaxPoolSize 80 +PassengerMinInstances 2 +PassengerPreStart http://127.0.0.1:8080/ +PassengerUseGlobalQueue off +RackBaseURI /broker +PassengerRuby /var/www/openshift/broker/script/broker_ruby +<Directory /var/www/openshift/broker/httpd/root/broker> + Options -MultiViews +</Directory> +" + +(* Variable: new_conf *) +let new_conf = "Listen 127.0.0.1:8080 +User nobody +Group apache +include /etc/httpd/conf.d/ruby193-passenger.conf +PassengerUser apache +PassengerMaxPoolSize 80 +PassengerMinInstances 2 +PassengerPreStart http://127.0.0.1:8080/ +PassengerUseGlobalQueue off +RackBaseURI /broker +PassengerRuby /var/www/openshift/broker/script/broker_ruby +<Directory /var/www/openshift/broker/httpd/root/broker> + Options -MultiViews +</Directory> +" + +let lns = OpenShift_Http.lns + +(* Test: OpenShift_Http.lns + * Get test against tree structure +*) +test lns get conf = + { "directive" = "Listen" {"arg" = "127.0.0.1:8080" } } + { "directive" = "User" { "arg" = "apache" } } + { "directive" = "Group" { "arg" = "apache" } } + { "directive" = "include" { "arg" = "/etc/httpd/conf.d/ruby193-passenger.conf" } } + { "directive" = "PassengerUser" { "arg" = "apache" } } + { "directive" = "PassengerMaxPoolSize" { "arg" = "80" } } + { "directive" = "PassengerMinInstances" { "arg" = "2" } } + { "directive" = "PassengerPreStart" { "arg" = "http://127.0.0.1:8080/" } } + { "directive" = "PassengerUseGlobalQueue" { "arg" = "off" } } + { "directive" = "RackBaseURI" { "arg" = "/broker" } } + { "directive" = "PassengerRuby" { "arg" = "/var/www/openshift/broker/script/broker_ruby" } } + { "Directory" + { "arg" = "/var/www/openshift/broker/httpd/root/broker" } + { "directive" = "Options" + { "arg" = "-MultiViews" } + } + } + +(* Test: OpenShift_Http.lns + * Put test changing user to nobody +*) +test lns put conf after set "/directive[2]/arg" "nobody" = new_conf + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_openshift_quickstarts.aug b/Sharp.Augeas.Test/lens/tests/test_openshift_quickstarts.aug new file mode 100644 index 0000000..017a92a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_openshift_quickstarts.aug @@ -0,0 +1,363 @@ +(* +Module: Test_OpenShift_Quickstarts + Provides unit tests and examples for the <OpenShift_Quickstarts> lens. +*) + +module Test_OpenShift_Quickstarts = + +(* Variable: conf *) +let conf = "[ + {\"quickstart\": { + \"id\": \"1\", + \"name\":\"CakePHP\", + \"website\":\"http://cakephp.org/\", + \"initial_git_url\":\"git://github.com/openshift/cakephp-example.git\", + \"cartridges\":[\"php-5.4\",\"mysql-5.1\"], + \"summary\":\"CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC.\", + \"tags\":[\"php\",\"cakephp\",\"framework\"], + \"admin_tags\":[] + }}, + {\"quickstart\": { + \"id\": \"2\", + \"name\":\"Django\", + \"website\":\"https://www.djangoproject.com/\", + \"initial_git_url\":\"git://github.com/openshift/django-example.git\", + \"cartridges\":[\"python-2.7\"], + \"summary\":\"A high-level Python web framework that encourages rapid development and clean, pragmatic design. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS.\", + \"tags\":[\"python\",\"django\",\"framework\"], + \"admin_tags\":[] + }}, + {\"quickstart\":{ + \"id\": \"4\", + \"name\":\"Drupal\", + \"website\":\"http://drupal.org/\", + \"initial_git_url\":\"git://github.com/openshift/drupal-example.git\", + \"cartridges\":[\"php-5.4\",\"mysql-5.1\"], + \"summary\":\"An open source content management platform written in PHP powering millions of websites and applications. It is built, used, and supported by an active and diverse community of people around the world. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS.\", + \"tags\":[\"php\",\"drupal\",\"wiki\",\"framework\",\"instant_app\"], + \"admin_tags\":[] + }}, + {\"quickstart\":{ + \"id\": \"6\", + \"name\":\"Ruby on Rails\", + \"website\":\"http://rubyonrails.org/\", + \"initial_git_url\":\"git://github.com/openshift/rails-example.git\", + \"cartridges\":[\"ruby-1.9\",\"mysql-5.1\"], + \"summary\":\"An open source web framework for Ruby that is optimized for programmer happiness and sustainable productivity. It lets you write beautiful code by favoring convention over configuration.\", + \"tags\":[\"ruby\",\"rails\",\"framework\"], + \"admin_tags\":[] + }}, + {\"quickstart\":{ + \"id\": \"8\", + \"name\":\"WordPress\", + \"website\":\"http://wordpress.org\", + \"initial_git_url\":\"git://github.com/openshift/wordpress-example.git\", + \"cartridges\":[\"php-5.4\",\"mysql-5.1\"], + \"summary\":\"A semantic personal publishing platform written in PHP with a MySQL back end, focusing on aesthetics, web standards, and usability. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS.\", + \"tags\":[\"php\",\"wordpress\",\"blog\",\"framework\",\"instant_app\"], + \"admin_tags\":[] + }} +]" + +(* Variable: new_conf *) +let new_conf = "[ + {\"quickstart\": { + \"id\": \"1\", + \"name\":\"CakePHP\", + \"website\":\"http://cakephp.org/\", + \"initial_git_url\":\"git://github.com/openshift/cakephp-example.git\", + \"cartridges\":[\"php-5.4\",\"mysql-5.1\"], + \"summary\":\"CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC.\", + \"tags\":[\"php\",\"cakephp\",\"framework\"], + \"admin_tags\":[] + }}, + {\"quickstart\": { + \"id\": \"2\", + \"name\":\"Django\", + \"website\":\"https://www.djangoproject.com/\", + \"initial_git_url\":\"git://github.com/openshift/django-example.git\", + \"cartridges\":[\"python-2.7\"], + \"summary\":\"A high-level Python web framework that encourages rapid development and clean, pragmatic design. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS.\", + \"tags\":[\"python\",\"django\",\"framework\"], + \"admin_tags\":[] + }}, + {\"quickstart\":{ + \"id\": \"4\", + \"name\":\"Drupal\", + \"website\":\"http://drupal.org/\", + \"initial_git_url\":\"git://github.com/openshift/drupal-example.git\", + \"cartridges\":[\"php-5.4\",\"mysql-5.1\"], + \"summary\":\"An open source content management platform written in PHP powering millions of websites and applications. It is built, used, and supported by an active and diverse community of people around the world. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS.\", + \"tags\":[\"php\",\"drupal\",\"wiki\",\"framework\",\"instant_app\"], + \"admin_tags\":[] + }}, + {\"quickstart\":{ + \"id\": \"6\", + \"name\":\"Ruby on Rails\", + \"website\":\"http://rubyonrails.org/\", + \"initial_git_url\":\"git://github.com/openshift/rails-example.git\", + \"cartridges\":[\"ruby-1.9\",\"mysql-5.1\"], + \"summary\":\"An open source web framework for Ruby that is optimized for programmer happiness and sustainable productivity. It lets you write beautiful code by favoring convention over configuration.\", + \"tags\":[\"ruby\",\"rails\",\"framework\"], + \"admin_tags\":[] + }}, + {\"quickstart\":{ + \"id\": \"8\", + \"name\":\"WordPress\", + \"website\":\"https://wordpress.org\", + \"initial_git_url\":\"git://github.com/openshift/wordpress-example.git\", + \"cartridges\":[\"php-5.4\",\"mysql-5.1\"], + \"summary\":\"A semantic personal publishing platform written in PHP with a MySQL back end, focusing on aesthetics, web standards, and usability. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS.\", + \"tags\":[\"php\",\"wordpress\",\"blog\",\"framework\",\"instant_app\"], + \"admin_tags\":[] + }} +]" + +(* Test: OpenShift_Quickstarts.lns *) +test OpenShift_Quickstarts.lns get conf = + { "array" + { } + { "dict" + { "entry" = "quickstart" + { "dict" + { } + { "entry" = "id" + { "string" = "1" } + } + { } + { "entry" = "name" + { "string" = "CakePHP" } + } + { } + { "entry" = "website" + { "string" = "http://cakephp.org/" } + } + { } + { "entry" = "initial_git_url" + { "string" = "git://github.com/openshift/cakephp-example.git" } + } + { } + { "entry" = "cartridges" + { "array" + { "string" = "php-5.4" } + { "string" = "mysql-5.1" } + } + } + { } + { "entry" = "summary" + { "string" = "CakePHP is a rapid development framework for PHP which uses commonly known design patterns like Active Record, Association Data Mapping, Front Controller and MVC." } + } + { } + { "entry" = "tags" + { "array" + { "string" = "php" } + { "string" = "cakephp" } + { "string" = "framework" } + } + } + { } + { "entry" = "admin_tags" + { "array" } + } + } + } + } + { } + { "dict" + { "entry" = "quickstart" + { "dict" + { } + { "entry" = "id" + { "string" = "2" } + } + { } + { "entry" = "name" + { "string" = "Django" } + } + { } + { "entry" = "website" + { "string" = "https://www.djangoproject.com/" } + } + { } + { "entry" = "initial_git_url" + { "string" = "git://github.com/openshift/django-example.git" } + } + { } + { "entry" = "cartridges" + { "array" + { "string" = "python-2.7" } + } + } + { } + { "entry" = "summary" + { "string" = "A high-level Python web framework that encourages rapid development and clean, pragmatic design. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS." } + } + { } + { "entry" = "tags" + { "array" + { "string" = "python" } + { "string" = "django" } + { "string" = "framework" } + } + } + { } + { "entry" = "admin_tags" + { "array" } + } + } + } + } + { } + { "dict" + { "entry" = "quickstart" + { "dict" + { } + { "entry" = "id" + { "string" = "4" } + } + { } + { "entry" = "name" + { "string" = "Drupal" } + } + { } + { "entry" = "website" + { "string" = "http://drupal.org/" } + } + { } + { "entry" = "initial_git_url" + { "string" = "git://github.com/openshift/drupal-example.git" } + } + { } + { "entry" = "cartridges" + { "array" + { "string" = "php-5.4" } + { "string" = "mysql-5.1" } + } + } + { } + { "entry" = "summary" + { "string" = "An open source content management platform written in PHP powering millions of websites and applications. It is built, used, and supported by an active and diverse community of people around the world. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS." } + } + { } + { "entry" = "tags" + { "array" + { "string" = "php" } + { "string" = "drupal" } + { "string" = "wiki" } + { "string" = "framework" } + { "string" = "instant_app" } + } + } + { } + { "entry" = "admin_tags" + { "array" } + } + } + } + } + { } + { "dict" + { "entry" = "quickstart" + { "dict" + { } + { "entry" = "id" + { "string" = "6" } + } + { } + { "entry" = "name" + { "string" = "Ruby on Rails" } + } + { } + { "entry" = "website" + { "string" = "http://rubyonrails.org/" } + } + { } + { "entry" = "initial_git_url" + { "string" = "git://github.com/openshift/rails-example.git" } + } + { } + { "entry" = "cartridges" + { "array" + { "string" = "ruby-1.9" } + { "string" = "mysql-5.1" } + } + } + { } + { "entry" = "summary" + { "string" = "An open source web framework for Ruby that is optimized for programmer happiness and sustainable productivity. It lets you write beautiful code by favoring convention over configuration." } + } + { } + { "entry" = "tags" + { "array" + { "string" = "ruby" } + { "string" = "rails" } + { "string" = "framework" } + } + } + { } + { "entry" = "admin_tags" + { "array" } + } + } + } + } + { } + { "dict" + { "entry" = "quickstart" + { "dict" + { } + { "entry" = "id" + { "string" = "8" } + } + { } + { "entry" = "name" + { "string" = "WordPress" } + } + { } + { "entry" = "website" + { "string" = "http://wordpress.org" } + } + { } + { "entry" = "initial_git_url" + { "string" = "git://github.com/openshift/wordpress-example.git" } + } + { } + { "entry" = "cartridges" + { "array" + { "string" = "php-5.4" } + { "string" = "mysql-5.1" } + } + } + { } + { "entry" = "summary" + { "string" = "A semantic personal publishing platform written in PHP with a MySQL back end, focusing on aesthetics, web standards, and usability. Administrator user name and password are written to $OPENSHIFT_DATA_DIR/CREDENTIALS." } + } + { } + { "entry" = "tags" + { "array" + { "string" = "php" } + { "string" = "wordpress" } + { "string" = "blog" } + { "string" = "framework" } + { "string" = "instant_app" } + } + } + { } + { "entry" = "admin_tags" + { "array" } + } + } + } + { } + } +} + + +(* FIXME: not yet supported: + * The manner in which the JSON utility lens currently works does not maintain + * whitepsace as per the Augeas specification in the put direction. + +test OpenShift_Quickstarts.lns put conf after set "/array/dict[5]/entry/dict/entry[3]/string" "https://wordpress.org" + = new_conf *) + +(* vim: set ts=4 expandtab sw=4: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_openvpn.aug b/Sharp.Augeas.Test/lens/tests/test_openvpn.aug new file mode 100644 index 0000000..f303a30 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_openvpn.aug @@ -0,0 +1,1254 @@ + +module Test_OpenVPN = + +let server_conf = " +daemon +local 10.0.5.20 +port 1194 +# TCP or UDP server? +proto udp +;dev tap +dev tun + +dev-node MyTap +ca ca.crt +cert server.crt +key server.key # This file should be kept secret + +# Diffie hellman parameters. +dh dh1024.pem + +server 10.8.0.0 255.255.255.0 +ifconfig-pool-persist ipp.txt + +client-config-dir /etc/openvpn/ccd +server-bridge 10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100 +route 10.9.0.0 255.255.255.0 +push \"route 192.168.10.0 255.255.255.0\" +learn-address ./script +push \"redirect-gateway\" +push \"dhcp-option DNS 10.8.0.1\" +push \"dhcp-option WINS 10.8.0.1\" +client-to-client +duplicate-cn +keepalive 10 120 +tls-auth ta.key 0 # This file is secret +cipher BF-CBC # Blowfish (default) +;cipher AES-128-CBC # AES +;cipher DES-EDE3-CBC # Triple-DES +comp-lzo +max-clients 100 +user nobody +group nobody +persist-key +persist-tun +status openvpn-status.log +log openvpn.log +log-append openvpn.log +verb 3 +mute 20 +management 10.0.5.20 1193 /etc/openvpn/mpass +" + +test OpenVPN.lns get server_conf = + {} + { "daemon" } + { "local" = "10.0.5.20" } + { "port" = "1194" } + { "#comment" = "TCP or UDP server?" } + { "proto" = "udp" } + { "#comment" = "dev tap" } + { "dev" = "tun" } + {} + { "dev-node" = "MyTap" } + { "ca" = "ca.crt" } + { "cert" = "server.crt" } + { "key" = "server.key" + { "#comment" = "This file should be kept secret" } } + {} + { "#comment" = "Diffie hellman parameters." } + { "dh" = "dh1024.pem" } + {} + { "server" + { "address" = "10.8.0.0" } + { "netmask" = "255.255.255.0" } } + { "ifconfig-pool-persist" + { "file" = "ipp.txt" } + } + {} + { "client-config-dir" = "/etc/openvpn/ccd" } + { "server-bridge" + { "address" = "10.8.0.4" } + { "netmask" = "255.255.255.0" } + { "start" = "10.8.0.50" } + { "end" = "10.8.0.100" } } + { "route" + { "address" = "10.9.0.0" } + { "netmask" = "255.255.255.0" } } + { "push" = "route 192.168.10.0 255.255.255.0" } + { "learn-address" = "./script" } + { "push" = "redirect-gateway" } + { "push" = "dhcp-option DNS 10.8.0.1" } + { "push" = "dhcp-option WINS 10.8.0.1" } + { "client-to-client" } + { "duplicate-cn" } + { "keepalive" + { "ping" = "10" } + { "timeout" = "120" } } + { "tls-auth" + { "key" = "ta.key" } + { "is_client" = "0" } + { "#comment" = "This file is secret" } } + { "cipher" = "BF-CBC" + { "#comment" = "Blowfish (default)" } } + { "#comment" = "cipher AES-128-CBC # AES" } + { "#comment" = "cipher DES-EDE3-CBC # Triple-DES" } + { "comp-lzo" } + { "max-clients" = "100" } + { "user" = "nobody" } + { "group" = "nobody" } + { "persist-key" } + { "persist-tun" } + { "status" + { "file" = "openvpn-status.log" } + } + { "log" = "openvpn.log" } + { "log-append" = "openvpn.log" } + { "verb" = "3" } + { "mute" = "20" } + { "management" + { "server" = "10.0.5.20" } + { "port" = "1193" } + { "pwfile" = "/etc/openvpn/mpass" } } + + + +let client_conf = " +client +remote my-server-1 1194 +;remote my-server-2 1194 +remote-random +resolv-retry infinite +nobind +http-proxy-retry # retry on connection failures +http-proxy mytest 1024 +mute-replay-warnings +ns-cert-type server +" + +test OpenVPN.lns get client_conf = + {} + { "client" } + { "remote" + { "server" = "my-server-1" } + { "port" = "1194" } } + { "#comment" = "remote my-server-2 1194" } + { "remote-random" } + { "resolv-retry" = "infinite" } + { "nobind" } + { "http-proxy-retry" + { "#comment" = "retry on connection failures" } } + { "http-proxy" + { "server" = "mytest" } + { "port" = "1024" } } + { "mute-replay-warnings" } + { "ns-cert-type" = "server" } + +(* Most (hopefully all) permutations for OpenVPN 2.3 + * NOTE: This completely ignores IPv6 because it's hard to tell which OpenVPN + * options actually work with IPv6. Thar be dragons. + *) +let all_permutations_conf = " +config /a/canonical/file +config relative_file +mode p2p +mode server +local 192.168.1.1 +local hostname +remote 192.168.1.1 1234 +remote hostname 1234 +remote hostname +remote 192.168.1.1 +remote hostname 1234 tcp +remote 192.168.1.1 1234 tcp +remote hostname 1234 udp +remote-random-hostname +#comment square <connection> blocks should go here +proto-force udp +proto-force tcp +remote-random +proto udp +proto tcp-client +proto tcp-server +connect-retry 5 +connect-timeout 10 +connect-retry-max 0 +show-proxy-settings +http-proxy servername 1234 +http-proxy servername 1234 auto +http-proxy servername 1234 auto-nct +http-proxy servername 1234 auto none +http-proxy servername 1234 auto basic +http-proxy servername 1234 auto ntlm +http-proxy servername 1234 relative_filename ntlm +http-proxy servername 1234 /canonical/filename basic +http-proxy-retry +http-proxy-timeout 5 +http-proxy-option VERSION 1.0 +http-proxy-option AGENT an unquoted string with spaces +http-proxy-option AGENT an_unquoted_string_without_spaces +socks-proxy servername +socks-proxy servername 1234 +socks-proxy servername 1234 /canonical/file +socks-proxy servername 1234 relative/file +socks-proxy-retry +resolv-retry 5 +float +ipchange my command goes here +port 1234 +lport 1234 +rport 1234 +bind +nobind +dev tun +dev tun0 +dev tap +dev tap0 +dev null +dev-type tun +dev-type tap +topology net30 +topology p2p +topology subnet +tun-ipv6 +dev-node /canonical/file +dev-node relative/file +lladdr 1.2.3.4 +iproute my command goes here +ifconfig 1.2.3.4 5.6.7.8 +ifconfig-noexec +ifconfig-nowarn +route 111.222.123.123 +route networkname +route vpn_gateway +route net_gateway +route remote_host +route 111.222.123.123 255.123.255.221 +route 111.222.123.123 default +route 111.222.123.123 255.123.255.231 111.222.123.1 +route 111.222.123.123 default 111.222.123.1 +route 111.222.123.123 255.123.255.231 default +route 111.222.123.123 default default +route 111.222.123.123 255.123.255.231 gatewayname +route 111.222.123.123 255.123.255.231 gatewayname 5 +route 111.222.123.123 255.123.255.231 vpn_gateway +route 111.222.123.123 255.123.255.231 net_gateway +route 111.222.123.123 255.123.255.231 remote_host +route 111.222.123.123 255.123.255.231 111.222.123.1 +route 111.222.123.123 255.123.255.231 111.222.123.1 5 +max-routes 5 +route-gateway gateway-name +route-gateway 111.222.123.1 +route-gateway dhcp +route-metric 5 +route-delay +route-delay 1 +route-delay 1 2 +route-up my command goes here +route-pre-down my command goes here +route-noexec +route-nopull +allow-pull-fqdn +client-nat snat 1.2.3.4 5.6.7.8 9.8.7.6 +client-nat dnat 1.2.3.4 5.6.7.8 9.8.7.6 +redirect-gateway local +redirect-gateway local autolocal +redirect-gateway local autolocal def1 bypass-dhcp bypass-dns block-local +link-mtu 5 +redirect-private local +redirect-private local autolocal +redirect-private local autolocal def1 bypass-dhcp bypass-dns block-local +tun-mtu 5 +tun-mtu-extra 5 +mtu-disc no +mtu-disc maybe +mtu-disc yes +mtu-test +fragment 5 +mssfix 1600 +sndbuf 65536 +rcvbuf 65535 +mark blahvalue +socket-flags TCP_NODELAY +txqueuelen 5 +shaper 50 +inactive 5 +inactive 5 1024 +ping 10 +ping-exit 10 +ping-restart 10 +keepalive 1 2 +ping-timer-rem +persist-tun +persist-key +persist-local-ip +persist-remote-ip +mlock +up my command goes here +up-delay +down my command goes here +down-pre +up-restart +setenv myname myvalue +setenv my0-_name my value with spaces +setenv-safe myname myvalue +setenv-safe my-_name my value with spaces +ignore-unknown-option anopt +ignore-unknown-option anopt anotheropt +script-security 3 +disable-occ +user username +group groupname +cd /canonical/dir +cd relative/dir/ +chroot /canonical/dir +chroot relative/dir/ +setcon selinux-context +daemon +daemon mydaemon_name +syslog +syslog my_syslog-name +errors-to-stderr +passtos +inetd +inetd wait +inetd nowait +inetd wait my-program_name +log myfilename +log-append myfilename +suppress-timestamps +writepid myfile +nice 5 +fast-io +multihome +echo stuff to echo until end of line +remap-usr1 SIGHUP +remap-usr1 SIGTERM +verb 6 +status myfile +status myfile 15 +status-version +status-version 3 +mute 20 +comp-lzo +comp-lzo yes +comp-lzo no +comp-lzo adaptive +management 123.123.123.123 1234 +management 123.123.123.123 1234 /canonical/file +management-client +management-query-passwords +management-query-proxy +management-query-remote +management-forget-disconnect +management-hold +management-signal +management-up-down +management-client-auth +management-client-pf +management-log-cache 5 +management-client-user myuser +management-client-user mygroup +plugin /canonical/file +plugin relative/file +plugin myfile an init string +server 1.2.3.4 255.255.255.0 +server 1.2.3.4 255.255.255.255 nopool +server-bridge 1.2.3.4 1.2.3.5 50.5.5.5 50.5.5.6 +server-bridge nogw +push \"my push string\" +push-reset +push-peer-info +disable +ifconfig-pool 1.1.1.1 2.2.2.2 +ifconfig-pool 1.1.1.1 2.2.2.2 255.255.255.0 +ifconfig-pool-persist myfile +ifconfig-pool-persist myfile 50 +ifconfig-pool-linear +ifconfig-push 1.1.1.1 2.2.2.2 +ifconfig-push 1.1.1.1 2.2.2.2 alias-name +iroute 1.1.1.1 +iroute 1.1.1.1 2.2.2.2 +client-to-client +duplicate-cn +client-connect my command goes here +client-disconnect my command goes here +client-config-dir directory +ccd-exclusive +tmp-dir /directory +hash-size 1 2 +bcast-buffers 5 +tcp-queue-limit 50 +tcp-nodelay +max-clients 50 +max-routes-per-client 50 +stale-routes-check 5 +stale-routes-check 5 50 +connect-freq 50 100 +learn-address my command goes here +auth-user-pass-verify /my/script/with/no/arguments.sh via-env +auth-user-pass-verify \"myscript.sh arg1 arg2\" via-file +opt-verify +auth-user-pass-optional +client-cert-not-required +username-as-common-name +port-share 1.1.1.1 1234 +port-share myhostname 1234 +port-share myhostname 1234 /canonical/dir +client +pull +auth-user-pass +auth-user-pass /canonical/file +auth-user-pass relative/file +auth-retry none +auth-retry nointeract +auth-retry interact +static-challenge challenge_no_spaces 1 +static-challenge \"my quoted challenge string\" 0 +server-poll-timeout 50 +explicit-exit-notify +explicit-exit-notify 5 +secret /canonicalfile +secret relativefile +secret filename 1 +secret filename 0 +key-direction +auth none +auth sha1 +cipher SHA1 +cipher sha1 +keysize 50 +prng SHA1 +prng SHA1 500 +engine +engine blah +no-replay +replay-window 64 +replay-window 64 16 +mute-replay-warnings +replay-persist /my/canonical/filename +no-iv +use-prediction-resistance +test-crypto +tls-server +tls-client +ca myfile +capath /mydir/ +dh myfile +cert myfile +extra-certs myfile +key myfile +tls-version-min 1.1 +tls-version-min 2 +tls-version-min 1.1 or-highest +tls-version-max 5.5 +pkcs12 myfile +verify-hash AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16 +pkcs11-cert-private 0 +pkcs11-cert-private 1 +pkcs11-id myname +pkcs11-id-management +pkcs11-pin-cache 50 +pkcs11-protected-authentication 0 +pkcs11-protected-authentication 1 +cryptoapicert \"SUBJ:Justin Akers\" +key-method 2 +tls-cipher DEFAULT:!EXP:!PSK:!SRP:!kRSA +tls-timeout 50 +reneg-bytes 50 +reneg-pkts 50 +reneg-sec 5 +hand-window 123 +tran-window 456 +single-session +tls-exit +tls-auth filename 1 +askpass /canonical/filename +auth-nocache +tls-verify my command goes here +tls-export-cert /a/directory/for/things +x509-username-field emailAddress +x509-username-field ext:subjectAltName +tls-remote myhostname +verify-x509-name hostname name +verify-x509-name hostname name-prefix +verify-x509-name hostname subject +ns-cert-type server +ns-cert-type client +remote-cert-tls server +remote-cert-tls client +remote-cert-ku 01 +remote-cert-ku 01 02 fa FF b3 +remote-cert-eku 123.3510.350.10 +remote-cert-eku \"TLS Web Client Authentication\" +remote-cert-eku serverAuth +crl-verify /a/file/path +crl-verify /a/directory/ dir +show-ciphers +show-digests +show-tls +show-engines +genkey +mktun +rmtun +ifconfig-ipv6 2000:123:456::/64 1234:99:123::124 +ifconfig-ipv6-push 2000:123:456::/64 1234:99:123::124 +iroute-ipv6 2000:123:456::/64 +route-ipv6 2000:123:456::/64 +route-ipv6 2000:123:456::/64 1234:99:123::124 +route-ipv6 2000:123:456::/64 1234:99:123::124 500 +server-ipv6 2000:123:456::/64 +ifconfig-ipv6-pool 2000:123:456::/64 + +" + +test OpenVPN.lns get all_permutations_conf = + { } + { "config" = "/a/canonical/file" } + { "config" = "relative_file" } + { "mode" = "p2p" } + { "mode" = "server" } + { "local" = "192.168.1.1" } + { "local" = "hostname" } + { "remote" + { "server" = "192.168.1.1" } + { "port" = "1234" } + } + { "remote" + { "server" = "hostname" } + { "port" = "1234" } + } + { "remote" + { "server" = "hostname" } + } + { "remote" + { "server" = "192.168.1.1" } + } + { "remote" + { "server" = "hostname" } + { "port" = "1234" } + { "proto" = "tcp" } + } + { "remote" + { "server" = "192.168.1.1" } + { "port" = "1234" } + { "proto" = "tcp" } + } + { "remote" + { "server" = "hostname" } + { "port" = "1234" } + { "proto" = "udp" } + } + { "remote-random-hostname" } + { "#comment" = "comment square <connection> blocks should go here" } + { "proto-force" = "udp" } + { "proto-force" = "tcp" } + { "remote-random" } + { "proto" = "udp" } + { "proto" = "tcp-client" } + { "proto" = "tcp-server" } + { "connect-retry" = "5" } + { "connect-timeout" = "10" } + { "connect-retry-max" = "0" } + { "show-proxy-settings" } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "auto" } + } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "auto-nct" } + } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "auto" } + { "auth-method" = "none" } + } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "auto" } + { "auth-method" = "basic" } + } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "auto" } + { "auth-method" = "ntlm" } + } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "relative_filename" } + { "auth-method" = "ntlm" } + } + { "http-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "/canonical/filename" } + { "auth-method" = "basic" } + } + { "http-proxy-retry" } + { "http-proxy-timeout" = "5" } + { "http-proxy-option" + { "option" = "VERSION" } + { "value" = "1.0" } + } + { "http-proxy-option" + { "option" = "AGENT" } + { "value" = "an unquoted string with spaces" } + } + { "http-proxy-option" + { "option" = "AGENT" } + { "value" = "an_unquoted_string_without_spaces" } + } + { "socks-proxy" + { "server" = "servername" } + } + { "socks-proxy" + { "server" = "servername" } + { "port" = "1234" } + } + { "socks-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "/canonical/file" } + } + { "socks-proxy" + { "server" = "servername" } + { "port" = "1234" } + { "auth" = "relative/file" } + } + { "socks-proxy-retry" } + { "resolv-retry" = "5" } + { "float" } + { "ipchange" = "my command goes here" } + { "port" = "1234" } + { "lport" = "1234" } + { "rport" = "1234" } + { "bind" } + { "nobind" } + { "dev" = "tun" } + { "dev" = "tun0" } + { "dev" = "tap" } + { "dev" = "tap0" } + { "dev" = "null" } + { "dev-type" = "tun" } + { "dev-type" = "tap" } + { "topology" = "net30" } + { "topology" = "p2p" } + { "topology" = "subnet" } + { "tun-ipv6" } + { "dev-node" = "/canonical/file" } + { "dev-node" = "relative/file" } + { "lladdr" = "1.2.3.4" } + { "iproute" = "my command goes here" } + { "ifconfig" + { "local" = "1.2.3.4" } + { "remote" = "5.6.7.8" } + } + { "ifconfig-noexec" } + { "ifconfig-nowarn" } + { "route" + { "address" = "111.222.123.123" } + } + { "route" + { "address" = "networkname" } + } + { "route" + { "address" = "vpn_gateway" } + } + { "route" + { "address" = "net_gateway" } + } + { "route" + { "address" = "remote_host" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.221" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "default" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "111.222.123.1" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "default" } + { "gateway" = "111.222.123.1" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "default" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "default" } + { "gateway" = "default" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "gatewayname" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "gatewayname" } + { "metric" = "5" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "vpn_gateway" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "net_gateway" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "remote_host" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "111.222.123.1" } + } + { "route" + { "address" = "111.222.123.123" } + { "netmask" = "255.123.255.231" } + { "gateway" = "111.222.123.1" } + { "metric" = "5" } + } + { "max-routes" = "5" } + { "route-gateway" = "gateway-name" } + { "route-gateway" = "111.222.123.1" } + { "route-gateway" = "dhcp" } + { "route-metric" = "5" } + { "route-delay" } + { "route-delay" + { "seconds" = "1" } + } + { "route-delay" + { "seconds" = "1" } + { "win-seconds" = "2" } + } + { "route-up" = "my command goes here" } + { "route-pre-down" = "my command goes here" } + { "route-noexec" } + { "route-nopull" } + { "allow-pull-fqdn" } + { "client-nat" + { "type" = "snat" } + { "network" = "1.2.3.4" } + { "netmask" = "5.6.7.8" } + { "alias" = "9.8.7.6" } + } + { "client-nat" + { "type" = "dnat" } + { "network" = "1.2.3.4" } + { "netmask" = "5.6.7.8" } + { "alias" = "9.8.7.6" } + } + { "redirect-gateway" + { "flag" = "local" } + } + { "redirect-gateway" + { "flag" = "local" } + { "flag" = "autolocal" } + } + { "redirect-gateway" + { "flag" = "local" } + { "flag" = "autolocal" } + { "flag" = "def1" } + { "flag" = "bypass-dhcp" } + { "flag" = "bypass-dns" } + { "flag" = "block-local" } + } + { "link-mtu" = "5" } + { "redirect-private" + { "flag" = "local" } + } + { "redirect-private" + { "flag" = "local" } + { "flag" = "autolocal" } + } + { "redirect-private" + { "flag" = "local" } + { "flag" = "autolocal" } + { "flag" = "def1" } + { "flag" = "bypass-dhcp" } + { "flag" = "bypass-dns" } + { "flag" = "block-local" } + } + { "tun-mtu" = "5" } + { "tun-mtu-extra" = "5" } + { "mtu-disc" = "no" } + { "mtu-disc" = "maybe" } + { "mtu-disc" = "yes" } + { "mtu-test" } + { "fragment" = "5" } + { "mssfix" = "1600" } + { "sndbuf" = "65536" } + { "rcvbuf" = "65535" } + { "mark" = "blahvalue" } + { "socket-flags" = "TCP_NODELAY" } + { "txqueuelen" = "5" } + { "shaper" = "50" } + { "inactive" + { "seconds" = "5" } + } + { "inactive" + { "seconds" = "5" } + { "bytes" = "1024" } + } + { "ping" = "10" } + { "ping-exit" = "10" } + { "ping-restart" = "10" } + { "keepalive" + { "ping" = "1" } + { "timeout" = "2" } + } + { "ping-timer-rem" } + { "persist-tun" } + { "persist-key" } + { "persist-local-ip" } + { "persist-remote-ip" } + { "mlock" } + { "up" = "my command goes here" } + { "up-delay" } + { "down" = "my command goes here" } + { "down-pre" } + { "up-restart" } + { "setenv" + { "myname" = "myvalue" } + } + { "setenv" + { "my0-_name" = "my value with spaces" } + } + { "setenv-safe" + { "myname" = "myvalue" } + } + { "setenv-safe" + { "my-_name" = "my value with spaces" } + } + { "ignore-unknown-option" + { "opt" = "anopt" } + } + { "ignore-unknown-option" + { "opt" = "anopt" } + { "opt" = "anotheropt" } + } + { "script-security" = "3" } + { "disable-occ" } + { "user" = "username" } + { "group" = "groupname" } + { "cd" = "/canonical/dir" } + { "cd" = "relative/dir/" } + { "chroot" = "/canonical/dir" } + { "chroot" = "relative/dir/" } + { "setcon" = "selinux-context" } + { "daemon" } + { "daemon" = "mydaemon_name" } + { "syslog" } + { "syslog" = "my_syslog-name" } + { "errors-to-stderr" } + { "passtos" } + { "inetd" } + { "inetd" + { "mode" = "wait" } + } + { "inetd" + { "mode" = "nowait" } + } + { "inetd" + { "mode" = "wait" } + { "progname" = "my-program_name" } + } + { "log" = "myfilename" } + { "log-append" = "myfilename" } + { "suppress-timestamps" } + { "writepid" = "myfile" } + { "nice" = "5" } + { "fast-io" } + { "multihome" } + { "echo" = "stuff to echo until end of line" } + { "remap-usr1" = "SIGHUP" } + { "remap-usr1" = "SIGTERM" } + { "verb" = "6" } + { "status" + { "file" = "myfile" } + } + { "status" + { "file" = "myfile" } + { "repeat-seconds" = "15" } + } + { "status-version" } + { "status-version" = "3" } + { "mute" = "20" } + { "comp-lzo" } + { "comp-lzo" = "yes" } + { "comp-lzo" = "no" } + { "comp-lzo" = "adaptive" } + { "management" + { "server" = "123.123.123.123" } + { "port" = "1234" } + } + { "management" + { "server" = "123.123.123.123" } + { "port" = "1234" } + { "pwfile" = "/canonical/file" } + } + { "management-client" } + { "management-query-passwords" } + { "management-query-proxy" } + { "management-query-remote" } + { "management-forget-disconnect" } + { "management-hold" } + { "management-signal" } + { "management-up-down" } + { "management-client-auth" } + { "management-client-pf" } + { "management-log-cache" = "5" } + { "management-client-user" = "myuser" } + { "management-client-user" = "mygroup" } + { "plugin" + { "file" = "/canonical/file" } + } + { "plugin" + { "file" = "relative/file" } + } + { "plugin" + { "file" = "myfile" } + { "init-string" = "an init string" } + } + { "server" + { "address" = "1.2.3.4" } + { "netmask" = "255.255.255.0" } + } + { "server" + { "address" = "1.2.3.4" } + { "netmask" = "255.255.255.255" } + { "nopool" } + } + { "server-bridge" + { "address" = "1.2.3.4" } + { "netmask" = "1.2.3.5" } + { "start" = "50.5.5.5" } + { "end" = "50.5.5.6" } + } + { "server-bridge" = "nogw" } + { "push" = "my push string" } + { "push-reset" } + { "push-peer-info" } + { "disable" } + { "ifconfig-pool" + { "start" = "1.1.1.1" } + { "end" = "2.2.2.2" } + } + { "ifconfig-pool" + { "start" = "1.1.1.1" } + { "end" = "2.2.2.2" } + { "netmask" = "255.255.255.0" } + } + { "ifconfig-pool-persist" + { "file" = "myfile" } + } + { "ifconfig-pool-persist" + { "file" = "myfile" } + { "seconds" = "50" } + } + { "ifconfig-pool-linear" } + { "ifconfig-push" + { "local" = "1.1.1.1" } + { "remote-netmask" = "2.2.2.2" } + } + { "ifconfig-push" + { "local" = "1.1.1.1" } + { "remote-netmask" = "2.2.2.2" } + { "alias" = "alias-name" } + } + { "iroute" + { "local" = "1.1.1.1" } + } + { "iroute" + { "local" = "1.1.1.1" } + { "netmask" = "2.2.2.2" } + } + { "client-to-client" } + { "duplicate-cn" } + { "client-connect" = "my command goes here" } + { "client-disconnect" = "my command goes here" } + { "client-config-dir" = "directory" } + { "ccd-exclusive" } + { "tmp-dir" = "/directory" } + { "hash-size" + { "real" = "1" } + { "virtual" = "2" } + } + { "bcast-buffers" = "5" } + { "tcp-queue-limit" = "50" } + { "tcp-nodelay" } + { "max-clients" = "50" } + { "max-routes-per-client" = "50" } + { "stale-routes-check" + { "age" = "5" } + } + { "stale-routes-check" + { "age" = "5" } + { "interval" = "50" } + } + { "connect-freq" + { "num" = "50" } + { "sec" = "100" } + } + { "learn-address" = "my command goes here" } + { "auth-user-pass-verify" + { + { "command" = "/my/script/with/no/arguments.sh" } + } + { "method" = "via-env" } + } + { "auth-user-pass-verify" + { + { "command" = "myscript.sh arg1 arg2" } + } + { "method" = "via-file" } + } + { "opt-verify" } + { "auth-user-pass-optional" } + { "client-cert-not-required" } + { "username-as-common-name" } + { "port-share" + { "host" = "1.1.1.1" } + { "port" = "1234" } + } + { "port-share" + { "host" = "myhostname" } + { "port" = "1234" } + } + { "port-share" + { "host" = "myhostname" } + { "port" = "1234" } + { "dir" = "/canonical/dir" } + } + { "client" } + { "pull" } + { "auth-user-pass" } + { "auth-user-pass" = "/canonical/file" } + { "auth-user-pass" = "relative/file" } + { "auth-retry" = "none" } + { "auth-retry" = "nointeract" } + { "auth-retry" = "interact" } + { "static-challenge" + { + { "text" = "challenge_no_spaces" } + } + { "echo" = "1" } + } + { "static-challenge" + { + { "text" = "my quoted challenge string" } + } + { "echo" = "0" } + } + { "server-poll-timeout" = "50" } + { "explicit-exit-notify" } + { "explicit-exit-notify" = "5" } + { "secret" + { "file" = "/canonicalfile" } + } + { "secret" + { "file" = "relativefile" } + } + { "secret" + { "file" = "filename" } + { "direction" = "1" } + } + { "secret" + { "file" = "filename" } + { "direction" = "0" } + } + { "key-direction" } + { "auth" = "none" } + { "auth" = "sha1" } + { "cipher" = "SHA1" } + { "cipher" = "sha1" } + { "keysize" = "50" } + { "prng" + { "algorithm" = "SHA1" } + } + { "prng" + { "algorithm" = "SHA1" } + { "nsl" = "500" } + } + { "engine" } + { "engine" = "blah" } + { "no-replay" } + { "replay-window" + { "window-size" = "64" } + } + { "replay-window" + { "window-size" = "64" } + { "seconds" = "16" } + } + { "mute-replay-warnings" } + { "replay-persist" = "/my/canonical/filename" } + { "no-iv" } + { "use-prediction-resistance" } + { "test-crypto" } + { "tls-server" } + { "tls-client" } + { "ca" = "myfile" } + { "capath" = "/mydir/" } + { "dh" = "myfile" } + { "cert" = "myfile" } + { "extra-certs" = "myfile" } + { "key" = "myfile" } + { "tls-version-min" = "1.1" } + { "tls-version-min" = "2" } + { "tls-version-min" = "1.1" + { "or-highest" } + } + { "tls-version-max" = "5.5" } + { "pkcs12" = "myfile" } + { "verify-hash" = "AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16" } + { "pkcs11-cert-private" = "0" } + { "pkcs11-cert-private" = "1" } + { "pkcs11-id" = "myname" } + { "pkcs11-id-management" } + { "pkcs11-pin-cache" = "50" } + { "pkcs11-protected-authentication" = "0" } + { "pkcs11-protected-authentication" = "1" } + { "cryptoapicert" + { "SUBJ" = "Justin Akers" } + } + { "key-method" = "2" } + { "tls-cipher" + { "cipher" = "DEFAULT" } + { "cipher" = "!EXP" } + { "cipher" = "!PSK" } + { "cipher" = "!SRP" } + { "cipher" = "!kRSA" } + } + { "tls-timeout" = "50" } + { "reneg-bytes" = "50" } + { "reneg-pkts" = "50" } + { "reneg-sec" = "5" } + { "hand-window" = "123" } + { "tran-window" = "456" } + { "single-session" } + { "tls-exit" } + { "tls-auth" + { "key" = "filename" } + { "is_client" = "1" } + } + { "askpass" = "/canonical/filename" } + { "auth-nocache" } + { "tls-verify" = "my command goes here" } + { "tls-export-cert" = "/a/directory/for/things" } + { "x509-username-field" + { "subj" = "emailAddress" } + } + { "x509-username-field" + { "ext" = "subjectAltName" } + } + { "tls-remote" = "myhostname" } + { "verify-x509-name" + { "name" = "hostname" } + { "type" = "name" } + } + { "verify-x509-name" + { "name" = "hostname" } + { "type" = "name-prefix" } + } + { "verify-x509-name" + { "name" = "hostname" } + { "type" = "subject" } + } + { "ns-cert-type" = "server" } + { "ns-cert-type" = "client" } + { "remote-cert-tls" = "server" } + { "remote-cert-tls" = "client" } + { "remote-cert-ku" + { "usage" = "01" } + } + { "remote-cert-ku" + { "usage" = "01" } + { "usage" = "02" } + { "usage" = "fa" } + { "usage" = "FF" } + { "usage" = "b3" } + } + { "remote-cert-eku" + { "oid" = "123.3510.350.10" } + } + { "remote-cert-eku" + { "symbol" = "TLS Web Client Authentication" } + } + { "remote-cert-eku" + { "symbol" = "serverAuth" } + } + { "crl-verify" = "/a/file/path" } + { "crl-verify" = "/a/directory/" + { "dir" } + } + { "show-ciphers" } + { "show-digests" } + { "show-tls" } + { "show-engines" } + { "genkey" } + { "mktun" } + { "rmtun" } + { "ifconfig-ipv6" + { "address" = "2000:123:456::/64" } + { "remote" = "1234:99:123::124" } + } + { "ifconfig-ipv6-push" + { "address" = "2000:123:456::/64" } + { "remote" = "1234:99:123::124" } + } + { "iroute-ipv6" = "2000:123:456::/64" } + { "route-ipv6" + { "network" = "2000:123:456::/64" } + } + { "route-ipv6" + { "network" = "2000:123:456::/64" } + { "gateway" = "1234:99:123::124" } + } + { "route-ipv6" + { "network" = "2000:123:456::/64" } + { "gateway" = "1234:99:123::124" } + { "metric" = "500" } + } + { "server-ipv6" = "2000:123:456::/64" } + { "ifconfig-ipv6-pool" = "2000:123:456::/64" } + { } + + diff --git a/Sharp.Augeas.Test/lens/tests/test_oz.aug b/Sharp.Augeas.Test/lens/tests/test_oz.aug new file mode 100644 index 0000000..e8afa69 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_oz.aug @@ -0,0 +1,36 @@ +module Test_oz = + + let conf = " +[paths] +output_dir = /var/lib/libvirt/images +data_dir = /var/lib/oz + +[libvirt] +uri = qemu:///system +image_type = raw +" + + test Oz.lns get conf = + {} + { "paths" + { "output_dir" = "/var/lib/libvirt/images" } + { "data_dir" = "/var/lib/oz" } + {} } + { "libvirt" + { "uri" = "qemu:///system" } + { "image_type" = "raw" } + } + + test Oz.lns put conf after + set "libvirt/cpus" "2" + = " +[paths] +output_dir = /var/lib/libvirt/images +data_dir = /var/lib/oz + +[libvirt] +uri = qemu:///system +image_type = raw +cpus=2 +" + diff --git a/Sharp.Augeas.Test/lens/tests/test_pagekite.aug b/Sharp.Augeas.Test/lens/tests/test_pagekite.aug new file mode 100644 index 0000000..d32bc4f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pagekite.aug @@ -0,0 +1,111 @@ +module Test_Pagekite = + +let conf1 = "# Use the pagekite.net service defaults. +defaults +" +test Pagekite.lns get conf1 = + { "#comment" = "Use the pagekite.net service defaults." } + { "defaults" } + + +let conf2 =" +frontends = pagekite.freedombox.me +ports=80,81 +" +test Pagekite.lns get conf2 = + { } + { "frontends" = "pagekite.freedombox.me" } + { "ports" + { "1" = "80" } + { "2" = "81" } } + + +let conf3 = "frontend=pagekite.freedombox.me +host=192.168.0.3 +" +test Pagekite.lns get conf3 = + { "frontend" = "pagekite.freedombox.me" } + { "host" = "192.168.0.3" } + + +let conf4 = "isfrontend +ports=80,443 +protos=http,https +domain=http,https:*.your.domain:MakeUpAPasswordHere +" +test Pagekite.lns get conf4 = + { "isfrontend" } + { "ports" + { "1" = "80" } + { "2" = "443" } } + { "protos" + { "1" = "http" } + { "2" = "https" } } + { "domain" = "http,https:*.your.domain:MakeUpAPasswordHere" } + +let conf_account = "kitename = my.freedombox.me +kitesecret = 0420 +# Delete this line! +abort_not_configured +" +test Pagekite.lns get conf_account = + { "kitename" = "my.freedombox.me" } + { "kitesecret" = "0420" } + { "#comment" = "Delete this line!" } + { "abort_not_configured" } + + +let conf_service = " +service_on = raw/22:@kitename : localhost:22 : @kitesecret +service_on=http:192.168.0.1:127.0.0.1:80: +service_on=https:yourhostname,fqdn:127.0.0.1:443: +" +test Pagekite.lns get conf_service = + { } + { "service_on" + { "1" + { "protocol" = "raw/22" } + { "kitename" = "@kitename" } + { "backend_host" = "localhost" } + { "backend_port" = "22" } + { "secret" = "@kitesecret" } + } + } + { "service_on" + { "2" + { "protocol" = "http" } + { "kitename" = "192.168.0.1" } + { "backend_host" = "127.0.0.1" } + { "backend_port" = "80" } + } + } + { "service_on" + { "3" + { "protocol" = "https" } + { "kitename" = "yourhostname,fqdn" } + { "backend_host" = "127.0.0.1" } + { "backend_port" = "443" } + } + } + + +let conf_encryption = " +frontend=frontend.your.domain:443 +fe_certname=frontend.your/domain +ca_certs=/etc/pagekite.d/site-cert.pem +tls_endpoint=frontend.your.domain:/path/to/frontend.pem +" +test Pagekite.lns get conf_encryption = + { } + { "frontend" = "frontend.your.domain:443" } + { "fe_certname" = "frontend.your/domain" } + { "ca_certs" = "/etc/pagekite.d/site-cert.pem" } + { "tls_endpoint" = "frontend.your.domain:/path/to/frontend.pem" } + + +let conf_service_cfg = "insecure +service_cfg = KITENAME.pagekite.me/80 : insecure : True +" +test Pagekite.lns get conf_service_cfg = + { "insecure" } + { "service_cfg" = "KITENAME.pagekite.me/80 : insecure : True" } diff --git a/Sharp.Augeas.Test/lens/tests/test_pam.aug b/Sharp.Augeas.Test/lens/tests/test_pam.aug new file mode 100644 index 0000000..187ed2e --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pam.aug @@ -0,0 +1,73 @@ +module Test_pam = + + let example = "#%PAM-1.0 +AUTH [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so +session optional pam_keyinit.so force revoke +" + + test Pam.lns get example = + { "#comment" = "%PAM-1.0" } + { "1" { "type" = "AUTH" } + { "control" = "[user_unknown=ignore success=ok ignore=ignore default=bad]" } + { "module" = "pam_securetty.so" } } + { "2" { "type" = "session" } + { "control" = "optional" } + { "module" = "pam_keyinit.so" } + { "argument" = "force" } + { "argument" = "revoke" } } + + test Pam.lns put example after + set "/1/control" "requisite" + = "#%PAM-1.0 +AUTH requisite pam_securetty.so +session optional pam_keyinit.so force revoke +" + + (* Check that trailing whitespace is handled & preserved *) + let trailing_ws = "auth\trequired\tpam_unix.so \n" + + test Pam.lns put trailing_ws after + set "/1/type" "auth" + = trailing_ws + + test Pam.lns get "@include common-password\n" = + { "include" = "common-password" } + + test Pam.lns get "-password optional pam_gnome_keyring.so\n" = + { "1" + { "optional" } + { "type" = "password" } + { "control" = "optional" } + { "module" = "pam_gnome_keyring.so" } + } + + test Pam.lns get "session optional pam_motd.so [motd=/etc/bad example]\n" = + { "1" + { "type" = "session" } + { "control" = "optional" } + { "module" = "pam_motd.so" } + { "argument" = "[motd=/etc/bad example]" } + } + +(* Multiline PAM entries; issue #590 *) +test Pam.lns get "account \\\ninclude \\\n system-auth\n" = + { "1" + { "type" = "account" } + { "control" = "include" } + { "module" = "system-auth" } } + +test Pam.lns get "account\\\n[success=1 default=ignore] \\ + pam_succeed_if.so\\\nuser\\\n =\\\nvagrant\\\nuse_uid\\\nquiet\n" = + { "1" + { "type" = "account" } + { "control" = "[success=1 default=ignore]" } + { "module" = "pam_succeed_if.so" } + { "argument" = "user" } + { "argument" = "=" } + { "argument" = "vagrant" } + { "argument" = "use_uid" } + { "argument" = "quiet" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_pamconf.aug b/Sharp.Augeas.Test/lens/tests/test_pamconf.aug new file mode 100644 index 0000000..6a23194 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pamconf.aug @@ -0,0 +1,35 @@ +module Test_pamconf = + + let example = "# Authentication management +# +# login service (explicit because of pam_dial_auth) +# +login auth requisite pam_authtok_get.so.1 +login auth required pam_dhkeys.so.1 arg + +other session required pam_unix_session.so.1 +" + + test PamConf.lns get example = + { "#comment" = "Authentication management" } + { } + { "#comment" = "login service (explicit because of pam_dial_auth)" } + { } + { "1" { "service" = "login" } + { "type" = "auth" } + { "control" = "requisite" } + { "module" = "pam_authtok_get.so.1" } } + { "2" { "service" = "login" } + { "type" = "auth" } + { "control" = "required" } + { "module" = "pam_dhkeys.so.1" } + { "argument" = "arg" } } + { } + { "3" { "service" = "other" } + { "type" = "session" } + { "control" = "required" } + { "module" = "pam_unix_session.so.1" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_passwd.aug b/Sharp.Augeas.Test/lens/tests/test_passwd.aug new file mode 100644 index 0000000..01d93fc --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_passwd.aug @@ -0,0 +1,104 @@ +module Test_Passwd = + +let conf = "root:x:0:0:root:/root:/bin/bash +libuuid:x:100:101::/var/lib/libuuid:/bin/sh +free:x:1000:1000:Free Ekanayaka,,,:/home/free:/bin/bash +root:*:0:0:Charlie &:/root:/bin/csh +" + +test Passwd.lns get conf = + { "root" + { "password" = "x" } + { "uid" = "0" } + { "gid" = "0" } + { "name" = "root" } + { "home" = "/root" } + { "shell" = "/bin/bash" } } + { "libuuid" + { "password" = "x" } + { "uid" = "100" } + { "gid" = "101" } + { "name" } + { "home" = "/var/lib/libuuid" } + { "shell" = "/bin/sh" } } + { "free" + { "password" = "x" } + { "uid" = "1000" } + { "gid" = "1000" } + { "name" = "Free Ekanayaka,,," } + { "home" = "/home/free" } + { "shell" = "/bin/bash" } } + { "root" + { "password" = "*" } + { "uid" = "0" } + { "gid" = "0" } + { "name" = "Charlie &" } + { "home" = "/root" } + { "shell" = "/bin/csh" } } + +(* Popular on Solaris *) +test Passwd.lns get "+@some-nis-group::::::\n" = + { "@nis" = "some-nis-group" } + +test Passwd.lns get "+\n" = + { "@nisdefault" } + +test Passwd.lns get "+::::::\n" = + { "@nisdefault" + { "password" = "" } + { "uid" = "" } + { "gid" = "" } + { "name" } + { "home" } + { "shell" } } + +test Passwd.lns get "+::::::/sbin/nologin\n" = + { "@nisdefault" + { "password" = "" } + { "uid" = "" } + { "gid" = "" } + { "name" } + { "home" } + { "shell" = "/sbin/nologin" } } + +test Passwd.lns get "+:*:0:0:::\n" = + { "@nisdefault" + { "password" = "*" } + { "uid" = "0" } + { "gid" = "0" } + { "name" } + { "home" } + { "shell" } } + +(* NIS entries with overrides, ticket #339 *) +test Passwd.lns get "+@bob:::::/home/bob:/bin/bash\n" = + { "@nis" = "bob" + { "home" = "/home/bob" } + { "shell" = "/bin/bash" } } + +(* NIS user entries *) +test Passwd.lns get "+bob::::::\n" = + { "@+nisuser" = "bob" } + +test Passwd.lns get "+bob::::User Comment:/home/bob:/bin/bash\n" = + { "@+nisuser" = "bob" + { "name" = "User Comment" } + { "home" = "/home/bob" } + { "shell" = "/bin/bash" } } + +test Passwd.lns put "+bob::::::\n" after + set "@+nisuser" "alice" += "+alice::::::\n" + +test Passwd.lns put "+bob::::::\n" after + set "@+nisuser/name" "User Comment"; + set "@+nisuser/home" "/home/bob"; + set "@+nisuser/shell" "/bin/bash" += "+bob::::User Comment:/home/bob:/bin/bash\n" + +test Passwd.lns get "-bob::::::\n" = + { "@-nisuser" = "bob" } + +test Passwd.lns put "-bob::::::\n" after + set "@-nisuser" "alice" += "-alice::::::\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_pbuilder.aug b/Sharp.Augeas.Test/lens/tests/test_pbuilder.aug new file mode 100644 index 0000000..9017381 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pbuilder.aug @@ -0,0 +1,20 @@ + + +module Test_Pbuilder = + +let conf = "BASETGZ=/var/cache/pbuilder/base.tgz +#EXTRAPACKAGES=gcc3.0-athlon-builder +export DEBIAN_BUILDARCH=athlon +BUILDPLACE=/var/cache/pbuilder/build/ +MIRRORSITE=http://ftp.jp.debian.org/debian +" + +test Pbuilder.lns get conf = + { "BASETGZ" = "/var/cache/pbuilder/base.tgz" } + { "#comment" = "EXTRAPACKAGES=gcc3.0-athlon-builder" } + { "DEBIAN_BUILDARCH" = "athlon" + { "export" } } + { "BUILDPLACE" = "/var/cache/pbuilder/build/" } + { "MIRRORSITE" = "http://ftp.jp.debian.org/debian" } + + diff --git a/Sharp.Augeas.Test/lens/tests/test_pg_hba.aug b/Sharp.Augeas.Test/lens/tests/test_pg_hba.aug new file mode 100644 index 0000000..b9f6786 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pg_hba.aug @@ -0,0 +1,177 @@ +module Test_pg_hba = + + (* Main test *) + let conf ="# TYPE DATABASE USER CIDR-ADDRESS METHOD + +local all all ident sameuser +# IPv4 local connections: +host all all 127.0.0.1/32 md5 +# Remote connections by hostname: +host all all foo.example.com md5 +# Remote connections by suffix of hostname/fqdn: +host all all .example.com md5 +# IPv6 local connections: +host all all ::1/128 md5 +" + + test Pg_Hba.lns get conf = + { "#comment" = "TYPE DATABASE USER CIDR-ADDRESS METHOD" } + {} + { "1" + { "type" = "local" } + { "database" = "all" } + { "user" = "all" } + { "method" = "ident" + { "option" = "sameuser" } } + } + { "#comment" = "IPv4 local connections:" } + { "2" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = "127.0.0.1/32" } + { "method" = "md5" } + } + { "#comment" = "Remote connections by hostname:" } + { "3" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = "foo.example.com" } + { "method" = "md5" } + } + { "#comment" = "Remote connections by suffix of hostname/fqdn:" } + { "4" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = ".example.com" } + { "method" = "md5" } + } + { "#comment" = "IPv6 local connections:" } + { "5" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = "::1/128" } + { "method" = "md5" } + } + +(* ------------------------------------------------------------- *) + + (* Simple local test *) + test Pg_Hba.lns get "local all all trust\n" = + { "1" + { "type" = "local" } + { "database" = "all" } + { "user" = "all" } + { "method" = "trust" } + } + + (* Remote test with comma-sparated database names *) + test Pg_Hba.lns get "hostssl db1,db2,db3 +pgusers 127.0.0.1/32 trust\n" = + { "1" + { "type" = "hostssl" } + { "database" = "db1" } + { "database" = "db2" } + { "database" = "db3" } + { "user" = "+pgusers" } + { "address" = "127.0.0.1/32" } + { "method" = "trust" } + } + + (* Test with comma-sparated user names *) + test Pg_Hba.lns get "hostnossl sameuser u1,u2,u3 127.0.0.1/32 trust\n" = + { "1" + { "type" = "hostnossl" } + { "database" = "sameuser" } + { "user" = "u1" } + { "user" = "u2" } + { "user" = "u3" } + { "address" = "127.0.0.1/32" } + { "method" = "trust" } + } + + (* Test with quoted database and user names *) + test Pg_Hba.lns get "host \"sameuser\" \"all\" 127.0.0.1/32 trust\n" = + { "1" + { "type" = "host" } + { "database" = "\"sameuser\"" } + { "user" = "\"all\"" } + { "address" = "127.0.0.1/32" } + { "method" = "trust" } + } + + (* Test with IP + netmask address format *) + test Pg_Hba.lns get "host all all 192.168.1.1 255.255.0.0 trust\n" = + { "1" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = "192.168.1.1 255.255.0.0" } + { "method" = "trust" } + } + + (* Test with fqdn as address *) + test Pg_Hba.lns get "host all all foo.example.com md5\n" = + { "1" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = "foo.example.com" } + { "method" = "md5" } + } + + (* Test with fqdn suffix as address *) + test Pg_Hba.lns get "host all all .example.com md5\n" = + { "1" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = ".example.com" } + { "method" = "md5" } + } + + (* Local types may not have and address *) + test Pg_Hba.lns get "local all all 127.0.0.1/32 trust\n" = * + + (* Remote types must have an address *) + test Pg_Hba.lns get "host all all trust\n" = * + + (* The space between the IP and the netmask must not be considered as a + column separator ("method" is missing here) *) + test Pg_Hba.lns get "host all all 192.168.1.1 255.255.0.0\n" = * + + (* Ticket #313: support authentication method options *) + test Pg_Hba.lns get "host all all .dev.example.com gss include_realm=0 krb_realm=EXAMPLE.COM map=somemap +host all all .dev.example.com ldap ldapserver=auth.example.com ldaptls=1 ldapprefix=\"uid=\" ldapsuffix=\",ou=people,dc=example,dc=com\"\n" = + { "1" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = ".dev.example.com" } + { "method" = "gss" + { "option" = "include_realm" + { "value" = "0" } } + { "option" = "krb_realm" + { "value" = "EXAMPLE.COM" } } + { "option" = "map" + { "value" = "somemap" } } } } + { "2" + { "type" = "host" } + { "database" = "all" } + { "user" = "all" } + { "address" = ".dev.example.com" } + { "method" = "ldap" + { "option" = "ldapserver" + { "value" = "auth.example.com" } } + { "option" = "ldaptls" + { "value" = "1" } } + { "option" = "ldapprefix" + { "value" = "uid=" } } + { "option" = "ldapsuffix" + { "value" = ",ou=people,dc=example,dc=com" } } } } + + (* Unsupported yet *) + (* test Pg_Hba.lns get "host \"db with spaces\" \"user with spaces\" 127.0.0.1/32 trust\n" =? *) + (* test Pg_Hba.lns get "host \"db,with,commas\" \"user,with,commas\" 127.0.0.1/32 trust\n" =? *) diff --git a/Sharp.Augeas.Test/lens/tests/test_pgbouncer.aug b/Sharp.Augeas.Test/lens/tests/test_pgbouncer.aug new file mode 100644 index 0000000..177dc6a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pgbouncer.aug @@ -0,0 +1,55 @@ +module Test_Pgbouncer = + let pgconfig =";; database name = connect string +;; +;; connect string params: +;; dbname= host= port= user= password= +[databases] +; foodb over unix socket +foodb = + +; redirect bardb to bazdb on localhost +bardb = host=localhost dbname=bazdb + +; acceess to dest database will go with single user +forcedb = host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO connect_query='SELECT 1' +[pgbouncer] +;;; Administrative settings +logfile = /var/log/pgbouncer/pgbouncer.log +pidfile = /var/run/pgbouncer/pgbouncer.pid +; ip address or * which means all ip-s +listen_addr = 127.0.0.1 +listen_port = 6432 +;auth_file = /8.0/main/global/pg_auth +auth_file = /var/lib/pgsql/data/global/pg_auth +admin_users = postgres +server_reset_query = DISCARD ALL +" + +test Pgbouncer.lns get pgconfig = + { "#comment" = "; database name = connect string" } + { "#comment" = ";" } + { "#comment" = "; connect string params:" } + { "#comment" = "; dbname= host= port= user= password=" } + { "databases" + { "#comment" = "foodb over unix socket" } + { "foodb" } + { } + { "#comment" = "redirect bardb to bazdb on localhost" } + { "bardb" = "host=localhost dbname=bazdb" } + { } + { "#comment" = "acceess to dest database will go with single user" } + { "forcedb" = "host=127.0.0.1 port=300 user=baz password=foo client_encoding=UNICODE datestyle=ISO connect_query='SELECT 1'" } + } + { "pgbouncer" + { "#comment" = ";; Administrative settings" } + { "logfile" = "/var/log/pgbouncer/pgbouncer.log" } + { "pidfile" = "/var/run/pgbouncer/pgbouncer.pid" } + { "#comment" = "ip address or * which means all ip-s" } + { "listen_addr" = "127.0.0.1" } + { "listen_port" = "6432" } + { "#comment" = "auth_file = /8.0/main/global/pg_auth" } + { "auth_file" = "/var/lib/pgsql/data/global/pg_auth" } + { "admin_users" = "postgres" } + { "server_reset_query" = "DISCARD ALL" } + } + \ No newline at end of file diff --git a/Sharp.Augeas.Test/lens/tests/test_php.aug b/Sharp.Augeas.Test/lens/tests/test_php.aug new file mode 100644 index 0000000..618f3ff --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_php.aug @@ -0,0 +1,61 @@ +module Test_php = + +let conf = " +safe_mode = Off +[PHP] +; Enable the PHP scripting language engine under Apache. +engine = On + +; Enable compatibility mode with Zend Engine 1 (PHP 4.x) +zend.ze1_compatibility_mode = Off + unserialize_callback_func= +date.default_latitude = 31.7667 + +[sqlite] +sqlite.assoc_case = 0 +" + + +test PHP.lns get conf = + { ".anon" + {} + { "safe_mode" = "Off" } } + { "PHP" + { "#comment" = "Enable the PHP scripting language engine under Apache." } + { "engine" = "On" } + {} + { "#comment" = "Enable compatibility mode with Zend Engine 1 (PHP 4.x)" } + { "zend.ze1_compatibility_mode" = "Off" } + { "unserialize_callback_func" } + { "date.default_latitude" = "31.7667" } + {} } + { "sqlite" + { "sqlite.assoc_case" = "0" } } + +test PHP.lns put conf after rm "noop" = conf + + +test PHP.lns get ";\n" = { ".anon" {} } + +(* Section titles can have spaces *) +test PHP.lns get "[mail function]\n" = { "mail function" } + +(* Keys can be lower and upper case *) +test PHP.lns get "[fake] +SMTP = localhost +mixed_KEY = 25 +" = + { "fake" + { "SMTP" = "localhost" } + { "mixed_KEY" = "25" } } + +(* Ticket #243 *) +test PHP.lns get "session.save_path = \"3;/var/lib/php5\"\n" = + { ".anon" + { "session.save_path" = "3;/var/lib/php5" } } + +(* GH issue #35 + php-fpm syntax *) +test PHP.lns get "php_admin_flag[log_errors] = on\n" = + { ".anon" + { "php_admin_flag[log_errors]" = "on" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_phpvars.aug b/Sharp.Augeas.Test/lens/tests/test_phpvars.aug new file mode 100644 index 0000000..e5590cf --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_phpvars.aug @@ -0,0 +1,72 @@ +module Test_phpvars = + +let conf = "<?pHp +/**/ +/** + * Multi line comment + * + */ + +/* One line comment */ + +// Inline comment +# Bash-style comment +global $version; +global $config_version; +$config_version = '1.4.0'; +$theme=array(); + +$theme[0]['NAME'] = 'Default'; // end-of line comment +$theme[0][\"PATH\"] = SM_PATH . 'themes/default_theme.php'; +$theme[0]['XPATH'] = '/some//x/path' ; +define ('MYVAR', ROOT . 'some value'); # end-of line comment +include_once( ROOT . \"/path/to/conf\" ); +include( ROOT . \"/path/to/conf\" ); +@include SM_PATH . 'config/config_local.php'; +class config { + var $tmppath = \"/tmp\"; + var $offline = 1; +} +?> +" + +test Phpvars.lns get conf = + { } + { "#mcomment" + { "1" = "*" } + { "2" = "* Multi line comment" } + { "3" = "*" } + } + { } + { "#mcomment" + { "1" = "One line comment" } + } + { } + { "#comment" = "Inline comment" } + { "#comment" = "Bash-style comment" } + { "global" = "version" } + { "global" = "config_version" } + { "$config_version" = "'1.4.0'" } + { "$theme" = "array()" } + { } + { "$theme" = "'Default'" + { "@arraykey" = "[0]['NAME']" } + { "#comment" = "end-of line comment" } } + { "$theme" = "SM_PATH . 'themes/default_theme.php'" + { "@arraykey" = "[0][\"PATH\"]" } + } + { "$theme" = "'/some//x/path'" + { "@arraykey" = "[0]['XPATH']" } + } + { "define" = "MYVAR" + { "value" = "ROOT . 'some value'" } + { "#comment" = "end-of line comment" } } + { "include_once" = "ROOT . \"/path/to/conf\"" } + { "include" = "ROOT . \"/path/to/conf\"" } + { "@include" = "SM_PATH . 'config/config_local.php'" } + { "config" + { } + {"$tmppath" = "\"/tmp\""} + {"$offline" = "1"} + } + { } diff --git a/Sharp.Augeas.Test/lens/tests/test_postfix_access.aug b/Sharp.Augeas.Test/lens/tests/test_postfix_access.aug new file mode 100644 index 0000000..e8b5872 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postfix_access.aug @@ -0,0 +1,53 @@ +(* Tests for the Postfix Access module *) + +module Test_postfix_access = + + let three_entries = "127.0.0.1 DISCARD You totally suck + Really +#ok no more comments +user@ REJECT +" + + test Postfix_access.record get "127.0.0.1 REJECT\n" = + { "1" { "pattern" = "127.0.0.1" } + { "action" = "REJECT" } } + + test Postfix_access.lns get three_entries = + { "1" { "pattern" = "127.0.0.1" } + { "action" = "DISCARD" } + { "parameters" = "You totally suck\n Really" } } + {"#comment" = "ok no more comments" } + { "2" { "pattern" = "user@" } + { "action" = "REJECT" } } + + test Postfix_access.record put "127.0.0.1 OK\n" after + set "/1/action" "REJECT" + = "127.0.0.1 REJECT\n" + + test Postfix_access.lns put three_entries after + set "/2/parameters" "Rejected you loser" ; + rm "/1/parameters" + = "127.0.0.1 DISCARD +#ok no more comments +user@ REJECT Rejected you loser +" + +(* Deleting the 'action' node violates the schema; each postfix access *) +(* entry must have one *) + test Postfix_access.lns put three_entries after + rm "/1/action" + = * + + (* Make sure blank lines get through *) + test Postfix_access.lns get "127.0.0.1\tREJECT \n \n\n +user@*\tOK\tI 'll let you in \n\tseriously\n" = + { "1" { "pattern" = "127.0.0.1" } + { "action" = "REJECT" } } + {} {} {} + { "2" { "pattern" = "user@*" } + { "action" = "OK" } + { "parameters" = "I 'll let you in \n\tseriously" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_postfix_main.aug b/Sharp.Augeas.Test/lens/tests/test_postfix_main.aug new file mode 100644 index 0000000..ef1f806 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postfix_main.aug @@ -0,0 +1,26 @@ +module Test_postfix_main = + +let conf = "# main.cf +myorigin = /etc/mailname + +smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +relayhost = +import_environment = + MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG TZ LANG=C \n KRB5CCNAME=FILE:${queue_directory}/kerberos/krb5_ccache\n" + +test Postfix_Main.lns get conf = + { "#comment" = "main.cf" } + { "myorigin" = "/etc/mailname" } + {} + { "smtpd_banner" = "$myhostname ESMTP $mail_name (Ubuntu)" } + { "mynetworks" = "127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128" } + { "relayhost" } + { "import_environment" = "MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG TZ LANG=C \n KRB5CCNAME=FILE:${queue_directory}/kerberos/krb5_ccache" } + +test Postfix_main.lns get "debugger_command = +\t PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin +\t ddd $daemon_directory/$process_name $process_id & sleep 5\n" + = + { "debugger_command" = "PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin + ddd $daemon_directory/$process_name $process_id & sleep 5" } diff --git a/Sharp.Augeas.Test/lens/tests/test_postfix_master.aug b/Sharp.Augeas.Test/lens/tests/test_postfix_master.aug new file mode 100644 index 0000000..356ce1b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postfix_master.aug @@ -0,0 +1,141 @@ +module Test_postfix_master = + +let conf = "# master.cf +smtp inet n - - 10? - smtpd +maildrop unix - n n - - pipe + flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} +" + +test Postfix_Master.lns get conf = + { "#comment" = "master.cf" } + { "smtp" + { "type" = "inet" } + { "private" = "n" } + { "unprivileged" = "-" } + { "chroot" = "-" } + { "wakeup" = "10?" } + { "limit" = "-" } + { "command" = "smtpd" } } + { "maildrop" + { "type" = "unix" } + { "private" = "-" } + { "unprivileged" = "n" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "-" } + { "command" = "pipe\n flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}" } } + +(* fixes bug #69 : accept double quotes in arguments *) +let conf2 = "# The Cyrus deliver program has changed incompatibly, multiple times. +cyrus unix - n n - - pipe + flags=R user=cyrus argv=/usr/sbin/cyrdeliver -e -m \"${extension}\" ${user} +" + +test Postfix_Master.lns get conf2 = + { "#comment" = "The Cyrus deliver program has changed incompatibly, multiple times." } + { "cyrus" + { "type" = "unix" } + { "private" = "-" } + { "unprivileged" = "n" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "-" } + { "command" = "pipe\n flags=R user=cyrus argv=/usr/sbin/cyrdeliver -e -m \"${extension}\" ${user}" } + } + +(* accept commas in arguments *) +let conf3 = "# master.cf +submission inet n - n - - smtpd + -o smtpd_client_restrictions=permit_sasl_authenticated,reject +" + +test Postfix_Master.lns get conf3 = + { "#comment" = "master.cf" } + { "submission" + { "type" = "inet" } + { "private" = "n" } + { "unprivileged" = "-" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "-" } + { "command" = "smtpd\n -o smtpd_client_restrictions=permit_sasl_authenticated,reject" } } + +(* : is allowed *) +let conf4 = "127.0.0.1:10060 inet n n n - 0 spawn + user=nobody argv=/usr/sbin/hapolicy -l --default=DEFER +" + +test Postfix_Master.lns get conf4 = + { "127.0.0.1:10060" + { "type" = "inet" } + { "private" = "n" } + { "unprivileged" = "n" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "0" } + { "command" = "spawn + user=nobody argv=/usr/sbin/hapolicy -l --default=DEFER" } + } + + +(* Spaces are allowed after the first word of the command *) +let conf5 = "sympa unix - n n - - pipe \n flags=R user=sympa argv=/home/sympa/bin/queue ${recipient} +" + +test Postfix_Master.lns get conf5 = + { "sympa" + { "type" = "unix" } + { "private" = "-" } + { "unprivileged" = "n" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "-" } + { "command" = "pipe \n flags=R user=sympa argv=/home/sympa/bin/queue ${recipient}" } + } + +(* Arobase is allowed in command *) +let conf6 = "sympafamilypfs unix - n n - - pipe + flags=R user=sympa argv=/home/sympa/bin/familyqueue ${user}@domain.net pfs +" +test Postfix_Master.lns get conf6 = + { "sympafamilypfs" + { "type" = "unix" } + { "private" = "-" } + { "unprivileged" = "n" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "-" } + { "command" = "pipe + flags=R user=sympa argv=/home/sympa/bin/familyqueue ${user}@domain.net pfs" } + } + +(* Ticket #345 *) +let conf7 = "# master.cf +submission inet n - n - - smtpd + -o mynetworks=127.0.0.1/8,[::1] +" + +test Postfix_Master.lns get conf7 = + { "#comment" = "master.cf" } + { "submission" + { "type" = "inet" } + { "private" = "n" } + { "unprivileged" = "-" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "-" } + { "command" = "smtpd\n -o mynetworks=127.0.0.1/8,[::1]" } } + +(* Ticket #635 *) +let conf8 = "postlog unix-dgram n - n - 1 postlogd\n" + +test Postfix_Master.lns get conf8 = + { "postlog" + { "type" = "unix-dgram" } + { "private" = "n" } + { "unprivileged" = "-" } + { "chroot" = "n" } + { "wakeup" = "-" } + { "limit" = "1" } + { "command" = "postlogd" } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_postfix_passwordmap.aug b/Sharp.Augeas.Test/lens/tests/test_postfix_passwordmap.aug new file mode 100644 index 0000000..4efd739 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postfix_passwordmap.aug @@ -0,0 +1,43 @@ +(* +Module: Test_Postfix_Passwordmap + Provides unit tests and examples for the <Postfix_Passwordmap> lens. +*) + +module Test_Postfix_Passwordmap = + +(* View: conf *) +let conf = "# comment +* username:password +[mail.isp.example] username:password +[mail.isp.example]:submission username:password +[mail.isp.example]:587 username:password +mail.isp.example username:password +user@mail.isp.example username: +mail.isp.example + username2:password2 +" + +(* Test: Postfix_Passwordmap.lns *) +test Postfix_Passwordmap.lns get conf = + { "#comment" = "comment" } + { "pattern" = "*" + { "username" = "username" } + { "password" = "password" } } + { "pattern" = "[mail.isp.example]" + { "username" = "username" } + { "password" = "password" } } + { "pattern" = "[mail.isp.example]:submission" + { "username" = "username" } + { "password" = "password" } } + { "pattern" = "[mail.isp.example]:587" + { "username" = "username" } + { "password" = "password" } } + { "pattern" = "mail.isp.example" + { "username" = "username" } + { "password" = "password" } } + { "pattern" = "user@mail.isp.example" + { "username" = "username" } + { "password" } } + { "pattern" = "mail.isp.example" + { "username" = "username2" } + { "password" = "password2" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_postfix_sasl_smtpd.aug b/Sharp.Augeas.Test/lens/tests/test_postfix_sasl_smtpd.aug new file mode 100644 index 0000000..231bc69 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postfix_sasl_smtpd.aug @@ -0,0 +1,19 @@ +module Test_Postfix_Sasl_Smtpd = + + + let conf = "pwcheck_method: auxprop saslauthd +auxprop_plugin: plesk +saslauthd_path: /private/plesk_saslauthd +mech_list: CRAM-MD5 PLAIN LOGIN +sql_engine: intentionally disabled +log_level: 4 +" + + + test Postfix_sasl_smtpd.lns get conf = + { "pwcheck_method" = "auxprop saslauthd" } + { "auxprop_plugin" = "plesk" } + { "saslauthd_path" = "/private/plesk_saslauthd" } + { "mech_list" = "CRAM-MD5 PLAIN LOGIN" } + { "sql_engine" = "intentionally disabled" } + { "log_level" = "4" } diff --git a/Sharp.Augeas.Test/lens/tests/test_postfix_transport.aug b/Sharp.Augeas.Test/lens/tests/test_postfix_transport.aug new file mode 100644 index 0000000..81fd9a9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postfix_transport.aug @@ -0,0 +1,58 @@ +(* +Module: Test_Postfix_Transport + Provides unit tests and examples for the <Postfix_Transport> lens. +*) + +module Test_Postfix_Transport = + +(* View: conf *) +let conf = "# a comment +the.backed-up.domain.tld relay:[their.mail.host.tld] +.my.domain : +* smtp:outbound-relay.my.domain +example.com uucp:example +example.com slow: +example.com :[gateway.example.com] +user.foo@example.com + smtp:bar.example:2025 +firstname_lastname@example.com discard: +.example.com error:mail for *.example.com is not deliverable +" + +(* Test: Postfix_Transport.lns *) +test Postfix_Transport.lns get conf = + { "#comment" = "a comment" } + { "pattern" = "the.backed-up.domain.tld" + { "transport" = "relay" } + { "nexthop" = "[their.mail.host.tld]" } } + { "pattern" = ".my.domain" + { "transport" } + { "nexthop" } } + { "pattern" = "*" + { "transport" = "smtp" } + { "nexthop" = "outbound-relay.my.domain" } } + { "pattern" = "example.com" + { "transport" = "uucp" } + { "nexthop" = "example" } } + { "pattern" = "example.com" + { "transport" = "slow" } + { "nexthop" } } + { "pattern" = "example.com" + { "transport" } + { "nexthop" = "[gateway.example.com]" } } + { "pattern" = "user.foo@example.com" + { "transport" = "smtp" } + { "nexthop" = "bar.example:2025" } } + { "pattern" = "firstname_lastname@example.com" + { "transport" = "discard" } + { "nexthop" } } + { "pattern" = ".example.com" + { "transport" = "error" } + { "nexthop" = "mail for *.example.com is not deliverable" } } + +(* Test: Postfix_Transport.lns + Bug #303 *) +test Postfix_Transport.lns get "user@example.com [12.34.56.78]:587\n" = + { "pattern" = "user@example.com" + { "host" = "[12.34.56.78]" } + { "port" = "587" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_postfix_virtual.aug b/Sharp.Augeas.Test/lens/tests/test_postfix_virtual.aug new file mode 100644 index 0000000..da33a4d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postfix_virtual.aug @@ -0,0 +1,50 @@ +(* +Module: Test_Postfix_Virtual + Provides unit tests and examples for the <Postfix_Virtual> lens. +*) + +module Test_Postfix_Virtual = + +(* View: conf *) +let conf = "# a comment +virtual-alias.domain anything +postmaster@virtual-alias.domain postmaster +user1@virtual-alias.domain address1 +user2@virtual-alias.domain + address2, + address3 +root robert.oot@domain.com +@example.net root,postmaster +postmaster mtaadmin+root=mta1 +some_user localuser +" + +(* Test: Postfix_Virtual.lns *) +test Postfix_Virtual.lns get conf = + { "#comment" = "a comment" } + { "pattern" = "virtual-alias.domain" + { "destination" = "anything" } + } + { "pattern" = "postmaster@virtual-alias.domain" + { "destination" = "postmaster" } + } + { "pattern" = "user1@virtual-alias.domain" + { "destination" = "address1" } + } + { "pattern" = "user2@virtual-alias.domain" + { "destination" = "address2" } + { "destination" = "address3" } + } + { "pattern" = "root" + { "destination" = "robert.oot@domain.com" } + } + { "pattern" = "@example.net" + { "destination" = "root" } + { "destination" = "postmaster" } + } + { "pattern" = "postmaster" + { "destination" = "mtaadmin+root=mta1" } + } + { "pattern" = "some_user" + { "destination" = "localuser" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_postgresql.aug b/Sharp.Augeas.Test/lens/tests/test_postgresql.aug new file mode 100644 index 0000000..a692850 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_postgresql.aug @@ -0,0 +1,248 @@ +(* +Module: Test_Postgresql + Provides unit tests and examples for the <Postgresql> lens. +*) + +module Test_Postgresql = + +(* "=" separator is optional *) +let missing_equal = "fsync on\n" +test Postgresql.lns get missing_equal = + { "fsync" = "on" } +test Postgresql.lns put missing_equal after + set "fsync" "off" = "fsync off\n" + +(* extra whitespace is valid anywhere *) +let extra_whitespace = " fsync = on # trailing comment \n" +test Postgresql.lns get extra_whitespace = + { "fsync" = "on" + { "#comment" = "trailing comment" } + } +test Postgresql.lns put extra_whitespace after + set "fsync" "off" = " fsync = off # trailing comment \n" + +(* no whitespace at all is also valid *) +let no_whitespace = "fsync=on\n" +test Postgresql.lns get no_whitespace = + { "fsync" = "on" } +test Postgresql.lns put no_whitespace after + set "fsync" "off" = "fsync=off\n" + +(* Some settings specify a memory or time value. [...] Valid memory units are + kB (kilobytes), MB (megabytes), and GB (gigabytes); valid time units are + ms (milliseconds), s (seconds), min (minutes), h (hours), and d (days). *) +let numeric_suffix_quotes = "shared_buffers = 24MB +archive_timeout = 2min +deadlock_timeout = '1s' +" +test Postgresql.lns get numeric_suffix_quotes = + { "shared_buffers" = "24MB" } + { "archive_timeout" = "2min" } + { "deadlock_timeout" = "1s" } +test Postgresql.lns put numeric_suffix_quotes after + set "deadlock_timeout" "2s"; + set "max_stack_depth" "2MB"; + set "shared_buffers" "48MB" = "shared_buffers = 48MB +archive_timeout = 2min +deadlock_timeout = '2s' +max_stack_depth = '2MB' +" + +(* floats and ints can be single quoted or not *) +let float_quotes = "seq_page_cost = 2.0 +random_page_cost = '4.0' +vacuum_freeze_min_age = 50000000 +vacuum_freeze_table_age = '150000000' +wal_buffers = -1 +" +test Postgresql.lns get float_quotes = + { "seq_page_cost" = "2.0" } + { "random_page_cost" = "4.0" } + { "vacuum_freeze_min_age" = "50000000" } + { "vacuum_freeze_table_age" = "150000000" } + { "wal_buffers" = "-1" } +test Postgresql.lns put float_quotes after + set "seq_page_cost" "5.0"; + set "vacuum_cost_limit" "200"; + set "bgwriter_lru_multiplier" "2.0"; + set "log_temp_files" "-1"; + set "wal_buffers" "1" = "seq_page_cost = 5.0 +random_page_cost = '4.0' +vacuum_freeze_min_age = 50000000 +vacuum_freeze_table_age = '150000000' +wal_buffers = 1 +vacuum_cost_limit = '200' +bgwriter_lru_multiplier = '2.0' +log_temp_files = '-1' +" + +(* Boolean values can be written as on, off, true, false, yes, no, 1, 0 (all + case-insensitive) or any unambiguous prefix of these. *) +let bool_quotes = "log_connections = yes +transform_null_equals = OFF +sql_inheritance = 'on' +synchronize_seqscans = 1 +standard_conforming_strings = fal +" +test Postgresql.lns get bool_quotes = + { "log_connections" = "yes" } + { "transform_null_equals" = "OFF" } + { "sql_inheritance" = "on" } + { "synchronize_seqscans" = "1" } + { "standard_conforming_strings" = "fal" } +test Postgresql.lns put bool_quotes after + set "sql_inheritance" "off"; + set "log_lock_waits" "off" = "log_connections = yes +transform_null_equals = OFF +sql_inheritance = 'off' +synchronize_seqscans = 1 +standard_conforming_strings = fal +log_lock_waits = 'off' +" + +(* Strings must be single-quoted, except if they have no special character *) +let string_quotes = "listen_addresses = 'localhost' +stats_temp_directory = pg_stat_tmp +lc_messages = 'en_US.UTF-8' +log_filename = log +archive_command = 'tar \'quoted option\'' +search_path = '\"$user\",public' +password_encryption = scram-sha-256 +" +test Postgresql.lns get string_quotes = + { "listen_addresses" = "localhost" } + { "stats_temp_directory" = "pg_stat_tmp" } + { "lc_messages" = "en_US.UTF-8" } + { "log_filename" = "log" } + { "archive_command" = "tar \'quoted option\'" } + { "search_path" = "\"$user\",public" } + { "password_encryption" = "scram-sha-256" } +test Postgresql.lns put string_quotes after + set "stats_temp_directory" "foo_bar"; + set "log_filename" "postgresql-%Y-%m-%d_%H%M%S.log"; + set "log_statement" "none" = "listen_addresses = 'localhost' +stats_temp_directory = foo_bar +lc_messages = 'en_US.UTF-8' +log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' +archive_command = 'tar \'quoted option\'' +search_path = '\"$user\",public' +password_encryption = scram-sha-256 +log_statement = 'none' +" + +(* external files can be included more than once *) +let include_keyword = "Include 'foo.conf' +# can appear several times +Include 'bar.conf' +" +test Postgresql.lns get include_keyword = + { "Include" = "foo.conf" } + { "#comment" = "can appear several times" } + { "Include" = "bar.conf" } + +(* Variable: conf + A full configuration file *) + let conf = "data_directory = '/var/lib/postgresql/8.4/main' # use data in another directory +hba_file = '/etc/postgresql/8.4/main/pg_hba.conf' # host-based authentication file +ident_file = '/etc/postgresql/8.4/main/pg_ident.conf' # ident configuration file + +# If external_pid_file is not explicitly set, no extra PID file is written. +external_pid_file = '/var/run/postgresql/8.4-main.pid' # write an extra PID file +listen_addresses = 'localhost' # what IP address(es) to listen on; +port = 5432 # (change requires restart) +max_connections = 100 # (change requires restart) +superuser_reserved_connections = 3 # (change requires restart) +unix_socket_directory = '/var/run/postgresql' # (change requires restart) +unix_socket_group = '' # (change requires restart) +unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +bonjour_name = '' # defaults to the computer name + +authentication_timeout = 1min # 1s-600s +ssl = true # (change requires restart) +ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers +ssl_renegotiation_limit = 512MB # amount of data between renegotiations +password_encryption = on +db_user_namespace = off + +search_path = '\"$user\",public' # schema names +default_tablespace = '' # a tablespace name, '' uses the default +temp_tablespaces = '' # a list of tablespace names, '' uses + +datestyle = 'iso, mdy' +intervalstyle = 'postgres' +timezone = unknown # actually, defaults to TZ environment +" + +(* Test: Postgresql.lns *) +test Postgresql.lns get conf = + { "data_directory" = "/var/lib/postgresql/8.4/main" + { "#comment" = "use data in another directory" } + } + { "hba_file" = "/etc/postgresql/8.4/main/pg_hba.conf" + { "#comment" = "host-based authentication file" } + } + { "ident_file" = "/etc/postgresql/8.4/main/pg_ident.conf" + { "#comment" = "ident configuration file" } + } + { } + { "#comment" = "If external_pid_file is not explicitly set, no extra PID file is written." } + { "external_pid_file" = "/var/run/postgresql/8.4-main.pid" + { "#comment" = "write an extra PID file" } + } + { "listen_addresses" = "localhost" + { "#comment" = "what IP address(es) to listen on;" } + } + { "port" = "5432" + { "#comment" = "(change requires restart)" } + } + { "max_connections" = "100" + { "#comment" = "(change requires restart)" } + } + { "superuser_reserved_connections" = "3" + { "#comment" = "(change requires restart)" } + } + { "unix_socket_directory" = "/var/run/postgresql" + { "#comment" = "(change requires restart)" } + } + { "unix_socket_group" = "" + { "#comment" = "(change requires restart)" } + } + { "unix_socket_permissions" = "0777" + { "#comment" = "begin with 0 to use octal notation" } + } + { "#comment" = "(change requires restart)" } + { "bonjour_name" = "" + { "#comment" = "defaults to the computer name" } + } + { } + { "authentication_timeout" = "1min" + { "#comment" = "1s-600s" } + } + { "ssl" = "true" + { "#comment" = "(change requires restart)" } + } + { "ssl_ciphers" = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" + { "#comment" = "allowed SSL ciphers" } + } + { "ssl_renegotiation_limit" = "512MB" + { "#comment" = "amount of data between renegotiations" } + } + { "password_encryption" = "on" } + { "db_user_namespace" = "off" } + { } + { "search_path" = "\"$user\",public" + { "#comment" = "schema names" } + } + { "default_tablespace" = "" + { "#comment" = "a tablespace name, '' uses the default" } + } + { "temp_tablespaces" = "" + { "#comment" = "a list of tablespace names, '' uses" } + } + { } + { "datestyle" = "iso, mdy" } + { "intervalstyle" = "postgres" } + { "timezone" = "unknown" + { "#comment" = "actually, defaults to TZ environment" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_properties.aug b/Sharp.Augeas.Test/lens/tests/test_properties.aug new file mode 100644 index 0000000..2b96ed2 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_properties.aug @@ -0,0 +1,175 @@ +module Test_properties = + let conf = " +# +# Test tomcat properties file +#tomcat.commented.value=1 + # config +tomcat.port = 8080 +tomcat.application.name=testapp + tomcat.application.description=my test application +property.with_underscore=works +empty.property= +empty.property.withtrailingspaces= \n! more comments +key: value +key2:value2 +key3 :value3 +key4:=value4 +key5\"=value5 +key6/c=value6 + +long.description=this is a description that happens to span \ + more than one line with a combination of tabs and \ + spaces \ \nor not + +# comment break + +short.break = a\ + b + +=empty_key + =empty_key + +cheeses + +spaces only +multi spaces + indented spaces + +\= =A +space and = equals +space with \ + multiline + +escaped\:colon=value +escaped\=equals=value +escaped\ space=value +" + +(* Other tests that aren't supported yet +overflow.description=\ + just wanted to indent it +*) + +let lns = Properties.lns + +test lns get conf = + { } { } + { "#comment" = "Test tomcat properties file" } + { "#comment" = "tomcat.commented.value=1" } + { "#comment" = "config" } + { "tomcat.port" = "8080" } + { "tomcat.application.name" = "testapp" } + { "tomcat.application.description" = "my test application" } + { "property.with_underscore" = "works" } + { "empty.property" } + { "empty.property.withtrailingspaces" } + { "!comment" = "more comments" } + { "key" = "value" } + { "key2" = "value2" } + { "key3" = "value3" } + { "key4" = "=value4" } + { "key5\"" = "value5" } + { "key6/c" = "value6" } + {} + { "long.description" = " < multi > " + { = "this is a description that happens to span " } + { = "more than one line with a combination of tabs and " } + { = "spaces " } + { = "or not" } + } + {} + { "#comment" = "comment break" } + {} + { "short.break" = " < multi > " + { = "a" } + { = "b" } + } + {} + { = "empty_key" } + { = "empty_key" } + {} + { "cheeses" } + {} + { "spaces" = "only" } + { "multi" = "spaces" } + { "indented" = "spaces" } + {} + { "\\=" = "A" } + { "space" = "and = equals" } + { "space" = " < multi > " + { = "with " } + { = "multiline" } + } + {} + { "escaped\:colon" = "value" } + { "escaped\=equals" = "value" } + { "escaped\ space" = "value" } +test lns put conf after + set "tomcat.port" "99"; + set "tomcat.application.host" "foo.network.com" + = " +# +# Test tomcat properties file +#tomcat.commented.value=1 + # config +tomcat.port = 99 +tomcat.application.name=testapp + tomcat.application.description=my test application +property.with_underscore=works +empty.property= +empty.property.withtrailingspaces= \n! more comments +key: value +key2:value2 +key3 :value3 +key4:=value4 +key5\"=value5 +key6/c=value6 + +long.description=this is a description that happens to span \ + more than one line with a combination of tabs and \ + spaces \ \nor not + +# comment break + +short.break = a\ + b + +=empty_key + =empty_key + +cheeses + +spaces only +multi spaces + indented spaces + +\= =A +space and = equals +space with \ + multiline + +escaped\:colon=value +escaped\=equals=value +escaped\ space=value +tomcat.application.host=foo.network.com +" + +(* GH issue #19: value on new line *) +test lns get "k=\ +b\ +c\n" = + { "k" = " < multi > " + { } { = "b" } { = "c" } } + +test lns get "tomcat.util.scan.DefaultJarScanner.jarsToSkip=\ +bootstrap.jar,commons-daemon.jar,tomcat-juli.jar\n" = + { "tomcat.util.scan.DefaultJarScanner.jarsToSkip" = " < multi > " + { } { = "bootstrap.jar,commons-daemon.jar,tomcat-juli.jar" } } + + +test lns get "# comment\r\na.b=val\r\nx=\r\n" = + { "#comment" = "comment" } + { "a.b" = "val" } + { "x" } + +test lns get "# \r\n! \r\n" = { } { } diff --git a/Sharp.Augeas.Test/lens/tests/test_protocols.aug b/Sharp.Augeas.Test/lens/tests/test_protocols.aug new file mode 100644 index 0000000..e9343a4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_protocols.aug @@ -0,0 +1,53 @@ +(* +Module: Test_Protocols + Provides unit tests and examples for the <Protocols> lens. +*) + +module Test_Protocols = + +(* Variable: conf *) +let conf = "# Internet (IP) protocols + +ip 0 IP # internet protocol, pseudo protocol number +#hopopt 0 HOPOPT # IPv6 Hop-by-Hop Option [RFC1883] +icmp 1 ICMP # internet control message protocol +igmp 2 IGMP # Internet Group Management +tp++ 39 TP++ # TP++ Transport Protocol +a/n 107 A/N # Active Networks +" + +(* Test: Protocols.lns *) +test Protocols.lns get conf = + { "#comment" = "Internet (IP) protocols" } + { } + { "1" + { "protocol" = "ip" } + { "number" = "0" } + { "alias" = "IP" } + { "#comment" = "internet protocol, pseudo protocol number" } + } + { "#comment" = "hopopt 0 HOPOPT # IPv6 Hop-by-Hop Option [RFC1883]" } + { "2" + { "protocol" = "icmp" } + { "number" = "1" } + { "alias" = "ICMP" } + { "#comment" = "internet control message protocol" } + } + { "3" + { "protocol" = "igmp" } + { "number" = "2" } + { "alias" = "IGMP" } + { "#comment" = "Internet Group Management" } + } + { "4" + { "protocol" = "tp++" } + { "number" = "39" } + { "alias" = "TP++" } + { "#comment" = "TP++ Transport Protocol" } + } + { "5" + { "protocol" = "a/n" } + { "number" = "107" } + { "alias" = "A/N" } + { "#comment" = "Active Networks" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_puppet.aug b/Sharp.Augeas.Test/lens/tests/test_puppet.aug new file mode 100644 index 0000000..a10ef01 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_puppet.aug @@ -0,0 +1,31 @@ +module Test_puppet = + + let conf = " +[main] +logdir=/var/log/puppet + + [puppetd] + server=misspiggy.network.com +" + + test Puppet.lns get conf = + {} + { "main" + { "logdir" = "/var/log/puppet" } + {} } + { "puppetd" + { "server" = "misspiggy.network.com" } } + + test Puppet.lns put conf after + set "main/vardir" "/var/lib/puppet"; + set "main/rundir" "/var/run/puppet" + = " +[main] +logdir=/var/log/puppet + +vardir=/var/lib/puppet +rundir=/var/run/puppet + [puppetd] + server=misspiggy.network.com +" + diff --git a/Sharp.Augeas.Test/lens/tests/test_puppet_auth.aug b/Sharp.Augeas.Test/lens/tests/test_puppet_auth.aug new file mode 100644 index 0000000..3adeedc --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_puppet_auth.aug @@ -0,0 +1,43 @@ +(* +Module: Test_Puppet_Auth + Provides unit tests and examples for the <Puppet_Auth> lens. +*) + +module Test_Puppet_Auth = + +(* Variable: full *) +let full = "path ~ ^/file_(metadata|content)/user_files/ +# Set environments +environment production, development +environment foo +method find, search +auth yes +method save + allow /^(.+\.)?example.com$/ + allow_ip 192.168.100.0/24 # Added in Puppet 3.0.0 +# This overrides the previous auth + authenticated any +" + +(* Test: Puppet_Auth.lns *) +test Puppet_Auth.lns get full = + { "path" = "^/file_(metadata|content)/user_files/" { "operator" = "~" } + { "#comment" = "Set environments" } + { "environment" + { "1" = "production" } + { "2" = "development" } } + { "environment" + { "3" = "foo" } } + { "method" + { "1" = "find" } + { "2" = "search" } } + { "auth" = "yes" } + { "method" + { "3" = "save" } } + { "allow" + { "1" = "/^(.+\.)?example.com$/" } } + { "allow_ip" + { "1" = "192.168.100.0/24" } + { "#comment" = "Added in Puppet 3.0.0" } } + { "#comment" = "This overrides the previous auth" } + { "auth" = "any" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_puppetfile.aug b/Sharp.Augeas.Test/lens/tests/test_puppetfile.aug new file mode 100644 index 0000000..dc46125 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_puppetfile.aug @@ -0,0 +1,158 @@ +(* +Module: Test_Puppetfile + Provides unit tests and examples for the <Puppetfile> lens. +*) +module Test_Puppetfile = + +(* Test: Puppetfile.lns *) +test Puppetfile.lns get "forge \"https://forgeapi.puppetlabs.com\" # the default forge + +mod 'puppetlabs-razor' +mod 'puppetlabs-ntp', \"0.0.3\" + +mod 'puppetlabs-apt', + :git => \"git://github.com/puppetlabs/puppetlabs-apt.git\" + +mod 'puppetlabs-stdlib', + :git => \"git://github.com/puppetlabs/puppetlabs-stdlib.git\" + +mod 'puppetlabs-apache', '0.6.0', + :github_tarball => 'puppetlabs/puppetlabs-apache' + +metadata # we want metadata\n" = + { "forge" = "https://forgeapi.puppetlabs.com" + { "#comment" = "the default forge" } } + { } + { "1" = "puppetlabs-razor" } + { "2" = "puppetlabs-ntp" + { "@version" = "0.0.3" } + } + { } + { "3" = "puppetlabs-apt" + { "git" = "git://github.com/puppetlabs/puppetlabs-apt.git" } + } + { } + { "4" = "puppetlabs-stdlib" + { "git" = "git://github.com/puppetlabs/puppetlabs-stdlib.git" } + } + { } + { "5" = "puppetlabs-apache" + { "@version" = "0.6.0" } + { "github_tarball" = "puppetlabs/puppetlabs-apache" } + } + { } + { "metadata" { "#comment" = "we want metadata" } } + +(* Test: Puppetfile.lns + Complex version conditions *) +test Puppetfile.lns get "mod 'puppetlabs/stdlib', '< 5.0.0' +mod 'theforeman/concat_native', '>= 1.3.0 < 1.4.0' +mod 'herculesteam/augeasproviders', '2.1.x'\n" = + { "1" = "puppetlabs/stdlib" + { "@version" = "< 5.0.0" } + } + { "2" = "theforeman/concat_native" + { "@version" = ">= 1.3.0 < 1.4.0" } + } + { "3" = "herculesteam/augeasproviders" + { "@version" = "2.1.x" } + } + +(* Test: Puppetfile.lns + Owner is not mandatory if git is given *) +test Puppetfile.lns get "mod 'stdlib', + :git => \"git://github.com/puppetlabs/puppetlabs-stdlib.git\"\n" = + { "1" = "stdlib" + { "git" = "git://github.com/puppetlabs/puppetlabs-stdlib.git" } } + + +(* Issue #427 *) +test Puppetfile.lns get "mod 'puppetlabs/apache', :latest\n" = + { "1" = "puppetlabs/apache" + { "latest" } } + +test Puppetfile.lns get "mod 'data', + :git => 'ssh://git@stash.example.com/bp/puppet-hiera.git', + :branch => :control_branch, + :default_branch => 'development', + :install_path => '.'\n" = + { "1" = "data" + { "git" = "ssh://git@stash.example.com/bp/puppet-hiera.git" } + { "branch" = ":control_branch" } + { "default_branch" = "development" } + { "install_path" = "." } } + +(* Comment: after module name comma + This conflicts with the comma comment tree below *) +test Puppetfile.lns get "mod 'data' # eol comment\n" = * + +(* Comment: after first comma *) +test Puppetfile.lns get "mod 'data', # eol comment + # and another + '1.2.3'\n" = + { "1" = "data" + { "#comment" = "eol comment" } + { "#comment" = "and another" } + { "@version" = "1.2.3" } } + +(* Comment: after version + Current culprit: need two \n *) +test Puppetfile.lns get "mod 'data', '1.2.3' # eol comment\n" = * +test Puppetfile.lns get "mod 'data', '1.2.3' # eol comment\n\n" = + { "1" = "data" + { "@version" = "1.2.3" { "#comment" = "eol comment" } } } + +(* Comment: eol after version comma *) +test Puppetfile.lns get "mod 'data', '1.2.3', # a comment + :local => true\n" = + { "1" = "data" + { "@version" = "1.2.3" } + { "#comment" = "a comment" } + { "local" = "true" } } + +(* Comment: after version comma with newline *) +test Puppetfile.lns get "mod 'data', '1.2.3', + # a comment + :local => true\n" = + { "1" = "data" + { "@version" = "1.2.3" } + { "#comment" = "a comment" } + { "local" = "true" } } + +(* Comment: eol before opts, without version *) +test Puppetfile.lns get "mod 'data', # a comment + # :ref => 'abcdef', + :local => true\n" = + { "1" = "data" + { "#comment" = "a comment" } + { "#comment" = ":ref => 'abcdef'," } + { "local" = "true" } } + +(* Comment: after opt comma *) +test Puppetfile.lns get "mod 'data', '1.2.3', + :ref => 'abcdef', # eol comment + :local => true\n" = + { "1" = "data" + { "@version" = "1.2.3" } + { "ref" = "abcdef" } + { "#comment" = "eol comment" } + { "local" = "true" } } + +(* Comment: in opts *) +test Puppetfile.lns get "mod 'data', '1.2.3', + :ref => 'abcdef', + # a comment + :local => true\n" = + { "1" = "data" + { "@version" = "1.2.3" } + { "ref" = "abcdef" } + { "#comment" = "a comment" } + { "local" = "true" } } + +(* Comment: after last opt *) +test Puppetfile.lns get "mod 'data', '1.2.3', + :local => true # eol comment\n\n" = + { "1" = "data" + { "@version" = "1.2.3" } + { "local" = "true" } + { "#comment" = "eol comment" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_puppetfileserver.aug b/Sharp.Augeas.Test/lens/tests/test_puppetfileserver.aug new file mode 100644 index 0000000..f299573 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_puppetfileserver.aug @@ -0,0 +1,42 @@ +(* Tests for the PuppetFileserver module *) + +module Test_puppetfileserver = + +let fileserver = "# This a comment + +[mount1] + # Mount1 options + path /etc/puppet/files/%h + allow host.domain1.com + allow *.domain2.com + deny badhost.domain2.com +[mount2] + allow * + deny *.evil.example.com + deny badhost.domain2.com +[mount3] +allow * # Puppet #6026: same line comment +# And trailing whitespace +allow * \n" + +test PuppetFileserver.lns get fileserver = + { "#comment" = "This a comment" } + { } + { "mount1" + { "#comment" = "Mount1 options" } + { "path" = "/etc/puppet/files/%h" } + { "allow" = "host.domain1.com" } + { "allow" = "*.domain2.com" } + { "deny" = "badhost.domain2.com" } + } + { "mount2" + { "allow" = "*" } + { "deny" = "*.evil.example.com" } + { "deny" = "badhost.domain2.com" } + } + { "mount3" + { "allow" = "*" + { "#comment" = "Puppet #6026: same line comment" } } + { "#comment" = "And trailing whitespace" } + { "allow" = "*" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_pylonspaste.aug b/Sharp.Augeas.Test/lens/tests/test_pylonspaste.aug new file mode 100644 index 0000000..1a324ff --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pylonspaste.aug @@ -0,0 +1,75 @@ +module Test_Pylonspaste = + let pylons_conf ="# baruwa - Pylons configuration +# The %(here)s variable will be replaced with the parent directory of this file +[uwsgi] +socket = /var/run/baruwa/baruwa.sock +processes = 5 +uid = baruwa +daemonize = /var/log/uwsgi/uwsgi-baruwa.log + +[server:main] +use = egg:Paste#http +host = 0.0.0.0 +port = 5000 + +[app:main] +use = egg:baruwa +full_stack = true +static_files = false +set debug = false + +[identifiers] +plugins = + form;browser + auth_tkt + +[authenticators] +plugins = + sa_auth + baruwa_pop3_auth + baruwa_imap_auth + baruwa_smtp_auth + baruwa_ldap_auth + baruwa_radius_auth +" + +test Pylonspaste.lns get pylons_conf = + { "#comment" = "baruwa - Pylons configuration" } + { "#comment" = "The %(here)s variable will be replaced with the parent directory of this file" } + { "uwsgi" + { "socket" = "/var/run/baruwa/baruwa.sock" } + { "processes" = "5" } + { "uid" = "baruwa" } + { "daemonize" = "/var/log/uwsgi/uwsgi-baruwa.log" } + { } + } + { "server:main" + { "use" = "egg:Paste#http" } + { "host" = "0.0.0.0" } + { "port" = "5000" } + { } + } + { "app:main" + { "use" = "egg:baruwa" } + { "full_stack" = "true" } + { "static_files" = "false" } + { "debug" = "false" } + { } + } + { "identifiers" + { "plugins" + { "1" = "form;browser" } + { "2" = "auth_tkt" } + } + {} + } + { "authenticators" + { "plugins" + { "1" = "sa_auth" } + { "2" = "baruwa_pop3_auth" } + { "3" = "baruwa_imap_auth" } + { "4" = "baruwa_smtp_auth" } + { "5" = "baruwa_ldap_auth" } + { "6" = "baruwa_radius_auth" } + } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_pythonpaste.aug b/Sharp.Augeas.Test/lens/tests/test_pythonpaste.aug new file mode 100644 index 0000000..fca7545 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_pythonpaste.aug @@ -0,0 +1,58 @@ +module Test_pythonpaste = + + let conf = " +#blah blah +[main] +pipeline = hello + +[composite:main] +use = egg:Paste#urlmap +/v2.0 = public_api +/: public_version_api +" + + test PythonPaste.lns get conf = + { } + { "#comment" = "blah blah" } + { "main" + { "pipeline" = "hello" } + { } + } + { "composite:main" + { "use" = "egg:Paste#urlmap" } + { "1" = "/v2.0 = public_api" } + { "2" = "/: public_version_api" } + } + + + test PythonPaste.lns put conf after + set "main/pipeline" "goodbye"; + set "composite:main/3" "/v3: a_new_api_version" + = " +#blah blah +[main] +pipeline = goodbye + +[composite:main] +use = egg:Paste#urlmap +/v2.0 = public_api +/: public_version_api +/v3: a_new_api_version +" + + (* Paste can define global config in DEFAULT, then override with "set" in sections, RHBZ#1175545 *) + test PythonPaste.lns get "[DEFAULT] +log_name = swift +log_facility = LOG_LOCAL1 + +[app:proxy-server] +use = egg:swift#proxy +set log_name = proxy-server\n" = + { "DEFAULT" + { "log_name" = "swift" } + { "log_facility" = "LOG_LOCAL1" } + { } } + { "app:proxy-server" + { "use" = "egg:swift#proxy" } + { "log_name" = "proxy-server" + { "@set" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_qpid.aug b/Sharp.Augeas.Test/lens/tests/test_qpid.aug new file mode 100644 index 0000000..4dc513d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_qpid.aug @@ -0,0 +1,48 @@ +(* +Module: Test_Qpid + Provides unit tests and examples for the <Qpid> lens. +*) + +module Test_Qpid = + +(* Variable: qpidd *) +let qpidd = "# Configuration file for qpidd. Entries are of the form: +# name=value + +# (Note: no spaces on either side of '='). Using default settings: +# \"qpidd --help\" or \"man qpidd\" for more details. +cluster-mechanism=ANONYMOUS +auth=no +max-connections=22000 +syslog-name=qpidd1 +" + +(* Test: Qpid.lns *) +test Qpid.lns get qpidd = + { "#comment" = "Configuration file for qpidd. Entries are of the form:" } + { "#comment" = "name=value" } + { } + { "#comment" = "(Note: no spaces on either side of '='). Using default settings:" } + { "#comment" = "\"qpidd --help\" or \"man qpidd\" for more details." } + { "cluster-mechanism" = "ANONYMOUS" } + { "auth" = "no" } + { "max-connections" = "22000" } + { "syslog-name" = "qpidd1" } + +(* Variable: qpidc *) +let qpidc = "# Configuration file for the qpid c++ client library. Entries are of +# the form: +# name=value + +ssl-cert-db=/root/certs/server_db +ssl-port=5674 +" + +(* Test: Qpid.lns *) +test Qpid.lns get qpidc = + { "#comment" = "Configuration file for the qpid c++ client library. Entries are of" } + { "#comment" = "the form:" } + { "#comment" = "name=value" } + { } + { "ssl-cert-db" = "/root/certs/server_db" } + { "ssl-port" = "5674" } diff --git a/Sharp.Augeas.Test/lens/tests/test_quote.aug b/Sharp.Augeas.Test/lens/tests/test_quote.aug new file mode 100644 index 0000000..411cdee --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_quote.aug @@ -0,0 +1,369 @@ +(* +Module: Test_Quote + Provides unit tests and examples for the <Quote> lens. +*) + +module Test_Quote = + +(* View: double *) +let double = [ label "double" . Quote.double ] + +(* Test: double *) +test double get "\" this is a test\"" = + { "double" = " this is a test" } + +(* View: double_opt *) +let double_opt = [ label "double_opt" . Quote.double_opt ] + +(* Test: double_opt *) +test double_opt get "\"this is a test\"" = + { "double_opt" = "this is a test" } + +(* Test: double_opt *) +test double_opt get "this is a test" = + { "double_opt" = "this is a test" } + +(* Test: double_opt + Value cannot start with a space *) +test double_opt get " this is a test" = * + +(* View: single *) +let single = [ label "single" . Quote.single ] + +(* Test: single *) +test single get "' this is a test'" = + { "single" = " this is a test" } + +(* View: single_opt *) +let single_opt = [ label "single_opt" . Quote.single_opt ] + +(* Test: single_opt *) +test single_opt get "'this is a test'" = + { "single_opt" = "this is a test" } + +(* Test: single_opt *) +test single_opt get "this is a test" = + { "single_opt" = "this is a test" } + +(* Test: single_opt + Value cannot start with a space *) +test single_opt get " this is a test" = * + +(* View: any *) +let any = [ label "any" . Quote.any ] + +(* Test: any *) +test any get "\" this is a test\"" = + { "any" = " this is a test" } + +(* Test: any *) +test any get "' this is a test'" = + { "any" = " this is a test" } + +(* View: any_opt *) +let any_opt = [ label "any_opt" . Quote.any_opt ] + +(* Test: any_opt *) +test any_opt get "\"this is a test\"" = + { "any_opt" = "this is a test" } + +(* Test: any_opt *) +test any_opt get "'this is a test'" = + { "any_opt" = "this is a test" } + +(* Test: any_opt *) +test any_opt get "this is a test" = + { "any_opt" = "this is a test" } + +(* Test: any_opt + Value cannot start with a space *) +test any_opt get " this is a test" = * + +(* View: double_opt_allow_spc *) +let double_opt_allow_spc = + let body = store /[^\n"]+/ in + [ label "double" . Quote.do_dquote_opt body ] + +(* Test: double_opt_allow_spc *) +test double_opt_allow_spc get " test with spaces " = + { "double" = " test with spaces " } + +(* Group: quote_spaces *) + +(* View: quote_spaces *) +let quote_spaces = + Quote.quote_spaces (label "spc") + +(* Test: quote_spaces + Unquoted value *) +test quote_spaces get "this" = + { "spc" = "this" } + +(* Test: quote_spaces + double quoted value *) +test quote_spaces get "\"this\"" = + { "spc" = "this" } + +(* Test: quote_spaces + single quoted value *) +test quote_spaces get "'this'" = + { "spc" = "this" } + +(* Test: quote_spaces + unquoted value with spaces *) +test quote_spaces get "this that those" = * + +(* Test: quote_spaces + double quoted value with spaces *) +test quote_spaces get "\"this that those\"" = + { "spc" = "this that those" } + +(* Test: quote_spaces + single quoted value with spaces *) +test quote_spaces get "'this that those'" = + { "spc" = "this that those" } + +(* Test: quote_spaces + remove spaces from double-quoted value *) +test quote_spaces put "\"this that those\"" + after set "spc" "thisthat" = + "\"thisthat\"" + +(* Test: quote_spaces + remove spaces from single-quoted value *) +test quote_spaces put "'this that those'" + after set "spc" "thisthat" = + "'thisthat'" + +(* Test: quote_spaces + add spaces to unquoted value *) +test quote_spaces put "this" + after set "spc" "this that those" = + "\"this that those\"" + +(* Test: quote_spaces + add spaces to double-quoted value *) +test quote_spaces put "\"this\"" + after set "spc" "this that those" = + "\"this that those\"" + +(* Test: quote_spaces + add spaces to single-quoted value *) +test quote_spaces put "'this'" + after set "spc" "this that those" = + "'this that those'" + +(* Group: dquote_spaces *) + +(* View: dquote_spaces *) +let dquote_spaces = + Quote.dquote_spaces (label "spc") + +(* Test: dquote_spaces + Unquoted value *) +test dquote_spaces get "this" = + { "spc" = "this" } + +(* Test: dquote_spaces + double quoted value *) +test dquote_spaces get "\"this\"" = + { "spc" = "this" } + +(* Test: dquote_spaces + single quoted value *) +test dquote_spaces get "'this'" = + { "spc" = "'this'" } + +(* Test: dquote_spaces + unquoted value with spaces *) +test dquote_spaces get "this that those" = * + +(* Test: dquote_spaces + double quoted value with spaces *) +test dquote_spaces get "\"this that those\"" = + { "spc" = "this that those" } + +(* Test: dquote_spaces + single quoted value with spaces *) +test dquote_spaces get "'this that those'" = * + +(* Test: dquote_spaces + remove spaces from double-quoted value *) +test dquote_spaces put "\"this that those\"" + after set "spc" "thisthat" = + "\"thisthat\"" + +(* Test: dquote_spaces + add spaces to unquoted value *) +test dquote_spaces put "this" + after set "spc" "this that those" = + "\"this that those\"" + +(* Test: dquote_spaces + add spaces to double-quoted value *) +test dquote_spaces put "\"this\"" + after set "spc" "this that those" = + "\"this that those\"" + +(* Test: dquote_spaces + add spaces to single-quoted value *) +test dquote_spaces put "'this'" + after set "spc" "this that those" = + "\"this that those\"" + +(* Group: squote_spaces *) + +(* View: squote_spaces *) +let squote_spaces = + Quote.squote_spaces (label "spc") + +(* Test: squote_spaces + Unquoted value *) +test squote_spaces get "this" = + { "spc" = "this" } + +(* Test: squote_spaces + double quoted value *) +test squote_spaces get "\"this\"" = + { "spc" = "\"this\"" } + +(* Test: squote_spaces + single quoted value *) +test squote_spaces get "'this'" = + { "spc" = "this" } + +(* Test: squote_spaces + unquoted value with spaces *) +test squote_spaces get "this that those" = * + +(* Test: squote_spaces + double quoted value with spaces *) +test squote_spaces get "\"this that those\"" = * + +(* Test: squote_spaces + single quoted value with spaces *) +test squote_spaces get "'this that those'" = + { "spc" = "this that those" } + +(* Test: squote_spaces + remove spaces from single-quoted value *) +test squote_spaces put "'this that those'" + after set "spc" "thisthat" = + "'thisthat'" + +(* Test: squote_spaces + add spaces to unquoted value *) +test squote_spaces put "this" + after set "spc" "this that those" = + "'this that those'" + +(* Test: squote_spaces + add spaces to double-quoted value *) +test squote_spaces put "\"this\"" + after set "spc" "this that those" = + "'this that those'" + +(* Test: squote_spaces + add spaces to single-quoted value *) +test squote_spaces put "'this'" + after set "spc" "this that those" = + "'this that those'" + +(* Group: nil cases *) + +(* View: dquote_opt_nil *) +let dquote_opt_nil = + let body = store Quote.double_opt_re + in [ label "dquote_opt_nil" . Quote.do_dquote_opt_nil body ]? + +(* Test: dquote_opt_nil *) +test dquote_opt_nil get "this" = + { "dquote_opt_nil" = "this" } + +(* Test: dquote_opt_nil *) +test dquote_opt_nil get "'this'" = + { "dquote_opt_nil" = "'this'" } + +(* Test: dquote_opt_nil *) +test dquote_opt_nil get "\"this\"" = + { "dquote_opt_nil" = "this" } + +(* Test: dquote_opt_nil *) +test dquote_opt_nil put "" + after set "dquote_opt_nil" "this" = + "this" + +(* Test: dquote_opt_nil *) +test dquote_opt_nil put "\"this\"" + after set "dquote_opt_nil" "this" = + "\"this\"" + +(* Test: dquote_opt_nil *) +test dquote_opt_nil put "'this'" + after set "dquote_opt_nil" "this" = + "this" + +(* View: squote_opt_nil *) +let squote_opt_nil = + let body = store Quote.single_opt_re + in [ label "squote_opt_nil" . Quote.do_squote_opt_nil body ]? + +(* Test: squote_opt_nil *) +test squote_opt_nil get "this" = + { "squote_opt_nil" = "this" } + +(* Test: squote_opt_nil *) +test squote_opt_nil get "'this'" = + { "squote_opt_nil" = "this" } + +(* Test: squote_opt_nil *) +test squote_opt_nil get "\"this\"" = + { "squote_opt_nil" = "\"this\"" } + +(* Test: squote_opt_nil *) +test squote_opt_nil put "" + after set "squote_opt_nil" "this" = + "this" + +(* Test: squote_opt_nil *) +test squote_opt_nil put "\"this\"" + after set "squote_opt_nil" "this" = + "this" + +(* Test: squote_opt_nil *) +test squote_opt_nil put "\"this\"" + after set "squote_opt_nil" "this" = + "this" + +(* View: quote_opt_nil *) +let quote_opt_nil = + let body = store Quote.any_opt_re + in [ label "quote_opt_nil" . Quote.do_quote_opt_nil body ]? + +(* Test: quote_opt_nil *) +test quote_opt_nil get "this" = + { "quote_opt_nil" = "this" } + +(* Test: quote_opt_nil *) +test quote_opt_nil get "'this'" = + { "quote_opt_nil" = "this" } + +(* Test: quote_opt_nil *) +test quote_opt_nil get "\"this\"" = + { "quote_opt_nil" = "this" } + +(* Test: quote_opt_nil *) +test quote_opt_nil put "" + after set "quote_opt_nil" "this" = + "this" + +(* Test: quote_opt_nil *) +test quote_opt_nil put "\"this\"" + after set "quote_opt_nil" "this" = + "\"this\"" + +(* Test: quote_opt_nil *) +test quote_opt_nil put "'this'" + after set "quote_opt_nil" "this" = + "'this'" + diff --git a/Sharp.Augeas.Test/lens/tests/test_rabbitmq.aug b/Sharp.Augeas.Test/lens/tests/test_rabbitmq.aug new file mode 100644 index 0000000..8a01541 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rabbitmq.aug @@ -0,0 +1,112 @@ +(* +Module: Test_Rabbitmq + Provides unit tests and examples for the <Rabbitmq> lens. +*) +module Test_Rabbitmq = + +(* Test: Rabbitmq.listeners *) +test Rabbitmq.listeners get "{ssl_listeners, [5671, {\"127.0.0.1\", 5672}]}" = + { "ssl_listeners" + { "value" = "5671" } + { "tuple" + { "value" = "127.0.0.1" } + { "value" = "5672" } } } + +(* Test: Rabbitmq.ssl_options *) +test Rabbitmq.ssl_options get "{ssl_options, [ + {cacertfile,\"/path/to/testca/cacert.pem\"}, + {certfile,\"/path/to/server/cert.pem\"}, + {keyfile,\"/path/to/server/key.pem\"}, + {verify,verify_peer}, + {versions, ['tlsv1.2', 'tlsv1.1', 'tlsv1']}, + {fail_if_no_peer_cert,false}]}" = + { "ssl_options" + { "cacertfile" = "/path/to/testca/cacert.pem" } + { "certfile" = "/path/to/server/cert.pem" } + { "keyfile" = "/path/to/server/key.pem" } + { "verify" = "verify_peer" } + { "versions" + { "value" = "tlsv1.2" } + { "value" = "tlsv1.1" } + { "value" = "tlsv1" } } + { "fail_if_no_peer_cert" = "false" } } + +(* Test: Rabbitmq.disk_free_limit *) +test Rabbitmq.disk_free_limit get "{disk_free_limit, 1000000000}" = + { "disk_free_limit" = "1000000000" } + +(* Test: Rabbitmq.disk_free_limit *) +test Rabbitmq.disk_free_limit get "{disk_free_limit, {mem_relative, 1.0}}" = + { "disk_free_limit" + { "tuple" + { "value" = "mem_relative" } + { "value" = "1.0" } } } + +(* Test: Rabbitmq.log_levels *) +test Rabbitmq.log_levels get "{log_levels, [{connection, info}]}" = + { "log_levels" + { "tuple" + { "value" = "connection" } + { "value" = "info" } } } + +(* Test: Rabbitmq.cluster_nodes *) +test Rabbitmq.cluster_nodes get "{cluster_nodes, {['rabbit@rabbit1', 'rabbit@rabbit2', 'rabbit@rabbit3'], disc}}" = + { "cluster_nodes" + { "tuple" + { "value" + { "value" = "rabbit@rabbit1" } + { "value" = "rabbit@rabbit2" } + { "value" = "rabbit@rabbit3" } } + { "value" = "disc" } } } + +(* Test: Rabbitmq.cluster_nodes + Apparently, tuples are not mandatory *) +test Rabbitmq.cluster_nodes get "{cluster_nodes, ['rabbit@rabbit1', 'rabbit@rabbit2', 'rabbit@rabbit3']}" = + { "cluster_nodes" + { "value" = "rabbit@rabbit1" } + { "value" = "rabbit@rabbit2" } + { "value" = "rabbit@rabbit3" } } + +(* Test: Rabbitmq.cluster_partition_handling, single value *) +test Rabbitmq.cluster_partition_handling get "{cluster_partition_handling, ignore}" = + { "cluster_partition_handling" = "ignore" } + +(* Test: Rabbitmq.cluster_partition_handling, tuple *) +test Rabbitmq.cluster_partition_handling get "{cluster_partition_handling, {pause_if_all_down, ['rabbit@rabbit1', 'rabbit@rabbit2', 'rabbit@rabbit3'], autoheal}}" = + { "cluster_partition_handling" + { "tuple" + { "value" = "pause_if_all_down" } + { "value" + { "value" = "rabbit@rabbit1" } + { "value" = "rabbit@rabbit2" } + { "value" = "rabbit@rabbit3" } } + { "value" = "autoheal" } } } + +(* Test: Rabbitmq.lns + Top-level test *) +test Rabbitmq.lns get " +% A standard configuration +[ + {rabbit, [ + {ssl_listeners, [5671]}, + {ssl_options, [{cacertfile,\"/path/to/testca/cacert.pem\"}, + {certfile,\"/path/to/server/cert.pem\"}, + {keyfile,\"/path/to/server/key.pem\"}, + {verify,verify_peer}, + {fail_if_no_peer_cert,false}]} + ]} +]. +% EOF\n" = + { } + { "#comment" = "A standard configuration" } + { "rabbit" + { "ssl_listeners" + { "value" = "5671" } } + { "ssl_options" + { "cacertfile" = "/path/to/testca/cacert.pem" } + { "certfile" = "/path/to/server/cert.pem" } + { "keyfile" = "/path/to/server/key.pem" } + { "verify" = "verify_peer" } + { "fail_if_no_peer_cert" = "false" } } } + { "#comment" = "EOF" } + diff --git a/Sharp.Augeas.Test/lens/tests/test_radicale.aug b/Sharp.Augeas.Test/lens/tests/test_radicale.aug new file mode 100644 index 0000000..83beb70 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_radicale.aug @@ -0,0 +1,77 @@ +module Test_radicale = + + let conf = " +[server] + +[encoding] + +[well-known] + +[auth] + +[git] + +[rights] + +[storage] + +[logging] + +[headers] + +" + + test Radicale.lns get conf = + {} + { "server" + {} } + { "encoding" + {} } + { "well-known" + {} } + { "auth" + {} } + { "git" + {} } + { "rights" + {} } + { "storage" + {} } + { "logging" + {} } + { "headers" + {} } + + test Radicale.lns put conf after + set "server/hosts" "127.0.0.1:5232, [::1]:5232"; + set "server/base_prefix" "/radicale/"; + set "well-known/caldav" "/radicale/%(user)s/caldav/"; + set "well-known/cardav" "/radicale/%(user)s/carddav/"; + set "auth/type" "remote_user"; + set "rights/type" "owner_only" + = " +[server] + +hosts=127.0.0.1:5232, [::1]:5232 +base_prefix=/radicale/ +[encoding] + +[well-known] + +caldav=/radicale/%(user)s/caldav/ +cardav=/radicale/%(user)s/carddav/ +[auth] + +type=remote_user +[git] + +[rights] + +type=owner_only +[storage] + +[logging] + +[headers] + +" diff --git a/Sharp.Augeas.Test/lens/tests/test_rancid.aug b/Sharp.Augeas.Test/lens/tests/test_rancid.aug new file mode 100644 index 0000000..884c974 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rancid.aug @@ -0,0 +1,30 @@ +module Test_rancid = + +(* Examples from router.db(5) *) +let rancid = "dial1.paris;cisco;up +core1.paris;cisco;down;in testing until 5/5/2001. +core2.paris;cisco;ticketed;Ticket 6054234, 5/3/2001 +border1.paris;juniper;up; +" + +test Rancid.lns get rancid = + { "device" = "dial1.paris" + { "type" = "cisco" } + { "state" = "up" } + } + { "device" = "core1.paris" + { "type" = "cisco" } + { "state" = "down" } + { "comment" = "in testing until 5/5/2001." } + } + { "device" = "core2.paris" + { "type" = "cisco" } + { "state" = "ticketed" } + { "comment" = "Ticket 6054234, 5/3/2001" } + } + { "device" = "border1.paris" + { "type" = "juniper" } + { "state" = "up" } + { "comment" = "" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_redis.aug b/Sharp.Augeas.Test/lens/tests/test_redis.aug new file mode 100644 index 0000000..01a519d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_redis.aug @@ -0,0 +1,264 @@ +(* +Module: Test_Redis + Provides unit tests and examples for the <Redis> lens. +*) + +module Test_Redis = + +let standard_entry = "dir /var/lib/redis\n" +test Redis.lns get standard_entry = { "dir" = "/var/lib/redis" } + +let double_quoted_entry = "dir \"/var/lib/redis\"\n" +test Redis.lns get double_quoted_entry = { "dir" = "/var/lib/redis" } + +let single_quoted_entry = "dir '/var/lib/redis'\n" +test Redis.lns get single_quoted_entry = { "dir" = "/var/lib/redis" } + +let extra_whitespace_entry = " dir /var/lib/redis \n" +test Redis.lns get extra_whitespace_entry = { "dir" = "/var/lib/redis" } + +let save_entry = "save 60 10000\n" +test Redis.lns get save_entry = +{ "save" + { "seconds" = "60" } + { "keys" = "10000" } +} + +let save_entry_quotes = "save '60' \"10000\"\n" +test Redis.lns get save_entry_quotes = +{ "save" + { "seconds" = "60" } + { "keys" = "10000" } +} + +let replicaof_entry = "slaveof 192.168.0.10 6379\nreplicaof 192.168.0.11 6380\n" +test Redis.lns get replicaof_entry = +{ "slaveof" + { "ip" = "192.168.0.10" } + { "port" = "6379" } } +{ "replicaof" + { "ip" = "192.168.0.11" } + { "port" = "6380" } } + +let rename_command_entry = "rename-command CONFIG CONFIG2\n" +test Redis.lns get rename_command_entry = +{ "rename-command" + { "from" = "CONFIG" } + { "to" = "CONFIG2" } +} + +let client_output_buffer_limit_entry_1 = "client-output-buffer-limit normal 0 0 0\n" +test Redis.lns get client_output_buffer_limit_entry_1 = +{ "client-output-buffer-limit" + { "class" = "normal" } + { "hard_limit" = "0" } + { "soft_limit" = "0" } + { "soft_seconds" = "0" } +} + +let client_output_buffer_limit_entry_2 = "client-output-buffer-limit slave 256mb 64mb 60\n" +test Redis.lns get client_output_buffer_limit_entry_2 = +{ "client-output-buffer-limit" + { "class" = "slave" } + { "hard_limit" = "256mb" } + { "soft_limit" = "64mb" } + { "soft_seconds" = "60" } +} + +let include_entry = "include /foo/redis.conf\ninclude /bar/redis.conf\n" +test Redis.lns get include_entry = +{ "include" = "/foo/redis.conf" } +{ "include" = "/bar/redis.conf" } + +let standard_comment = "# a comment\n" +test Redis.lns get standard_comment = { "#comment" = "a comment" } + +let extra_whitespace_comment = " # another comment \n" +test Redis.lns get extra_whitespace_comment = { "#comment" = "another comment" } + +let redis_conf = "# Redis configuration file example + +# Note on units: when memory size is needed, it is possible to specify +# it in the usual form of 1k 5GB 4M and so forth: +# +# 1k => 1000 bytes +# 1kb => 1024 bytes +# 1m => 1000000 bytes +# 1mb => 1024*1024 bytes +# 1g => 1000000000 bytes +# 1gb => 1024*1024*1024 bytes +# +# units are case insensitive so 1GB 1Gb 1gB are all the same. + +# By default Redis does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +daemonize yes + +# When running daemonized, Redis writes a pid file in /var/run/redis.pid by +# default. You can specify a custom pid file location here. +pidfile /var/run/redis/redis-server.pid + +# Accept connections on the specified port, default is 6379. +# If port 0 is specified Redis will not listen on a TCP socket. +port 6379 + +# If you want you can bind a single interface, if the bind option is not +# specified all the interfaces will listen for incoming connections. +# +bind 127.0.0.1 + +# Note: you can disable saving at all commenting all the \"save\" lines. + +save 900 1 +save 300 10 +save 60 10000 + +# Include one or more other config files here. This is useful if you +# have a standard template that goes to all redis server but also need +# to customize a few per-server settings. Include files can include +# other files, so use this wisely. +# +include /path/to/local.conf +include /path/to/other.conf +" + +test Redis.lns get redis_conf = + { "#comment" = "Redis configuration file example" } + { } + { "#comment" = "Note on units: when memory size is needed, it is possible to specify" } + { "#comment" = "it in the usual form of 1k 5GB 4M and so forth:" } + { } + { "#comment" = "1k => 1000 bytes" } + { "#comment" = "1kb => 1024 bytes" } + { "#comment" = "1m => 1000000 bytes" } + { "#comment" = "1mb => 1024*1024 bytes" } + { "#comment" = "1g => 1000000000 bytes" } + { "#comment" = "1gb => 1024*1024*1024 bytes" } + { } + { "#comment" = "units are case insensitive so 1GB 1Gb 1gB are all the same." } + { } + { "#comment" = "By default Redis does not run as a daemon. Use 'yes' if you need it." } + { "#comment" = "Note that Redis will write a pid file in /var/run/redis.pid when daemonized." } + { "daemonize" = "yes" } + { } + { "#comment" = "When running daemonized, Redis writes a pid file in /var/run/redis.pid by" } + { "#comment" = "default. You can specify a custom pid file location here." } + { "pidfile" = "/var/run/redis/redis-server.pid" } + { } + { "#comment" = "Accept connections on the specified port, default is 6379." } + { "#comment" = "If port 0 is specified Redis will not listen on a TCP socket." } + { "port" = "6379" } + { } + { "#comment" = "If you want you can bind a single interface, if the bind option is not" } + { "#comment" = "specified all the interfaces will listen for incoming connections." } + { } + { "bind" { "ip" = "127.0.0.1" } } + { } + { "#comment" = "Note: you can disable saving at all commenting all the \"save\" lines." } + { } + { "save" + { "seconds" = "900" } + { "keys" = "1" } + } + { "save" + { "seconds" = "300" } + { "keys" = "10" } + } + { "save" + { "seconds" = "60" } + { "keys" = "10000" } + } + { } + { "#comment" = "Include one or more other config files here. This is useful if you" } + { "#comment" = "have a standard template that goes to all redis server but also need" } + { "#comment" = "to customize a few per-server settings. Include files can include" } + { "#comment" = "other files, so use this wisely." } + { } + { "include" = "/path/to/local.conf" } + { "include" = "/path/to/other.conf" } + +(* Test: Redis.lns + Empty value (GH issue #115) *) +test Redis.lns get "notify-keyspace-events \"\"\n" = + { "notify-keyspace-events" = "" } + +(* Test: Redis.lns + Multiple bind IP addresses (GH issue #194) *) +test Redis.lns get "bind 127.0.0.1 \"::1\" 192.168.1.1\n" = + { "bind" + { "ip" = "127.0.0.1" } + { "ip" = "::1" } + { "ip" = "192.168.1.1" } } + +test Redis.lns get "bind 127.0.0.1\n bind 192.168.1.1\n" = + { "bind" + { "ip" = "127.0.0.1" } } + { "bind" + { "ip" = "192.168.1.1" } } + +let sentinel_conf = "sentinel myid ccae7d051dfaa62078cb3ac3dec100240e637d5a +sentinel deny-scripts-reconfig yes +sentinel monitor Master 8.8.8.8 6379 2 +sentinel monitor Othercluster 1.1.1.1 6380 4 +sentinel config-epoch Master 693 +sentinel leader-epoch Master 691 +sentinel known-replica Master 4.4.4.4 6379 +sentinel known-replica Master 1.1.1.1 6379 +sentinel known-sentinel Master 4.4.4.4 26379 9bbd89f3846b5366f7da4d20b516fdc3f5c3a993 +sentinel known-sentinel Master 1.1.1.1 26379 f435adae0efeb9d5841712d05d7399f7584f333b +sentinel known-sentinel Othercluster 4.4.4.4 26379 9bbd89f3846b5366f7da4d20b516fdc3f5c3a993 +sentinel known-sentinel Othercluster 1.1.1.1 26379 f435adae0efeb9d5841712d05d7399f7584f333b +sentinel current-epoch 693 +" + +test Redis.lns get sentinel_conf = + { "sentinel" = "myid" + { "value" = "ccae7d051dfaa62078cb3ac3dec100240e637d5a" } } + { "sentinel" = "deny-scripts-reconfig" + { "value" = "yes" } } + { "sentinel" = "monitor" + { "cluster" = "Master" } + { "ip" = "8.8.8.8" } + { "port" = "6379" } + { "quorum" = "2" } } + { "sentinel" = "monitor" + { "cluster" = "Othercluster" } + { "ip" = "1.1.1.1" } + { "port" = "6380" } + { "quorum" = "4" } } + { "sentinel" = "config-epoch" + { "cluster" = "Master" } + { "epoch" = "693" } } + { "sentinel" = "leader-epoch" + { "cluster" = "Master" } + { "epoch" = "691" } } + { "sentinel" = "known-replica" + { "cluster" = "Master" } + { "ip" = "4.4.4.4" } + { "port" = "6379" } } + { "sentinel" = "known-replica" + { "cluster" = "Master" } + { "ip" = "1.1.1.1" } + { "port" = "6379" } } + { "sentinel" = "known-sentinel" + { "cluster" = "Master" } + { "ip" = "4.4.4.4" } + { "port" = "26379" } + { "id" = "9bbd89f3846b5366f7da4d20b516fdc3f5c3a993" } } + { "sentinel" = "known-sentinel" + { "cluster" = "Master" } + { "ip" = "1.1.1.1" } + { "port" = "26379" } + { "id" = "f435adae0efeb9d5841712d05d7399f7584f333b" } } + { "sentinel" = "known-sentinel" + { "cluster" = "Othercluster" } + { "ip" = "4.4.4.4" } + { "port" = "26379" } + { "id" = "9bbd89f3846b5366f7da4d20b516fdc3f5c3a993" } } + { "sentinel" = "known-sentinel" + { "cluster" = "Othercluster" } + { "ip" = "1.1.1.1" } + { "port" = "26379" } + { "id" = "f435adae0efeb9d5841712d05d7399f7584f333b" } } + { "sentinel" = "current-epoch" + { "value" = "693" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_reprepro_uploaders.aug b/Sharp.Augeas.Test/lens/tests/test_reprepro_uploaders.aug new file mode 100644 index 0000000..14d6c16 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_reprepro_uploaders.aug @@ -0,0 +1,166 @@ +(* +Module: Test_Reprepro_Uploaders + Provides unit tests and examples for the <Reprepro_Uploaders> lens. +*) + +module Test_Reprepro_Uploaders = + +(* Test: Reprepro_Uploaders.entry + A star condition gets mapped as direct value + of the "allow" node. + *) +test Reprepro_Uploaders.entry get + "allow * by anybody\n" = + + { "allow" = "*" + { "by" = "anybody" } } + +(* Test: Reprepro_Uploaders.entry + For simple keys, the "by" node gets the value "key" + and the key ID gets mapped in a "key" subnode. + *) +test Reprepro_Uploaders.entry get + "allow * by key ABCD1234\n" = + + { "allow" = "*" + { "by" = "key" + { "key" = "ABCD1234" } } } + +(* Test: Reprepro_Uploaders.entry + Conditions are mapped inside a tree containing + at least an "and" node and an "or" subnode. + + The value of each "or" subnode is the type of check + (e.g. "source"), and this node contains "or" subnodes + with the value(s) allowed for the check (e.g. "bash"). *) +test Reprepro_Uploaders.entry get + "allow source 'bash' by anybody\n" = + + { "allow" + { "and" + { "or" = "source" + { "or" = "bash" } } } + { "by" = "anybody" } } + +(* Test: Reprepro_Uploaders.entry + Check the field distribution *) +test Reprepro_Uploaders.entry get + "allow distribution 'sid' by anybody\n" = + + { "allow" + { "and" + { "or" = "distribution" + { "or" = "sid" } } } + { "by" = "anybody" } } + +(* Test: Reprepro_Uploaders.entry + Some checks use the "contain" keyword to loosen the condition. + In that case, a "contain" subnode is added. Be sure to check for it + to know how the condition has to be checked. + *) +test Reprepro_Uploaders.entry get + "allow source 'bash' and binaries contain 'bash-doc' by anybody\n" = + + { "allow" + { "and" + { "or" = "source" + { "or" = "bash" } } } + { "and" + { "or" = "binaries" + { "contain" } + { "or" = "bash-doc" } } } + { "by" = "anybody" } } + +(* Test: Reprepro_Uploaders.entry + Some checks support multiple values, separated by '|'. + In this case, each value gets added to an "or" subnode. + *) +test Reprepro_Uploaders.entry get + + "allow sections 'main'|'restricted' and source 'bash' or binaries contain 'bash-doc' by anybody\n" = + + { "allow" + { "and" + { "or" = "sections" + { "or" = "main" } + { "or" = "restricted" } } } + { "and" + { "or" = "source" + { "or" = "bash" } } + { "or" = "binaries" + { "contain" } + { "or" = "bash-doc" } } } + { "by" = "anybody" } } + +(* Test: Reprepro_Uploaders.entry + Negated conditions are mapped with a "not" subnode. *) +test Reprepro_Uploaders.entry get + + "allow not source 'bash' by anybody\n" = + + { "allow" + { "and" + { "or" = "source" + { "not" } + { "or" = "bash" } } } + { "by" = "anybody" } } + + + +(* Variable: conf + A full configuration *) +let conf = "# ftpmaster +allow * by key 74BF771E + +allow sections 'desktop/*' by anybody +allow sections 'gforge/*' and binaries contain 'bzr' or not source '*melanie*'|'katya' by any key +" + +(* Test: Reprepro_Uploaders.lns + Testing the full <conf> against <Reprepro_Uploaders.lns> *) +test Reprepro_Uploaders.lns get conf = + { "#comment" = "ftpmaster" } + { "allow" = "*" + { "by" = "key" + { "key" = "74BF771E" } } } + { } + { "allow" + { "and" { "or" = "sections" { "or" = "desktop/*" } } } + { "by" = "anybody" } } + { "allow" + { "and" { "or" = "sections" { "or" = "gforge/*" } } } + { "and" { "or" = "binaries" { "contain" } { "or" = "bzr" } } + { "or" = "source" { "not" } { "or" = "*melanie*" } { "or" = "katya" } } } + { "by" = "key" + { "key" = "any" } } } + +(* Test: Reprepro_Uploaders.lns + Support group conditions, GH #283 *) +test Reprepro_Uploaders.lns get "allow sections 'desktop/*' by group groupname\n" = + { "allow" + { "and" { "or" = "sections" { "or" = "desktop/*" } } } + { "by" = "group" { "group" = "groupname" } } } + +(* Test: Reprepro_Uploaders.lns + Declare group condition, GH #283 *) +test Reprepro_Uploaders.lns get "group groupname add key-id\n" = + { "group" = "groupname" + { "add" = "key-id" } } + +(* Test: Reprepro_Uploaders.lns + Group inheritance, GH #283 *) +test Reprepro_Uploaders.lns get "group groupname contains group2\n" = + { "group" = "groupname" + { "contains" = "group2" } } + +(* Test: Reprepro_Uploaders.lns + Empty group, GH #283 *) +test Reprepro_Uploaders.lns get "group groupname empty\n" = + { "group" = "groupname" + { "empty" } } + +(* Test: Reprepro_Uploaders.lns + Unused group, GH #283 *) +test Reprepro_Uploaders.lns get "group groupname unused\n" = + { "group" = "groupname" + { "unused" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_resolv.aug b/Sharp.Augeas.Test/lens/tests/test_resolv.aug new file mode 100644 index 0000000..1f81634 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_resolv.aug @@ -0,0 +1,59 @@ +module Test_resolv = + + let conf = "# Sample resolv.conf +; With multiple comment styles +nameserver 192.168.0.3 # and EOL comments +nameserver ff02::1 +domain mynet.com # and EOL comments +search mynet.com anotherorg.net + +# A sortlist now +sortlist 130.155.160.0/255.255.240.0 130.155.0.0 + +options ndots:3 debug timeout:2 +options no-ip6-dotint single-request-reopen # and EOL comments + +lookup file bind +family inet6 inet4 +" + +test Resolv.lns get conf = + { "#comment" = "Sample resolv.conf" } + { "#comment" = "With multiple comment styles" } + { "nameserver" = "192.168.0.3" + { "#comment" = "and EOL comments" } } + { "nameserver" = "ff02::1" } + { "domain" = "mynet.com" + { "#comment" = "and EOL comments" } } + { "search" + { "domain" = "mynet.com" } + { "domain" = "anotherorg.net" } } + {} + { "#comment" = "A sortlist now" } + { "sortlist" + { "ipaddr" = "130.155.160.0" + { "netmask" = "255.255.240.0" } } + { "ipaddr" = "130.155.0.0" } } + {} + { "options" + { "ndots" = "3" } + { "debug" } + { "timeout" = "2" } } + { "options" + { "ip6-dotint" + { "negate" } } + { "single-request-reopen" } + { "#comment" = "and EOL comments" } } + {} + { "lookup" + { "file" } + { "bind" } } + { "family" + { "inet6" } + { "inet4" } } + +test Resolv.ip6_dotint + put "ip6-dotint" + after set "/ip6-dotint/negate" "" = "no-ip6-dotint" + +test Resolv.lns get "; \r\n; \t \n" = { } { } diff --git a/Sharp.Augeas.Test/lens/tests/test_rhsm.aug b/Sharp.Augeas.Test/lens/tests/test_rhsm.aug new file mode 100644 index 0000000..219a5be --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rhsm.aug @@ -0,0 +1,151 @@ +(* +Module: Test_Rhsm + Provides unit tests and examples for the <Rhsm> lens. +*) + +module Test_rhsm = + + (* Variable: conf + A full rhsm.conf *) + let conf = "# Red Hat Subscription Manager Configuration File: + +# Unified Entitlement Platform Configuration +[server] +# Server hostname: +hostname = subscription.rhn.redhat.com + +# Server prefix: +prefix = /subscription + +# Server port: +port = 443 + +# Set to 1 to disable certificate validation: +insecure = 0 + +# Set the depth of certs which should be checked +# when validating a certificate +ssl_verify_depth = 3 + +# an http proxy server to use +proxy_hostname = + +# port for http proxy server +proxy_port = + +# user name for authenticating to an http proxy, if needed +proxy_user = + +# password for basic http proxy auth, if needed +proxy_password = + +[rhsm] +# Content base URL: +baseurl= https://cdn.redhat.com + +# Server CA certificate location: +ca_cert_dir = /etc/rhsm/ca/ + +# Default CA cert to use when generating yum repo configs: +repo_ca_cert = %(ca_cert_dir)sredhat-uep.pem + +# Where the certificates should be stored +productCertDir = /etc/pki/product +entitlementCertDir = /etc/pki/entitlement +consumerCertDir = /etc/pki/consumer + +# Manage generation of yum repositories for subscribed content: +manage_repos = 1 + +# Refresh repo files with server overrides on every yum command +full_refresh_on_yum = 0 + +# If set to zero, the client will not report the package profile to +# the subscription management service. +report_package_profile = 1 + +# The directory to search for subscription manager plugins +pluginDir = /usr/share/rhsm-plugins + +# The directory to search for plugin configuration files +pluginConfDir = /etc/rhsm/pluginconf.d + +[rhsmcertd] +# Interval to run cert check (in minutes): +certCheckInterval = 240 +# Interval to run auto-attach (in minutes): +autoAttachInterval = 1440 +" + + test Rhsm.lns get conf = + { "#comment" = "Red Hat Subscription Manager Configuration File:" } + { } + { "#comment" = "Unified Entitlement Platform Configuration" } + { "server" + { "#comment" = "Server hostname:" } + { "hostname" = "subscription.rhn.redhat.com" } + { } + { "#comment" = "Server prefix:" } + { "prefix" = "/subscription" } + { } + { "#comment" = "Server port:" } + { "port" = "443" } + { } + { "#comment" = "Set to 1 to disable certificate validation:" } + { "insecure" = "0" } + { } + { "#comment" = "Set the depth of certs which should be checked" } + { "#comment" = "when validating a certificate" } + { "ssl_verify_depth" = "3" } + { } + { "#comment" = "an http proxy server to use" } + { "proxy_hostname" } + { } + { "#comment" = "port for http proxy server" } + { "proxy_port" } + { } + { "#comment" = "user name for authenticating to an http proxy, if needed" } + { "proxy_user" } + { } + { "#comment" = "password for basic http proxy auth, if needed" } + { "proxy_password" } + { } + } + { "rhsm" + { "#comment" = "Content base URL:" } + { "baseurl" = "https://cdn.redhat.com" } + { } + { "#comment" = "Server CA certificate location:" } + { "ca_cert_dir" = "/etc/rhsm/ca/" } + { } + { "#comment" = "Default CA cert to use when generating yum repo configs:" } + { "repo_ca_cert" = "%(ca_cert_dir)sredhat-uep.pem" } + { } + { "#comment" = "Where the certificates should be stored" } + { "productCertDir" = "/etc/pki/product" } + { "entitlementCertDir" = "/etc/pki/entitlement" } + { "consumerCertDir" = "/etc/pki/consumer" } + { } + { "#comment" = "Manage generation of yum repositories for subscribed content:" } + { "manage_repos" = "1" } + { } + { "#comment" = "Refresh repo files with server overrides on every yum command" } + { "full_refresh_on_yum" = "0" } + { } + { "#comment" = "If set to zero, the client will not report the package profile to" } + { "#comment" = "the subscription management service." } + { "report_package_profile" = "1" } + { } + { "#comment" = "The directory to search for subscription manager plugins" } + { "pluginDir" = "/usr/share/rhsm-plugins" } + { } + { "#comment" = "The directory to search for plugin configuration files" } + { "pluginConfDir" = "/etc/rhsm/pluginconf.d" } + { } + } + { "rhsmcertd" + { "#comment" = "Interval to run cert check (in minutes):" } + { "certCheckInterval" = "240" } + { "#comment" = "Interval to run auto-attach (in minutes):" } + { "autoAttachInterval" = "1440" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_rmt.aug b/Sharp.Augeas.Test/lens/tests/test_rmt.aug new file mode 100644 index 0000000..4bb7d68 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rmt.aug @@ -0,0 +1,38 @@ +module Test_rmt = + +let conf = "#ident @(#)rmt.dfl 1.2 05/08/09 Copyr 2000 J. Schilling +# +# This file is /etc/default/rmt + +DEBUG=/tmp/RMT +USER=* + +ACCESS=rtape sparky /dev/rmt/* +ACCESS=* * /dev/rmt/* + +# Historically, Red Hat rmt was not so ^^ restrictive. +ACCESS=* * * +" + +test Rmt.lns get conf = + { "#comment" = "ident @(#)rmt.dfl 1.2 05/08/09 Copyr 2000 J. Schilling" } + { } + { "#comment" = "This file is /etc/default/rmt" } + { } + { "DEBUG" = "/tmp/RMT" } + { "USER" = "*" } + { } + { "ACCESS" + { "name" = "rtape" } + { "host" = "sparky" } + { "path" = "/dev/rmt/*" } } + { "ACCESS" + { "name" = "*" } + { "host" = "*" } + { "path" = "/dev/rmt/*" } } + { } + { "#comment" = "Historically, Red Hat rmt was not so ^^ restrictive." } + { "ACCESS" + { "name" = "*" } + { "host" = "*" } + { "path" = "*" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_rsyncd.aug b/Sharp.Augeas.Test/lens/tests/test_rsyncd.aug new file mode 100644 index 0000000..4484320 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rsyncd.aug @@ -0,0 +1,56 @@ +module Test_rsyncd = + + let conf = " +# A more sophisticated example would be: + +uid = nobody + gid = nobody +use chroot = yes +max connections = 4 +syslog facility = local5 +pid file = /var/run/rsyncd.pid + +[ftp] + # this is a comment + path = /var/ftp/./pub + comment = whole ftp area (approx 6.1 GB) + + [cvs] + ; comment with semicolon + path = /data/cvs + comment = CVS repository (requires authentication) + auth users = tridge, susan # comment at EOL + secrets file = /etc/rsyncd.secrets + +" + + test Rsyncd.lns get conf = + { ".anon" + {} + { "#comment" = "A more sophisticated example would be:" } + {} + { "uid" = "nobody" } + { "gid" = "nobody" } + { "use chroot" = "yes" } + { "max connections" = "4" } + { "syslog facility" = "local5" } + { "pid file" = "/var/run/rsyncd.pid" } + {} + } + { "ftp" + { "#comment" = "this is a comment" } + { "path" = "/var/ftp/./pub" } + { "comment" = "whole ftp area (approx 6.1 GB)" } + {} + } + { "cvs" + { "#comment" = "comment with semicolon" } + { "path" = "/data/cvs" } + { "comment" = "CVS repository (requires authentication)" } + { "auth users" = "tridge, susan" + { "#comment" = "comment at EOL" } + } + { "secrets file" = "/etc/rsyncd.secrets" } + {} + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_rsyslog.aug b/Sharp.Augeas.Test/lens/tests/test_rsyslog.aug new file mode 100644 index 0000000..e83613a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rsyslog.aug @@ -0,0 +1,261 @@ +(* +Module: Test_Rsyslog + Provides unit tests and examples for the <Rsyslog> lens. +*) + +module Test_Rsyslog = + +(* Variable: conf *) +let conf = "# rsyslog v5 configuration file + +$ModLoad imuxsock # provides support for local system logging (e.g. via logger command) +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +module(load=\"immark\" markmessageperiod=\"60\" fakeoption=\"bar\") #provides --MARK-- message capability + +timezone(id=\"CET\" offset=\"+01:00\") + +$UDPServerRun 514 +$InputTCPServerRun 514 +$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat +$ActionFileEnableSync on +$IncludeConfig /etc/rsyslog.d/*.conf + +*.info;mail.none;authpriv.none;cron.none /var/log/messages +authpriv.* /var/log/secure +*.emerg * +*.* @2.7.4.1 +*.* @@2.7.4.1 +*.emerg :omusrmsg:* +*.emerg :omusrmsg:foo,bar +*.emerg | /dev/xconsole +" + +(* Test: Rsyslog.lns *) +test Rsyslog.lns get conf = + { "#comment" = "rsyslog v5 configuration file" } + { } + { "$ModLoad" = "imuxsock" + { "#comment" = "provides support for local system logging (e.g. via logger command)" } + } + { "$ModLoad" = "imklog" + { "#comment" = "provides kernel logging support (previously done by rklogd)" } + } + { "module" + { "load" = "immark" } + { "markmessageperiod" = "60" } + { "fakeoption" = "bar" } + { "#comment" = "provides --MARK-- message capability" } + } + { } + { "timezone" + { "id" = "CET" } + { "offset" = "+01:00" } + } + { } + { "$UDPServerRun" = "514" } + { "$InputTCPServerRun" = "514" } + { "$ActionFileDefaultTemplate" = "RSYSLOG_TraditionalFileFormat" } + { "$ActionFileEnableSync" = "on" } + { "$IncludeConfig" = "/etc/rsyslog.d/*.conf" } + { } + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "info" } + } + { "selector" + { "facility" = "mail" } + { "level" = "none" } + } + { "selector" + { "facility" = "authpriv" } + { "level" = "none" } + } + { "selector" + { "facility" = "cron" } + { "level" = "none" } + } + { "action" + { "file" = "/var/log/messages" } + } + } + { "entry" + { "selector" + { "facility" = "authpriv" } + { "level" = "*" } + } + { "action" + { "file" = "/var/log/secure" } + } + } + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "emerg" } + } + { "action" + { "user" = "*" } + } + } + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "*" } + } + { "action" + { "protocol" = "@" } + { "hostname" = "2.7.4.1" } + } + } + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "*" } + } + { "action" + { "protocol" = "@@" } + { "hostname" = "2.7.4.1" } + } + } + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "emerg" } + } + { "action" + { "omusrmsg" = "*" } + } + } + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "emerg" } + } + { "action" + { "omusrmsg" = "foo" } + { "omusrmsg" = "bar" } } + } + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "emerg" } + } + { "action" + { "pipe" = "/dev/xconsole" } + } + } + +(* Parse complex $template lines, RHBZ#1083016 *) +test Rsyslog.lns get "$template SpiceTmpl,\"%TIMESTAMP%.%TIMESTAMP:::date-subseconds% %syslogtag% %syslogseverity-text%:%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\\n\"\n" = + { "$template" = "SpiceTmpl,\"%TIMESTAMP%.%TIMESTAMP:::date-subseconds% %syslogtag% %syslogseverity-text%:%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\\n\"" } + +(* Parse property-based filters, RHBZ#1083016 *) +test Rsyslog.lns get ":programname, startswith, \"spice-vdagent\" /var/log/spice-vdagent.log;SpiceTmpl\n" = + { "filter" + { "property" = "programname" } + { "operation" = "startswith" } + { "value" = "spice-vdagent" } + { "action" + { "file" = "/var/log/spice-vdagent.log" } + { "template" = "SpiceTmpl" } } } + +test Rsyslog.lns get ":msg, !contains, \"error\" /var/log/noterror.log\n" = + { "filter" + { "property" = "msg" } + { "operation" = "!contains" } + { "value" = "error" } + { "action" + { "file" = "/var/log/noterror.log" } } } + +test Rsyslog.lns get ":msg,!contains,\"garbage\" ~\n" = + { "filter" + { "property" = "msg" } + { "operation" = "!contains" } + { "value" = "garbage" } + { "action" + { "discard" } } } + +test Rsyslog.lns put "" after + set "/module[1]/load" "imuxsock" + = "module(load=\"imuxsock\")\n" + +test Rsyslog.lns put "" after + set "/module[1]/load" "imuxsock" ; + set "/module[1]/SysSock.RateLimit.Interval" "0" + = "module(load=\"imuxsock\" SysSock.RateLimit.Interval=\"0\")\n" + +test Rsyslog.lns put "" after + set "/module[1]/load" "imuxsock" ; + set "/module[1]/SysSock.RateLimit.Interval" "0" ; + set "/module[1]/SysSock.RateLimit.Burst" "1" + = "module(load=\"imuxsock\" SysSock.RateLimit.Interval=\"0\" SysSock.RateLimit.Burst=\"1\")\n" + +(* On Fedora 26, there are comments in module statements *) +test Rsyslog.lns get "module(load=\"imuxsock\" # provides support for local system logging (e.g. via logger command) + SysSock.Use=\"off\") # Turn off message reception via local log socket; + # local messages are retrieved through imjournal now.\n" = + { "module" + { "load" = "imuxsock" } + { "SysSock.Use" = "off" } + { "#comment" = "Turn off message reception via local log socket;" } } + { "#comment" = "local messages are retrieved through imjournal now." } + +(* rsyslog doesn't use bsd-like #! or #+/- specifications *) +test Rsyslog.lns get "#!prog\n" = { "#comment" = "!prog" } +test Rsyslog.lns get "#+host\n" = { "#comment" = "+host" } +test Rsyslog.lns get "#-host\n" = { "#comment" = "-host" } + +(* Added in rsyslog 8.33 *) +test Rsyslog.lns get "include(file=\"/etc/rsyslog.d/*.conf\" mode=\"optional\")\n" = + { "include" + { "file" = "/etc/rsyslog.d/*.conf" } + { "mode" = "optional" } } + +(* Dynamic file name template *) +test Rsyslog.lns get "*.* ?DynamicFile\n" = + { "entry" + { "selector" + { "facility" = "*" } + { "level" = "*" } + } + { "action" + { "dynamic" = "DynamicFile" } + } + } + +(* Multiple actions in filters and selectors *) +test Rsyslog.lns get ":msg, startswith, \"iptables:\" -/var/log/iptables.log +& ~ +# Save boot messages also to boot.log +local7.* /var/log/boot.log +local3.err /var/log/nfsen/nfsenlog +& /var/log/also.log +\n" = + { "filter" + { "property" = "msg" } + { "operation" = "startswith" } + { "value" = "iptables:" } + { "action" + { "no_sync" } + { "file" = "/var/log/iptables.log" } } + { "action" + { "discard" } } + } + { "#comment" = "Save boot messages also to boot.log" } + { "entry" + { "selector" + { "facility" = "local7" } + { "level" = "*" } } + { "action" + { "file" = "/var/log/boot.log" } } + } + { "entry" + { "selector" + { "facility" = "local3" } + { "level" = "err" } } + { "action" + { "file" = "/var/log/nfsen/nfsenlog" } } + { "action" + { "file" = "/var/log/also.log" } } } + { } + diff --git a/Sharp.Augeas.Test/lens/tests/test_rtadvd.aug b/Sharp.Augeas.Test/lens/tests/test_rtadvd.aug new file mode 100644 index 0000000..da32216 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rtadvd.aug @@ -0,0 +1,30 @@ +module Test_rtadvd = + +(* Example from rtadvd.conf(5) *) +let rtadvd_conf = "default:\\ + :chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\ + :pinfoflags=\"la\":vltime#2592000:pltime#604800:mtu#0: +ef0:\\ + :addr=\"2001:db8:ffff:1000::\":prefixlen#64:tc=default: +" + +test Rtadvd.lns get rtadvd_conf = + { "record" + { "name" = "default" } + { "capability" = "chlim#64" } + { "capability" = "raflags#0" } + { "capability" = "rltime#1800" } + { "capability" = "rtime#0" } + { "capability" = "retrans#0" } + { "capability" = "pinfoflags=\"la\"" } + { "capability" = "vltime#2592000" } + { "capability" = "pltime#604800" } + { "capability" = "mtu#0" } + } + { "record" + { "name" = "ef0" } + { "capability" = "addr=\"2001:db8:ffff:1000::\"" } + { "capability" = "prefixlen#64" } + { "capability" = "tc=default" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_rx.aug b/Sharp.Augeas.Test/lens/tests/test_rx.aug new file mode 100644 index 0000000..4e7c4d3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_rx.aug @@ -0,0 +1,70 @@ +module Test_rx = + +let sto_ipv4 = [ label "IP" . store Rx.ipv4 ] + +test sto_ipv4 get "192.168.0.1" = { "IP" = "192.168.0.1" } +test sto_ipv4 get "255.255.255.254" = { "IP" = "255.255.255.254" } + +let sto_ipv6 = [ label "IP" . store Rx.ipv6 ] +test sto_ipv6 get "fe80::215:f2ff:fea4:b8d9" = { "IP" = "fe80::215:f2ff:fea4:b8d9" } + +let sto_ip = [ label "IP" . store Rx.ip ] + +test sto_ip get "192.168.0.1" = { "IP" = "192.168.0.1" } +test sto_ip get "255.255.255.254" = { "IP" = "255.255.255.254" } +test sto_ip get "fe80::215:f2ff:fea4:b8d9" = { "IP" = "fe80::215:f2ff:fea4:b8d9" } + +(* iso_8601 *) +let iso_8601 = [ label "date" . store Rx.iso_8601 ] + +test iso_8601 get "2009-12T12:34" = { "date" = "2009-12T12:34" } +test iso_8601 get "2009" = { "date" = "2009" } +test iso_8601 get "2009-05-19" = { "date" = "2009-05-19" } +test iso_8601 get "2009-05-19" = { "date" = "2009-05-19" } +test iso_8601 get "20090519" = { "date" = "20090519" } +test iso_8601 get "2009123" = { "date" = "2009123" } +test iso_8601 get "2009-05" = { "date" = "2009-05" } +test iso_8601 get "2009-123" = { "date" = "2009-123" } +test iso_8601 get "2009-222" = { "date" = "2009-222" } +test iso_8601 get "2009-001" = { "date" = "2009-001" } +test iso_8601 get "2009-W01-1" = { "date" = "2009-W01-1" } +test iso_8601 get "2009-W51-1" = { "date" = "2009-W51-1" } +test iso_8601 get "2009-W511" = { "date" = "2009-W511" } +test iso_8601 get "2009-W33" = { "date" = "2009-W33" } +test iso_8601 get "2009W511" = { "date" = "2009W511" } +test iso_8601 get "2009-05-19" = { "date" = "2009-05-19" } +test iso_8601 get "2009-05-19 00:00" = { "date" = "2009-05-19 00:00" } +test iso_8601 get "2009-05-19 14" = { "date" = "2009-05-19 14" } +test iso_8601 get "2009-05-19 14:31" = { "date" = "2009-05-19 14:31" } +test iso_8601 get "2009-05-19 14:39:22" = { "date" = "2009-05-19 14:39:22" } +test iso_8601 get "2009-05-19T14:39Z" = { "date" = "2009-05-19T14:39Z" } +test iso_8601 get "2009-W21-2" = { "date" = "2009-W21-2" } +test iso_8601 get "2009-W21-2T01:22" = { "date" = "2009-W21-2T01:22" } +test iso_8601 get "2009-139" = { "date" = "2009-139" } +test iso_8601 get "2009-05-19 14:39:22-06:00" = { "date" = "2009-05-19 14:39:22-06:00" } +test iso_8601 get "2009-05-19 14:39:22+0600" = { "date" = "2009-05-19 14:39:22+0600" } +test iso_8601 get "2009-05-19 14:39:22-01" = { "date" = "2009-05-19 14:39:22-01" } +test iso_8601 get "20090621T0545Z" = { "date" = "20090621T0545Z" } +test iso_8601 get "2007-04-06T00:00" = { "date" = "2007-04-06T00:00" } +test iso_8601 get "2007-04-05T24:00" = { "date" = "2007-04-05T24:00" } +test iso_8601 get "2010-02-18T16:23:48.5" = { "date" = "2010-02-18T16:23:48.5" } +test iso_8601 get "2010-02-18T16:23:48,444" = { "date" = "2010-02-18T16:23:48,444" } +test iso_8601 get "2010-02-18T16:23:48,3-06:00" = { "date" = "2010-02-18T16:23:48,3-06:00" } +test iso_8601 get "2010-02-18T16:23.4" = { "date" = "2010-02-18T16:23.4" } +test iso_8601 get "2010-02-18T16:23,25" = { "date" = "2010-02-18T16:23,25" } +test iso_8601 get "2010-02-18T16:23.33+0600" = { "date" = "2010-02-18T16:23.33+0600" } +test iso_8601 get "2010-02-18T16.23334444" = { "date" = "2010-02-18T16.23334444" } +test iso_8601 get "2010-02-18T16,2283" = { "date" = "2010-02-18T16,2283" } +test iso_8601 get "2009-05-19 143922.500" = { "date" = "2009-05-19 143922.500" } +test iso_8601 get "2009-05-19 1439,55" = { "date" = "2009-05-19 1439,55" } + +(* url_3986 *) +let url_3986 = [ label "url" . store Rx.url_3986 ] + +test url_3986 get "http://tools.ietf.org/rfc/rfc3986.txt" = { "url" = "http://tools.ietf.org/rfc/rfc3986.txt" } +test url_3986 get "https://github.com/hercules-team/augeas/" = { "url" = "https://github.com/hercules-team/augeas/" } +test url_3986 get "http://www.ics.uci.edu:80/pub/ietf/uri/#Related" = { "url" = "http://www.ics.uci.edu:80/pub/ietf/uri/#Related" } +test url_3986 get "EXAMPLE://a/./b/../b/%63/%7bfoo%7d" = { "url" = "EXAMPLE://a/./b/../b/%63/%7bfoo%7d" } +test url_3986 get "http://a/b/c/g;?x=1/y#z" = { "url" = "http://a/b/c/g;?x=1/y#z" } +test url_3986 get "eXaMpLe://a.very.sub.domain.tld:1234/b/c/e/f/g.txt;?x=1/y&q=%7b-w-%7b#z" = { "url" = "eXaMpLe://a.very.sub.domain.tld:1234/b/c/e/f/g.txt;?x=1/y&q=%7b-w-%7b#z" } + diff --git a/Sharp.Augeas.Test/lens/tests/test_samba.aug b/Sharp.Augeas.Test/lens/tests/test_samba.aug new file mode 100644 index 0000000..fc96a1c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_samba.aug @@ -0,0 +1,103 @@ +module Test_samba = + + let conf = "# +# Sample configuration file for the Samba suite for Debian GNU/Linux. +# +# +# This is the main Samba configuration file. You should read the +# smb.conf(5) manual page in order to understand the options listed +# here. Samba has a huge number of configurable options most of which +# are not shown in this example +# + +#======================= Global Settings ======================= + +[global] + +## Browsing/Identification ### + +# Change this to the workgroup/NT-domain name your Samba server will part of + workgroup = WORKGROUP + +# server string is the equivalent of the NT Description field + server string = %h server (Samba, Ubuntu) + +# Windows Internet Name Serving Support Section: +# WINS Support - Tells the NMBD component of Samba to enable its WINS Server +; wins support = no + +# Windows clients look for this share name as a source of downloadable +# printer drivers +[print$] + comment = All Printers + browseable = no + path = /tmp + printable = yes + public = yes + writable = no + create mode = 0700 + printcap name = /etc/printcap + print command = /usr/bin/lpr -P%p -r %s + printing = cups +" + + test Samba.lns get conf = + {} + { "#comment" = "Sample configuration file for the Samba suite for Debian GNU/Linux." } + {} + {} + { "#comment" = "This is the main Samba configuration file. You should read the" } + { "#comment" = "smb.conf(5) manual page in order to understand the options listed" } + { "#comment" = "here. Samba has a huge number of configurable options most of which" } + { "#comment" = "are not shown in this example" } + {} + {} + { "#comment" = "======================= Global Settings =======================" } + {} + { "target" = "global" + {} + { "#comment" = "# Browsing/Identification ###" } + {} + { "#comment" = "Change this to the workgroup/NT-domain name your Samba server will part of" } + { "workgroup" = "WORKGROUP" } + {} + { "#comment" = "server string is the equivalent of the NT Description field" } + { "server string" = "%h server (Samba, Ubuntu)" } + {} + { "#comment" = "Windows Internet Name Serving Support Section:" } + { "#comment" = "WINS Support - Tells the NMBD component of Samba to enable its WINS Server" } + { "#comment" = "wins support = no" } + {} + { "#comment" = "Windows clients look for this share name as a source of downloadable" } + { "#comment" = "printer drivers" } } + { "target" = "print$" + { "comment" = "All Printers" } + { "browseable" = "no" } + { "path" = "/tmp" } + { "printable" = "yes" } + { "public" = "yes" } + { "writable" = "no" } + { "create mode" = "0700" } + { "printcap name" = "/etc/printcap" } + { "print command" = "/usr/bin/lpr -P%p -r %s" } + { "printing" = "cups" } } + + test Samba.lns get "[test]\ncrazy:entry = foo\n" = + { "target" = "test" + {"crazy:entry" = "foo"}} + + (* Test complex idmap commands with asterisk in key name, ticket #354 *) + test Samba.lns get "[test] + idmap backend = tdb + idmap uid = 1000000-1999999 + idmap gid = 1000000-1999999 + + idmap config CORP : backend = ad + idmap config * : range = 1000-999999\n" = + { "target" = "test" + { "idmap backend" = "tdb" } + { "idmap uid" = "1000000-1999999" } + { "idmap gid" = "1000000-1999999" } + { } + { "idmap config CORP : backend" = "ad" } + { "idmap config * : range" = "1000-999999" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_schroot.aug b/Sharp.Augeas.Test/lens/tests/test_schroot.aug new file mode 100644 index 0000000..71dec8c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_schroot.aug @@ -0,0 +1,97 @@ +module Test_schroot = + + let conf = "# Sample configuration + +[sid] +type=plain +description=Debian unstable +description[fr_FR]=Debian instable +location=/srv/chroot/sid +priority=3 +groups=sbuild +root-groups=root +aliases=unstable,default + +[etch] +type=block-device +description=Debian testing +priority=2 +#groups=sbuild-security +aliases=testing +device=/dev/hda_vg/etch_chroot +mount-options=-o atime +run-setup-scripts=true +run-exec-scripts=true + +[sid-file] +type=file +description=Debian sid file-based chroot +priority=3 +groups=sbuild +file=/srv/chroots/sid.tar.gz +run-setup-scripts=true +run-exec-scripts=true + +[sid-snapshot] +type=lvm-snapshot +description=Debian unstable LVM snapshot +priority=3 +groups=sbuild +root-groups=root +device=/dev/hda_vg/sid_chroot +mount-options=-o atime,sync,user_xattr +lvm-snapshot-options=--size 2G +run-setup-scripts=true +run-exec-scripts=true +" + + test Schroot.lns get conf = + { "#comment" = "Sample configuration" } + { } + { "sid" + { "type" = "plain" } + { "description" = "Debian unstable" } + { "description" = "Debian instable" + { "lang" = "fr_FR" } + } + { "location" = "/srv/chroot/sid" } + { "priority" = "3" } + { "groups" = "sbuild" } + { "root-groups" = "root" } + { "aliases" = "unstable,default" } + { } + } + { "etch" + { "type" = "block-device" } + { "description" = "Debian testing" } + { "priority" = "2" } + { "#comment" = "groups=sbuild-security" } + { "aliases" = "testing" } + { "device" = "/dev/hda_vg/etch_chroot" } + { "mount-options" = "-o atime" } + { "run-setup-scripts" = "true" } + { "run-exec-scripts" = "true" } + { } + } + { "sid-file" + { "type" = "file" } + { "description" = "Debian sid file-based chroot" } + { "priority" = "3" } + { "groups" = "sbuild" } + { "file" = "/srv/chroots/sid.tar.gz" } + { "run-setup-scripts" = "true" } + { "run-exec-scripts" = "true" } + { } + } + { "sid-snapshot" + { "type" = "lvm-snapshot" } + { "description" = "Debian unstable LVM snapshot" } + { "priority" = "3" } + { "groups" = "sbuild" } + { "root-groups" = "root" } + { "device" = "/dev/hda_vg/sid_chroot" } + { "mount-options" = "-o atime,sync,user_xattr" } + { "lvm-snapshot-options" = "--size 2G" } + { "run-setup-scripts" = "true" } + { "run-exec-scripts" = "true" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_securetty.aug b/Sharp.Augeas.Test/lens/tests/test_securetty.aug new file mode 100644 index 0000000..1aa0d1d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_securetty.aug @@ -0,0 +1,31 @@ +module Test_securetty = + + (* basic test *) + let basic = "tty0\ntty1\ntty2\n" + + (* declare the lens to test and the resulting tree *) + test Securetty.lns get basic = + { "1" = "tty0" } + { "2" = "tty1" } + { "3" = "tty2" } + + (* complete test *) + let complete = "# some comment + +tty0 +# X11 display +:0.0 + +console # allow root from console +" + + (* declare the lens to test and the resulting tree *) + test Securetty.lns get complete = + { "#comment" = "some comment" } + {} + { "1" = "tty0" } + { "#comment" = "X11 display" } + { "2" = ":0.0" } + {} + { "3" = "console" + { "#comment" = "allow root from console" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_semanage.aug b/Sharp.Augeas.Test/lens/tests/test_semanage.aug new file mode 100644 index 0000000..a6ceaca --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_semanage.aug @@ -0,0 +1,81 @@ +(* +Module: Test_Semanage + Provides unit tests and examples for the <Semanage> lens. +*) + +module Test_Semanage = + +(* Variable: phony_conf *) +let phony_conf = "# this is a comment + +mykey = myvalue # eol comment +anotherkey = another value +" + +(* Test: Semanage.lns *) +test Semanage.lns get phony_conf = + { "#comment" = "this is a comment" } + { } + { "mykey" = "myvalue" + { "#comment" = "eol comment" } } + { "anotherkey" = "another value" } + +(* Test: Semanage.lns + Quotes are OK in variables that do not begin with a quote *) +test Semanage.lns get "UserParameter=custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'\n" = + { "UserParameter" = "custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'" } + +(* Test: Semanage.lns + Support empty values *) +test Semanage.lns get "foo =\n" = + { "foo" } + +(* Variable: conf *) +let conf = "module-store = direct +module-store = \"source\" + +#policy-version = 19 + +expand-check=0 + +usepasswd=False +bzip-small=true +bzip-blocksize=5 +ignoredirs=/root + +[sefcontext_compile] +path = /usr/sbin/sefcontext_compile +args = -r $@ + +[end] + +config=test + +[verify module] +test=value +[end] +" + +(* Test: Semanage.lns *) +test Semanage.lns get conf = + { "module-store" = "direct" } + { "module-store" = "source" } + { } + { "#comment" = "policy-version = 19" } + { } + { "expand-check" = "0" } + { } + { "usepasswd" = "False" } + { "bzip-small" = "true" } + { "bzip-blocksize" = "5" } + { "ignoredirs" = "/root" } + { } + { "@group" = "sefcontext_compile" + { "path" = "/usr/sbin/sefcontext_compile" } + { "args" = "-r $@" } + { } } + { } + { "config" = "test" } + { } + { "@group" = "verify module" + { "test" = "value" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_services.aug b/Sharp.Augeas.Test/lens/tests/test_services.aug new file mode 100644 index 0000000..28725fe --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_services.aug @@ -0,0 +1,88 @@ +(* Tests for the Services module *) + +module Test_services = + + let example = "# a comment + +tcpmux 1/tcp # TCP port service multiplexer +echo 7/udp +discard 9/tcp sink null +systat 11/tcp users +# another comment +whois++ 63/tcp +z39.50 210/tcp z3950 wais # NISO Z39.50 database \n" + + test Services.lns get example = + { "#comment" = "a comment" } + { } + { "service-name" = "tcpmux" + { "port" = "1" } + { "protocol" = "tcp" } + { "#comment" = "TCP port service multiplexer" } } + { "service-name" = "echo" + { "port" = "7" } + { "protocol" = "udp" } } + { "service-name" = "discard" + { "port" = "9" } + { "protocol" = "tcp" } + { "alias" = "sink" } + { "alias" = "null" } } + { "service-name" = "systat" + { "port" = "11" } + { "protocol" = "tcp" } + { "alias" = "users" } } + { "#comment" = "another comment" } + { "service-name" = "whois++" + { "port" = "63" } + { "protocol" = "tcp" } } + { "service-name" = "z39.50" + { "port" = "210" } + { "protocol" = "tcp" } + { "alias" = "z3950" } + { "alias" = "wais" } + { "#comment" = "NISO Z39.50 database" } } + + (* We completely suppress empty comments *) + test Services.record get "mtp\t\t1911/tcp\t\t\t#\n" = + { "service-name" = "mtp" + { "port" = "1911" } + { "protocol" = "tcp" } } + + (* And comments with one space in *) + test Services.lns get "mtp\t\t\t1911/tcp\t\t\t# \nfoo 123/tcp\n" = + { "service-name" = "mtp" + { "port" = "1911" } + { "protocol" = "tcp" } } + { "service-name" = "foo" + { "port" = "123" } + { "protocol" = "tcp" } } + + test Services.lns get "sql*net\t\t66/tcp\t\t\t# Oracle SQL*NET\n" = + { "service-name" = "sql*net" + { "port" = "66" } + { "protocol" = "tcp" } + { "#comment" = "Oracle SQL*NET" } } + + (* Fake service to check that we allow enoughspecial characters *) + test Services.lns get "special.*+-/chars\t0/proto\n" = + { "service-name" = "special.*+-/chars" + { "port" = "0" } + { "protocol" = "proto" } } + + test Services.lns put "tcpmux 1/tcp # some comment\n" + after rm "/service-name/#comment" = "tcpmux 1/tcp\n" + + (* On AIX, port ranges are valid *) + test Services.lns get "x11 6000-6063/tcp # X Window System\n" = + { "service-name" = "x11" + { "start" = "6000" } + { "end" = "6063" } + { "protocol" = "tcp" } + { "#comment" = "X Window System" } } + + (* Colons permitted in service names, RHBZ#1121263 *) + test Services.lns get "SWRPC.ACCESS.BSS:BS_rmq 48102/tcp # SWIFTAlliance_SWRPC ACCESS\n" = + { "service-name" = "SWRPC.ACCESS.BSS:BS_rmq" + { "port" = "48102" } + { "protocol" = "tcp" } + { "#comment" = "SWIFTAlliance_SWRPC ACCESS" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_shadow.aug b/Sharp.Augeas.Test/lens/tests/test_shadow.aug new file mode 100644 index 0000000..ed3e222 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_shadow.aug @@ -0,0 +1,81 @@ +module Test_Shadow = + +let conf = "root:x:0:0:999999:7::: +libuuid:*:0:0:0:::: +expired:$6$INVALID:0:0:0:::100: +locked:!$6$INVALID:0:0:0:::: +" + +test Shadow.lns get conf = + { "root" + { "password" = "x" } + { "lastchange_date" = "0" } + { "minage_days" = "0" } + { "maxage_days" = "999999" } + { "warn_days" = "7" } + { "inactive_days" = "" } + { "expire_date" = "" } + { "flag" = "" } } + { "libuuid" + { "password" = "*" } + { "lastchange_date" = "0" } + { "minage_days" = "0" } + { "maxage_days" = "0" } + { "warn_days" = "" } + { "inactive_days" = "" } + { "expire_date" = "" } + { "flag" = "" } } + { "expired" + { "password" = "$6$INVALID" } + { "lastchange_date" = "0" } + { "minage_days" = "0" } + { "maxage_days" = "0" } + { "warn_days" = "" } + { "inactive_days" = "" } + { "expire_date" = "100" } + { "flag" = "" } } + { "locked" + { "password" = "!$6$INVALID" } + { "lastchange_date" = "0" } + { "minage_days" = "0" } + { "maxage_days" = "0" } + { "warn_days" = "" } + { "inactive_days" = "" } + { "expire_date" = "" } + { "flag" = "" } } + +test Shadow.lns get "+\n" = + { "@nisdefault" } + +test Shadow.lns get "+::::::::\n" = + { "@nisdefault" + { "password" = "" } + { "lastchange_date" = "" } + { "minage_days" = "" } + { "maxage_days" = "" } + { "warn_days" = "" } + { "inactive_days" = "" } + { "expire_date" = "" } + { "flag" = "" } } + +test Shadow.lns put "+\n" after + set "@nisdefault/password" ""; + set "@nisdefault/lastchange_date" ""; + set "@nisdefault/minage_days" ""; + set "@nisdefault/maxage_days" ""; + set "@nisdefault/warn_days" ""; + set "@nisdefault/inactive_days" ""; + set "@nisdefault/expire_date" ""; + set "@nisdefault/flag" "" += "+::::::::\n" + +test Shadow.lns put "+::::::::\n" after + rm "@nisdefault/password"; + rm "@nisdefault/lastchange_date"; + rm "@nisdefault/minage_days"; + rm "@nisdefault/maxage_days"; + rm "@nisdefault/warn_days"; + rm "@nisdefault/inactive_days"; + rm "@nisdefault/expire_date"; + rm "@nisdefault/flag" += "+\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_shells.aug b/Sharp.Augeas.Test/lens/tests/test_shells.aug new file mode 100644 index 0000000..ff81c4a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_shells.aug @@ -0,0 +1,18 @@ +(* Test for shells lens *) + +module Test_shells = + + let conf = "# this is a comment + +/bin/bash +/bin/tcsh +/opt/csw/bin/bash # CSWbash +" + + test Shells.lns get conf = + { "#comment" = "this is a comment" } + {} + { "1" = "/bin/bash" } + { "2" = "/bin/tcsh" } + { "3" = "/opt/csw/bin/bash" + { "#comment" = "CSWbash" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_shellvars.aug b/Sharp.Augeas.Test/lens/tests/test_shellvars.aug new file mode 100644 index 0000000..a3b80a4 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_shellvars.aug @@ -0,0 +1,783 @@ +(* Test for shell lens *) +module Test_shellvars = + + let lns = Shellvars.lns + + let eth_static = "# Intel Corporation PRO/100 VE Network Connection +DEVICE=eth0 +BOOTPROTO=static +BROADCAST=172.31.0.255 +HWADDR=ab:cd:ef:12:34:56 +export IPADDR=172.31.0.31 # this is our IP +#DHCP_HOSTNAME=host.example.com +NETMASK=255.255.255.0 +NETWORK=172.31.0.0 +unset ONBOOT # We do not want this var +" + let empty_val = "EMPTY=\nDEVICE=eth0\n" + + let key_brack = "SOME_KEY[1]=\nDEVICE=eth0\n" + + test lns get eth_static = + { "#comment" = "Intel Corporation PRO/100 VE Network Connection" } + { "DEVICE" = "eth0" } + { "BOOTPROTO" = "static" } + { "BROADCAST" = "172.31.0.255" } + { "HWADDR" = "ab:cd:ef:12:34:56" } + { "IPADDR" = "172.31.0.31" + { "export" } + { "#comment" = "this is our IP" } } + { "#comment" = "DHCP_HOSTNAME=host.example.com" } + { "NETMASK" = "255.255.255.0" } + { "NETWORK" = "172.31.0.0" } + { "@unset" + { "1" = "ONBOOT" } + { "#comment" = "We do not want this var" } } + + test lns put eth_static after + set "BOOTPROTO" "dhcp" ; + rm "IPADDR" ; + rm "BROADCAST" ; + rm "NETMASK" ; + rm "NETWORK" + = "# Intel Corporation PRO/100 VE Network Connection +DEVICE=eth0 +BOOTPROTO=dhcp +HWADDR=ab:cd:ef:12:34:56 +#DHCP_HOSTNAME=host.example.com +unset ONBOOT # We do not want this var +" + test lns get empty_val = + { "EMPTY" = "" } { "DEVICE" = "eth0" } + + test lns get key_brack = + { "SOME_KEY[1]" = "" } { "DEVICE" = "eth0" } + + test lns get "smartd_opts=\"-q never\"\n" = + { "smartd_opts" = "\"-q never\"" } + + test lns get "var=val \n" = { "var" = "val" } + + test lns get ". /etc/java/java.conf\n" = + { ".source" = "/etc/java/java.conf" } + + (* Quoted strings and other oddities *) + test lns get "var=\"foo 'bar'\"\n" = + { "var" = "\"foo 'bar'\"" } + + test lns get "var='Some \"funny\" value'\n" = + { "var" = "'Some \"funny\" value'" } + + test lns get "var=\"\\\"\"\n" = + { "var" = "\"\\\"\"" } + + test lns get "var=\\\"\n" = + { "var" = "\\\"" } + + test lns get "var=ab#c\n" = + { "var" = "ab#c" } + + test lns get "var=ab #c\n" = + { "var" = "ab" + { "#comment" = "c" } } + + test lns get "var=ab; #c\n" = + { "var" = "ab" } + { "#comment" = "c" } + + test lns put "var=ab; #c\n" after + set "/#comment" "d" = + "var=ab; #d\n" + + test lns get "var=ab;\n" = + { "var" = "ab" } + + test lns get "var='ab#c'\n" = + { "var" = "'ab#c'" } + + test lns get "var=\"ab#c\"\n" = + { "var" = "\"ab#c\"" } + + test lns get "ESSID='Joe'\"'\"'s net'\n" = + { "ESSID" = "'Joe'\"'\"'s net'" } + + test lns get "var=`ab#c`\n" = + { "var" = "`ab#c`" } + + test lns get "var=`grep nameserver /etc/resolv.conf | head -1`\n" = + { "var" = "`grep nameserver /etc/resolv.conf | head -1`" } + + test lns put "var=ab #c\n" + after rm "/var/#comment" = "var=ab\n" + + test lns put "var=ab\n" + after set "/var/#comment" "this is a var" = + "var=ab # this is a var\n" + + (* Handling of arrays *) + test lns get "var=(val1 \"val\\\"2\\\"\" val3)\n" = + { "var" + { "1" = "val1" } + { "2" = "\"val\\\"2\\\"\"" } + { "3" = "val3" } } + + test lns get "var=()\n" = { "var" = "()" } + + test lns put "var=()\n" after + set "var" "value" + = "var=value\n" + + test lns put "var=(v1 v2)\n" after + rm "var/*" ; + set "var" "value" + = "var=value\n" + + test lns put "var=(v1 v2)\n" after + set "var/3" "v3" + = "var=(v1 v2 v3)\n" + + test lns get "var=(v1 v2 \n \t v3)\n" = + { "var" + { "1" = "v1" } + { "2" = "v2" } + { "3" = "v3" } } + + (* Allow spaces after/before opening/closing parens for array *) + test lns get "config_eth1=( \"10.128.0.48/24\" )\n" = + { "config_eth1" { "1" = "\"10.128.0.48/24\"" } } + + (* Bug 109: allow a bare export *) + test lns get "export FOO\n" = + { "@export" + { "1" = "FOO" } } + + (* Bug 73: allow ulimit builtin *) + test lns get "ulimit -c unlimited\n" = + { "@builtin" = "ulimit" { "args" = "-c unlimited" } } + + (* Allow shift builtin *) + test Shellvars.lns get "shift\nshift 2\n" = + { "@builtin" = "shift" } + { "@builtin" = "shift" { "args" = "2" } } + + (* Allow exit builtin *) + test Shellvars.lns get "exit\nexit 2\n" = + { "@builtin" = "exit" } + { "@builtin" = "exit" { "args" = "2" } } + + (* Allow wrapping builtin arguments to multiple lines *) + test Shellvars.lns get "ulimit -c \\\nunlimited\nulimit \\\n -x 123\n" = + { "@builtin" = "ulimit" { "args" = "-c \\\nunlimited" } } + { "@builtin" = "ulimit" { "args" = "-x 123" } } + + (* Test semicolons *) + test lns get "VAR1=\"this;is;a;test\"\nVAR2=this;\n" = + { "VAR1" = "\"this;is;a;test\"" } + { "VAR2" = "this" } + + (* Bug 230: parse conditions *) + test lns get "if [ -f /etc/default/keyboard ]; then\n. /etc/default/keyboard\nfi\n" = + { "@if" = "[ -f /etc/default/keyboard ]" { ".source" = "/etc/default/keyboard" } } + + (* Recursive condition *) + test lns get "if [ -f /tmp/file1 ]; then + if [ -f /tmp/file2 ] + then + . /tmp/file2 + elif [ -f /tmp/file3 ]; then + . /tmp/file3; else; . /tmp/file4 + fi +else + . /tmp/file3 +fi\n" = + { "@if" = "[ -f /tmp/file1 ]" + { "@if" = "[ -f /tmp/file2 ]" + { ".source" = "/tmp/file2" } + { "@elif" = "[ -f /tmp/file3 ]" + { ".source" = "/tmp/file3" } } + { "@else" + { ".source" = "/tmp/file4" } + } + } + { "@else" + { ".source" = "/tmp/file3" } + } + } + + (* Multiple elif *) + test Shellvars.lns get "if [ -f /tmp/file1 ]; then + . /tmp/file1 + elif [ -f /tmp/file2 ]; then + . /tmp/file2 + elif [ -f /tmp/file3 ]; then + . /tmp/file3 + fi\n" = + { "@if" = "[ -f /tmp/file1 ]" + { ".source" = "/tmp/file1" } + { "@elif" = "[ -f /tmp/file2 ]" + { ".source" = "/tmp/file2" } + } + { "@elif" = "[ -f /tmp/file3 ]" + { ".source" = "/tmp/file3" } + } + } + + + (* Comment or eol *) + test lns get "VAR=value # eol-comment\n" = + { "VAR" = "value" + { "#comment" = "eol-comment" } + } + + (* One-liners *) + test lns get "if [ -f /tmp/file1 ]; then . /tmp/file1; else . /tmp/file2; fi\n" = + { "@if" = "[ -f /tmp/file1 ]" + { ".source" = "/tmp/file1" } + { "@else" + { ".source" = "/tmp/file2" } + } + } + + (* Loops *) + test lns get "for f in /tmp/file*; do + while [ 1 ]; do . $f; done +done\n" = + { "@for" = "f in /tmp/file*" + { "@while" = "[ 1 ]" + { ".source" = "$f" } + } + } + + (* Case *) + test lns get "case $f in + /tmp/file1) + . /tmp/file1 + ;; + /tmp/file2) + . /tmp/file2 + ;; + *) + unset f + ;; +esac\n" = + { "@case" = "$f" + { "@case_entry" + { "@pattern" = "/tmp/file1" } + { ".source" = "/tmp/file1" } } + { "@case_entry" + { "@pattern" = "/tmp/file2" } + { ".source" = "/tmp/file2" } } + { "@case_entry" + { "@pattern" = "*" } + { "@unset" + { "1" = "f" } } } } + + (* Select *) + test lns get "select i in a b c; do . /tmp/file$i + done\n" = + { "@select" = "i in a b c" + { ".source" = "/tmp/file$i" } + } + + (* Return *) + test lns get "return\nreturn 2\n" = + { "@return" } + { "@return" = "2" } + + (* Functions *) + test Shellvars.lns get "foo() { + . /tmp/bar + }\n" = + { "@function" = "foo" + { ".source" = "/tmp/bar" } + } + + test Shellvars.lns get "function foo () { + . /tmp/bar + }\n" = + { "@function" = "foo" + { ".source" = "/tmp/bar" } + } + + test Shellvars.lns get "foo() ( + . /tmp/bar + )\n" = + { "@function" = "foo" + { ".source" = "/tmp/bar" } + } + + (* Dollar assignment *) + test Shellvars.lns get "FOO=$(bar arg)\n" = + { "FOO" = "$(bar arg)" } + + (* Empty lines before esac *) + test Shellvars.lns get "case $f in + a) + B=C + ;; + + esac\n" = + { "@case" = "$f" + { "@case_entry" + { "@pattern" = "a" } + { "B" = "C" } } + } + + + (* Empty lines before a case_entry *) + test Shellvars.lns get "case $f in + + a) + B=C + ;; + + b) + A=D + ;; + esac\n" = + { "@case" = "$f" + { "@case_entry" + { "@pattern" = "a" } + { "B" = "C" } } + { "@case_entry" + { "@pattern" = "b" } + { "A" = "D" } } } + + + (* Comments anywhere *) + test Shellvars.lns get "case ${INTERFACE} in +# comment before +eth0) +# comment in +OPTIONS=() +;; + +# comment before 2 +*) +# comment in 2 +unset f +;; +# comment after +esac\n" = + { "@case" = "${INTERFACE}" + { "#comment" = "comment before" } + { "@case_entry" + { "@pattern" = "eth0" } + { "#comment" = "comment in" } + { "OPTIONS" = "()" } } + { "#comment" = "comment before 2" } + { "@case_entry" + { "@pattern" = "*" } + { "#comment" = "comment in 2" } + { "@unset" + { "1" = "f" } } } + { "#comment" = "comment after" } } + + (* Empty case *) + test Shellvars.lns get "case $a in + *) + ;; + esac\n" = + { "@case" = "$a" + { "@case_entry" { "@pattern" = "*" } } } + + (* case variables can be surrounded by double quotes *) + test Shellvars.lns get "case \"${options}\" in +*debug*) + shift + ;; +esac\n" = + { "@case" = "\"${options}\"" + { "@case_entry" + { "@pattern" = "*debug*" } + { "@builtin" = "shift" } } } + + (* Double quoted values can have newlines *) + test Shellvars.lns get "FOO=\"123\n456\"\n" = + { "FOO" = "\"123\n456\"" } + + (* Single quoted values can have newlines *) + test Shellvars.lns get "FOO='123\n456'\n" = + { "FOO" = "'123\n456'" } + + (* bquoted values can have semi-colons *) + test Shellvars.lns get "FOO=`bar=date;$bar`\n" = + { "FOO" = "`bar=date;$bar`" } + + (* dollar-assigned values can have semi-colons *) + test Shellvars.lns get "FOO=$(bar=date;$bar)\n" = + { "FOO" = "$(bar=date;$bar)" } + + (* dollar-assigned value in bquot *) + test Shellvars.lns get "FOO=`echo $(date)`\n" = + { "FOO" = "`echo $(date)`" } + + (* bquot value in dollar-assigned value *) + test Shellvars.lns get "FOO=$(echo `date`)\n" = + { "FOO" = "$(echo `date`)" } + + (* dbquot *) + test Shellvars.lns get "FOO=``bar``\n" = + { "FOO" = "``bar``" } + + (* Partial quoting is allowed *) + test Shellvars.lns get "FOO=\"$bar\"/'baz'/$(quux)$((1 + 2))\n" = + { "FOO" = "\"$bar\"/'baz'/$(quux)$((1 + 2))" } + + (* unset can be used on wildcard variables *) + test Shellvars.lns get "unset ${!LC_*}\n" = + { "@unset" + { "1" = "${!LC_*}" } } + + (* Empty comment before entries *) + test Shellvars.lns get "# \nfoo=bar\n" = + { "foo" = "bar" } + + (* Empty comment after entries *) + test Shellvars.lns get "foo=bar\n# \n\n" = + { "foo" = "bar" } + + (* Whitespace between lines *) + test Shellvars.lns get "DEVICE=eth0\n\nBOOTPROTO=static\n" = + { "DEVICE" = "eth0" } + { "BOOTPROTO" = "static" } + + (* Whitespace after line *) + test Shellvars.lns get "DEVICE=eth0\n\n" = + { "DEVICE" = "eth0" } + + (* Fails adding variable assignment between comment and blank line *) + let ins_after_comment = "# foo + +" + test lns put ins_after_comment after + insa "foo" "#comment" ; + set "foo" "yes" + = "# foo\n\nfoo=yes\n" + + (* Make sure to support empty comments *) + test lns get "# foo + # + # + foo=bar + #\n" = + { "#comment" = "foo" } + { "foo" = "bar" } + + (* Single quotes in arrays, ticket #357 *) + test lns get "DLAGENTS=('ftp::/usr/bin/curl -fC - --ftp-pasv --retry 3 --retry-delay 3 -o %o %u' + 'scp::/usr/bin/scp -C %u %o')\n" = + { "DLAGENTS" + { "1" = "'ftp::/usr/bin/curl -fC - --ftp-pasv --retry 3 --retry-delay 3 -o %o %u'" } + { "2" = "'scp::/usr/bin/scp -C %u %o'" } } + + (* Accept continued lines in quoted values *) + test lns get "BLAH=\" \ +test \ +test2\"\n" = + { "BLAH" = "\" \\\ntest \\\ntest2\"" } + + (* Export of multiple variables, RHBZ#1033795 *) + test lns get "export TestVar1 TestVar2\n" = + { "@export" + { "1" = "TestVar1" } + { "2" = "TestVar2" } } + + (* Support ;; on same line as a case statement entry, RHBZ#1033799 *) + test lns get "case $ARG in + 0) TestVar=\"test0\" ;; + 1) TestVar=\"test1\" ;; +esac\n" = + { "@case" = "$ARG" + { "@case_entry" + { "@pattern" = "0" } + { "TestVar" = "\"test0\"" } } + { "@case_entry" + { "@pattern" = "1" } + { "TestVar" = "\"test1\"" } } } + + (* case: support ;; on the same line with multiple commands *) + test lns get "case $ARG in + 0) Foo=0; Bar=1;; + 1) + Foo=2 + Bar=3; Baz=4;; +esac\n" = + { "@case" = "$ARG" + { "@case_entry" + { "@pattern" = "0" } + { "Foo" = "0" } + { "Bar" = "1" } + } + { "@case_entry" + { "@pattern" = "1" } + { "Foo" = "2" } + { "Bar" = "3" } + { "Baz" = "4" } + } + } + +(* Test: Shellvars.lns + Support `##` bashism in conditions (GH issue #118) *) +test Shellvars.lns get "if [ \"${APACHE_CONFDIR##/etc/apache2-}\" != \"${APACHE_CONFDIR}\" ] ; then + SUFFIX=\"-${APACHE_CONFDIR##/etc/apache2-}\" +else + SUFFIX= +fi\n" = + { "@if" = "[ \"${APACHE_CONFDIR##/etc/apache2-}\" != \"${APACHE_CONFDIR}\" ]" + { "SUFFIX" = "\"-${APACHE_CONFDIR##/etc/apache2-}\"" } + { "@else" + { "SUFFIX" = "" } + } + } + + (* Support $(( .. )) arithmetic expansion in variable assignment, RHBZ#1100550 *) + test lns get "export MALLOC_PERTURB_=$(($RANDOM % 255 + 1))\n" = + { "MALLOC_PERTURB_" = "$(($RANDOM % 255 + 1))" + { "export" } } + + (* + * Github issue 202 + *) + let starts_with_blank = "\n \nVAR=value\n" + + test lns get starts_with_blank = { "VAR" = "value" } + + (* It is now possible to insert at the beginning of a file + * that starts with blank lines *) + test lns put starts_with_blank after + insb "#comment" "/*[1]"; + set "/#comment[1]" "a comment" = + " # a comment\nVAR=value\n" + + (* Modifications of the file lose the blank lines though *) + test lns put starts_with_blank after + set "/VAR2" "abc" = "VAR=value\nVAR2=abc\n" + + test lns put starts_with_blank after + rm "/VAR"; + set "/VAR2" "abc" = "VAR2=abc\n" + + test lns put starts_with_blank after + rm "/VAR" = "" + + (* Support associative arrays *) + test lns get "var[alpha_beta,gamma]=something\n" = + { "var[alpha_beta,gamma]" = "something" } + + (* GH #188: support more conditions *) + test Shellvars.lns get "[ -f $FILENAME ]\n" = + { "@condition" = "-f $FILENAME" + { "type" = "[" } } + + test Shellvars.lns get "[[ -f $FILENAME ]]\n" = + { "@condition" = "-f $FILENAME" + { "type" = "[[" } } + + (* Allow wrapping loop condition to multiple lines *) + test Shellvars.lns get "for x in foo \\\nbar\\\nbaz; do y=$x; done\n" = + { "@for" = "x in foo \\\nbar\\\nbaz" { "y" = "$x" } } + + (* Allow quotes in loop conditions *) + test Shellvars.lns get "for x in \"$@\"; do y=$x; done\n" = + { "@for" = "x in \"$@\"" { "y" = "$x" } } + + (* case: support quotes and spaces in pattern lists *) + test lns get "case $ARG in + \"foo bar\") + Foo=0 + ;; + baz | quux) + Foo=1 + ;; +esac\n" = + { "@case" = "$ARG" + { "@case_entry" + { "@pattern" = "\"foo bar\"" } + { "Foo" = "0" } + } + { "@case_entry" + { "@pattern" = "baz" } + { "@pattern" = "quux" } + { "Foo" = "1" } + } + } + + (* eval *) + test lns get "eval `dircolors`\n" = + { "@eval" = "`dircolors`" } + + (* alias *) + test lns get "alias ls='ls $LS_OPTIONS'\n" = + { "@alias" = "ls" { "value" = "'ls $LS_OPTIONS'" } } + + test lns get "alias ls-options='ls $LS_OPTIONS'\n" = + { "@alias" = "ls-options" { "value" = "'ls $LS_OPTIONS'" } } + + (* Allow && and || constructs after condition *) + test Shellvars.lns get "[ -f $FILENAME ] && do this || or that\n" = + { "@condition" = "-f $FILENAME" + { "type" = "[" } + { "@and" = "do this" } + { "@or" = "or that" } } + +(* Test: Shellvars.lns + Parse (almost) any command *) +test Shellvars.lns get "echo foobar 'and this is baz' +/usr/local/bin/myscript-with-dash_and_underscore.sh with args +echo foo \ +bar\n" = + { "@command" = "echo" + { "@arg" = "foobar 'and this is baz'" } + } + { "@command" = "/usr/local/bin/myscript-with-dash_and_underscore.sh" + { "@arg" = "with args" } + } + { "@command" = "echo" + { "@arg" = "foo \\\nbar" } + } + +(* Test: Shellvars.lns + Support pipes in commands *) +test Shellvars.lns get "echo \"$STRING\" | grep foo\n" = + { "@command" = "echo" + { "@arg" = "\"$STRING\"" } + { "@pipe" + { "@command" = "grep" + { "@arg" = "foo" } } } } + +(* Test: Shellvars.lns + Support && and || after command + GH #215 *) +test Shellvars.lns get "grep -q \"Debian\" /etc/issue && echo moo\n" = + { "@command" = "grep" + { "@arg" = "-q \"Debian\" /etc/issue" } + { "@and" + { "@command" = "echo" + { "@arg" = "moo" } } } } + +test Shellvars.lns get "grep -q \"Debian\" /etc/issue || echo baa\n" = + { "@command" = "grep" + { "@arg" = "-q \"Debian\" /etc/issue" } + { "@or" + { "@command" = "echo" + { "@arg" = "baa" } } } } + +test Shellvars.lns get "grep -q \"Debian\" /etc/issue && DEBIAN=1\n" = + { "@command" = "grep" + { "@arg" = "-q \"Debian\" /etc/issue" } + { "@and" + { "DEBIAN" = "1" } } } + +test Shellvars.lns get "cat /etc/issue | grep -q \"Debian\" && echo moo || echo baa\n" = + { "@command" = "cat" + { "@arg" = "/etc/issue" } + { "@pipe" + { "@command" = "grep" + { "@arg" = "-q \"Debian\"" } + { "@and" + { "@command" = "echo" + { "@arg" = "moo" } + { "@or" + { "@command" = "echo" + { "@arg" = "baa" } } } } } } } } + +(* Command-specific environment variables *) +test Shellvars.lns get "abc=def \\\n ghi=\"jkl mno\" command arg1 arg2\n" = + { "@command" = "command" + { "abc" = "def" } + { "ghi" = "\"jkl mno\"" } + { "@arg" = "arg1 arg2" } + } + +(* Wrapped command sequences *) + +test Shellvars.lns get "foo && \\\nbar baz \\\n|| qux \\\n quux\\\ncorge grault\n" = + { "@command" = "foo" + { "@and" + { "@command" = "bar" + { "@arg" = "baz" } + { "@or" { "@command" = "qux" { "@arg" = "quux\\\ncorge grault" } } } + } + } + } + +(* Comment after function definition (Issue #339) *) +test Shellvars.lns get "SetDir() # hello +{ + echo +}\n" = + { "@function" = "SetDir" + { "#comment" = "hello" } + { "@command" = "echo" } + } + +(* Function with new lines *) +test Shellvars.lns get "MyFunc() +{ + echo +}\n" = + { "@function" = "MyFunc" + { "@command" = "echo" } + } + +(* Pipe and newline without cl (Issue #339) *) +test Shellvars.lns get "echo | +tr\n" = + { "@command" = "echo" + { "@pipe" + { "@command" = "tr" } } } + + +(* Subshell (Issue #339) *) +test Shellvars.lns get "{ echo +}\n" = + { "@subshell" + { "@command" = "echo" } + } + +(* One-liner function *) +test Shellvars.lns get "MyFunc() { echo; }\n" = + { "@function" = "MyFunc" + { "@command" = "echo" } + } + +(* Support and/or in if conditions *) +test Shellvars.lns get "if [ -f /tmp/file1 ] && [ -f /tmp/file2 ] || [ -f /tmp/file3 ]; then + echo foo +fi +" = + { "@if" = "[ -f /tmp/file1 ]" + { "@and" = "[ -f /tmp/file2 ]" } + { "@or" = "[ -f /tmp/file3 ]" } + { "@command" = "echo" + { "@arg" = "foo" } + } + } + +(* Support variable as command *) +test Shellvars.lns get "$FOO bar\n" = + { "@command" = "$FOO" + { "@arg" = "bar" } + } + + +(********************************************************* + * Group: Unsupported syntax * + * * + * The following tests are known to be failing currently * + *********************************************************) + +(* Any piping (Issue #343) *) +test Shellvars.lns get "FOO=bar && BAR=foo +echo foo || { echo bar; } +echo FOO | myfunc() { echo bar; }\n" = * + + +(* Stream redirections (Issue #626 *) +test Shellvars.lns get "echo foo 2>&1 >/dev/null\n" = * + + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_shellvars_list.aug b/Sharp.Augeas.Test/lens/tests/test_shellvars_list.aug new file mode 100644 index 0000000..3fcb969 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_shellvars_list.aug @@ -0,0 +1,144 @@ +(* Test for shell list handling lens *) +module Test_shellvars_list = + + let list_vals = "# Some comment +MODULES_LOADED_ON_BOOT=\"ipv6 sunrpc\" + +DEFAULT_APPEND=\"showopts noresume console=tty0 console=ttyS0,115200n8 ro\" + +LOADER_TYPE=\"grub\" +" + + test Shellvars_list.lns get list_vals = + { "#comment" = "Some comment" } + { "MODULES_LOADED_ON_BOOT" + { "quote" = "\"" } + { "value" = "ipv6" } + { "value" = "sunrpc" } } + { } + { "DEFAULT_APPEND" + { "quote" = "\"" } + { "value" = "showopts" } + { "value" = "noresume" } + { "value" = "console=tty0" } + { "value" = "console=ttyS0,115200n8" } + { "value" = "ro" } } + { } + { "LOADER_TYPE" + { "quote" = "\"" } + { "value" = "grub" } } + + + (* append a value *) + test Shellvars_list.lns put "VAR=\"test1\t \ntest2\"\n" after + set "VAR/value[last()+1]" "test3" + = "VAR=\"test1\t \ntest2 test3\"\n" + + (* in double quoted lists, single quotes and escaped values are allowed *) + test Shellvars_list.lns get "VAR=\"test'1 test2 a\ \\\"longer\\\"\ test\"\n" = + { "VAR" + { "quote" = "\"" } + { "value" = "test'1" } + { "value" = "test2" } + { "value" = "a\ \\\"longer\\\"\ test" } } + + (* add new value, delete one and append something *) + test Shellvars_list.lns put list_vals after + set "FAILSAVE_APPEND/quote" "\"" ; + set "FAILSAVE_APPEND/value[last()+1]" "console=ttyS0" ; + rm "LOADER_TYPE" ; + rm "MODULES_LOADED_ON_BOOT/value[1]" ; + set "DEFAULT_APPEND/value[last()+1]" "teststring" + = "# Some comment +MODULES_LOADED_ON_BOOT=\"sunrpc\" + +DEFAULT_APPEND=\"showopts noresume console=tty0 console=ttyS0,115200n8 ro teststring\" + +FAILSAVE_APPEND=\"console=ttyS0\" +" + + (* test of single quotes (leading/trailing whitespaces are kept *) + (* leading/trailing) *) + test Shellvars_list.lns put "VAR=' \t test1\t \ntest2 '\n" after + set "VAR/value[last()+1]" "test3" + = "VAR=' \t test1\t \ntest2 test3 '\n" + + (* change quotes (leading/trailing whitespaces are lost *) + test Shellvars_list.lns put "VAR=' \t test1\t \ntest2 '\n" after + set "VAR/quote" "\"" + = "VAR=\"test1\t \ntest2\"\n" + + (* double quotes are allowed in single quoted lists *) + test Shellvars_list.lns get "VAR='test\"1 test2'\n" = + { "VAR" + { "quote" = "'" } + { "value" = "test\"1" } + { "value" = "test2" } } + + (* empty list with quotes *) + test Shellvars_list.lns get "VAR=''\n" = + { "VAR" + { "quote" = "'" } } + + (* unquoted value *) + test Shellvars_list.lns get "VAR=test\n" = + { "VAR" + { "quote" = "" } + { "value" = "test" } } + + (* uquoted value with escaped space etc. *) + test Shellvars_list.lns get "VAR=a\\ \\\"long\\\"\\ test\n" = + { "VAR" + { "quote" = "" } + { "value" = "a\\ \\\"long\\\"\\ test" } } + + (* append to unquoted value *) + test Shellvars_list.lns put "VAR=test1\n" after + set "VAR/quote" "\""; + set "VAR/value[last()+1]" "test2" + = "VAR=\"test1 test2\"\n" + + (* empty entry *) + test Shellvars_list.lns get "VAR=\n" = + { "VAR" + { "quote" = "" } } + + (* set value w/o quotes to empty value... *) + test Shellvars_list.lns put "VAR=\n" after + set "VAR/value[last()+1]" "test" + = "VAR=test\n" + + (* ... or no value *) + test Shellvars_list.lns put "" after + set "VAR/quote" ""; + set "VAR/value[1]" "test" + = "VAR=test\n" + + (* Ticket #368 - backticks *) + test Shellvars_list.lns get "GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`\n" = + { "GRUB_DISTRIBUTOR" + { "quote" = "" } + { "value" = "`lsb_release -i -s 2> /dev/null || echo Debian`" } } + + (* Test: Shellvars_list.lns + Ticket #342: end-of-line comments *) + test Shellvars_list.lns get "service_ping=\"ping/icmp\" #ping\n" = + { "service_ping" + { "quote" = "\"" } + { "value" = "ping/icmp" } + { "#comment" = "ping" } } + + (* Test: Shellvars_list.lns + Support double-quoted continued lines *) + test Shellvars_list.lns get "DAEMON_OPTS=\"-a :6081 \ + -T localhost:6082\"\n" = + { "DAEMON_OPTS" + { "quote" = "\"" } + { "value" = "-a" } + { "value" = ":6081" } + { "value" = "-T" } + { "value" = "localhost:6082" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_simplelines.aug b/Sharp.Augeas.Test/lens/tests/test_simplelines.aug new file mode 100644 index 0000000..90bd9de --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_simplelines.aug @@ -0,0 +1,42 @@ +(* +Module: Test_Simplelines + Provides unit tests and examples for the <Simplelines> lens. +*) + +module Test_Simplelines = + +(* Variable: conf *) +let conf = "# This is a comment + +word +a line + indented line +with $péci@l cH@r2ct3rs +" + +(* Test: Simplelines.lns *) +test Simplelines.lns get conf = + { "#comment" = "This is a comment" } + { } + { "1" = "word" } + { "2" = "a line" } + { "3" = "indented line" } + { "4" = "with $péci@l cH@r2ct3rs" } + +(* Variable: cronallow *) + let cronallow = "# Test comment +# +user1 +another + +user2 +" + +(* Test: cron.allow file *) + test SimpleLines.lns get cronallow = + { "#comment" = "Test comment" } + { } + { "1" = "user1" } + { "2" = "another" } + { } + { "3" = "user2" } diff --git a/Sharp.Augeas.Test/lens/tests/test_simplevars.aug b/Sharp.Augeas.Test/lens/tests/test_simplevars.aug new file mode 100644 index 0000000..1d1ad00 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_simplevars.aug @@ -0,0 +1,36 @@ +(* +Module: Test_Simplevars + Provides unit tests and examples for the <Simplevars> lens. +*) + +module Test_Simplevars = + +(* Variable: conf *) +let conf = "# this is a comment + +mykey = myvalue # eol comment +anotherkey = another value +" + +(* Test: Simplevars.lns *) +test Simplevars.lns get conf = + { "#comment" = "this is a comment" } + { } + { "mykey" = "myvalue" + { "#comment" = "eol comment" } } + { "anotherkey" = "another value" } + +(* Test: Simplevars.lns + Quotes are OK in variables that do not begin with a quote *) +test Simplevars.lns get "UserParameter=custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'\n" = + { "UserParameter" = "custom.vfs.dev.read.ops[*],cat /proc/diskstats | grep $1 | head -1 | awk '{print $$4}'" } + +(* Test: Simplevars.lns + Support flags *) +test Simplevars.lns get "dnsadminapp\n" = + { "dnsadminapp" } + +(* Test: Simplevars.lns + Support empty values *) +test Simplevars.lns get "foo =\n" = + { "foo" = "" { } } diff --git a/Sharp.Augeas.Test/lens/tests/test_sip_conf.aug b/Sharp.Augeas.Test/lens/tests/test_sip_conf.aug new file mode 100644 index 0000000..bd1faf1 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_sip_conf.aug @@ -0,0 +1,113 @@ +module Test_sip_conf = + +let conf = "[general] +context=default ; Default context for incoming calls +udpbindaddr=0.0.0.0 ; IP address to bind UDP listen socket to (0.0.0.0 binds to all) +; The address family of the bound UDP address is used to determine how Asterisk performs +; DNS lookups. In cases a) and c) above, only A records are considered. In case b), only +; AAAA records are considered. In case d), both A and AAAA records are considered. Note, + + +[basic-options-title](!,superclass-template);a template for my preferred codecs !@#$%#@$%^^&%%^*&$% + #comment after the title + dtmfmode=rfc2833 + context=from-office + type=friend + + +[my-codecs](!) ; a template for my preferred codecs + disallow=all + allow=ilbc + allow=g729 + allow=gsm + allow=g723 + allow=ulaw + +[2133](natted-phone,my-codecs) ;;;;; some sort of comment + secret = peekaboo +[2134](natted-phone,ulaw-phone) + secret = not_very_secret +[2136](public-phone,ulaw-phone) + secret = not_very_secret_either +" + +test Sip_Conf.lns get conf = + { "title" = "general" + { "context" = "default" + { "#comment" = "Default context for incoming calls" } + } + { "udpbindaddr" = "0.0.0.0" + { "#comment" = "IP address to bind UDP listen socket to (0.0.0.0 binds to all)" } + } + { "#comment" = "The address family of the bound UDP address is used to determine how Asterisk performs" } + { "#comment" = "DNS lookups. In cases a) and c) above, only A records are considered. In case b), only" } + { "#comment" = "AAAA records are considered. In case d), both A and AAAA records are considered. Note," } + { } + { } + } + { "title" = "basic-options-title" + { "@is_template" } + { "@use_template" = "superclass-template" } + { "#title_comment" = ";a template for my preferred codecs !@#$%#@$%^^&%%^*&$%" } + { "#comment" = "comment after the title" } + { "dtmfmode" = "rfc2833" } + { "context" = "from-office" } + { "type" = "friend" } + { } + { } + } + { "title" = "my-codecs" + { "@is_template" } + { "#title_comment" = " ; a template for my preferred codecs" } + { "disallow" = "all" } + { "allow" = "ilbc" } + { "allow" = "g729" } + { "allow" = "gsm" } + { "allow" = "g723" } + { "allow" = "ulaw" } + { } + } + { "title" = "2133" + { "@use_template" = "natted-phone" } + { "@use_template" = "my-codecs" } + { "#title_comment" = " ;;;;; some sort of comment" } + { "secret" = "peekaboo" } + } + { "title" = "2134" + { "@use_template" = "natted-phone" } + { "@use_template" = "ulaw-phone" } + { "secret" = "not_very_secret" } + } + { "title" = "2136" + { "@use_template" = "public-phone" } + { "@use_template" = "ulaw-phone" } + { "secret" = "not_very_secret_either" } + } + + (********************************************* + * Tests for update, create, delete + * + *********************************************) + + (********************************************* + * Test to confirm that we can update the + * default context + * + *********************************************) + test Sip_Conf.lns put "[general]\ncontext=default\n" after + set "title[.='general']/context" "updated" + = "[general]\ncontext=updated +" + + (********************************************* + * Test to confirm that we can create a + * new title with a context + * + *********************************************) + test Sip_Conf.lns put "[general]\ncontext=default\n" after + set "/title[.='newtitle']" "newtitle"; set "/title[.='newtitle']/context" "foobarbaz" + = "[general]\ncontext=default +[newtitle] +context=foobarbaz +" + diff --git a/Sharp.Augeas.Test/lens/tests/test_slapd.aug b/Sharp.Augeas.Test/lens/tests/test_slapd.aug new file mode 100644 index 0000000..a4bbb4e --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_slapd.aug @@ -0,0 +1,94 @@ +module Test_slapd = + +let conf = "# This is the main slapd configuration file. See slapd.conf(5) for more +# info on the configuration options. + +####################################################################### +# Global Directives: + +# Features to permit +#allow bind_v2 + +# Schema and objectClass definitions +include /etc/ldap/schema/core.schema + +####################################################################### +# Specific Directives for database #1, of type hdb: +# Database specific directives apply to this databasse until another +# 'database' directive occurs +database hdb + +# The base of your directory in database #1 +suffix \"dc=nodomain\" + +access to attrs=userPassword,shadowLastChange + by dn=\"cn=admin,dc=nodomain\" write + by anonymous auth + by self write + by * none +" + +test Slapd.lns get conf = + { "#comment" = "This is the main slapd configuration file. See slapd.conf(5) for more" } + { "#comment" = "info on the configuration options." } + {} + { "#comment" = "######################################################################" } + { "#comment" = "Global Directives:"} + {} + { "#comment" = "Features to permit" } + { "#comment" = "allow bind_v2" } + {} + { "#comment" = "Schema and objectClass definitions" } + { "include" = "/etc/ldap/schema/core.schema" } + {} + { "#comment" = "######################################################################" } + { "#comment" = "Specific Directives for database #1, of type hdb:" } + { "#comment" = "Database specific directives apply to this databasse until another" } + { "#comment" = "'database' directive occurs" } + { "database" = "hdb" + {} + { "#comment" = "The base of your directory in database #1" } + { "suffix" = "dc=nodomain" } + {} + { "access to" = "attrs=userPassword,shadowLastChange" + { "by" = "dn=\"cn=admin,dc=nodomain\"" + { "access" = "write" } } + { "by" = "anonymous" + { "access" = "auth" } } + { "by" = "self" + { "access" = "write" } } + { "by" = "*" + { "access" = "none" } } } } + +(* Test: Slapd.lns + Full access test with who/access/control *) +test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" + by self write stop\n" = + { "access to" = "dn.subtree=\"dc=example,dc=com\"" + { "by" = "self" + { "access" = "write" } + { "control" = "stop" } } } + +(* Test: Slapd.lns + access test with who *) +test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" + by self\n" = + { "access to" = "dn.subtree=\"dc=example,dc=com\"" + { "by" = "self" } } + +(* Test: Slapd.lns + access test with who/access *) +test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" + by self write\n" = + { "access to" = "dn.subtree=\"dc=example,dc=com\"" + { "by" = "self" + { "access" = "write" } } } + +(* Test: Slapd.lns + access test with who/control *) +test Slapd.lns get "access to dn.subtree=\"dc=example,dc=com\" + by self stop\n" = + { "access to" = "dn.subtree=\"dc=example,dc=com\"" + { "by" = "self" + { "control" = "stop" } } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_smbusers.aug b/Sharp.Augeas.Test/lens/tests/test_smbusers.aug new file mode 100644 index 0000000..167e88b --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_smbusers.aug @@ -0,0 +1,31 @@ +(* +Module: Test_SmbUsers + Provides unit tests and examples for the <SmbUsers> lens. +*) + +module Test_SmbUsers = + +(* Variable: conf *) +let conf = "# this is a comment + +jarwin = JosephArwin +manderso = MarkAnderson MarkusAndersonus +users = @account +nobody = * +;commented = SomeOne +" + +(* Test: Simplevars.lns *) +test SmbUsers.lns get conf = + { "#comment" = "this is a comment" } + { } + { "jarwin" + { "username" = "JosephArwin" } } + { "manderso" + { "username" = "MarkAnderson" } + { "username" = "MarkusAndersonus" } } + { "users" + { "username" = "@account" } } + { "nobody" + { "username" = "*" } } + { "#comment" = "commented = SomeOne" } diff --git a/Sharp.Augeas.Test/lens/tests/test_solaris_system.aug b/Sharp.Augeas.Test/lens/tests/test_solaris_system.aug new file mode 100644 index 0000000..511337e --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_solaris_system.aug @@ -0,0 +1,104 @@ +(* Test for system lens *) +module Test_solaris_system = + + let conf = "*ident \"@(#)system 1.18 97/06/27 SMI\" /* SVR4 1.5 */ +* +* SYSTEM SPECIFICATION FILE +* + +moddir: /kernel /usr/kernel /other/modules + +rootfs:ufs +rootdev:/sbus@1,f8000000/esp@0,800000/sd@3,0:a + +include: win +include: sys/shmsys + +exclude: win +exclude: sys/shmsys + +forceload: drv/foo +forceload: drv/ssd + +set nautopush=32 +set noexec_user_stack=1 +set zfs:zfs_arc_max=12884901888 +set test_module:debug = 0x13 +set fcp:ssfcp_enable_auto_configuration=1 +set scsi_options = 0x7F8 +set moddebug & ~0x880 +set moddebug | 0x40 +" + + test Solaris_System.lns get conf = + { "#comment" = "ident \"@(#)system 1.18 97/06/27 SMI\" /* SVR4 1.5 */" } + { } + { "#comment" = "SYSTEM SPECIFICATION FILE" } + { } + { } + { "moddir" + { "1" = "/kernel" } + { "2" = "/usr/kernel" } + { "3" = "/other/modules" } } + { } + { "rootfs" = "ufs" } + { "rootdev" = "/sbus@1,f8000000/esp@0,800000/sd@3,0:a" } + { } + { "include" = "win" } + { "include" = "sys/shmsys" } + { } + { "exclude" = "win" } + { "exclude" = "sys/shmsys" } + { } + { "forceload" = "drv/foo" } + { "forceload" = "drv/ssd" } + { } + { "set" + { "variable" = "nautopush" } + { "operator" = "=" } + { "value" = "32" } } + { "set" + { "variable" = "noexec_user_stack" } + { "operator" = "=" } + { "value" = "1" } } + { "set" + { "module" = "zfs" } + { "variable" = "zfs_arc_max" } + { "operator" = "=" } + { "value" = "12884901888" } } + { "set" + { "module" = "test_module" } + { "variable" = "debug" } + { "operator" = "=" } + { "value" = "0x13" } } + { "set" + { "module" = "fcp" } + { "variable" = "ssfcp_enable_auto_configuration" } + { "operator" = "=" } + { "value" = "1" } } + { "set" + { "variable" = "scsi_options" } + { "operator" = "=" } + { "value" = "0x7F8" } } + { "set" + { "variable" = "moddebug" } + { "operator" = "&" } + { "value" = "~0x880" } } + { "set" + { "variable" = "moddebug" } + { "operator" = "|" } + { "value" = "0x40" } } + +(* Check that moddir supports colons and spaces *) + let moddir_colons = "moddir:/kernel:/usr/kernel:/other/modules +" + + test Solaris_System.lns get moddir_colons = + { "moddir" + { "1" = "/kernel" } + { "2" = "/usr/kernel" } + { "3" = "/other/modules" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_soma.aug b/Sharp.Augeas.Test/lens/tests/test_soma.aug new file mode 100644 index 0000000..5346af6 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_soma.aug @@ -0,0 +1,15 @@ +module Test_soma = + +let conf = "# comment +User = soma + +OptionsItem = \"-msglevel avsync=5 -ao jack -af volnorm -novideo -noconsolecontrols -nojoystick -nolirc -nomouseinput\" +Debug = 3 +" + +test Soma.lns get conf = + { "#comment" = "comment" } + { "User" = "soma" } + {} + { "OptionsItem" = "\"-msglevel avsync=5 -ao jack -af volnorm -novideo -noconsolecontrols -nojoystick -nolirc -nomouseinput\"" } + { "Debug" = "3" } diff --git a/Sharp.Augeas.Test/lens/tests/test_spacevars.aug b/Sharp.Augeas.Test/lens/tests/test_spacevars.aug new file mode 100644 index 0000000..5d02296 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_spacevars.aug @@ -0,0 +1,21 @@ +module Test_spacevars = + + let conf ="# This a spaced key/value configuration file. +keyword value + +# I like comments +very.useful-key my=value + +a.flag +" + + let lns = Spacevars.lns + + test lns get conf = + { "#comment" = "This a spaced key/value configuration file."} + { "keyword" = "value" } + {} + { "#comment" = "I like comments"} + { "very.useful-key" = "my=value" } + {} + { "a.flag" } diff --git a/Sharp.Augeas.Test/lens/tests/test_splunk.aug b/Sharp.Augeas.Test/lens/tests/test_splunk.aug new file mode 100644 index 0000000..c7ec69d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_splunk.aug @@ -0,0 +1,160 @@ +(** + * + * This module is used to test the Splunk module for valid extractions. + * Written by Tim Brigham. + * This file is licensed under the LGPLv2+, like the rest of Augeas. + **) + +module Test_splunk = + +(** inputs.conf **) + + let inputs = "[default] +host = splunk-node-1.example.com +enable_autocomplete_login = False +_meta = metakey::metaval foo::bar + +[udp://514] +connection_host = none +source = test +sourcetype = syslog + +" +test Splunk.lns get inputs = + { "target" = "default" + { "host" = "splunk-node-1.example.com" } + { "enable_autocomplete_login" = "False" } + { "_meta" = "metakey::metaval foo::bar" } + {}} + { "target" = "udp://514" + { "connection_host" = "none" } + { "source" = "test" } + { "sourcetype" = "syslog" } + {}} + + +(** web.conf **) + let web = "[settings] +enableSplunkWebSSL = 1 +enable_autocomplete_login = False +" + + +test Splunk.lns get web = + { "target" = "settings" + { "enableSplunkWebSSL" = "1" } + { "enable_autocomplete_login" = "False" } + } + + + +(** props.conf **) + + let props = "[splunkd_stdout] +PREFIX_SOURCETYPE = False +SHOULD_LINEMERGE = False +is_valid = False +maxDist = 99 + +" + +test Splunk.lns get props = + { + "target" = "splunkd_stdout" + { "PREFIX_SOURCETYPE" = "False" } + { "SHOULD_LINEMERGE" = "False" } + { "is_valid" = "False" } + { "maxDist" = "99" } + {}} + +(** tenants.conf **) + let tenants = "[tenant:default] +whitelist.0 = * +" + +test Splunk.lns get tenants = + { "target" = "tenant:default" + { "whitelist.0" = "*" } + } + + + + let server = "[license] +active_group = Free +master_uri = https://myserver.mydomain.com:8089 + +[general] +serverName = splunk-node-1 +trustedIP = 127.0.0.1 +guid = XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXXXXXXXX + +[sslConfig] +sslKeysfilePassword = $1$XX2X4XX6XXXXXXXXX + +" + +test Splunk.lns get server = + { "target" = "license" + { "active_group" = "Free" } + { "master_uri" = "https://myserver.mydomain.com:8089" } + {}} + { "target" = "general" + { "serverName" = "splunk-node-1" } + { "trustedIP" = "127.0.0.1" } + { "guid" = "XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXXXXXXXX" } + {}} + { "target" = "sslConfig" + { "sslKeysfilePassword" = "$1$XX2X4XX6XXXXXXXXX" } + {}} + + +(* test anonymous attributes *) +let anon = " +# master +serverName = splunk-node-1 + +# slave +serverName = splunk-node-2 + +[general] +serverName = splunk-node-3 + +" + +test Splunk.lns get anon = + { ".anon" + { } + { "#comment" = "master" } + { "serverName" = "splunk-node-1" } + { } + { "#comment" = "slave" } + { "serverName" = "splunk-node-2" } + { } + } + { "target" = "general" + { "serverName" = "splunk-node-3" } + { } + } + + +(* test empty value entry *) + +let override = " +[general] +# normal entry +foo = bar +# override entry +foo = +" + +test Splunk.lns get override = + { ".anon" + { } + } + { "target" = "general" + { "#comment" = "normal entry" } + { "foo" = "bar" } + { "#comment" = "override entry" } + { "foo" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_squid.aug b/Sharp.Augeas.Test/lens/tests/test_squid.aug new file mode 100644 index 0000000..9c450f9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_squid.aug @@ -0,0 +1,216 @@ +module Test_squid = + +let conf = "# comment at the beginning of the file + +auth_param negotiate children 5 +acl many_spaces rep_header Content-Disposition -i [[:space:]]{3,} +acl CONNECT method CONNECT +# comment in the middle + acl local_network src 192.168.1.0/24 + +http_access allow manager localhost +http_access allow local_network +" + +test Squid.lns get conf = + { "#comment" = "comment at the beginning of the file" } + {} + { "auth_param" + { "scheme" = "negotiate" } + { "parameter" = "children" } + { "setting" = "5" } } + { "acl" + { "many_spaces" + { "type" = "rep_header" } + { "setting" = "Content-Disposition" } + { "parameters" + { "1" = "-i" } + { "2" = "[[:space:]]{3,}" } } } } + { "acl" + { "CONNECT" + { "type" = "method" } + { "setting" = "CONNECT" } } } + { "#comment" = "comment in the middle" } + { "acl" + { "local_network" + { "type" = "src" } + { "setting" = "192.168.1.0/24" } } } + {} + { "http_access" + { "allow" = "manager" + { "parameters" + { "1" = "localhost" } } } } + { "http_access" + { "allow" = "local_network" } } + +(* + This tests the Debian lenny default squid.conf + Comments were stripped out +*) + +let debian_lenny_default = "acl all src all +acl manager proto cache_object +acl localhost src 127.0.0.1/32 +acl to_localhost dst 127.0.0.0/8 +acl purge method PURGE +acl CONNECT method CONNECT +http_access allow manager localhost +http_access deny manager +http_access allow purge localhost +http_access deny purge +http_access deny !Safe_ports +http_access deny CONNECT !SSL_ports +http_access allow localhost +http_access deny all +no_cache deny query_no_cache +icp_access allow localnet +icp_access deny all +http_port 3128 +hierarchy_stoplist cgi-bin ? +access_log /var/log/squid/access.log squid +refresh_pattern ^ftp: 1440 20% 10080 +refresh_pattern ^gopher: 1440 0% 1440 +refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 +refresh_pattern (Release|Package(.gz)*)$ 0 20% 2880 +refresh_pattern . 0 20% 4320 ignore-reload ignore-auth # testing options +acl shoutcast rep_header X-HTTP09-First-Line ^ICY\s[0-9] +upgrade_http0.9 deny shoutcast +acl apache rep_header Server ^Apache +broken_vary_encoding allow apache +extension_methods REPORT MERGE MKACTIVITY CHECKOUT +hosts_file /etc/hosts +coredump_dir /var/spool/squid +" + +test Squid.lns get debian_lenny_default = + { "acl" + { "all" + { "type" = "src" } + { "setting" = "all" } + } + } + { "acl" + { "manager" + { "type" = "proto" } + { "setting" = "cache_object" } + } + } + { "acl" + { "localhost" + { "type" = "src" } + { "setting" = "127.0.0.1/32" } + } + } + { "acl" + { "to_localhost" + { "type" = "dst" } + { "setting" = "127.0.0.0/8" } + } + } + { "acl" + { "purge" + { "type" = "method" } + { "setting" = "PURGE" } + } + } + { "acl" + { "CONNECT" + { "type" = "method" } + { "setting" = "CONNECT" } + } + } + { "http_access" + { "allow" = "manager" + { "parameters" + { "1" = "localhost" } + } + } + } + { "http_access" + { "deny" = "manager" } + } + { "http_access" + { "allow" = "purge" + { "parameters" + { "1" = "localhost" } + } + } + } + { "http_access" + { "deny" = "purge" } + } + { "http_access" + { "deny" = "!Safe_ports" } + } + { "http_access" + { "deny" = "CONNECT" + { "parameters" + { "1" = "!SSL_ports" } + } + } + } + { "http_access" + { "allow" = "localhost" } + } + { "http_access" + { "deny" = "all" } + } + { "no_cache" = "deny query_no_cache" } + { "icp_access" = "allow localnet" } + { "icp_access" = "deny all" } + { "http_port" = "3128" } + { "hierarchy_stoplist" = "cgi-bin ?" } + { "access_log" = "/var/log/squid/access.log squid" } + { "refresh_pattern" = "^ftp:" + { "min" = "1440" } + { "percent" = "20" } + { "max" = "10080" } } + { "refresh_pattern" = "^gopher:" + { "min" = "1440" } + { "percent" = "0" } + { "max" = "1440" } } + { "refresh_pattern" = "(/cgi-bin/|\?)" + { "case_insensitive" } + { "min" = "0" } + { "percent" = "0" } + { "max" = "0" } } + { "refresh_pattern" = "(Release|Package(.gz)*)$" + { "min" = "0" } + { "percent" = "20" } + { "max" = "2880" } } + { "refresh_pattern" = "." + { "min" = "0" } + { "percent" = "20" } + { "max" = "4320" } + { "option" = "ignore-reload" } + { "option" = "ignore-auth" } + { "#comment" = "testing options" } } + { "acl" + { "shoutcast" + { "type" = "rep_header" } + { "setting" = "X-HTTP09-First-Line" } + { "parameters" + { "1" = "^ICY\s[0-9]" } + } + } + } + { "upgrade_http0.9" + { "deny" = "shoutcast" } } + { "acl" + { "apache" + { "type" = "rep_header" } + { "setting" = "Server" } + { "parameters" + { "1" = "^Apache" } + } + } + } + { "broken_vary_encoding" + { "allow" = "apache" } } + { "extension_methods" + { "1" = "REPORT" } + { "2" = "MERGE" } + { "3" = "MKACTIVITY" } + { "4" = "CHECKOUT" } } + { "hosts_file" = "/etc/hosts" } + { "coredump_dir" = "/var/spool/squid" } diff --git a/Sharp.Augeas.Test/lens/tests/test_ssh.aug b/Sharp.Augeas.Test/lens/tests/test_ssh.aug new file mode 100644 index 0000000..456624e --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_ssh.aug @@ -0,0 +1,132 @@ +(* Module: Test_ssh *) +module Test_ssh = + + let conf = +"# start +IdentityFile /etc/ssh/identity.asc + +Match final all + GSSAPIAuthentication yes + +Host suse.cz + ForwardAgent yes +SendEnv LC_LANG + +Host * + ForwardAgent no +ForwardX11Trusted yes + +# IdentityFile ~/.ssh/identity + SendEnv LC_IDENTIFICATION LC_ALL LC_* +ProxyCommand ssh -q -W %h:%p gateway.example.com +RemoteForward [1.2.3.4]:20023 localhost:22 +RemoteForward 2221 lhost1:22 +LocalForward 3001 remotehost:3000 +Ciphers aes128-ctr,aes192-ctr +MACs hmac-md5,hmac-sha1,umac-64@openssh.com +HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,ssh-rsa-cert-v01@openssh.com,ssh-rsa +KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 +PubkeyAcceptedKeyTypes ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,ssh-rsa-cert-v01@openssh.com,ssh-rsa +" + + test Ssh.lns get conf = + { "#comment" = "start" } + { "IdentityFile" = "/etc/ssh/identity.asc" } + { } + { "Match" + { "Condition" + { "final" = "all" } + } + { "Settings" + { "GSSAPIAuthentication" = "yes" } + { } + } + } + { "Host" = "suse.cz" + { "ForwardAgent" = "yes" } + { "SendEnv" + { "1" = "LC_LANG" } } + { } + } + { "Host" = "*" + { "ForwardAgent" = "no" } + { "ForwardX11Trusted" = "yes" } + { } + { "#comment" = "IdentityFile ~/.ssh/identity" } + { "SendEnv" + { "1" = "LC_IDENTIFICATION" } + { "2" = "LC_ALL" } + { "3" = "LC_*" } } + { "ProxyCommand" = "ssh -q -W %h:%p gateway.example.com" } + { "RemoteForward" + { "[1.2.3.4]:20023" = "localhost:22" } + } + { "RemoteForward" + { "2221" = "lhost1:22" } + } + { "LocalForward" + { "3001" = "remotehost:3000" } + } + { "Ciphers" + { "1" = "aes128-ctr" } + { "2" = "aes192-ctr" } + } + { "MACs" + { "1" = "hmac-md5" } + { "2" = "hmac-sha1" } + { "3" = "umac-64@openssh.com" } + } + { "HostKeyAlgorithms" + { "1" = "ssh-ed25519-cert-v01@openssh.com" } + { "2" = "ssh-ed25519" } + { "3" = "ssh-rsa-cert-v01@openssh.com" } + { "4" = "ssh-rsa" } + } + { "KexAlgorithms" + { "1" = "curve25519-sha256@libssh.org" } + { "2" = "diffie-hellman-group-exchange-sha256" } + } + { "PubkeyAcceptedKeyTypes" + { "1" = "ssh-ed25519-cert-v01@openssh.com" } + { "2" = "ssh-ed25519" } + { "3" = "ssh-rsa-cert-v01@openssh.com" } + { "4" = "ssh-rsa" } + } + } + +(* Test: Ssh.lns + Proxycommand is case-insensitive *) + +test Ssh.lns get "Proxycommand ssh -q test nc -q0 %h 22\n" = + { "Proxycommand" = "ssh -q test nc -q0 %h 22" } + +(* Test: Ssh.lns + GlobalKnownHostsFile *) +test Ssh.lns get "GlobalKnownHostsFile /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2\n" = + { "GlobalKnownHostsFile" + { "1" = "/etc/ssh/ssh_known_hosts" } + { "2" = "/etc/ssh/ssh_known_hosts2" } + } + +(* Keywords can be separated from their arguments with '=', too *) +test Ssh.lns get "Host mail.watzmann.net + LocalForward=11111 mail.watzmann.net:110\n" = + { "Host" = "mail.watzmann.net" + { "LocalForward" + { "11111" = "mail.watzmann.net:110" } } } + +test Ssh.lns get "ForwardAgent=yes\n" = + { "ForwardAgent" = "yes" } + +test Ssh.lns get "ForwardAgent =\tyes\n" = + { "ForwardAgent" = "yes" } + +(* Issue #605 *) +test Ssh.lns get "RekeyLimit 1G 1h\n" = + { "RekeyLimit" + { "amount" = "1G" } + { "duration" = "1h" } } + +test Ssh.lns get "RekeyLimit 1G\n" = + { "RekeyLimit" + { "amount" = "1G" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_sshd.aug b/Sharp.Augeas.Test/lens/tests/test_sshd.aug new file mode 100644 index 0000000..5e3a49c --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_sshd.aug @@ -0,0 +1,175 @@ +(* Module: Test_sshd *) +module Test_sshd = + + let accept_env = "Protocol 2 +AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT +AcceptEnv LC_IDENTIFICATION LC_ALL\n" + + test Sshd.lns get accept_env = + { "Protocol" = "2" } + { "AcceptEnv" + { "1" = "LC_PAPER" } + { "2" = "LC_NAME" } + { "3" = "LC_ADDRESS" } + { "4" = "LC_TELEPHONE" } + { "5" = "LC_MEASUREMENT" } } + { "AcceptEnv" + { "6" = "LC_IDENTIFICATION" } + { "7" = "LC_ALL" } } + + + test Sshd.lns get "HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_dsa_key\n" = + { "HostKey" = "/etc/ssh/ssh_host_rsa_key" } + { "HostKey" = "/etc/ssh/ssh_host_dsa_key" } + + + test Sshd.lns put accept_env after + rm "AcceptEnv"; + rm "AcceptEnv"; + set "Protocol" "1.5"; + set "X11Forwarding" "yes" + = "Protocol 1.5\nX11Forwarding yes\n" + + test Sshd.lns get "AuthorizedKeysFile %h/.ssh/authorized_keys\n" = + { "AuthorizedKeysFile" = "%h/.ssh/authorized_keys" } + + test Sshd.lns get "Subsystem sftp /usr/lib/openssh/sftp-server\n" = + { "Subsystem" + { "sftp" = "/usr/lib/openssh/sftp-server" } } + + test Sshd.lns get "Subsystem sftp-test /usr/lib/openssh/sftp-server\n" = + { "Subsystem" + { "sftp-test" = "/usr/lib/openssh/sftp-server" } } + + + + let match_blocks = "X11Forwarding yes +Match User sarko Group pres.* + Banner /etc/bienvenue.txt + X11Forwarding no +Match User bush Group pres.* Host white.house.* +Banner /etc/welcome.txt +Match Group \"Domain users\" + X11Forwarding yes +" + test Sshd.lns get match_blocks = + { "X11Forwarding" = "yes"} + { "Match" + { "Condition" { "User" = "sarko" } + { "Group" = "pres.*" } } + { "Settings" { "Banner" = "/etc/bienvenue.txt" } + { "X11Forwarding" = "no" } } } + { "Match" + { "Condition" { "User" = "bush" } + { "Group" = "pres.*" } + { "Host" = "white.house.*" } } + { "Settings" { "Banner" = "/etc/welcome.txt" } } } + { "Match" + { "Condition" { "Group" = "Domain users" } } + { "Settings" { "X11Forwarding" = "yes" } } } + + test Sshd.lns put match_blocks after + insb "Subsystem" "/Match[1]"; + set "/Subsystem/sftp" "/usr/libexec/openssh/sftp-server" + = "X11Forwarding yes +Subsystem sftp /usr/libexec/openssh/sftp-server +Match User sarko Group pres.* + Banner /etc/bienvenue.txt + X11Forwarding no +Match User bush Group pres.* Host white.house.* +Banner /etc/welcome.txt +Match Group \"Domain users\" + X11Forwarding yes\n" + +(* Test: Sshd.lns + Indent when adding to a Match group *) + test Sshd.lns put match_blocks after + set "Match[1]/Settings/PermitRootLogin" "yes"; + set "Match[1]/Settings/#comment" "a comment" = +"X11Forwarding yes +Match User sarko Group pres.* + Banner /etc/bienvenue.txt + X11Forwarding no + PermitRootLogin yes + # a comment +Match User bush Group pres.* Host white.house.* +Banner /etc/welcome.txt +Match Group \"Domain users\" + X11Forwarding yes\n" + + +(* Test: Sshd.lns + Parse Ciphers, KexAlgorithms, HostKeyAlgorithms as lists (GH issue #69) *) +test Sshd.lns get "Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes128-ctr +KexAlgorithms diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1 +HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa\n" = + { "Ciphers" + { "1" = "aes256-gcm@openssh.com" } + { "2" = "aes128-gcm@openssh.com" } + { "3" = "aes256-ctr" } + { "4" = "aes128-ctr" } + } + { "KexAlgorithms" + { "1" = "diffie-hellman-group-exchange-sha256" } + { "2" = "diffie-hellman-group14-sha1" } + { "3" = "diffie-hellman-group-exchange-sha1" } + } + { "HostKeyAlgorithms" + { "1" = "ssh-ed25519-cert-v01@openssh.com" } + { "2" = "ssh-rsa-cert-v01@openssh.com" } + { "3" = "ssh-ed25519" } + { "4" = "ssh-rsa" } + } + +(* Test: Sshd.lns + Keys are case-insensitive *) +test Sshd.lns get "ciPheRs aes256-gcm@openssh.com,aes128-ctr +maTcH User foo + x11forwarding no\n" = + { "ciPheRs" + { "1" = "aes256-gcm@openssh.com" } + { "2" = "aes128-ctr" } + } + { "maTcH" + { "Condition" + { "User" = "foo" } + } + { "Settings" + { "x11forwarding" = "no" } + } + } + +(* Test: Sshd.lns + Allow AllowGroups in Match groups (GH issue #75) *) +test Sshd.lns get "Match User foo + AllowGroups users\n" = + { "Match" { "Condition" { "User" = "foo" } } + { "Settings" { "AllowGroups" { "1" = "users" } } } } + +(* Test: Sshd.lns + Recognize quoted group names with spaces in AllowGroups and similar + (Issue #477) *) +test Sshd.lns get "Match User foo + AllowGroups math-domain-users \"access admins\"\n" = + { "Match" { "Condition" { "User" = "foo" } } + { "Settings" + { "AllowGroups" + { "1" = "math-domain-users" } + { "2" = "access admins" } } } } + +test Sshd.lns put "Match User foo\nAllowGroups users\n" after + set "/Match/Settings/AllowGroups/1" "all people" = + "Match User foo\nAllowGroups \"all people\"\n" + +test Sshd.lns put "Match User foo\nAllowGroups users\n" after + set "/Match/Settings/AllowGroups/01" "all people" = + "Match User foo\nAllowGroups users \"all people\"\n" + +test Sshd.lns put "Match User foo\nAllowGroups users\n" after + set "/Match/Settings/AllowGroups/01" "people" = + "Match User foo\nAllowGroups users people\n" + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_sssd.aug b/Sharp.Augeas.Test/lens/tests/test_sssd.aug new file mode 100644 index 0000000..b5ea771 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_sssd.aug @@ -0,0 +1,45 @@ +(* +Module: Test_sssd + Test cases for the sssd lense + +Author: Erinn Looney-Triggs + +About: License + This file is licensed under the LGPLv2+, like the rest of Augeas. +*) +module Test_sssd = + +let conf = "[domain/example.com] +#Comment here +; another comment +cache_credentials = True +krb5_store_password_if_offline = True +ipa_server = _srv_, ipa.example.com +[sssd] +services = nss, pam +config_file_version = 2 + +domains = example.com +[nss] + +[pam] +" + +test Sssd.lns get conf = + { "target" = "domain/example.com" + { "#comment" = "Comment here" } + { "#comment" = "another comment" } + { "cache_credentials" = "True" } + { "krb5_store_password_if_offline" = "True" } + { "ipa_server" = "_srv_, ipa.example.com" } + } + { "target" = "sssd" + { "services" = "nss, pam" } + { "config_file_version" = "2" } + { } + { "domains" = "example.com" } + } + { "target" = "nss" + { } + } + { "target" = "pam" } diff --git a/Sharp.Augeas.Test/lens/tests/test_star.aug b/Sharp.Augeas.Test/lens/tests/test_star.aug new file mode 100644 index 0000000..8f0064a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_star.aug @@ -0,0 +1,63 @@ +module Test_star = + +let conf = "# @(#)star.dfl 1.2 05/08/09 Copyright 2003 J. Schilling +# +# This file is /etc/default/star + +STAR_FIFOSIZE= 32m + +STAR_FIFOSIZE_MAX= 100m + +archive0=/dev/rmt/0 20 0 N +archive1=/dev/rmt/0n 20 0 n +archive2=/dev/rmt/1 20 0 y +archive3=/dev/rmt/1n 20 0 +archive4=/dev/rmt/0 126 0 +archive5=/dev/rmt/0n 126 0 +archive6=/dev/rmt/1 126 0 +archive7=/dev/rmt/1n 126 0 +" +test Star.lns get conf = + { "#comment" = "@(#)star.dfl 1.2 05/08/09 Copyright 2003 J. Schilling" } + { } + { "#comment" = "This file is /etc/default/star" } + { } + { "STAR_FIFOSIZE" = "32m" } + { } + { "STAR_FIFOSIZE_MAX" = "100m" } + { } + { "archive0" + { "device" = "/dev/rmt/0" } + { "block" = "20" } + { "size" = "0" } + { "istape" = "N" } } + { "archive1" + { "device" = "/dev/rmt/0n" } + { "block" = "20" } + { "size" = "0" } + { "istape" = "n" } } + { "archive2" + { "device" = "/dev/rmt/1" } + { "block" = "20" } + { "size" = "0" } + { "istape" = "y" } } + { "archive3" + { "device" = "/dev/rmt/1n" } + { "block" = "20" } + { "size" = "0" } } + { "archive4" + { "device" = "/dev/rmt/0" } + { "block" = "126" } + { "size" = "0" } } + { "archive5" + { "device" = "/dev/rmt/0n" } + { "block" = "126" } + { "size" = "0" } } + { "archive6" + { "device" = "/dev/rmt/1" } + { "block" = "126" } + { "size" = "0" } } + { "archive7" + { "device" = "/dev/rmt/1n" } + { "block" = "126" } + { "size" = "0" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_strongswan.aug b/Sharp.Augeas.Test/lens/tests/test_strongswan.aug new file mode 100644 index 0000000..82e960f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_strongswan.aug @@ -0,0 +1,126 @@ +(* + Some of the configuration snippets have been copied from the strongSwan + source tree. +*) + +module Test_Strongswan = + +(* conf/strongswan.conf *) +let default = " +# strongswan.conf - strongSwan configuration file +# +# Refer to the strongswan.conf(5) manpage for details +# +# Configuration changes should be made in the included files + +charon { + load_modular = yes + plugins { + include strongswan.d/charon/*.conf + } +} + +include strongswan.d/*.conf +" + +test Strongswan.lns get default = + { "#comment" = "strongswan.conf - strongSwan configuration file" } + { "#comment" = "Refer to the strongswan.conf(5) manpage for details" } + { "#comment" = "Configuration changes should be made in the included files" } + { "charon" + { "load_modular" = "yes" } + { "plugins" { "include" = "strongswan.d/charon/*.conf" } } + } + { "include" = "strongswan.d/*.conf" } + +(* conf/strongswan.conf.5.head.in *) +let man_example = " + a = b + section-one { + somevalue = asdf + subsection { + othervalue = xxx + } + # yei, a comment + yetanother = zz + } + section-two { + x = 12 + } +" + +test Strongswan.lns get man_example = + { "a" = "b" } + { "section-one" + { "somevalue" = "asdf" } + { "subsection" { "othervalue" = "xxx" } } + { "#comment" = "yei, a comment" } + { "yetanother" = "zz" } + } + { "section-two" { "x" = "12" } } + +test Strongswan.lns get "foo { bar = baz\n } quux {}\t#quuux\n" = + { "foo" { "bar" = "baz" } } + { "quux" } + { "#comment" = "quuux" } + + +let connection = " + +connections { + foo { + pools = bar, baz + proposals = aes256gcm16-aes128gcm16-ecp512, aes256-sha256-sha1-ecp256-modp4096-modp2048, 3des-md5-modp768 + } + children { + bar { + esp_proposals = aes128-sha256-sha1,3des-md5 + } + } +} +" + +test Strongswan.lns get connection = + { "connections" + { "foo" + { "#list" = "pools" + { "1" = "bar" } + { "2" = "baz" } + } + { "#proposals" = "proposals" + { "1" + { "1" = "aes256gcm16" } + { "2" = "aes128gcm16" } + { "3" = "ecp512" } + } + { "2" + { "1" = "aes256" } + { "2" = "sha256" } + { "3" = "sha1" } + { "4" = "ecp256" } + { "5" = "modp4096" } + { "6" = "modp2048" } + } + { "3" + { "1" = "3des" } + { "2" = "md5" } + { "3" = "modp768" } + } + } + } + { "children" + { "bar" + { "#proposals" = "esp_proposals" + { "1" + { "1" = "aes128" } + { "2" = "sha256" } + { "3" = "sha1" } + } + { "2" + { "1" = "3des" } + { "2" = "md5" } + } + } + } + } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_stunnel.aug b/Sharp.Augeas.Test/lens/tests/test_stunnel.aug new file mode 100644 index 0000000..a84b18f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_stunnel.aug @@ -0,0 +1,38 @@ +module Test_stunnel = + let conf ="; Test stunnel-like config file +; Foo bar baz +cert = /path/1 +key = /path/2 + +sslVersion = SSLv3 + +; another comment + +[service1] +accept = 49999 +connect = servicedest:1234 + +[service2] +accept = 1234 +" + + test Stunnel.lns get conf = + { ".anon" + { "#comment" = "Test stunnel-like config file" } + { "#comment" = "Foo bar baz" } + { "cert" = "/path/1" } + { "key" = "/path/2" } + {} + { "sslVersion" = "SSLv3" } + {} + { "#comment" = "another comment" } + {} + } + { "service1" + { "accept" = "49999" } + { "connect" = "servicedest:1234" } + {} + } + { "service2" + { "accept" = "1234" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_subversion.aug b/Sharp.Augeas.Test/lens/tests/test_subversion.aug new file mode 100644 index 0000000..0090dad --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_subversion.aug @@ -0,0 +1,118 @@ +(* +Module: Test_Subversion + Provides unit tests and examples for the <Subversion> lens. +*) + +module Test_Subversion = + +(* Variable: conf *) +let conf = "# This file configures various client-side behaviors. +[auth] +password-stores = gnome-keyring,kwallet +store-passwords = no +store-auth-creds = no + +[helpers] +editor-cmd = /usr/bin/vim +diff-cmd = /usr/bin/diff +diff3-cmd = /usr/bin/diff3 +diff3-has-program-arg = yes + +[tunnels] +ssh = $SVN_SSH ssh -o ControlMaster=no +rsh = /path/to/rsh -l myusername + +[miscellany] +global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo + *.rej *~ #*# .#* .*.swp .DS_Store +# Set log-encoding to the default encoding for log messages +log-encoding = latin1 +use-commit-times = yes +no-unlock = yes +mime-types-file = /path/to/mime.types +preserved-conflict-file-exts = doc ppt xls od? +enable-auto-props = yes +interactive-conflicts = no + +[auto-props] +*.c = svn:eol-style=native +*.cpp = svn:eol-style=native +*.h = svn:eol-style=native +*.dsp = svn:eol-style=CRLF +*.dsw = svn:eol-style=CRLF +*.sh = svn:eol-style=native;svn:executable +*.txt = svn:eol-style=native +*.png = svn:mime-type=image/png +*.jpg = svn:mime-type=image/jpeg +Makefile = svn:eol-style=native +" + +(* Test: Subversion.lns *) +test Subversion.lns get conf = +{ "#comment" = "This file configures various client-side behaviors." } + { "auth" + { "password-stores" + { "1" = "gnome-keyring" } + { "2" = "kwallet" } } + { "store-passwords" = "no" } + { "store-auth-creds" = "no" } + { } + } + { "helpers" + { "editor-cmd" = "/usr/bin/vim" } + { "diff-cmd" = "/usr/bin/diff" } + { "diff3-cmd" = "/usr/bin/diff3" } + { "diff3-has-program-arg" = "yes" } + { } + } + { "tunnels" + { "ssh" = "$SVN_SSH ssh -o ControlMaster=no" } + { "rsh" = "/path/to/rsh -l myusername" } + { } + } + { "miscellany" + { "global-ignores" + { "1" = "*.o" } + { "2" = "*.lo" } + { "3" = "*.la" } + { "4" = "*.al" } + { "5" = ".libs" } + { "6" = "*.so" } + { "7" = "*.so.[0-9]*" } + { "8" = "*.a" } + { "9" = "*.pyc" } + { "10" = "*.pyo" } + { "11" = "*.rej" } + { "12" = "*~" } + { "13" = "#*#" } + { "14" = ".#*" } + { "15" = ".*.swp" } + { "16" = ".DS_Store" } } + { "#comment" = "Set log-encoding to the default encoding for log messages" } + { "log-encoding" = "latin1" } + { "use-commit-times" = "yes" } + { "no-unlock" = "yes" } + { "mime-types-file" = "/path/to/mime.types" } + { "preserved-conflict-file-exts" + { "1" = "doc" } + { "2" = "ppt" } + { "3" = "xls" } + { "4" = "od?" } } + { "enable-auto-props" = "yes" } + { "interactive-conflicts" = "no" } + { } + } + { "auto-props" + { "*.c" = "svn:eol-style=native" } + { "*.cpp" = "svn:eol-style=native" } + { "*.h" = "svn:eol-style=native" } + { "*.dsp" = "svn:eol-style=CRLF" } + { "*.dsw" = "svn:eol-style=CRLF" } + { "*.sh" = "svn:eol-style=native;svn:executable" } + { "*.txt" = "svn:eol-style=native" } + { "*.png" = "svn:mime-type=image/png" } + { "*.jpg" = "svn:mime-type=image/jpeg" } + { "Makefile" = "svn:eol-style=native" } + } + + diff --git a/Sharp.Augeas.Test/lens/tests/test_sudoers.aug b/Sharp.Augeas.Test/lens/tests/test_sudoers.aug new file mode 100644 index 0000000..44228b7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_sudoers.aug @@ -0,0 +1,383 @@ +(* Module: Test_sudoers *) +module Test_sudoers = + +let test_user = [ label "user" . Sudoers.sto_to_com_user . Util.eol ]* + +(* Test: test_user *) +test test_user get "root +@pbuilder ++secre-taries +@my\ admin\ group +EXAMPLE\\\\cslack +%ad.domain.com\\\\sudo-users +MY\ EX-AMPLE\ 9\\\\cslack\ group +" = + { "user" = "root" } + { "user" = "@pbuilder" } + { "user" = "+secre-taries" } + { "user" = "@my\\ admin\\ group" } + { "user" = "EXAMPLE\\\\cslack" } + { "user" = "%ad.domain.com\\\\sudo-users" } + { "user" = "MY\\ EX-AMPLE\\ 9\\\\cslack\\ group" } + +let conf = " + Host_Alias LOCALNET = 192.168.0.0/24, localhost + + # User alias specification + +User_Alias EXAMPLE_ADMINS = cslack, EXAMPLE\\\\cslack,\ + EXAMPLE\\\\jmalstrom + +# Cmnd alias specification + +Cmnd_Alias \ + DEBIAN_TOOLS \ + = \ + /usr/bin/apt-get,\ + /usr/bin/auto-get, \ + /usr/bin/dpkg, /usr/bin/dselect, /usr/sbin/dpkg-reconfigure \ + : PBUILDER = /usr/sbin/pbuilder + + Cmnd_Alias ICAL = /bin/cat /home/rpinson/.kde/share/apps/korganizer/std.ics + + Defaults@LOCALNET !lecture, \ + \t\t tty_tickets,!fqdn, !!env_reset + +Defaults !visiblepw + +Defaults:buildd env_keep+=\"APT_CONFIG DEBIAN_FRONTEND SHELL\" +Defaults!PBUILDER env_keep+=\"HOME ARCH DIST DISTRIBUTION PDEBUILD_PBUILDER\" + +# User privilege specification +root ALL=(ALL) ALL +root ALL=(: ALL) ALL +root ALL=(ALL :ALL) ALL + +# Members of the admin group may gain root privileges +%admin ALL=(ALL) ALL, NOPASSWD : NOSETENV: \ + DEBIAN_TOOLS +%pbuilder LOCALNET = NOPASSWD: PBUILDER +www-data +biglab=(rpinson)NOEXEC: ICAL \ + : \ + localhost = NOPASSWD: /usr/bin/test + + +secretaries ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root* + +@my\ admin\ group ALL=(root) NOPASSWD: /usr/bin/python /usr/local/sbin/filterlog -iu\\=www /var/log/something.log +#includedir /etc/sudoers.d +#include /etc/sudoers.d +@includedir /etc/sudoers.d +@include /etc/sudoers.file +" + + test Sudoers.lns get conf = + {} + { "Host_Alias" + { "alias" + { "name" = "LOCALNET" } + { "host" = "192.168.0.0/24" } + { "host" = "localhost" } } } + {} + { "#comment" = "User alias specification" } + {} + { "User_Alias" + { "alias" + { "name" = "EXAMPLE_ADMINS" } + { "user" = "cslack" } + { "user" = "EXAMPLE\\\\cslack" } + { "user" = "EXAMPLE\\\\jmalstrom" } } } + {} + { "#comment" = "Cmnd alias specification" } + {} + { "Cmnd_Alias" + { "alias" + { "name" = "DEBIAN_TOOLS" } + { "command" = "/usr/bin/apt-get" } + { "command" = "/usr/bin/auto-get" } + { "command" = "/usr/bin/dpkg" } + { "command" = "/usr/bin/dselect" } + { "command" = "/usr/sbin/dpkg-reconfigure" } } + { "alias" + { "name" = "PBUILDER" } + { "command" = "/usr/sbin/pbuilder" } } } + {} + { "Cmnd_Alias" + { "alias" + { "name" = "ICAL" } + { "command" = "/bin/cat /home/rpinson/.kde/share/apps/korganizer/std.ics" } } } + {} + { "Defaults" + { "type" = "@LOCALNET" } + { "lecture" { "negate" } } + { "tty_tickets" } + { "fqdn" { "negate" } } + { "env_reset" } } + {} + { "Defaults" + { "visiblepw" { "negate" } } } + {} + { "Defaults" + { "type" = ":buildd" } + { "env_keep" + { "append" } + { "var" = "APT_CONFIG" } + { "var" = "DEBIAN_FRONTEND" } + { "var" = "SHELL" } } } + { "Defaults" + { "type" = "!PBUILDER" } + { "env_keep" + { "append" } + { "var" = "HOME" } + { "var" = "ARCH" } + { "var" = "DIST" } + { "var" = "DISTRIBUTION" } + { "var" = "PDEBUILD_PBUILDER" } } } + {} + { "#comment" = "User privilege specification" } + { "spec" + { "user" = "root" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } } } + { "spec" + { "user" = "root" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_group" = "ALL" } } } } + { "spec" + { "user" = "root" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } + { "runas_group" = "ALL" } } } } + {} + { "#comment" = "Members of the admin group may gain root privileges" } + { "spec" + { "user" = "%admin" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } + { "command" = "DEBIAN_TOOLS" + { "tag" = "NOPASSWD" } + { "tag" = "NOSETENV" } } } } + { "spec" + { "user" = "%pbuilder" } + { "host_group" + { "host" = "LOCALNET" } + { "command" = "PBUILDER" + { "tag" = "NOPASSWD" } } } } + { "spec" + { "user" = "www-data" } + { "host_group" + { "host" = "+biglab" } + { "command" = "ICAL" + { "runas_user" = "rpinson" } + { "tag" = "NOEXEC" } } } + { "host_group" + { "host" = "localhost" } + { "command" = "/usr/bin/test" + { "tag" = "NOPASSWD" } } } } + {} + { "spec" + { "user" = "+secretaries" } + { "host_group" + { "host" = "ALPHA" } + { "command" = "/usr/bin/su [!-]*" } + { "command" = "/usr/bin/su *root*" + { "negate" } } } } + {} + { "spec" + { "user" = "@my\ admin\ group" } + { "host_group" + { "host" = "ALL" } + { "command" = "/usr/bin/python /usr/local/sbin/filterlog -iu\\=www /var/log/something.log" + { "runas_user" = "root" } + { "tag" = "NOPASSWD" } + } + } + } + { "#includedir" = "/etc/sudoers.d" } + { "#include" = "/etc/sudoers.d" } + { "@includedir" = "/etc/sudoers.d" } + { "@include" = "/etc/sudoers.file" } + +test Sudoers.parameter_integer_bool + put "umask = 022" + after set "/umask/negate" "" = "!umask" + +test Sudoers.parameter_integer_bool + put "!!!!!umask" + after rm "/umask/negate"; set "/umask" "022" = "!!!!umask = 022" + +test Sudoers.parameter_integer_bool put "!!!!umask = 022" after + set "/umask/negate" "" = "!!!!!umask" + +test Sudoers.parameter_integer_bool get "!!!umask = 022" = * + +(* BZ 566134 *) + +let s = "Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin\n" +test Sudoers.lns get s = + { "Defaults" + { "secure_path" = "/sbin:/bin:/usr/sbin:/usr/bin" } } + +(* #724 - check timestamp_timeout is extracted OK if unsigned OR negative (-1) *) +test Sudoers.lns get "Defaults timestamp_timeout = 3\n" = + { "Defaults" + { "timestamp_timeout" = "3" } } +test Sudoers.lns get "Defaults timestamp_timeout = -1\n" = + { "Defaults" + { "timestamp_timeout" = "-1" } } + +(* Ticket #206, comments at end of lines *) +let commenteol = "# +Defaults targetpw # ask for +Host_Alias LOCALNET = 192.168.0.0/24 # foo eol +root ALL=(ALL) ALL # all root\n" +test Sudoers.lns get commenteol = + {} + { "Defaults" + { "targetpw" } + { "#comment" = "ask for" } } + { "Host_Alias" + { "alias" + { "name" = "LOCALNET" } + { "host" = "192.168.0.0/24" } } + { "#comment" = "foo eol" } } + { "spec" + { "user" = "root" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } } + { "#comment" = "all root" } } + +(* Allow = in commands *) +test Sudoers.spec get "root ALL= /usr/bin/mylvmbackup --configfile=/etc/mylvbackup_amanda.conf\n" = + { "spec" + { "user" = "root" } + { "host_group" + { "host" = "ALL" } + { "command" = "/usr/bin/mylvmbackup --configfile=/etc/mylvbackup_amanda.conf" } } } + +(* Allow commands without full path + -- if they begin with a lowcase letter *) +test Sudoers.spec get "root ALL= sudoedit /etc/passwd\n" = + { "spec" + { "user" = "root" } + { "host_group" + { "host" = "ALL" } + { "command" = "sudoedit /etc/passwd" } } } + +(* Ticket #263, quoted values in defaults line *) +let defaults_spaces = "Defaults passprompt=\"Your SecurID Passcode: \"\n" +test Sudoers.lns get defaults_spaces = + { "Defaults" + { "passprompt" = "\"Your SecurID Passcode: \"" } + } + +(* Ticket #263, quoted values in defaults line (string/bool parameters) *) +let defaults_spaces_strbool = "Defaults mailfrom=\"root@example.com\"\n" +test Sudoers.lns get defaults_spaces_strbool = + { "Defaults" + { "mailfrom" = "\"root@example.com\"" } + } + +(* Test: Sudoers.spec + Spec users can be aliases *) +test Sudoers.spec get "APACHE_ADMIN ALL= ALL\n" = + { "spec" + { "user" = "APACHE_ADMIN" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" } } } + +(* Test: Sudoers.spec + Ticket #337: allow period in user names *) +test Sudoers.spec get "user.one somehost = ALL\n" = + { "spec" + { "user" = "user.one" } + { "host_group" + { "host" = "somehost" } + { "command" = "ALL" } + } + } + +(* Test: Sudoers.spec + Ticket #370: allow underscore in group names *) +test Sudoers.spec get "%sudo_users ALL=(ALL) ALL\n" = + { "spec" + { "user" = "%sudo_users" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } + } + } + +(* Test: Sudoers.spec + allow ad group names with backslashes *) +test Sudoers.spec get "%ad.domain.com\\\\sudo-users ALL=(ALL) ALL\n" = + { "spec" + { "user" = "%ad.domain.com\\\\sudo-users" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } + } + } + +(* Test: Sudoers.spec + Ticket #376: allow uppercase characters in user names *) +test Sudoers.spec get "%GrOup ALL = (ALL) ALL\n" = + { "spec" + { "user" = "%GrOup" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } + } + } + +(* Test: Sudoers.spec + allow + in user-/groupnames *) +test Sudoers.spec get "group+user somehost = ALL\n" = + { "spec" + { "user" = "group+user" } + { "host_group" + { "host" = "somehost" } + { "command" = "ALL" } + } + } + +(* Test: Sudoers.spec + GH #262: Sudoers lens doesn't support `!` for command aliases *) +test Sudoers.spec get "%opssudoers ALL=(ALL) ALL, !!!BANNED\n" = + { "spec" + { "user" = "%opssudoers" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } + { "command" = "BANNED" + { "negate" } } + } + } + +(* Test: Sudoers.spec + Handle multiple `!` properly in commands *) +test Sudoers.spec get "%opssudoers ALL=(ALL) ALL, !!!/bin/mount\n" = + { "spec" + { "user" = "%opssudoers" } + { "host_group" + { "host" = "ALL" } + { "command" = "ALL" + { "runas_user" = "ALL" } } + { "command" = "/bin/mount" + { "negate" } } + } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_sysconfig.aug b/Sharp.Augeas.Test/lens/tests/test_sysconfig.aug new file mode 100644 index 0000000..660844f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_sysconfig.aug @@ -0,0 +1,162 @@ +(* Test for sysconfig lens *) +module Test_sysconfig = + + let lns = Sysconfig.lns + + let eth_static = "# Intel Corporation PRO/100 VE Network Connection +DEVICE=eth0 +BOOTPROTO=static +BROADCAST=172.31.0.255 +HWADDR=ab:cd:ef:12:34:56 +export IPADDR=172.31.0.31 # this is our IP +#DHCP_HOSTNAME=host.example.com +NETMASK=255.255.255.0 +NETWORK=172.31.0.0 +unset ONBOOT # We do not want this var +" + let empty_val = "EMPTY=\nDEVICE=eth0\n" + + let key_brack = "SOME_KEY[1]=\nDEVICE=eth0\n" + + test lns get eth_static = + { "#comment" = "Intel Corporation PRO/100 VE Network Connection" } + { "DEVICE" = "eth0" } + { "BOOTPROTO" = "static" } + { "BROADCAST" = "172.31.0.255" } + { "HWADDR" = "ab:cd:ef:12:34:56" } + { "IPADDR" = "172.31.0.31" + { "export" } + { "#comment" = "this is our IP" } } + { "#comment" = "DHCP_HOSTNAME=host.example.com" } + { "NETMASK" = "255.255.255.0" } + { "NETWORK" = "172.31.0.0" } + { "@unset" + { "1" = "ONBOOT" } + { "#comment" = "We do not want this var" } } + + test lns put eth_static after + set "BOOTPROTO" "dhcp" ; + rm "IPADDR" ; + rm "BROADCAST" ; + rm "NETMASK" ; + rm "NETWORK" + = "# Intel Corporation PRO/100 VE Network Connection +DEVICE=eth0 +BOOTPROTO=dhcp +HWADDR=ab:cd:ef:12:34:56 +#DHCP_HOSTNAME=host.example.com +unset ONBOOT # We do not want this var +" + test lns get empty_val = + { "EMPTY" = "" } { "DEVICE" = "eth0" } + + test lns get key_brack = + { "SOME_KEY[1]" = "" } { "DEVICE" = "eth0" } + + test lns get "smartd_opts=\"-q never\"\n" = + { "smartd_opts" = "-q never" } + + test lns get "var=val \n" = { "var" = "val" } + + test lns get ". /etc/java/java.conf\n" = + { ".source" = "/etc/java/java.conf" } + + (* Quoted strings and other oddities *) + test lns get "var=\"foo 'bar'\"\n" = + { "var" = "foo 'bar'" } + + test lns get "var=\"eth0\"\n" = + { "var" = "eth0" } + + test lns get "var='eth0'\n" = + { "var" = "eth0" } + + test lns get "var='Some \"funny\" value'\n" = + { "var" = "Some \"funny\" value" } + + test lns get "var=\"\\\"\"\n" = + { "var" = "\\\"" } + + test lns get "var=\\\"\n" = + { "var" = "\\\"" } + + test lns get "var=ab#c\n" = + { "var" = "ab#c" } + + test lns get "var='ab#c'\n" = + { "var" = "ab#c" } + + test lns get "var=\"ab#c\"\n" = + { "var" = "ab#c" } + + test lns get "var=\"ab#c\"\n" = + { "var" = "ab#c" } + + (* We don't handle backticks *) + test lns get + "var=`grep nameserver /etc/resolv.conf | head -1`\n" = * + + test lns get "var=ab #c\n" = + { "var" = "ab" + { "#comment" = "c" } } + + test lns put "var=ab #c\n" + after rm "/var/#comment" = "var=ab\n" + + test lns put "var=ab\n" + after set "/var/#comment" "this is a var" = + "var=ab # this is a var\n" + + (* Test semicolons *) + test lns get "VAR1=\"this;is;a;test\"\nVAR2=this;\n" = + { "VAR1" = "this;is;a;test" } + { "VAR2" = "this" } + + (* BZ 761246 *) + test lns get "DEVICE=\"eth0\";\n" = + { "DEVICE" = "eth0" } + + test lns put "DEVICE=\"eth0\";\n" after + set "/DEVICE" "em1" = "DEVICE=\"em1\";\n" + + test lns get "DEVICE=\"eth0\"; # remark\n" = + { "DEVICE" = "eth0" } + { "#comment" = "remark" } + + (* Bug 109: allow a bare export *) + test lns get "export FOO\n" = + { "@export" + { "1" = "FOO" } } + + (* Check we put quotes in when changes require them *) + test lns put "var=\"v\"\n" after rm "/foo" = + "var=\"v\"\n" + + test lns put "var=v\n" after set "/var" "v w"= + "var=\"v w\"\n" + + test lns put "var='v'\n" after set "/var" "v w"= + "var='v w'\n" + + test lns put "var=v\n" after set "/var" "v'w"= + "var=\"v'w\"\n" + + test lns put "var=v\n" after set "/var" "v\"w"= + "var='v\"w'\n" + + (* RHBZ#1043636: empty comment lines after comments *) + test lns get "#MOUNTD_NFS_V3\n#\n" = + { "#comment" = "MOUNTD_NFS_V3" } + + (* Handle leading whitespace at the beginning of a line correctly *) + test lns get " var=value\n" = { "var" = "value" } + + test lns put " var=value\n" after set "/var" "val2" = " var=val2\n" + + test lns get "\t \tvar=value\n" = { "var" = "value" } + + test lns get " export var=value\n" = { "var" = "value" { "export" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_sysconfig_route.aug b/Sharp.Augeas.Test/lens/tests/test_sysconfig_route.aug new file mode 100644 index 0000000..a3c2275 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_sysconfig_route.aug @@ -0,0 +1,15 @@ +(* +Module: Test_Sysconfig_Route + Provides unit tests and examples for the <Sysconfig_Route> lens. +*) +module Test_sysconfig_route = + +(* Test: Sysconfig_Route.lns *) +test Sysconfig_Route.lns get "10.40.11.102/32 via 10.40.8.1\n10.1.8.0/24 via 10.40.8.254\n" = +{ "10.40.8.1" = "10.40.11.102/32" } +{ "10.40.8.254" = "10.1.8.0/24" } + +(* Test: Sysconfig_Route.lns *) +test Sysconfig_Route.lns get "10.40.11.102/32 via 10.40.8.1\n10.1.8.0/24 via 10.40.8.1\n" = +{ "10.40.8.1" = "10.40.11.102/32" } +{ "10.40.8.1" = "10.1.8.0/24" } diff --git a/Sharp.Augeas.Test/lens/tests/test_sysctl.aug b/Sharp.Augeas.Test/lens/tests/test_sysctl.aug new file mode 100644 index 0000000..42f31c0 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_sysctl.aug @@ -0,0 +1,51 @@ +(* +Module: Test_Sysctl + Provides unit tests and examples for the <Sysctl> lens. +*) + +module Test_sysctl = + +(* Variable: default_sysctl *) +let default_sysctl = "# Kernel sysctl configuration file +# Controls IP packet forwarding +net.ipv4.ip_forward = 0 + +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.conf.default.accept_source_route = \t0 +kernel.sysrq = 0 + +; Semicolon comments are also allowed +net.ipv4.tcp_mem = \t393216 524288 786432 +" + +(* Test: Sysctl.lns *) +test Sysctl.lns get default_sysctl = + { "#comment" = "Kernel sysctl configuration file" } + { "#comment" = "Controls IP packet forwarding"} + { "net.ipv4.ip_forward" = "0" } + { } + { "net.ipv4.conf.default.rp_filter" = "1" } + { "net.ipv4.conf.default.accept_source_route" = "0" } + { "kernel.sysrq" = "0" } + { } + { "#comment" = "Semicolon comments are also allowed" } + { "net.ipv4.tcp_mem" = "393216 524288 786432" } + +(* Test: Sysctl.lns *) +test Sysctl.lns put default_sysctl after + set "net.ipv4.ip_forward" "1" ; + rm "net.ipv4.conf.default.rp_filter" ; + rm "net.ipv4.conf.default.accept_source_route" ; + rm "kernel.sysrq" + = "# Kernel sysctl configuration file +# Controls IP packet forwarding +net.ipv4.ip_forward = 1 + + +; Semicolon comments are also allowed +net.ipv4.tcp_mem = \t393216 524288 786432 +" + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_syslog.aug b/Sharp.Augeas.Test/lens/tests/test_syslog.aug new file mode 100644 index 0000000..2621491 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_syslog.aug @@ -0,0 +1,356 @@ +module Test_syslog = + + let conf="# $FreeBSD: src/etc/syslog.conf,v 1.30.2.1 2009/08/03 08:13:06 kensmith Exp $ +# + +daemon.info /var/log/cvsupd.log +security.* -/var/log/security +*.notice;authpriv.none;kern.debug;lpr.info;mail.crit;news.err /var/log/messages +uucp,news.crit /var/log/spooler +*.emerg * +daemon.!info /var/log/foo +daemon.<=info /var/log/foo +daemon.!<=info /var/log/foo +*.* @syslog.far.away +*.* @syslog.far.away:123 +*.* @@syslog.far.away +*.* @@syslog.far.away:123 +*.* @[2001::1]:514 +*.* foo,bar +*.* |\"/usr/bin/soft arg\" +!startslip +# get that out +*.* /var/log/slip.log +!pppd,ppp + +*.* /var/log/ppp.log +!+startslip +*.* /var/log/slip.log +!-startslip +*.* /var/log/slip.log +#!pppd +*.* /var/log/ppp.log ++foo.example.com +daemon.info /var/log/cvsupd.log ++foo.example.com,bar.example.com +daemon.info /var/log/cvsupd.log +#+bar.example.com +daemon.info /var/log/cvsupd.log +-foo.example.com +daemon.info /var/log/cvsupd.log ++* +daemon.info /var/log/cvsupd.log +!* +daemon.info /var/log/cvsupd.log +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +# !pppd +" + + test Syslog.lns get conf = + { "#comment" = "$FreeBSD: src/etc/syslog.conf,v 1.30.2.1 2009/08/03 08:13:06 kensmith Exp $" } + { } + { } + { "entry" + { "selector" { "facility" = "daemon" } { "level" = "info" } } + { "action" { "file" = "/var/log/cvsupd.log" } } + } + { "entry" + { "selector" { "facility" = "security" } { "level" = "*" } } + { "action" { "no_sync" } { "file" = "/var/log/security" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "notice" } } + { "selector" { "facility" = "authpriv" } { "level" = "none" } } + { "selector" { "facility" = "kern" } { "level" = "debug" } } + { "selector" { "facility" = "lpr" } { "level" = "info" } } + { "selector" { "facility" = "mail" } { "level" = "crit" } } + { "selector" { "facility" = "news" } { "level" = "err" } } + { "action" { "file" = "/var/log/messages" } } + } + { "entry" + { "selector" { "facility" = "uucp" } { "facility" = "news" } { "level" = "crit" } } + { "action" { "file" = "/var/log/spooler" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "emerg" } } + { "action" { "user" = "*" } } + } + { "entry" + { "selector" { "facility" = "daemon" } { "comparison" = "!" } { "level" = "info" } } + { "action" { "file" = "/var/log/foo" } } + } + { "entry" + { "selector" { "facility" = "daemon" } { "comparison" = "<=" } { "level" = "info" } } + { "action" { "file" = "/var/log/foo" } } + } + { "entry" + { "selector" { "facility" = "daemon" } { "comparison" = "!<=" } { "level" = "info" } } + { "action" { "file" = "/var/log/foo" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "protocol" = "@" } { "hostname" = "syslog.far.away" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "protocol" = "@" } { "hostname" = "syslog.far.away" } { "port" = "123" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "protocol" = "@@" } { "hostname" = "syslog.far.away" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "protocol" = "@@" } { "hostname" = "syslog.far.away" } { "port" = "123" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "protocol" = "@" } { "hostname" = "[2001::1]" } { "port" = "514" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "user" = "foo" } { "user" = "bar" } } + } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "program" = "\"/usr/bin/soft arg\"" } } + } + { "program" + { "program" = "startslip" } + { "#comment" = "get that out" } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "file" = "/var/log/slip.log" } } + } + } + { "program" + { "program" = "pppd" } + { "program" = "ppp" } + { } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "file" = "/var/log/ppp.log" } } + } + } + { "program" + { "program" = "startslip" } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "file" = "/var/log/slip.log" } } + } + } + { "program" + { "reverse" } + { "program" = "startslip" } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "file" = "/var/log/slip.log" } } + } + } + { "program" + { "program" = "pppd" } + { "entry" + { "selector" { "facility" = "*" } { "level" = "*" } } + { "action" { "file" = "/var/log/ppp.log" } } + } + } + { "hostname" + { "hostname" = "foo.example.com" } + { "entry" + { "selector" { "facility" = "daemon" } { "level" = "info" } } + { "action" { "file" = "/var/log/cvsupd.log" } } + } + } + { "hostname" + { "hostname" = "foo.example.com" } + { "hostname" = "bar.example.com" } + { "entry" + { "selector" { "facility" = "daemon" } { "level" = "info" } } + { "action" { "file" = "/var/log/cvsupd.log" } } + } + } + { "hostname" + { "hostname" = "bar.example.com" } + { "entry" + { "selector" { "facility" = "daemon" } { "level" = "info" } } + { "action" { "file" = "/var/log/cvsupd.log" } } + } + } + { "hostname" + { "reverse" } + { "hostname" = "foo.example.com" } + { "entry" + { "selector" { "facility" = "daemon" } { "level" = "info" } } + { "action" { "file" = "/var/log/cvsupd.log" } } + } + } + { "hostname" + { "hostname" = "*" } + { "entry" + { "selector" { "facility" = "daemon" } { "level" = "info" } } + { "action" { "file" = "/var/log/cvsupd.log" } } + } + } + { "program" + { "program" = "*" } + { "entry" + { "selector" { "facility" = "daemon" } { "level" = "info" } } + { "action" { "file" = "/var/log/cvsupd.log" } } } + { "entry" + { "selector" { "facility" = "*" } { "comparison" = "=" } { "level" = "debug" } } + { "selector" { "facility" = "auth" } { "facility" = "authpriv" } { "level" = "none" } } + { "selector" { "facility" = "news" } { "level" = "none" } } + { "selector" { "facility" = "mail" } { "level" = "none" } } + { "action" { "no_sync" } { "file" = "/var/log/debug" } } } + { "#comment" = "!pppd" } + } + + (* changing file *) + test Syslog.lns put "*.* /var\n" after + set "/entry[1]/action/file" "/foo" + = "*.* /foo\n" + + (* changing file to discard *) + test Syslog.lns put "*.* /var\n" after + rm "/entry[1]/action/file" ; + set "/entry[1]/action/discard" "" + = "*.* ~\n" + + (* removing entry *) + test Syslog.lns put "*.* /var\n" after + rm "/entry[1]" + = "" + + (* changing facility and level *) + test Syslog.lns put "*.* /var\n" after + set "/entry[1]/selector/facility" "daemon" ; + set "/entry[1]/selector/level" "info" + = "daemon.info /var\n" + + (* insert a facility *) + test Syslog.lns put "daemon.* /var\n" after + insa "facility" "/entry/selector/facility" ; + set "/entry/selector/facility[2]" "mail" + = "daemon,mail.* /var\n" + + (* creating an entry *) + test Syslog.lns put "" after + set "/entry/selector/facility" "daemon" ; + set "/entry/selector/level" "info" ; + set "/entry/action/file" "/var" + = "daemon.info\t/var\n" + + (* inserting an entry before *) + test Syslog.lns put "*.* /var\n" after + insb "entry" "/entry" ; + set "/entry[1]/selector/facility" "daemon" ; + set "/entry[1]/selector/level" "info" ; + set "/entry[1]/action/file" "/foo" + = "daemon.info /foo\n*.*\t/var\n" + + (* inserting an entry after *) + test Syslog.lns put "*.* /var\n" after + insa "entry" "/entry" ; + set "/entry[2]/selector/facility" "daemon" ; + set "/entry[2]/selector/level" "info" ; + set "/entry[2]/action/file" "/foo" + = "*.* /var\ndaemon.info\t/foo\n" + + (* insert sync on a file *) + test Syslog.lns put "*.* /var\n" after + insb "no_sync" "/entry/action/file" + = "*.* -/var\n" + + (* changing file to remote host *) + test Syslog.lns put "*.* /var\n" after + rm "/entry/action/file" ; + set "/entry/action/protocol" "@" ; + set "/entry/action/hostname" "far.far.away" + = "*.* @far.far.away\n" + + (* changing file to remote host *) + test Syslog.lns put "*.* /var/lib\n" after + rm "/entry/action/file" ; + set "/entry/action/protocol" "@@" ; + set "/entry/action/hostname" "far.far.away" + = "*.* @@far.far.away\n" + + (* changing file to * *) + test Syslog.lns put "*.* /var\n" after + rm "/entry/action/file" ; + set "/entry/action/user" "*" + = "*.* *\n" + + (* changing file to users *) + test Syslog.lns put "*.* /var\n" after + rm "/entry/action/file" ; + set "/entry/action/user[1]" "john" ; + set "/entry/action/user[2]" "paul" ; + set "/entry/action/user[3]" "george" ; + set "/entry/action/user[4]" "ringo" + = "*.* john,paul,george,ringo\n" + + (* changing file to program *) + test Syslog.lns put "*.* /var\n" after + rm "/entry/action/file" ; + set "/entry/action/program" "/usr/bin/foo" + = "*.* |/usr/bin/foo\n" + + (* inserting a matching program *) + test Syslog.lns put "" after + insa "program" "/" ; + set "/program/program" "foo" + = "!foo\n" + + (* inserting an entry to a matching program *) + test Syslog.lns put "!foo\n" after + set "/program/entry/selector/facility" "*" ; + set "/program/entry/selector/level" "*" ; + set "/program/entry/action/file" "/foo" + = "!foo\n*.*\t/foo\n" + + (* inserting a matching hostname *) + test Syslog.lns put "" after + insa "hostname" "/" ; + set "/hostname/hostname" "foo.foo.away" + = "+foo.foo.away\n" + + (* inserting an entry to a matching hostname *) + test Syslog.lns put "+foo.foo.away\n" after + set "/hostname/entry/selector/facility" "*" ; + set "/hostname/entry/selector/level" "*" ; + set "/hostname/entry/action/file" "/foo" + = "+foo.foo.away\n*.*\t/foo\n" + + (* inserting a reverse matching hostname *) + test Syslog.lns put "" after + insa "hostname" "/" ; + set "/hostname/reverse" "" ; + set "/hostname/hostname" "foo.foo.away" + = "-foo.foo.away\n" + + (* tokens can contain capital letters *) + test Syslog.lns get "LOCAL5.* -/var/log/foo.log\n" = + { "entry" + { "selector" + { "facility" = "LOCAL5" } + { "level" = "*" } + } + { "action" + { "no_sync" } + { "file" = "/var/log/foo.log" } + } + } + + (* test for commented out statements *) + test Syslog.lns put "" after + set "#comment" "!pppd" = "# !pppd\n" + + (* allow space before comments *) + test Syslog.lns get " \t# space comment\n" = + { "#comment" = "space comment" } + + test Syslog.lns get "include /etc/syslog.d\n" = + { "include" = "/etc/syslog.d" } diff --git a/Sharp.Augeas.Test/lens/tests/test_systemd.aug b/Sharp.Augeas.Test/lens/tests/test_systemd.aug new file mode 100644 index 0000000..19c5707 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_systemd.aug @@ -0,0 +1,355 @@ +(* +Module: Test_Systemd + Provides unit tests and examples for the <Systemd> lens. +*) + +module Test_Systemd = + +(* Variable: desc *) +let desc = "[Unit] +Description=RPC +Description=RPC bind service +Description=RPC bind\\ +service +Description= Resets System Activity Logs +" +(* Test: Systemd.lns *) +test Systemd.lns get desc = + { "Unit" + { "Description" + { "value" = "RPC" } + } + { "Description" + { "value" = "RPC bind service" } + } + { "Description" + { "value" = "RPC bind\ +service" } + } + { "Description" + { "value" = "Resets System Activity Logs" } + } + } + +(* Variable: multi *) +let multi = "[Unit] +After=syslog.target network.target +Also=canberra-system-shutdown.service canberra-system-shutdown-reboot.service +Before=sysinit.target shutdown.target +CapabilityBoundingSet=CAP_SYS_ADMIN CAP_SETUID CAP_SETGID +Conflicts=emergency.service emergency.target +ControlGroup=%R/user/%I/shared cpu:/ +ListenNetlink=kobject-uevent 1 +Requires=shutdown.target umount.target final.target +Sockets=udev-control.socket udev-kernel.socket +WantedBy=halt.target poweroff.target +Wants=local-fs.target swap.target +Wants=local-fs.target \ +swap.target +Wants=local-fs.target\ +swap.target +Wants= local-fs.target +" +(* Test: Systemd.lns *) +test Systemd.lns get multi = + { "Unit" + { "After" + { "value" = "syslog.target" } + { "value" = "network.target" } + } + { "Also" + { "value" = "canberra-system-shutdown.service" } + { "value" = "canberra-system-shutdown-reboot.service" } + } + { "Before" + { "value" = "sysinit.target" } + { "value" = "shutdown.target" } + } + { "CapabilityBoundingSet" + { "value" = "CAP_SYS_ADMIN" } + { "value" = "CAP_SETUID" } + { "value" = "CAP_SETGID" } + } + { "Conflicts" + { "value" = "emergency.service" } + { "value" = "emergency.target" } + } + { "ControlGroup" + { "value" = "%R/user/%I/shared" } + { "value" = "cpu:/" } + } + { "ListenNetlink" + { "value" = "kobject-uevent" } + { "value" = "1" } + } + { "Requires" + { "value" = "shutdown.target" } + { "value" = "umount.target" } + { "value" = "final.target" } + } + { "Sockets" + { "value" = "udev-control.socket" } + { "value" = "udev-kernel.socket" } + } + { "WantedBy" + { "value" = "halt.target" } + { "value" = "poweroff.target" } + } + { "Wants" + { "value" = "local-fs.target" } + { "value" = "swap.target" } + } + { "Wants" + { "value" = "local-fs.target" } + { "value" = "swap.target" } + } + { "Wants" + { "value" = "local-fs.target" } + { "value" = "swap.target" } + } + { "Wants" + { "value" = "local-fs.target" } + } + } + +(* Variable: exec *) +let exec = "[Service] +ExecStart=/bin/ls +ExecReload=/bin/kill -USR1 $MAINPID +ExecStart=/sbin/rpcbind -w +ExecStartPost=/bin/systemctl disable firstboot-graphical.service firstboot-text.service +ExecStartPre=/sbin/modprobe -qa $SUPPORTED_DRIVERS +ExecStop=/usr/sbin/aiccu stop +ExecStopPost=-/bin/systemctl poweroff +ExecStopPost=@/bin/systemctl poweroff +ExecStopPost=-@/bin/systemctl poweroff +ExecStopPost=/bin/systemctl\ +poweroff +" +(* Test: Systemd.lns *) +test Systemd.lns get exec = + { "Service" + { "ExecStart" + { "command" = "/bin/ls" } + } + { "ExecReload" + { "command" = "/bin/kill" } + { "arguments" + { "1" = "-USR1" } + { "2" = "$MAINPID" } + } + } + { "ExecStart" + { "command" = "/sbin/rpcbind" } + { "arguments" + { "1" = "-w" } + } + } + { "ExecStartPost" + { "command" = "/bin/systemctl" } + { "arguments" + { "1" = "disable" } + { "2" = "firstboot-graphical.service" } + { "3" = "firstboot-text.service" } + } + } + { "ExecStartPre" + { "command" = "/sbin/modprobe" } + { "arguments" + { "1" = "-qa" } + { "2" = "$SUPPORTED_DRIVERS" } + } + } + { "ExecStop" + { "command" = "/usr/sbin/aiccu" } + { "arguments" + { "1" = "stop" } + } + } + { "ExecStopPost" + { "ignoreexit" } + { "command" = "/bin/systemctl" } + { "arguments" + { "1" = "poweroff" } + } + } + { "ExecStopPost" + { "arg0" } + { "command" = "/bin/systemctl" } + { "arguments" + { "1" = "poweroff" } + } + } + { "ExecStopPost" + { "ignoreexit" } + { "arg0" } + { "command" = "/bin/systemctl" } + { "arguments" + { "1" = "poweroff" } + } + } + { "ExecStopPost" + { "command" = "/bin/systemctl" } + { "arguments" + { "1" = "poweroff" } + } + } + } + +(* Variable: env *) +let env = "[Service] +Environment=LANG=C +Environment=LANG=C FOO=BAR +Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION= +Environment=LANG=C\ +FOO=BAR +Environment=\"LANG=foo bar\" FOO=BAR +Environment=OPTIONS=\"-LS0-6d\" +Environment=OPTIONS='-LS0-6d' +Environment=VAR=\"with some spaces\" VAR2='more spaces' +Environment=VAR='with some spaces' +" +(* Test: Systemd.lns *) +test Systemd.lns get env = + { "Service" + { "Environment" + { "LANG" = "C" } + } + { "Environment" + { "LANG" = "C" } + { "FOO" = "BAR" } + } + { "Environment" + { "LANG" } + { "LANGUAGE" } + { "LC_CTYPE" } + { "LC_NUMERIC" } + { "LC_TIME" } + { "LC_COLLATE" } + { "LC_MONETARY" } + { "LC_MESSAGES" } + { "LC_PAPER" } + { "LC_NAME" } + { "LC_ADDRESS" } + { "LC_TELEPHONE" } + { "LC_MEASUREMENT" } + { "LC_IDENTIFICATION" } + } + { "Environment" + { "LANG" = "C" } + { "FOO" = "BAR" } + } + { "Environment" + { "LANG" = "foo bar" } + { "FOO" = "BAR" } + } + { "Environment" + { "OPTIONS" = "\"-LS0-6d\"" } + } + { "Environment" + { "OPTIONS" = "'-LS0-6d'" } + } + { "Environment" + { "VAR" = "\"with some spaces\"" } + { "VAR2" = "'more spaces'" } + } + { "Environment" + { "VAR" = "'with some spaces'" } + } + } + +(* Variable: unit *) +let unit = "# This file is part of systemd. +# + +# See systemd.special(7) for details + +.include /etc/example + +[Unit] +Description=Locale Service +# Add another file +.include /etc/example + +[Service] +ExecStart=/lib/systemd/systemd-localed +Type=dbus +BusName=org.freedesktop.locale1 +CapabilityBoundingSet= + +" +(* Test: Systemd.lns *) +test Systemd.lns get unit = + { "#comment" = "This file is part of systemd." } + {} + { } + { "#comment" = "See systemd.special(7) for details" } + { } + { ".include" = "/etc/example" } + { } + { "Unit" + { "Description" + { "value" = "Locale Service" } + } + { "#comment" = "Add another file" } + { ".include" = "/etc/example" } + { } + } + { "Service" + { "ExecStart" + { "command" = "/lib/systemd/systemd-localed" } + } + { "Type" + { "value" = "dbus" } + } + { "BusName" + { "value" = "org.freedesktop.locale1" } + } + { "CapabilityBoundingSet" } + { } + } + +(* Test: Systemd.lns + Values can contain backslashes *) +test Systemd.entry_command get "ExecStart=/usr/bin/find /var/lib/sudo -exec /usr/bin/touch -t 198501010000 '{}' \073\n" = + { "ExecStart" + { "command" = "/usr/bin/find" } + { "arguments" + { "1" = "/var/lib/sudo" } + { "2" = "-exec" } + { "3" = "/usr/bin/touch" } + { "4" = "-t" } + { "5" = "198501010000" } + { "6" = "'{}'" } + { "7" = "\073" } + } + } + +let exec_tmux = "ExecStart=/usr/bin/tmux unbind-key -a; \ + kill-window -t anaconda:shell; \ + bind-key ? list-keys\n" + +(* Test: Systemd.lns + Semicolons are permitted in entry values, e.g. as part of a command *) +test Systemd.entry_command get exec_tmux = + { "ExecStart" + { "command" = "/usr/bin/tmux" } + { "arguments" + { "1" = "unbind-key" } + { "2" = "-a;" } + { "3" = "kill-window" } + { "4" = "-t" } + { "5" = "anaconda:shell;" } + { "6" = "bind-key" } + { "7" = "?" } + { "8" = "list-keys" } } } + +(* Test: Systemd.lns + # and ; are OK for standalone comments, but # only for EOL comments *) +test Systemd.lns get "[Service]\n# hash\n; semicolon\nExecStart=/bin/echo # hash\n" = + { "Service" + { "#comment" = "hash" } + { "#comment" = "semicolon" } + { "ExecStart" + { "command" = "/bin/echo" } + { "#comment" = "hash" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_termcap.aug b/Sharp.Augeas.Test/lens/tests/test_termcap.aug new file mode 100644 index 0000000..7e31aba --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_termcap.aug @@ -0,0 +1,443 @@ +module Test_termcap = + +(* Sample termcap entry with escaped ':''s *) +let termcap = "vt420pc|DEC VT420 w/PC keyboard:\\ + :@7=\\E[4~:F1=\\E[23~:F2=\\E[24~:F3=\\E[11;2~:F4=\\E[12;2~:\\ + :F5=\\E[13;2~:F6=\\E[14;2~:F7=\\E[15;2~:F8=\\E[17;2~:\\ + :F9=\\E[18;2~:FA=\\E[19;2~:FB=\\E[20;2~:FC=\\E[21;2~:\\ + :FD=\\E[23;2~:FE=\\E[24;2~:FF=\\E[23~:FG=\\E[24~:FH=\\E[25~:\\ + :FI=\\E[26~:FJ=\\E[28~:FK=\\E[29~:FL=\\E[31~:FM=\\E[32~:\\ + :FN=\\E[33~:FO=\\E[34~:FP=\\E[35~:FQ=\\E[36~:FR=\\E[23;2~:\\ + :FS=\\E[24;2~:FT=\\E[25;2~:FU=\\E[26;2~:FV=\\E[28;2~:\\ + :FW=\\E[29;2~:FX=\\E[31;2~:FY=\\E[32;2~:FZ=\\E[33;2~:\\ + :Fa=\\E[34;2~:Fb=\\E[35;2~:Fc=\\E[36;2~:\\ + :S6=USR_TERM\\:vt420pcdos\\::k1=\\E[11~:k2=\\E[12~:\\ + :k3=\\E[13~:k4=\\E[14~:k5=\\E[15~:k6=\\E[17~:k7=\\E[18~:\\ + :k8=\\E[19~:k9=\\E[20~:k;=\\E[21~:kD=\\177:kh=\\E[H:\\ + :..px=\\EP1;1|%?%{16}%p1%>%t%{0}%e%{21}%p1%>%t%{1}%e%{25}%p1%>%t%{2}%e%{27}%p1%>%t%{3}%e%{30}%p1%>%t%{4}%e%{5}%;%p1%+%d/%p2%s\E\\\\:\\ + :tc=vt420: +" + +test Termcap.lns get termcap = + { "record" + { "name" = "vt420pc" } + { "name" = "DEC VT420 w/PC keyboard" } + { "capability" = "@7=\\E[4~" } + { "capability" = "F1=\\E[23~" } + { "capability" = "F2=\\E[24~" } + { "capability" = "F3=\\E[11;2~" } + { "capability" = "F4=\\E[12;2~" } + { "capability" = "F5=\\E[13;2~" } + { "capability" = "F6=\\E[14;2~" } + { "capability" = "F7=\\E[15;2~" } + { "capability" = "F8=\\E[17;2~" } + { "capability" = "F9=\\E[18;2~" } + { "capability" = "FA=\\E[19;2~" } + { "capability" = "FB=\\E[20;2~" } + { "capability" = "FC=\\E[21;2~" } + { "capability" = "FD=\\E[23;2~" } + { "capability" = "FE=\\E[24;2~" } + { "capability" = "FF=\\E[23~" } + { "capability" = "FG=\\E[24~" } + { "capability" = "FH=\\E[25~" } + { "capability" = "FI=\\E[26~" } + { "capability" = "FJ=\\E[28~" } + { "capability" = "FK=\\E[29~" } + { "capability" = "FL=\\E[31~" } + { "capability" = "FM=\\E[32~" } + { "capability" = "FN=\\E[33~" } + { "capability" = "FO=\\E[34~" } + { "capability" = "FP=\\E[35~" } + { "capability" = "FQ=\\E[36~" } + { "capability" = "FR=\\E[23;2~" } + { "capability" = "FS=\\E[24;2~" } + { "capability" = "FT=\\E[25;2~" } + { "capability" = "FU=\\E[26;2~" } + { "capability" = "FV=\\E[28;2~" } + { "capability" = "FW=\\E[29;2~" } + { "capability" = "FX=\\E[31;2~" } + { "capability" = "FY=\\E[32;2~" } + { "capability" = "FZ=\\E[33;2~" } + { "capability" = "Fa=\\E[34;2~" } + { "capability" = "Fb=\\E[35;2~" } + { "capability" = "Fc=\\E[36;2~" } + { "capability" = "S6=USR_TERM\\:vt420pcdos\\:" } + { "capability" = "k1=\\E[11~" } + { "capability" = "k2=\\E[12~" } + { "capability" = "k3=\\E[13~" } + { "capability" = "k4=\\E[14~" } + { "capability" = "k5=\\E[15~" } + { "capability" = "k6=\\E[17~" } + { "capability" = "k7=\\E[18~" } + { "capability" = "k8=\\E[19~" } + { "capability" = "k9=\\E[20~" } + { "capability" = "k;=\\E[21~" } + { "capability" = "kD=\\177" } + { "capability" = "kh=\\E[H" } + { "capability" = "..px=\\EP1;1|%?%{16}%p1%>%t%{0}%e%{21}%p1%>%t%{1}%e%{25}%p1%>%t%{2}%e%{27}%p1%>%t%{3}%e%{30}%p1%>%t%{4}%e%{5}%;%p1%+%d/%p2%s\\E\\\\" } + { "capability" = "tc=vt420" } + } + +let termcap2 = "tws-generic|dku7102|Bull Questar tws terminals:\\ + :am:es:hs:mi:ms:xn:xo:xs@:\\ + :co#80:it#8:li#24:ws#80:\\ + :AL=\\E[%dL:DC=\\E[%dP:DL=\\E[%dM:DO=\\E[%dB:LE=\\E[%dD:\\ + :RI=\\E[%dC:UP=\\E[%dA:al=\\E[L:bl=^G:bt=\\E[Z:cd=\\E[J:ce=\\E[K:\\ + :cl=\\E[2J:cm=\\E[%i%d;%df:cr=^M:ct=\\E[3g:dc=\\E[P:dl=\\E[M:\\ + :do=^J:ds=\\EPY99\\:98\\E\\\\\\E[0;98v\\E[2J\\E[v:ei=\\E[4l:\\ + :fs=\\E[v:ho=\\E[H:i1=\\E[?=h\\Ec\\E`\\E[?>h\\EPY99\\:98\\E\\\\\\\\:\\ + :i2=\\Eb\\E[?<h:im=\\E[4h:\\ + :is=\\E[5;>;12;18;?<l\\E[=h\\EP1s\\E\\\\\\E[\\027p:\\ + :k1=\\E[1u\\027:k2=\\E[2u\\027:k3=\\E[3u\\027:k4=\\E[4u\\027:\\ + :k5=\\E[5u\\027:k6=\\E[6u\\027:k7=\\E[7u\\027:k8=\\E[8u\\027:\\ + :kD=\\E[P:kb=^H:kd=\\E[B:kh=\\E[H:kl=\\E[D:kr=\\E[C:ku=\\E[A:\\ + :le=^H:ll=\\E[H\\E[A:mb=\\E[0;5m:me=\\E[0m\\017:mh=\\E[0;2m:\\ + :mr=\\E[0;7m:nd=\\E[C:rs=\\E[?=h\\Ec:se=\\E[m:sf=^J:so=\\E[0;7m:\\ + :st=\\EH:ta=\\E[I:te=\\E[0;98v\\E[2J\\E[v:\\ + :ti=\\E[?>h\\EPY99\\:98\\E\\\\\\\\:\\ + :ts=\\EPY99\\:98\\E\\\\\\E[0;98v\\E[2;7m:ue=\\E[m:up=\\E[A:\\ + :us=\\E[0;4m:ve=\\E[r:vi=\\E[1r: +" + +test Termcap.lns get termcap2 = + { "record" + { "name" = "tws-generic" } + { "name" = "dku7102" } + { "name" = "Bull Questar tws terminals" } + { "capability" = "am" } + { "capability" = "es" } + { "capability" = "hs" } + { "capability" = "mi" } + { "capability" = "ms" } + { "capability" = "xn" } + { "capability" = "xo" } + { "capability" = "xs@" } + { "capability" = "co#80" } + { "capability" = "it#8" } + { "capability" = "li#24" } + { "capability" = "ws#80" } + { "capability" = "AL=\\E[%dL" } + { "capability" = "DC=\\E[%dP" } + { "capability" = "DL=\\E[%dM" } + { "capability" = "DO=\\E[%dB" } + { "capability" = "LE=\\E[%dD" } + { "capability" = "RI=\\E[%dC" } + { "capability" = "UP=\\E[%dA" } + { "capability" = "al=\\E[L" } + { "capability" = "bl=^G" } + { "capability" = "bt=\\E[Z" } + { "capability" = "cd=\\E[J" } + { "capability" = "ce=\\E[K" } + { "capability" = "cl=\\E[2J" } + { "capability" = "cm=\\E[%i%d;%df" } + { "capability" = "cr=^M" } + { "capability" = "ct=\\E[3g" } + { "capability" = "dc=\\E[P" } + { "capability" = "dl=\\E[M" } + { "capability" = "do=^J" } + { "capability" = "ds=\\EPY99\\:98\\E\\\\\\E[0;98v\\E[2J\\E[v" } + { "capability" = "ei=\\E[4l" } + { "capability" = "fs=\\E[v" } + { "capability" = "ho=\\E[H" } + { "capability" = "i1=\\E[?=h\\Ec\\E`\\E[?>h\\EPY99\\:98\\E\\\\\\\\" } + { "capability" = "i2=\\Eb\\E[?<h" } + { "capability" = "im=\\E[4h" } + { "capability" = "is=\\E[5;>;12;18;?<l\\E[=h\\EP1s\\E\\\\\\E[\\027p" } + { "capability" = "k1=\\E[1u\\027" } + { "capability" = "k2=\\E[2u\\027" } + { "capability" = "k3=\\E[3u\\027" } + { "capability" = "k4=\\E[4u\\027" } + { "capability" = "k5=\\E[5u\\027" } + { "capability" = "k6=\\E[6u\\027" } + { "capability" = "k7=\\E[7u\\027" } + { "capability" = "k8=\\E[8u\\027" } + { "capability" = "kD=\\E[P" } + { "capability" = "kb=^H" } + { "capability" = "kd=\\E[B" } + { "capability" = "kh=\\E[H" } + { "capability" = "kl=\\E[D" } + { "capability" = "kr=\\E[C" } + { "capability" = "ku=\\E[A" } + { "capability" = "le=^H" } + { "capability" = "ll=\\E[H\\E[A" } + { "capability" = "mb=\\E[0;5m" } + { "capability" = "me=\\E[0m\\017" } + { "capability" = "mh=\\E[0;2m" } + { "capability" = "mr=\\E[0;7m" } + { "capability" = "nd=\\E[C" } + { "capability" = "rs=\\E[?=h\\Ec" } + { "capability" = "se=\\E[m" } + { "capability" = "sf=^J" } + { "capability" = "so=\\E[0;7m" } + { "capability" = "st=\\EH" } + { "capability" = "ta=\\E[I" } + { "capability" = "te=\\E[0;98v\\E[2J\\E[v" } + { "capability" = "ti=\\E[?>h\\EPY99\\:98\\E\\\\\\\\" } + { "capability" = "ts=\\EPY99\\:98\\E\\\\\\E[0;98v\\E[2;7m" } + { "capability" = "ue=\\E[m" } + { "capability" = "up=\\E[A" } + { "capability" = "us=\\E[0;4m" } + { "capability" = "ve=\\E[r" } + { "capability" = "vi=\\E[1r" } + } + +let termcap3 = "stv52|MiNT virtual console:\\ + :am:ms:\\ + :co#80:it#8:li#30:\\ + :%1=\\EH:&8=\\EK:F1=\\Ep:F2=\\Eq:F3=\\Er:F4=\\Es:F5=\\Et:F6=\\Eu:\\ + :F7=\\Ev:F8=\\Ew:F9=\\Ex:FA=\\Ey:al=\\EL:bl=^G:cd=\\EJ:ce=\\EK:\\ + :cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:k1=\\EP:\\ + :k2=\\EQ:k3=\\ER:k4=\\ES:k5=\\ET:k6=\\EU:k7=\\EV:k8=\\EW:k9=\\EX:\\ + :k;=\\EY:kD=\\177:kI=\\EI:kN=\\Eb:kP=\\Ea:kb=^H:kd=\\EB:kh=\\EE:\\ + :kl=\\ED:kr=\\EC:ku=\\EA:le=^H:mb=\\Er:md=\\EyA:me=\\Ez_:mh=\\Em:\\ + :mr=\\Ep:nd=\\EC:nw=2*\\r\\n:op=\\Eb@\\EcO:r1=\\Ez_\\Eb@\\EcA:\\ + :se=\\Eq:sf=2*\\n:so=\\Ep:sr=2*\\EI:ta=^I:te=\\Ev\\E. \\Ee\\Ez_:\\ + :ti=\\Ev\\Ee\\Ez_:ue=\\EzH:up=\\EA:us=\\EyH:ve=\\E. \\Ee:vi=\\Ef:\\ + :vs=\\E.\": +" + +test Termcap.lns get termcap3 = + { "record" + { "name" = "stv52" } + { "name" = "MiNT virtual console" } + { "capability" = "am" } + { "capability" = "ms" } + { "capability" = "co#80" } + { "capability" = "it#8" } + { "capability" = "li#30" } + { "capability" = "%1=\\EH" } + { "capability" = "&8=\\EK" } + { "capability" = "F1=\\Ep" } + { "capability" = "F2=\\Eq" } + { "capability" = "F3=\\Er" } + { "capability" = "F4=\\Es" } + { "capability" = "F5=\\Et" } + { "capability" = "F6=\\Eu" } + { "capability" = "F7=\\Ev" } + { "capability" = "F8=\\Ew" } + { "capability" = "F9=\\Ex" } + { "capability" = "FA=\\Ey" } + { "capability" = "al=\\EL" } + { "capability" = "bl=^G" } + { "capability" = "cd=\\EJ" } + { "capability" = "ce=\\EK" } + { "capability" = "cl=\\EE" } + { "capability" = "cm=\\EY%+ %+ " } + { "capability" = "cr=^M" } + { "capability" = "dl=\\EM" } + { "capability" = "do=\\EB" } + { "capability" = "ho=\\EH" } + { "capability" = "k1=\\EP" } + { "capability" = "k2=\\EQ" } + { "capability" = "k3=\\ER" } + { "capability" = "k4=\\ES" } + { "capability" = "k5=\\ET" } + { "capability" = "k6=\\EU" } + { "capability" = "k7=\\EV" } + { "capability" = "k8=\\EW" } + { "capability" = "k9=\\EX" } + { "capability" = "k;=\\EY" } + { "capability" = "kD=\\177" } + { "capability" = "kI=\\EI" } + { "capability" = "kN=\\Eb" } + { "capability" = "kP=\\Ea" } + { "capability" = "kb=^H" } + { "capability" = "kd=\\EB" } + { "capability" = "kh=\\EE" } + { "capability" = "kl=\\ED" } + { "capability" = "kr=\\EC" } + { "capability" = "ku=\\EA" } + { "capability" = "le=^H" } + { "capability" = "mb=\\Er" } + { "capability" = "md=\\EyA" } + { "capability" = "me=\\Ez_" } + { "capability" = "mh=\\Em" } + { "capability" = "mr=\\Ep" } + { "capability" = "nd=\\EC" } + { "capability" = "nw=2*\\r\\n" } + { "capability" = "op=\\Eb@\\EcO" } + { "capability" = "r1=\\Ez_\\Eb@\\EcA" } + { "capability" = "se=\\Eq" } + { "capability" = "sf=2*\\n" } + { "capability" = "so=\\Ep" } + { "capability" = "sr=2*\\EI" } + { "capability" = "ta=^I" } + { "capability" = "te=\\Ev\\E. \\Ee\\Ez_" } + { "capability" = "ti=\\Ev\\Ee\\Ez_" } + { "capability" = "ue=\\EzH" } + { "capability" = "up=\\EA" } + { "capability" = "us=\\EyH" } + { "capability" = "ve=\\E. \\Ee" } + { "capability" = "vi=\\Ef" } + { "capability" = "vs=\\E.\"" } + } + +let termcap4 = "rbcomm|IBM PC with RBcomm and EMACS keybindings:\\ + :am:bw:mi:ms:xn:\\ + :co#80:it#8:li#25:\\ + :AL=\\E[%dL:DL=\\E[%dM:al=^K:bl=^G:bt=\\E[Z:cd=^F5:ce=^P^P:\\ + :cl=^L:cm=\\037%r%+ %+ :cr=^M:cs=\\E[%i%d;%dr:dc=^W:dl=^Z:\\ + :dm=:do=^C:ec=\\E[%dX:ed=:ei=^]:im=^\\:\\ + :is=\\017\\035\\E(B\\E)0\\E[?7h\\E[?3l\\E[>8g:kb=^H:kd=^N:\\ + :ke=\\E>:kh=^A:kl=^B:kr=^F:ks=\\E=:ku=^P:le=^H:mb=\\E[5m:\\ + :md=\\E[1m:me=\\E[m:mk=\\E[8m:mr=^R:nd=^B:nw=^M\\ED:\\ + :r1=\\017\\E(B\\E)0\\025\\E[?3l\\E[>8g:rc=\\E8:rp=\\030%.%.:\\ + :sc=\\E7:se=^U:sf=\\ED:so=^R:sr=\\EM:ta=^I:te=:ti=:ue=^U:up=^^:\\ + :us=^T:ve=\\E[?25h:vi=\\E[?25l: +" + +test Termcap.lns get termcap4 = + { "record" + { "name" = "rbcomm" } + { "name" = "IBM PC with RBcomm and EMACS keybindings" } + { "capability" = "am" } + { "capability" = "bw" } + { "capability" = "mi" } + { "capability" = "ms" } + { "capability" = "xn" } + { "capability" = "co#80" } + { "capability" = "it#8" } + { "capability" = "li#25" } + { "capability" = "AL=\\E[%dL" } + { "capability" = "DL=\\E[%dM" } + { "capability" = "al=^K" } + { "capability" = "bl=^G" } + { "capability" = "bt=\\E[Z" } + { "capability" = "cd=^F5" } + { "capability" = "ce=^P^P" } + { "capability" = "cl=^L" } + { "capability" = "cm=\\037%r%+ %+ " } + { "capability" = "cr=^M" } + { "capability" = "cs=\\E[%i%d;%dr" } + { "capability" = "dc=^W" } + { "capability" = "dl=^Z" } + { "capability" = "dm=" } + { "capability" = "do=^C" } + { "capability" = "ec=\\E[%dX" } + { "capability" = "ed=" } + { "capability" = "ei=^]" } + { "capability" = "im=^\\" } + { "capability" = "is=\\017\\035\\E(B\\E)0\\E[?7h\\E[?3l\\E[>8g" } + { "capability" = "kb=^H" } + { "capability" = "kd=^N" } + { "capability" = "ke=\\E>" } + { "capability" = "kh=^A" } + { "capability" = "kl=^B" } + { "capability" = "kr=^F" } + { "capability" = "ks=\\E=" } + { "capability" = "ku=^P" } + { "capability" = "le=^H" } + { "capability" = "mb=\\E[5m" } + { "capability" = "md=\\E[1m" } + { "capability" = "me=\\E[m" } + { "capability" = "mk=\\E[8m" } + { "capability" = "mr=^R" } + { "capability" = "nd=^B" } + { "capability" = "nw=^M\\ED" } + { "capability" = "r1=\\017\\E(B\\E)0\\025\\E[?3l\\E[>8g" } + { "capability" = "rc=\\E8" } + { "capability" = "rp=\\030%.%." } + { "capability" = "sc=\\E7" } + { "capability" = "se=^U" } + { "capability" = "sf=\\ED" } + { "capability" = "so=^R" } + { "capability" = "sr=\\EM" } + { "capability" = "ta=^I" } + { "capability" = "te=" } + { "capability" = "ti=" } + { "capability" = "ue=^U" } + { "capability" = "up=^^" } + { "capability" = "us=^T" } + { "capability" = "ve=\\E[?25h" } + { "capability" = "vi=\\E[?25l" } + } + +let termcap5 = "rxvt+pcfkeys|fragment for PC-style fkeys:\\ + :#2=\\E[7$:#3=\\E[2$:#4=\\E[d:%c=\\E[6$:%e=\\E[5$:%i=\\E[c:\\ + :*4=\\E[3$:*6=\\E[4~:*7=\\E[8$:@0=\\E[1~:@7=\\E[8~:F1=\\E[23~:\\ + :F2=\\E[24~:F3=\\E[25~:F4=\\E[26~:F5=\\E[28~:F6=\\E[29~:\\ + :F7=\\E[31~:F8=\\E[32~:F9=\\E[33~:FA=\\E[34~:FB=\\E[23$:\\ + :FC=\\E[24$:FD=\\E[11\\136:FE=\\E[12\\136:FF=\\E[13\\136:FG=\\E[14\\136:\\ + :FH=\\E[15\\136:FI=\\E[17\\136:FJ=\\E[18\\136:FK=\\E[19\\136:FL=\\E[20\\136:\\ + :FM=\\E[21\\136:FN=\\E[23\\136:FO=\\E[24\\136:FP=\\E[25\\136:FQ=\\E[26\\136:\\ + :FR=\\E[28\\136:FS=\\E[29\\136:FT=\\E[31\\136:FU=\\E[32\\136:FV=\\E[33\\136:\\ + :FW=\\E[34\\136:FX=\\E[23@:FY=\\E[24@:k1=\\E[11~:k2=\\E[12~:\\ + :k3=\\E[13~:k4=\\E[14~:k5=\\E[15~:k6=\\E[17~:k7=\\E[18~:\\ + :k8=\\E[19~:k9=\\E[20~:k;=\\E[21~:kD=\\E[3~:kE=\\E[8\\136:kF=\\E[a:\\ + :kI=\\E[2~:kN=\\E[6~:kP=\\E[5~:kR=\\E[b:kd=\\E[B:kh=\\E[7~:\\ + :kl=\\E[D:kr=\\E[C:ku=\\E[A: +" + +test Termcap.lns get termcap5 = + { "record" + { "name" = "rxvt+pcfkeys" } + { "name" = "fragment for PC-style fkeys" } + { "capability" = "#2=\\E[7$" } + { "capability" = "#3=\\E[2$" } + { "capability" = "#4=\\E[d" } + { "capability" = "%c=\\E[6$" } + { "capability" = "%e=\\E[5$" } + { "capability" = "%i=\\E[c" } + { "capability" = "*4=\\E[3$" } + { "capability" = "*6=\\E[4~" } + { "capability" = "*7=\\E[8$" } + { "capability" = "@0=\\E[1~" } + { "capability" = "@7=\\E[8~" } + { "capability" = "F1=\\E[23~" } + { "capability" = "F2=\\E[24~" } + { "capability" = "F3=\\E[25~" } + { "capability" = "F4=\\E[26~" } + { "capability" = "F5=\\E[28~" } + { "capability" = "F6=\\E[29~" } + { "capability" = "F7=\\E[31~" } + { "capability" = "F8=\\E[32~" } + { "capability" = "F9=\\E[33~" } + { "capability" = "FA=\\E[34~" } + { "capability" = "FB=\\E[23$" } + { "capability" = "FC=\\E[24$" } + { "capability" = "FD=\\E[11\\136" } + { "capability" = "FE=\\E[12\\136" } + { "capability" = "FF=\\E[13\\136" } + { "capability" = "FG=\\E[14\\136" } + { "capability" = "FH=\\E[15\\136" } + { "capability" = "FI=\\E[17\\136" } + { "capability" = "FJ=\\E[18\\136" } + { "capability" = "FK=\\E[19\\136" } + { "capability" = "FL=\\E[20\\136" } + { "capability" = "FM=\\E[21\\136" } + { "capability" = "FN=\\E[23\\136" } + { "capability" = "FO=\\E[24\\136" } + { "capability" = "FP=\\E[25\\136" } + { "capability" = "FQ=\\E[26\\136" } + { "capability" = "FR=\\E[28\\136" } + { "capability" = "FS=\\E[29\\136" } + { "capability" = "FT=\\E[31\\136" } + { "capability" = "FU=\\E[32\\136" } + { "capability" = "FV=\\E[33\\136" } + { "capability" = "FW=\\E[34\\136" } + { "capability" = "FX=\\E[23@" } + { "capability" = "FY=\\E[24@" } + { "capability" = "k1=\\E[11~" } + { "capability" = "k2=\\E[12~" } + { "capability" = "k3=\\E[13~" } + { "capability" = "k4=\\E[14~" } + { "capability" = "k5=\\E[15~" } + { "capability" = "k6=\\E[17~" } + { "capability" = "k7=\\E[18~" } + { "capability" = "k8=\\E[19~" } + { "capability" = "k9=\\E[20~" } + { "capability" = "k;=\\E[21~" } + { "capability" = "kD=\\E[3~" } + { "capability" = "kE=\\E[8\\136" } + { "capability" = "kF=\\E[a" } + { "capability" = "kI=\\E[2~" } + { "capability" = "kN=\\E[6~" } + { "capability" = "kP=\\E[5~" } + { "capability" = "kR=\\E[b" } + { "capability" = "kd=\\E[B" } + { "capability" = "kh=\\E[7~" } + { "capability" = "kl=\\E[D" } + { "capability" = "kr=\\E[C" } + { "capability" = "ku=\\E[A" } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_thttpd.aug b/Sharp.Augeas.Test/lens/tests/test_thttpd.aug new file mode 100644 index 0000000..77eef85 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_thttpd.aug @@ -0,0 +1,45 @@ +(* +Module: Test_Thttpd + Provides unit tests and examples for the <Thttpd> lens. +*) + +module Test_Thttpd = + +let conf = "# This file is for thttpd processes created by /etc/init.d/thttpd. +# Commentary is based closely on the thttpd(8) 2.25b manpage, by Jef Poskanzer. + +# Specifies an alternate port number to listen on. +port=80 +host= + + dir=/var/www +chroot + novhost + + # Specifies what user to switch to after initialization when started as root. +user=www-data # EOL comment +nosymlinks # EOL comment +" + +test Thttpd.lns get conf = + { "#comment" = "This file is for thttpd processes created by /etc/init.d/thttpd." } + { "#comment" = "Commentary is based closely on the thttpd(8) 2.25b manpage, by Jef Poskanzer." } + { } + { "#comment" = "Specifies an alternate port number to listen on." } + { "port" = "80" } + { "host" = "" } + { } + { "dir" = "/var/www" } + { "chroot" } + { "novhost" } + { } + { "#comment" = "Specifies what user to switch to after initialization when started as root." } + { "user" = "www-data" + { "#comment" = "EOL comment" } + } + { "nosymlinks" + { "#comment" = "EOL comment" } + } + +(* There must not be spaces around the '=' *) +test Thttpd.lns get "port = 80" = * diff --git a/Sharp.Augeas.Test/lens/tests/test_tinc.aug b/Sharp.Augeas.Test/lens/tests/test_tinc.aug new file mode 100644 index 0000000..224de62 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_tinc.aug @@ -0,0 +1,40 @@ +module Test_tinc = + +let lns = Tinc.lns + +test lns get "Subnet = 10.1.4.5\n" = { "Subnet" = "10.1.4.5" } +test lns get "foo = bar\n" = { "foo" = "bar" } +test lns get "foo bar\n" = { "foo" = "bar" } +test lns get "foo bar\n" = { "foo" = "bar" } + +test lns get +"-----BEGIN RSA PUBLIC KEY----- +abcde +-----END RSA PUBLIC KEY-----" = { "#key" = "abcde" } + +test lns get "foo = bar\nbar = baz\n" = + { "foo" = "bar" } + { "bar" = "baz" } + +test lns get +"foo = bar + +-----BEGIN RSA PUBLIC KEY----- +bar +-----END RSA PUBLIC KEY-----" = + { "foo" = "bar" } + { } + { "#key" = "bar" } + + +(* +test lns get +"-----BEGIN RSA PUBLIC KEY----- +foo +-----END RSA PUBLIC KEY----- + +-----BEGIN RSA PUBLIC KEY----- +bar +-----END RSA PUBLIC KEY----- +" = ? +*) diff --git a/Sharp.Augeas.Test/lens/tests/test_tmpfiles.aug b/Sharp.Augeas.Test/lens/tests/test_tmpfiles.aug new file mode 100644 index 0000000..6ced069 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_tmpfiles.aug @@ -0,0 +1,425 @@ +(* +Module: Test_Tmpfiles + Provides unit tests and examples for the <Tmpfiles> lens. +*) + +module Test_Tmpfiles = + +(************************************************************************ + * Group: VALID EXAMPLES + *************************************************************************) + (* Variable: simple +One line, simple example *) + let simple = "d /run/user 0755 root mysql 10d -\n" + + (* Variable: simple_tree +Tree for <simple> *) + let simple_tree = + { + "1" + { "type" = "d" } + { "path" = "/run/user" } + { "mode" = "0755" } + { "uid" = "root" } + { "gid" = "mysql" } + { "age" = "10d" } + { "argument" = "-" } + } + + (* Variable: complex +A more complex example, comes from the manual *) + let complex = "#Type Path Mode UID GID Age Argument\nd /run/user 0755 root root 10d -\nL /tmp/foobar - - - - /dev/null\n" + + (* Variable: complex_tree +Tree for <complex> and <trailing_ws> *) + let complex_tree = + { "#comment" = "Type Path Mode UID GID Age Argument" } + { "1" + { "type" = "d" } + { "path" = "/run/user" } + { "mode" = "0755" } + { "uid" = "root" } + { "gid" = "root" } + { "age" = "10d" } + { "argument" = "-" } + } + { "2" + { "type" = "L" } + { "path" = "/tmp/foobar" } + { "mode" = "-" } + { "uid" = "-" } + { "gid" = "-" } + { "age" = "-" } + { "argument" = "/dev/null" } + } + + (* Variable: trailing_ws +The complex example with extra spaces *) + let trailing_ws = " #Type Path Mode UID GID Age Argument \n d /run/user 0755 root root 10d - \t\n L /tmp/foobar - - - - /dev/null\t\n" + + (* Variable: empty +Empty example *) + let empty = "\n\n\n" + + (* Variable: exclamation_mark +Example with an exclamation mark in the type *) + let exclamation_mark = "D! /tmp/foo - - - - -\n" + + (* Variable: exclamation_mark_tree +Tree for <exclamation_mark> *) + let exclamation_mark_tree = + { + "1" + { "type" = "D!" } + { "path" = "/tmp/foo" } + { "mode" = "-" } + { "uid" = "-" } + { "gid" = "-" } + { "age" = "-" } + { "argument" = "-" } + } + + (* Variable: minus +Example with an minus mark in the type *) + let minus = "D- /tmp/foo - - - - -\n" + + (* Variable: minus_tree +Tree for <minus_tree> *) + let minus_tree = + { + "1" + { "type" = "D-" } + { "path" = "/tmp/foo" } + { "mode" = "-" } + { "uid" = "-" } + { "gid" = "-" } + { "age" = "-" } + { "argument" = "-" } + } + + (* Variable: short +Example with only type and path *) + let short = "A+ /tmp/foo\n" + + (* Variable: short_tree +Tree for <short> *) + let short_tree = + { + "1" + { "type" = "A+" } + { "path" = "/tmp/foo" } + } + + (* Variable: short_mode +Example with only 3 fields *) + let short_mode = "c+! /tmp/foo ~0755\n" + + (* Variable: short_mode_tree +Tree for <short_mode> *) + let short_mode_tree = + { + "1" + { "type" = "c+!" } + { "path" = "/tmp/foo" } + { "mode" = "~0755" } + } + + (* Variable: short_uid +Example with only 4 fields *) + let short_uid = "A+ /tmp/foo - 0\n" + + (* Variable: short_uid_tree +Tree for <short_uid> *) + let short_uid_tree = + { + "1" + { "type" = "A+" } + { "path" = "/tmp/foo" } + { "mode" = "-" } + { "uid" = "0" } + } + + (* Variable: short_gid +Example with only 5 fields *) + let short_gid = "z /tmp/bar/foo -\t- augd\n" + + (* Variable: short_gid_tree +Tree for <short_gid> *) + let short_gid_tree = + { + "1" + { "type" = "z" } + { "path" = "/tmp/bar/foo" } + { "mode" = "-" } + { "uid" = "-" } + { "gid" = "augd" } + } + + (* Variable: short_age +Example with only 6 fields *) + let short_age = "H /var/tmp/fooBarFOO - jj jj ~10d\n" + + (* Variable: short_age_tree +Tree for <short_age> *) + let short_age_tree = + { + "1" + { "type" = "H" } + { "path" = "/var/tmp/fooBarFOO" } + { "mode" = "-" } + { "uid" = "jj" } + { "gid" = "jj" } + { "age" = "~10d" } + } + + (* Variable: complex_arg +Complex argument example. That one comes from the manual *) + let complex_arg = "t /run/screen - - - - user.name=\"John Smith\" security.SMACK64=screen\n" + + (* Variable: complex_arg_tree +Tree for <complex_arg> *) + let complex_arg_tree = + { + "1" + { "type" = "t" } + { "path" = "/run/screen" } + { "mode" = "-" } + { "uid" = "-" } + { "gid" = "-" } + { "age" = "-" } + { "argument" = "user.name=\"John Smith\" security.SMACK64=screen" } + } + + (* Variable: valid_short_args +A short argument value example. *) + let valid_short_args = "h /var/log/journal - - - - C\nh /var/log/journal - - - - +C\n" + + (* Variable: valid_short_args_tree +Tree for <valid_short_args> *) + let valid_short_args_tree = + { + "1" + { "type" = "h" } + { "path" = "/var/log/journal" } + { "mode" = "-" } + { "uid" = "-" } + { "gid" = "-" } + { "age" = "-" } + { "argument" = "C" } + } + { + "2" + { "type" = "h" } + { "path" = "/var/log/journal" } + { "mode" = "-" } + { "uid" = "-" } + { "gid" = "-" } + { "age" = "-" } + { "argument" = "+C" } + } + + (* Variable: valid_age +Example with a complex age. *) + let valid_age = "v /var/tmp/js 4221 johnsmith - ~10d12h\n" + + (* Variable: valid_age_tree +Tree for <valid_age> *) + let valid_age_tree = + { + "1" + { "type" = "v" } + { "path" = "/var/tmp/js" } + { "mode" = "4221" } + { "uid" = "johnsmith" } + { "gid" = "-" } + { "age" = "~10d12h" } + } + + (* Variable: valid_second +Example with full age unit *) + let valid_second = "p+ /var/tmp - jsmith - 0second\n" + + (* Variable: valid_second_tree +Tree for <valid_second> *) + let valid_second_tree = + { + "1" + { "type" = "p+" } + { "path" = "/var/tmp" } + { "mode" = "-" } + { "uid" = "jsmith" } + { "gid" = "-" } + { "age" = "0second" } + } + + (* Variable: valid_days +Example with full age unit (plural) *) + let valid_days = "x /var/tmp/manu - jonhsmith - 9days\n" + + (* Variable: valid_days_tree +Tree for <valid_days> *) + let valid_days_tree = + { + "1" + { "type" = "x" } + { "path" = "/var/tmp/manu" } + { "mode" = "-" } + { "uid" = "jonhsmith" } + { "gid" = "-" } + { "age" = "9days" } + } + + (* Variable: percent +Test with a percent sign *) + let percent = "m /var/log/%m 2755 root systemdjournal - -\n" + + (* Variable: percent_tree +Tree for <percent> *) + let percent_tree = + { + "1" + { "type" = "m" } + { "path" = "/var/log/%m" } + { "mode" = "2755" } + { "uid" = "root" } + { "gid" = "systemdjournal" } + { "age" = "-" } + { "argument" = "-" } + } + + (* Variable: hyphen +Test with a hyphen in gid *) + let hyphen = "L /var/log/journal 2755 root systemd-journal - -\n" + + (* Variable: hyphen_tree +Tree for <hyphen> *) + let hyphen_tree = + { + "1" + { "type" = "L" } + { "path" = "/var/log/journal" } + { "mode" = "2755" } + { "uid" = "root" } + { "gid" = "systemd-journal" } + { "age" = "-" } + { "argument" = "-" } + } + + (* Variable: valid_base +A valid test to be re-used by the failure cases *) + let valid_base = "H /var/tmp/js 0000 jonhsmith 60 1s foo\n" + + (* Variable: valid_base_tree +Tree for <valid_base> *) + let valid_base_tree = + { + "1" + { "type" = "H" } + { "path" = "/var/tmp/js" } + { "mode" = "0000" } + { "uid" = "jonhsmith" } + { "gid" = "60" } + { "age" = "1s" } + { "argument" = "foo" } + } + + (* Variable: mode3 +Mode field example with only three digits *) + let mode3 = "c+! /tmp/foo 755\n" + + (* Variable: mode3_tree +Tree for <mode3> *) + let mode3_tree = + { + "1" + { "type" = "c+!" } + { "path" = "/tmp/foo" } + { "mode" = "755" } + } + +(************************************************************************ + * Group: INVALID EXAMPLES + *************************************************************************) + + (* Variable: invalid_too_short +Invalid example that do not contain path *) + let invalid_too_short = "H\n" + + (* Variable: invalid_age +Invalid example that contain invalid age *) + let invalid_age = "H /var/tmp/js 0000 jonhsmith 60 1sss foo\n" + + (* Variable: invalid_type +Invalid example that contain invalid type (bad letter) *) + let invalid_type = "i /var/tmp/js 0000 jonhsmith 60 1s foo\n" + + (* Variable: invalid_type_num + Invalid example that contain invalid type (numeric) *) + let invalid_type_num = "1 /var/tmp/js 0000 jonhsmith 60 1s foo\n" + + (* Variable: invalid_mode +Invalid example that contain invalid mode (bad int) *) + let invalid_mode = "H /var/tmp/js 8000 jonhsmith 60 1s foo\n" + + (* Variable: invalid_mode_alpha +Invalid example that contain invalid mode (letter) *) + let invalid_mode_alpha = "H /var/tmp/js a000 jonhsmith 60 1s foo\n" + + test Tmpfiles.lns get simple = simple_tree + + test Tmpfiles.lns get complex = complex_tree + + test Tmpfiles.lns get trailing_ws = complex_tree + + test Tmpfiles.lns get empty = {}{}{} + + test Tmpfiles.lns get exclamation_mark = exclamation_mark_tree + + test Tmpfiles.lns get minus = minus_tree + + test Tmpfiles.lns get short = short_tree + + test Tmpfiles.lns get short_mode = short_mode_tree + + test Tmpfiles.lns get short_uid = short_uid_tree + + test Tmpfiles.lns get short_gid = short_gid_tree + + test Tmpfiles.lns get short_age = short_age_tree + + test Tmpfiles.lns get complex_arg = complex_arg_tree + + test Tmpfiles.lns get valid_short_args = valid_short_args_tree + + test Tmpfiles.lns get valid_second = valid_second_tree + + test Tmpfiles.lns get valid_days = valid_days_tree + + test Tmpfiles.lns get valid_age = valid_age_tree + + test Tmpfiles.lns get percent = percent_tree + + test Tmpfiles.lns get hyphen = hyphen_tree + + test Tmpfiles.lns get valid_base = valid_base_tree + + test Tmpfiles.lns get mode3 = mode3_tree + + +(* failure cases *) + + test Tmpfiles.lns get invalid_too_short = * + + test Tmpfiles.lns get invalid_age = * + + test Tmpfiles.lns get invalid_type = * + + test Tmpfiles.lns get invalid_type_num = * + + test Tmpfiles.lns get invalid_mode = * + + test Tmpfiles.lns get invalid_mode_alpha = * + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_toml.aug b/Sharp.Augeas.Test/lens/tests/test_toml.aug new file mode 100644 index 0000000..d3247a3 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_toml.aug @@ -0,0 +1,333 @@ +module Test_Toml = + +(* Test: Toml.norec + String value *) +test Toml.norec get "\"foo\"" = { "string" = "foo" } + +(* Test: Toml.norec + Integer value *) +test Toml.norec get "42" = { "integer" = "42" } + +(* Test: Toml.norec + Positive integer value *) +test Toml.norec get "+42" = { "integer" = "+42" } + +(* Test: Toml.norec + Negative integer value *) +test Toml.norec get "-42" = { "integer" = "-42" } + +(* Test: Toml.norec + Large integer value *) +test Toml.norec get "5_349_221" = { "integer" = "5_349_221" } + +(* Test: Toml.norec + Hexadecimal integer value *) +test Toml.norec get "0xDEADBEEF" = { "integer" = "0xDEADBEEF" } + +(* Test: Toml.norec + Octal integer value *) +test Toml.norec get "0o755" = { "integer" = "0o755" } + +(* Test: Toml.norec + Binary integer value *) +test Toml.norec get "0b11010110" = { "integer" = "0b11010110" } + +(* Test: Toml.norec + Float value *) +test Toml.norec get "3.14" = { "float" = "3.14" } + +(* Test: Toml.norec + Positive float value *) +test Toml.norec get "+3.14" = { "float" = "+3.14" } + +(* Test: Toml.norec + Negative float value *) +test Toml.norec get "-3.14" = { "float" = "-3.14" } + +(* Test: Toml.norec + Complex float value *) +test Toml.norec get "-3_220.145_223e-34" = { "float" = "-3_220.145_223e-34" } + +(* Test: Toml.norec + Inf float value *) +test Toml.norec get "-inf" = { "float" = "-inf" } + +(* Test: Toml.norec + Nan float value *) +test Toml.norec get "-nan" = { "float" = "-nan" } + +(* Test: Toml.norec + Bool value *) +test Toml.norec get "true" = { "bool" = "true" } + +(* Test: Toml.norec + Datetime value *) +test Toml.norec get "1979-05-27T07:32:00Z" = + { "datetime" = "1979-05-27T07:32:00Z" } +test Toml.norec get "1979-05-27 07:32:00.999999" = + { "datetime" = "1979-05-27 07:32:00.999999" } + +(* Test: Toml.norec + Date value *) +test Toml.norec get "1979-05-27" = + { "date" = "1979-05-27" } + +(* Test: Toml.norec + Time value *) +test Toml.norec get "07:32:00" = + { "time" = "07:32:00" } + +(* Test: Toml.norec + String value with newline *) +test Toml.norec get "\"bar\nbaz\"" = + { "string" = "bar\nbaz" } + +(* Test: Toml.norec + Multiline value *) +test Toml.norec get "\"\"\"\nbar\nbaz\n \"\"\"" = + { "string_multi" = "bar\nbaz" } + +(* Test: Toml.norec + Literal string value *) +test Toml.norec get "'bar\nbaz'" = + { "string_literal" = "bar\nbaz" } + +(* Test: Toml.array_norec + Empty array *) +test Toml.array_norec get "[ ]" = + { "array" {} } + +(* Test: Toml.array_norec + Array of strings *) +test Toml.array_norec get "[ \"foo\", \"bar\" ]" = + { "array" {} + { "string" = "foo" } {} + { "string" = "bar" } {} } + +(* Test: Toml.array_norec + Array of arrays *) +test Toml.array_rec get "[ [ \"foo\", [ 42, 43 ] ], \"bar\" ]" = + { "array" {} + { "array" {} + { "string" = "foo" } {} + { "array" {} + { "integer" = "42" } {} + { "integer" = "43" } {} } {} } {} + { "string" = "bar" } {} } + +(* Test: Toml.lns + Global parameters *) +test Toml.lns get "# Globals +foo = \"bar\"\n" = + { "#comment" = "Globals" } + { "entry" = "foo" { "string" = "bar" } } + +(* Test: Toml.lns + Simple section/value *) +test Toml.lns get "[foo] +bar = \"baz\"\n" = + { "table" = "foo" { "entry" = "bar" { "string" = "baz" } } } + +(* Test: Toml.lns + Subsections *) +test Toml.lns get "[foo] +title = \"bar\" + [foo.one] + hello = \"world\"\n" = + { "table" = "foo" + { "entry" = "title" { "string" = "bar" } } } + { "table" = "foo.one" + { "entry" = "hello" { "string" = "world" } } } + +(* Test: Toml.lns + Nested subsections *) +test Toml.lns get "[foo] +[foo.one] +[foo.one.two] +bar = \"baz\"\n" = + { "table" = "foo" } + { "table" = "foo.one" } + { "table" = "foo.one.two" + { "entry" = "bar" { "string" = "baz" } } } + +(* Test: Toml.lns + Arrays of tables *) +test Toml.lns get "[[products]] +name = \"Hammer\" +sku = 738594937 + +[[products]] + +[[products]] +name = \"Nail\" +sku = 284758393 +color = \"gray\"\n" = + { "@table" = "products" + { "entry" = "name" + { "string" = "Hammer" } } + { "entry" = "sku" + { "integer" = "738594937" } } + { } + } + { "@table" = "products" + { } + } + { "@table" = "products" + { "entry" = "name" + { "string" = "Nail" } } + { "entry" = "sku" + { "integer" = "284758393" } } + { "entry" = "color" + { "string" = "gray" } } + } + +(* Test: Toml.entry + Empty inline table *) +test Toml.entry get "name = { }\n" = + { "entry" = "name" + { "inline_table" + { } } } + +(* Test: Toml.entry + Inline table *) +test Toml.entry get "name = { first = \"Tom\", last = \"Preston-Werner\" }\n" = + { "entry" = "name" + { "inline_table" {} + { "entry" = "first" + { "string" = "Tom" } } {} + { "entry" = "last" + { "string" = "Preston-Werner" } } {} } } + +(* Test: Toml.entry + Array value in inline_table *) +test Toml.entry get "foo = { bar = [\"baz\"] }\n" = + { "entry" = "foo" + { "inline_table" {} + { "entry" = "bar" + { "array" + { "string" = "baz" } } } {} } } + + +(* Variable: example + The example from https://github.com/mojombo/toml *) +let example = "# This is a TOML document. Boom. + +title = \"TOML Example\" + +[owner] +name = \"Tom Preston-Werner\" +organization = \"GitHub\" +bio = \"GitHub Cofounder & CEO\nLikes tater tots and beer.\" +dob = 1979-05-27T07:32:00Z # First class dates? Why not? + +[database] +server = \"192.168.1.1\" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true + +[servers] + + # You can indent as you please. Tabs or spaces. TOML don't care. + [servers.alpha] + ip = \"10.0.0.1\" + dc = \"eqdc10\" + + [servers.beta] + ip = \"10.0.0.2\" + dc = \"eqdc10\" + country = \"中国\" # This should be parsed as UTF-8 + +[clients] +data = [ [\"gamma\", \"delta\"], [1, 2] ] # just an update to make sure parsers support it + +# Line breaks are OK when inside arrays +hosts = [ + \"alpha\", + \"omega\" +] + +# Products + + [[products]] + name = \"Hammer\" + sku = 738594937 + + [[products]] + name = \"Nail\" + sku = 284758393 + color = \"gray\" +" + +test Toml.lns get example = + { "#comment" = "This is a TOML document. Boom." } { } + { "entry" = "title" + { "string" = "TOML Example" } } { } + { "table" = "owner" + { "entry" = "name" + { "string" = "Tom Preston-Werner" } } + { "entry" = "organization" + { "string" = "GitHub" } } + { "entry" = "bio" + { "string" = "GitHub Cofounder & CEO +Likes tater tots and beer." } + } + { "entry" = "dob" + { "datetime" = "1979-05-27T07:32:00Z" } + { "#comment" = "First class dates? Why not?" } } { } } + { "table" = "database" + { "entry" = "server" + { "string" = "192.168.1.1" } } + { "entry" = "ports" + { "array" { } + { "integer" = "8001" } { } + { "integer" = "8001" } { } + { "integer" = "8002" } { } } } + { "entry" = "connection_max" + { "integer" = "5000" } } + { "entry" = "enabled" + { "bool" = "true" } } { } } + { "table" = "servers" { } + { "#comment" = "You can indent as you please. Tabs or spaces. TOML don't care." } } + { "table" = "servers.alpha" + { "entry" = "ip" + { "string" = "10.0.0.1" } } + { "entry" = "dc" + { "string" = "eqdc10" } } { } } + { "table" = "servers.beta" + { "entry" = "ip" + { "string" = "10.0.0.2" } } + { "entry" = "dc" + { "string" = "eqdc10" } } + { "entry" = "country" + { "string" = "中国" } + { "#comment" = "This should be parsed as UTF-8" } } { } } + { "table" = "clients" + { "entry" = "data" + { "array" { } + { "array" + { "string" = "gamma" } { } + { "string" = "delta" } } { } + { "array" + { "integer" = "1" } { } + { "integer" = "2" } } { } } + { "#comment" = "just an update to make sure parsers support it" } } { } + { "#comment" = "Line breaks are OK when inside arrays" } + { "entry" = "hosts" + { "array" { } + { "string" = "alpha" } { } + { "string" = "omega" } { } } } { } + { "#comment" = "Products" } { } } + { "@table" = "products" + { "entry" = "name" + { "string" = "Hammer" } } + { "entry" = "sku" + { "integer" = "738594937" } } { } } + { "@table" = "products" + { "entry" = "name" + { "string" = "Nail" } } + { "entry" = "sku" + { "integer" = "284758393" } } + { "entry" = "color" + { "string" = "gray" } } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_trapperkeeper.aug b/Sharp.Augeas.Test/lens/tests/test_trapperkeeper.aug new file mode 100644 index 0000000..369e8f9 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_trapperkeeper.aug @@ -0,0 +1,141 @@ +module Test_Trapperkeeper = + +(* Variable: config *) +let config = " + # This is a comment + webserver: { + bar: { + # A comment + host: localhost + port= 9000 + default-server: true + } + + foo: { + host: localhost + port = 10000 + } +} + +jruby-puppet: { + # This setting determines where JRuby will look for gems. It is also + # used by the `puppetserver gem` command line tool. + gem-home: /var/lib/puppet/jruby-gems + + # (optional) path to puppet conf dir; if not specified, will use the puppet default + master-conf-dir: /etc/puppet + + # (optional) path to puppet var dir; if not specified, will use the puppet default + master-var-dir: /var/lib/puppet + + # (optional) maximum number of JRuby instances to allow; defaults to <num-cpus>+2 + #max-active-instances: 1 +} + + +# CA-related settings +certificate-authority: { + + # settings for the certificate_status HTTP endpoint + certificate-status: { + + # this setting contains a list of client certnames who are whitelisted to + # have access to the certificate_status endpoint. Any requests made to + # this endpoint that do not present a valid client cert mentioned in + # this list will be denied access. + client-whitelist: [] + } +} + +os-settings: { + ruby-load-path: [/usr/lib/ruby/vendor_ruby, /home/foo/ruby ] +} +\n" + +(* Test: Trapperkeeper.lns + Test full config file *) +test Trapperkeeper.lns get config = + { } + { "#comment" = "This is a comment" } + { "@hash" = "webserver" + { "@hash" = "bar" + { "#comment" = "A comment" } + { "@simple" = "host" { "@value" = "localhost" } } + { "@simple" = "port" { "@value" = "9000" } } + { "@simple" = "default-server" { "@value" = "true" } } + } + { } + { "@hash" = "foo" + { "@simple" = "host" { "@value" = "localhost" } } + { "@simple" = "port" { "@value" = "10000" } } + } + } + { } + { "@hash" = "jruby-puppet" + { "#comment" = "This setting determines where JRuby will look for gems. It is also" } + { "#comment" = "used by the `puppetserver gem` command line tool." } + { "@simple" = "gem-home" { "@value" = "/var/lib/puppet/jruby-gems" } } + { } + { "#comment" = "(optional) path to puppet conf dir; if not specified, will use the puppet default" } + { "@simple" = "master-conf-dir" { "@value" = "/etc/puppet" } } + { } + { "#comment" = "(optional) path to puppet var dir; if not specified, will use the puppet default" } + { "@simple" = "master-var-dir" { "@value" = "/var/lib/puppet" } } + { } + { "#comment" = "(optional) maximum number of JRuby instances to allow; defaults to <num-cpus>+2" } + { "#comment" = "max-active-instances: 1" } + } + { } + { } + { "#comment" = "CA-related settings" } + { "@hash" = "certificate-authority" + { "#comment" = "settings for the certificate_status HTTP endpoint" } + { "@hash" = "certificate-status" + { "#comment" = "this setting contains a list of client certnames who are whitelisted to" } + { "#comment" = "have access to the certificate_status endpoint. Any requests made to" } + { "#comment" = "this endpoint that do not present a valid client cert mentioned in" } + { "#comment" = "this list will be denied access." } + { "@array" = "client-whitelist" } + } + } + { } + { "@hash" = "os-settings" + { "@array" = "ruby-load-path" + { "1" = "/usr/lib/ruby/vendor_ruby" } + { "2" = "/home/foo/ruby" } + } + } + { } + + +(* Test: Trapperkeeper.lns + Should parse an empty file *) +test Trapperkeeper.lns get "\n" = {} + +(* Test: Trapperkeeper.lns + Values can be quoted *) +test Trapperkeeper.lns get "os-settings: { + ruby-load-paths: [\"/usr/lib/ruby/site_ruby/1.8\"] +}\n" = + { "@hash" = "os-settings" + { "@array" = "ruby-load-paths" + { "1" = "/usr/lib/ruby/site_ruby/1.8" } + } + } + +(* Test: Trapperkeeper.lns + Keys can be quoted *) +test Trapperkeeper.lns get "test: { + \"x\": true +}\n" = + { "@hash" = "test" + { "@simple" = "x" { "@value" = "true" } } } + +(* Test: Trapperkeeper.lns + Keys can contain / (GH #7) +*) +test Trapperkeeper.lns get "test: { + \"x/y\" : z +}\n" = + { "@hash" = "test" + { "@simple" = "x/y" { "@value" = "z" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_tuned.aug b/Sharp.Augeas.Test/lens/tests/test_tuned.aug new file mode 100644 index 0000000..e31b19a --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_tuned.aug @@ -0,0 +1,13 @@ +module Test_tuned = + +let conf = "# Global tuned configuration file. + +dynamic_tuning = 0 +update_interval = 10 +" + +test Tuned.lns get conf = + { "#comment" = "Global tuned configuration file." } + { } + { "dynamic_tuning" = "0" } + { "update_interval" = "10" } diff --git a/Sharp.Augeas.Test/lens/tests/test_up2date.aug b/Sharp.Augeas.Test/lens/tests/test_up2date.aug new file mode 100644 index 0000000..b51ca08 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_up2date.aug @@ -0,0 +1,209 @@ +(* +Module: Test_Up2date + Provides unit tests and examples for the <Up2date> lens. +*) + +module Test_Up2date = + +(* Variable: empty *) +let empty = "keyword= +" +test Up2date.lns get empty = + { "1" = "keyword" } + +(* Variable: list_empty *) +let list_empty = "keyword=; +" +test Up2date.lns get list_empty = + { "1" = "keyword" + { "values" } } + +(* Variable: list_one *) +let list_one = "keyword=foo; +" +test Up2date.lns get list_one = + { "1" = "keyword" + { "values" + { "1" = "foo" } } } + +(* Variable: list_two + Probably not useful, up2date throws "bar" away *) +let list_two = "keyword=foo;bar +" +test Up2date.lns get list_two = + { "1" = "keyword" + { "values" + { "1" = "foo" } + { "2" = "bar" } } } + +(* Variable: list_two_trailing *) +let list_two_trailing = "keyword=foo;bar; +" +test Up2date.lns get list_two_trailing = + { "1" = "keyword" + { "values" + { "1" = "foo" } + { "2" = "bar" } } } + +(* Variable: conf *) +let conf = "# Red Hat Update Agent config file. +# Format: 1.0 + +debug[comment]=Whether or not debugging is enabled +debug=0 + +systemIdPath[comment]=Location of system id +systemIdPath=/etc/sysconfig/rhn/systemid + +serverURL[comment]=Remote server URL (use FQDN) +#serverURL=https://xmlrpc.rhn.redhat.com/XMLRPC +serverURL=https://enter.your.server.url.here/XMLRPC + +hostedWhitelist[comment]=RHN Hosted URL's +hostedWhitelist= + +enableProxy[comment]=Use a HTTP Proxy +enableProxy=0 + +versionOverride[comment]=Override the automatically determined system version +versionOverride= + +httpProxy[comment]=HTTP proxy in host:port format, e.g. squid.redhat.com:3128 +httpProxy= + +noReboot[comment]=Disable the reboot actions +noReboot=0 + +networkRetries[comment]=Number of attempts to make at network connections before giving up +networkRetries=1 + +disallowConfChanges[comment]=Config options that can not be overwritten by a config update action +disallowConfChanges=noReboot;sslCACert;useNoSSLForPackages;noSSLServerURL;serverURL;disallowConfChanges; + +sslCACert[comment]=The CA cert used to verify the ssl server +sslCACert=/usr/share/rhn/RHNS-CA-CERT + +# Akamai does not support http protocol, therefore setting this option as side effect disable \"Location aware\" function +useNoSSLForPackages[comment]=Use the noSSLServerURL for package, package list, and header fetching (disable Akamai) +useNoSSLForPackages=0 + +retrieveOnly[comment]=Retrieve packages only +retrieveOnly=0 + +skipNetwork[comment]=Skips network information in hardware profile sync during registration. +skipNetwork=0 + +tmpDir[comment]=Use this Directory to place the temporary transport files +tmpDir=/tmp + +writeChangesToLog[comment]=Log to /var/log/up2date which packages has been added and removed +writeChangesToLog=0 + +stagingContent[comment]=Retrieve content of future actions in advance +stagingContent=1 + +stagingContentWindow[comment]=How much forward we should look for future actions. In hours. +stagingContentWindow=24 +" + +(* Test: Up2date.lns *) +test Up2date.lns get conf = + { "#comment" = "Red Hat Update Agent config file." } + { "#comment" = "Format: 1.0" } + { } + { "1" = "debug[comment]" + { "value" = "Whether or not debugging is enabled" } } + { "2" = "debug" + { "value" = "0" } } + { } + { "3" = "systemIdPath[comment]" + { "value" = "Location of system id" } } + { "4" = "systemIdPath" + { "value" = "/etc/sysconfig/rhn/systemid" } } + { } + { "5" = "serverURL[comment]" + { "value" = "Remote server URL (use FQDN)" } } + { "#comment" = "serverURL=https://xmlrpc.rhn.redhat.com/XMLRPC" } + { "6" = "serverURL" + { "value" = "https://enter.your.server.url.here/XMLRPC" } } + { } + { "7" = "hostedWhitelist[comment]" + { "value" = "RHN Hosted URL's" } } + { "8" = "hostedWhitelist" } + { } + { "9" = "enableProxy[comment]" + { "value" = "Use a HTTP Proxy" } } + { "10" = "enableProxy" + { "value" = "0" } } + { } + { "11" = "versionOverride[comment]" + { "value" = "Override the automatically determined system version" } } + { "12" = "versionOverride" } + { } + { "13" = "httpProxy[comment]" + { "value" = "HTTP proxy in host:port format, e.g. squid.redhat.com:3128" } } + { "14" = "httpProxy" } + { } + { "15" = "noReboot[comment]" + { "value" = "Disable the reboot actions" } } + { "16" = "noReboot" + { "value" = "0" } } + { } + { "17" = "networkRetries[comment]" + { "value" = "Number of attempts to make at network connections before giving up" } } + { "18" = "networkRetries" + { "value" = "1" } } + { } + { "19" = "disallowConfChanges[comment]" + { "value" = "Config options that can not be overwritten by a config update action" } } + { "20" = "disallowConfChanges" + { "values" + { "1" = "noReboot" } + { "2" = "sslCACert" } + { "3" = "useNoSSLForPackages" } + { "4" = "noSSLServerURL" } + { "5" = "serverURL" } + { "6" = "disallowConfChanges" } } } + { } + { "21" = "sslCACert[comment]" + { "value" = "The CA cert used to verify the ssl server" } } + { "22" = "sslCACert" + { "value" = "/usr/share/rhn/RHNS-CA-CERT" } } + { } + { "#comment" = "Akamai does not support http protocol, therefore setting this option as side effect disable \"Location aware\" function" } + { "23" = "useNoSSLForPackages[comment]" + { "value" = "Use the noSSLServerURL for package, package list, and header fetching (disable Akamai)" } } + { "24" = "useNoSSLForPackages" + { "value" = "0" } } + { } + { "25" = "retrieveOnly[comment]" + { "value" = "Retrieve packages only" } } + { "26" = "retrieveOnly" + { "value" = "0" } } + { } + { "27" = "skipNetwork[comment]" + { "value" = "Skips network information in hardware profile sync during registration." } } + { "28" = "skipNetwork" + { "value" = "0" } } + { } + { "29" = "tmpDir[comment]" + { "value" = "Use this Directory to place the temporary transport files" } } + { "30" = "tmpDir" + { "value" = "/tmp" } } + { } + { "31" = "writeChangesToLog[comment]" + { "value" = "Log to /var/log/up2date which packages has been added and removed" } } + { "32" = "writeChangesToLog" + { "value" = "0" } } + { } + { "33" = "stagingContent[comment]" + { "value" = "Retrieve content of future actions in advance" } } + { "34" = "stagingContent" + { "value" = "1" } } + { } + { "35" = "stagingContentWindow[comment]" + { "value" = "How much forward we should look for future actions. In hours." } } + { "36" = "stagingContentWindow" + { "value" = "24" } } + + diff --git a/Sharp.Augeas.Test/lens/tests/test_updatedb.aug b/Sharp.Augeas.Test/lens/tests/test_updatedb.aug new file mode 100644 index 0000000..4939d01 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_updatedb.aug @@ -0,0 +1,32 @@ +(* +Module: Test_UpdateDB + Provides unit tests and examples for the <UpdateDB> lens. +*) +module Test_UpdateDB = + +(* Test: UpdateDB.lns + Simple get test *) +test UpdateDB.lns get "# A comment +PRUNEPATHS=\"/tmp /var/spool /media /home/.ecryptfs\" +PRUNEFS= \"NFS nfs nfs4 rpc_pipefs\" +PRUNE_BIND_MOUNTS = \"yes\"\n" = + { "#comment" = "A comment" } + { "PRUNEPATHS" + { "entry" = "/tmp" } + { "entry" = "/var/spool" } + { "entry" = "/media" } + { "entry" = "/home/.ecryptfs" } + } + { "PRUNEFS" + { "entry" = "NFS" } + { "entry" = "nfs" } + { "entry" = "nfs4" } + { "entry" = "rpc_pipefs" } + } + { "PRUNE_BIND_MOUNTS" = "yes" } + +(* Test: UpdateDB.lns + Adding to a list *) +test UpdateDB.lns put "PRUNEFS=\"NFS nfs nfs4 rpc_pipefs\"\n" + after set "/PRUNEFS/entry[last()+1]" "ecryptfs" = +"PRUNEFS=\"NFS nfs nfs4 rpc_pipefs ecryptfs\"\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_util.aug b/Sharp.Augeas.Test/lens/tests/test_util.aug new file mode 100644 index 0000000..2904892 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_util.aug @@ -0,0 +1,24 @@ +module Test_Util = + +test Util.empty_c_style get "/* */\n" = + { } + +test Util.comment_multiline get "/* comment */\n" = + { "#mcomment" + { "1" = "comment" } + } + +test Util.comment_multiline get "/*\ncomment\n*/\n" = + { "#mcomment" + { "1" = "comment" } + } + +test Util.comment_multiline get "/** + * Multi line comment + * + */\n" = + { "#mcomment" + { "1" = "*" } + { "2" = "* Multi line comment" } + { "3" = "*" } + } diff --git a/Sharp.Augeas.Test/lens/tests/test_vfstab.aug b/Sharp.Augeas.Test/lens/tests/test_vfstab.aug new file mode 100644 index 0000000..54eb4ae --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_vfstab.aug @@ -0,0 +1,88 @@ +module Test_vfstab = + + let simple = "/dev/dsk/c0t0d0s1 /dev/rdsk/c0t0d0s1 /test ufs 1 yes ro\n" + let simple_tree = + { "1" + { "spec" = "/dev/dsk/c0t0d0s1" } + { "fsck" = "/dev/rdsk/c0t0d0s1" } + { "file" = "/test" } + { "vfstype" = "ufs" } + { "passno" = "1" } + { "atboot" = "yes" } + { "opt" = "ro" } } + test Vfstab.lns get simple = simple_tree + + let trailing_ws = "/dev/dsk/c0t0d0s1\t /dev/rdsk/c0t0d0s1\t /test\t ufs\t 1\t yes\t ro \t \n" + test Vfstab.lns get trailing_ws = simple_tree + + (* Now test combinations where unneeded fields can be replaced by dashes and + then should not appear in the tree. *) + let gen_empty_field(fsck:string) (passno:string) (opt:string) = + "/dev/dsk/c0t0d0s1\t " . fsck . "\t /test\t ufs\t " . passno . " yes " . opt . "\t\n" + + (* Missing fsck *) + let no_fsck = gen_empty_field "-" "1" "ro" + test Vfstab.lns get no_fsck = + { "1" + { "spec" = "/dev/dsk/c0t0d0s1" } + { "file" = "/test" } + { "vfstype" = "ufs" } + { "passno" = "1" } + { "atboot" = "yes" } + { "opt" = "ro" } } + + test Vfstab.lns put no_fsck after + insa "fsck" "/1/spec" ; + set "/1/fsck" "/dev/rdsk/c0t0d0s1" = gen_empty_field "/dev/rdsk/c0t0d0s1" "1" "ro" + + (* Missing passno *) + let no_passno = gen_empty_field "/dev/rdsk/c0t0d0s1" "-" "ro" + test Vfstab.lns get no_passno = + { "1" + { "spec" = "/dev/dsk/c0t0d0s1" } + { "fsck" = "/dev/rdsk/c0t0d0s1" } + { "file" = "/test" } + { "vfstype" = "ufs" } + { "atboot" = "yes" } + { "opt" = "ro" } } + + test Vfstab.lns put no_passno after + insa "passno" "/1/vfstype" ; + set "/1/passno" "1" = gen_empty_field "/dev/rdsk/c0t0d0s1" "1" "ro" + + (* Missing opts *) + let no_opts = gen_empty_field "/dev/rdsk/c0t0d0s1" "1" "-" + test Vfstab.lns get no_opts = + { "1" + { "spec" = "/dev/dsk/c0t0d0s1" } + { "fsck" = "/dev/rdsk/c0t0d0s1" } + { "file" = "/test" } + { "vfstype" = "ufs" } + { "passno" = "1" } + { "atboot" = "yes" } } + + test Vfstab.lns put no_opts after + insa "opt" "/1/atboot" ; + insa "opt" "/1/atboot" ; + set "/1/opt[1]" "ro" ; + set "/1/opt[2]" "fg" = gen_empty_field "/dev/rdsk/c0t0d0s1" "1" "ro,fg" + + let multi_opts = "/dev/dsk/c0t0d0s1 /dev/rdsk/c0t0d0s1 /test ufs 1 yes ro,nosuid,retry=5,fg\n" + let multi_opts_tree = + { "1" + { "spec" = "/dev/dsk/c0t0d0s1" } + { "fsck" = "/dev/rdsk/c0t0d0s1" } + { "file" = "/test" } + { "vfstype" = "ufs" } + { "passno" = "1" } + { "atboot" = "yes" } + { "opt" = "ro" } + { "opt" = "nosuid" } + { "opt" = "retry" + { "value" = "5" } } + { "opt" = "fg" } } + test Vfstab.lns get multi_opts = multi_opts_tree + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_vmware_config.aug b/Sharp.Augeas.Test/lens/tests/test_vmware_config.aug new file mode 100644 index 0000000..2431b6d --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_vmware_config.aug @@ -0,0 +1,49 @@ +(* +Module: Test_VMware_Config + Provides unit tests and examples for the <VMware_Config> lens. +*) + +module Test_VMware_Config = + +(* Variable: conf *) +let conf = "libdir = \"/usr/lib/vmware\" +dhcpd.fullpath = \"/usr/bin/vmnet-dhcpd\" +authd.fullpath = \"/usr/sbin/vmware-authd\" +authd.client.port = \"902\" +loop.fullpath = \"/usr/bin/vmware-loop\" +vmware.fullpath = \"/usr/bin/vmware\" +control.fullpath = \"/usr/bin/vmware-cmd\" +serverd.fullpath = \"/usr/sbin/vmware-serverd\" +wizard.fullpath = \"/usr/bin/vmware-wizard\" +serverd.init.fullpath = \"/usr/lib/vmware/serverd/init.pl\" +serverd.vpxuser = \"vpxuser\" +serverd.snmpdconf.subagentenabled = \"TRUE\" +template.useFlatDisks = \"TRUE\" +autoStart.defaultStartDelay = \"60\" +autoStart.enabled = \"True\" +autoStart.defaultStopDelay = \"60\" +" + +(* Test: VMware_Config.lns *) +test VMware_Config.lns get conf = + { "libdir" = "/usr/lib/vmware" } + { "dhcpd.fullpath" = "/usr/bin/vmnet-dhcpd" } + { "authd.fullpath" = "/usr/sbin/vmware-authd" } + { "authd.client.port" = "902" } + { "loop.fullpath" = "/usr/bin/vmware-loop" } + { "vmware.fullpath" = "/usr/bin/vmware" } + { "control.fullpath" = "/usr/bin/vmware-cmd" } + { "serverd.fullpath" = "/usr/sbin/vmware-serverd" } + { "wizard.fullpath" = "/usr/bin/vmware-wizard" } + { "serverd.init.fullpath" = "/usr/lib/vmware/serverd/init.pl" } + { "serverd.vpxuser" = "vpxuser" } + { "serverd.snmpdconf.subagentenabled" = "TRUE" } + { "template.useFlatDisks" = "TRUE" } + { "autoStart.defaultStartDelay" = "60" } + { "autoStart.enabled" = "True" } + { "autoStart.defaultStopDelay" = "60" } + +(* Test: VMware_Config.lns + Quotes are not mandatory *) +test VMware_Config.lns get "xkeymap.nokeycodeMap = true\n" = + { "xkeymap.nokeycodeMap" = "true" } diff --git a/Sharp.Augeas.Test/lens/tests/test_vsftpd.aug b/Sharp.Augeas.Test/lens/tests/test_vsftpd.aug new file mode 100644 index 0000000..9db0a11 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_vsftpd.aug @@ -0,0 +1,74 @@ +module Test_vsftpd = + +test Vsftpd.lns get "listen=YES\nmdtm_write=false\n" = + { "listen" = "YES" } + { "mdtm_write" = "false" } + +test Vsftpd.lns get "listen=on\n" = * + +test Vsftpd.lns get "local_umask=0777\n" = { "local_umask" = "0777" } + +test Vsftpd.lns get "listen_port=ftp\n" = * + +test Vsftpd.lns get "ftp_username=ftp_user\n" = { "ftp_username" = "ftp_user" } + +(* There must not be spaces around the '=' *) +test Vsftpd.lns get "anon_root = /var/lib/vsftpd/anon" = * + + +let conf = "# Example config file /etc/vsftpd/vsftpd.conf +# +# The default compiled in settings are fairly paranoid. This sample file +# loosens things up a bit, to make the ftp daemon more usable. +# Please see vsftpd.conf.5 for all compiled in defaults. +# +# Allow anonymous FTP? (Beware - allowed by default if you comment this out). +anonymous_enable=YES +# +# Default umask for local users is 077. You may wish to change this to 022, +# if your users expect that (022 is used by most other ftpd's) +local_umask=022 +# +# You may specify an explicit list of local users to chroot() to their home +# directory. If chroot_local_user is YES, then this list becomes a list of +# users to NOT chroot(). +chroot_list_enable=YES +# (default follows) +chroot_list_file=/etc/vsftpd/chroot_list +# + +pam_service_name=vsftpd +userlist_enable=YES +tcp_wrappers=YES +allow_writeable_chroot=YES + +" + +test Vsftpd.lns get conf = + { "#comment" = "Example config file /etc/vsftpd/vsftpd.conf" } + {} + { "#comment" = "The default compiled in settings are fairly paranoid. This sample file" } + { "#comment" = "loosens things up a bit, to make the ftp daemon more usable." } + { "#comment" = "Please see vsftpd.conf.5 for all compiled in defaults." } + {} + { "#comment" = "Allow anonymous FTP? (Beware - allowed by default if you comment this out)." } + { "anonymous_enable" = "YES" } + {} + { "#comment" = "Default umask for local users is 077. You may wish to change this to 022," } + { "#comment" = "if your users expect that (022 is used by most other ftpd's)" } + { "local_umask" = "022" } + {} + { "#comment" = "You may specify an explicit list of local users to chroot() to their home" } + { "#comment" = "directory. If chroot_local_user is YES, then this list becomes a list of" } + { "#comment" = "users to NOT chroot()." } + { "chroot_list_enable" = "YES" } + { "#comment" = "(default follows)" } + { "chroot_list_file" = "/etc/vsftpd/chroot_list" } + {} + {} + { "pam_service_name" = "vsftpd" } + { "userlist_enable" = "YES" } + { "tcp_wrappers" = "YES" } + { "allow_writeable_chroot" = "YES" } + {} + diff --git a/Sharp.Augeas.Test/lens/tests/test_webmin.aug b/Sharp.Augeas.Test/lens/tests/test_webmin.aug new file mode 100644 index 0000000..a61dc38 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_webmin.aug @@ -0,0 +1,11 @@ +module Test_webmin = + +let conf = "port=10000 +realm=Webmin Server +denyfile=\.pl$ +" + +test Webmin.lns get conf = + { "port" = "10000" } + { "realm" = "Webmin Server" } + { "denyfile" = "\.pl$" } diff --git a/Sharp.Augeas.Test/lens/tests/test_wine.aug b/Sharp.Augeas.Test/lens/tests/test_wine.aug new file mode 100644 index 0000000..3faf31f --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_wine.aug @@ -0,0 +1,163 @@ +module Test_wine = + +let s1 = "WINE REGISTRY Version 2 +;; All keys relative to \\Machine + +[Software\\Borland\\Database Engine\\Settings\\SYSTEM\\INIT] 1255960431 +\"SHAREDMEMLOCATION\"=\"9000\" + +[Software\\Classes\\.gif] 1255960430 +@=\"giffile\" +\"Content Type\"=\"image/gif\" + +[Software\\Classes\\CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}] 1255960430 +\"CLSID\"=\"{1B544C20-FD0B-11CE-8C63-00AA0044B51E}\" +\"FilterData\"=hex:02,00,00,00,00,00,60,00,02,00,00,00,00,00,00,00,30,70,69,33,\ + 9f,53,00,20,af,0b,a7,70,76,69,64,73,00,00,10,00,80,00,00,aa,00,38,9b,71,00,\ + 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 +\"FriendlyName\"=\"AVI Splitter\" + +[Software\\Classes\\CLSID\\{0AFACED1-E828-11D1-9187-B532F1E9575D}\\ShellFolder] 1255960429 +\"Attributes\"=dword:60010000 +\"CallForAttributes\"=dword:f0000000 +" + +test Wine.lns get s1 = + { "registry" = "WINE REGISTRY" } + { "version" = "2" } + { "#comment" = "All keys relative to \Machine" } + { } + { "section" = "Software\Borland\Database Engine\Settings\SYSTEM\INIT" + { "timestamp" = "1255960431" } + { "entry" + { "key" = "SHAREDMEMLOCATION" } + { "value" = "9000" } } + { } } + { "section" = "Software\Classes\.gif" + { "timestamp" = "1255960430" } + { "anon" { "value" = "giffile" } } + { "entry" + { "key" = "Content Type" } + { "value" = "image/gif" } } + { } } + { "section" = "Software\Classes\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}" + { "timestamp" = "1255960430" } + { "entry" + { "key" = "CLSID" } + { "value" = "{1B544C20-FD0B-11CE-8C63-00AA0044B51E}" } } + { "entry" + { "key" = "FilterData" } + { "type" = "hex" } + { "value" = "02,00,00,00,00,00,60,00,02,00,00,00,00,00,00,00,30,70,69,33,\ + 9f,53,00,20,af,0b,a7,70,76,69,64,73,00,00,10,00,80,00,00,aa,00,38,9b,71,00,\ + 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00" } } + { "entry" + { "key" = "FriendlyName" } + { "value" = "AVI Splitter" } } + { } } + { "section" = "Software\Classes\CLSID\{0AFACED1-E828-11D1-9187-B532F1E9575D}\ShellFolder" + { "timestamp" = "1255960429" } + { "entry" + { "key" = "Attributes" } + { "type" = "dword" } + { "value" = "60010000" } } + { "entry" + { "key" = "CallForAttributes" } + { "type" = "dword" } + { "value" = "f0000000" } } } + +(* The weird 'str(2)' type *) +let s2 = "[Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders] 1248768928 +\"AppData\"=str(2):\"%USERPROFILE%\\Application Data\" +\"Cache\"=str(2):\"%USERPROFILE%\\Local Settings\\Temporary Internet Files\" +\"Cookies\"=str(2):\"%USERPROFILE%\\Cookies\" +\"Desktop\"=str(2):\"%USERPROFILE%\\Desktop\" +" + +test Wine.section get s2 = + { "section" = + "Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" + { "timestamp" = "1248768928" } + { "entry" + { "key" = "AppData" } + { "type" = "str(2)" } + { "value" = "%USERPROFILE%\Application Data" } } + { "entry" + { "key" = "Cache" } + { "type" = "str(2)" } + { "value" = "%USERPROFILE%\Local Settings\Temporary Internet Files" } } + { "entry" + { "key" = "Cookies" } + { "type" = "str(2)" } + { "value" = "%USERPROFILE%\Cookies" } } + { "entry" + { "key" = "Desktop" } + { "type" = "str(2)" } + { "value" = "%USERPROFILE%\Desktop" } } } + +(* Quoted doublequotes embedded in the string *) +let s3 = "[Software\\Classes\\CLSID\\Shell\\OpenHomePage\\Command] 1248768931 +@=\"\\\"C:\\Program Files\\Internet Explorer\\iexplore.exe\\\"\"\n" + +test Wine.section get s3 = + { "section" = "Software\Classes\CLSID\Shell\OpenHomePage\Command" + { "timestamp" = "1248768931" } + { "anon" + { "value" = "\\\"C:\Program Files\Internet Explorer\iexplore.exe\\\"" } } } + +(* There's a str(7) type, too *) +let s4 = "[Software\\Microsoft\\Cryptography\\OID\\EncodingType 1\\CertDllVerifyRevocation\\DEFAULT] 1248768928 +\"Dll\"=str(7):\"cryptnet.dll\0\"\n" + +test Wine.section get s4 = + { "section" = "Software\Microsoft\Cryptography\OID\EncodingType 1\CertDllVerifyRevocation\DEFAULT" + { "timestamp" = "1248768928" } + { "entry" + { "key" = "Dll" } + { "type" = "str(7)" } + { "value" = "cryptnet.dll\0" } } } + +(* The Windows Registry Editor header *) +test Wine.header get "Windows Registry Editor Version 5.00\n" = + { "registry" = "Windows Registry Editor" } + { "version" = "5.00" } + +(* The type hex(7) *) +let s5 = "[HKEY_LOCAL_MACHINE\SOFTWARE\ADFS] +\"Patches\"=hex(7):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,61,00,\ + 64,00,66,00,73,00,73,00,70,00,32,00,2e,00,6d,00,73,00,70,00,\ + 00,00,00,00,f8 +" +test Wine.section get s5 = + { "section" = "HKEY_LOCAL_MACHINE\SOFTWARE\ADFS" + { "entry" + { "key" = "Patches" } + { "type" = "hex(7)" } + { "value" = "25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,61,00,\ + 64,00,66,00,73,00,73,00,70,00,32,00,2e,00,6d,00,73,00,70,00,\ + 00,00,00,00,f8" } } } + +(* Test DOS line endings *) +let s6 = "Windows Registry Editor Version 5.00\r\n\r +[HKEY_LOCAL_MACHINE\SOFTWARE\C07ft5Y\WinXP]\r +\"@\"=\"\"\r +\r +[HKEY_LOCAL_MACHINE\SOFTWARE\Classes]\r\n" + +test Wine.lns get s6 = + { "registry" = "Windows Registry Editor" } + { "version" = "5.00" } + { } + { "section" = "HKEY_LOCAL_MACHINE\SOFTWARE\C07ft5Y\WinXP" + { "anon" { "value" = "" } } + { } } + { "section" = "HKEY_LOCAL_MACHINE\SOFTWARE\Classes" } + +(* Keys can contain '/' *) +let s7 = +"\"application/vnd.ms-xpsdocument\"=\"{c18d5e87-12b4-46a3-ae40-67cf39bc6758}\"\n" + +test Wine.entry get s7 = + { "entry" + { "key" = "application/vnd.ms-xpsdocument" } + { "value" = "{c18d5e87-12b4-46a3-ae40-67cf39bc6758}" } } diff --git a/Sharp.Augeas.Test/lens/tests/test_xendconfsxp.aug b/Sharp.Augeas.Test/lens/tests/test_xendconfsxp.aug new file mode 100644 index 0000000..3a893d5 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_xendconfsxp.aug @@ -0,0 +1,334 @@ +module Test_xendconfsxp = + + (* Empty file and comments *) + + test Xendconfsxp.lns get "\n" = { } + + test Xendconfsxp.lns get "# my comment\n" = + { "#scomment" = " my comment" } + + test Xendconfsxp.lns get " \n# my comment\n" = + { } + { "#scomment" = " my comment" } + + test Xendconfsxp.lns get "# my comment\n\n" = + { "#scomment" = " my comment" } + { } + + test Xendconfsxp.lns get "# my comment\n \n" = + { "#scomment" = " my comment" } + { } + + test Xendconfsxp.lns get "# my comment\n#com2\n" = + { "#scomment" = " my comment" } + { "#scomment" = "com2" } + + test Xendconfsxp.lns get "# my comment\n\n" = + { "#scomment" = " my comment" } + { } + + test Xendconfsxp.lns get "\n# my comment\n" = + { } + { "#scomment" = " my comment" } + + test Xendconfsxp.lns get "(key value)" = + { "key" { "item" = "value" } } + + test Xendconfsxp.lns get "(key value)\n# com\n" = + { "key" { "item" = "value" } } + { } + { "#scomment" = " com" } + + test Xendconfsxp.lns get "(k2ey value)" = + { "k2ey" { "item" = "value" } } + + test Xendconfsxp.lns get "(- value)" = + { "-" { "item" = "value" } } + + test Xendconfsxp.lns get "(-bar value)" = + { "-bar" { "item" = "value" } } + + test Xendconfsxp.lns get "(k-ey v-alue)\n# com\n" = + { "k-ey" { "item" = "v-alue" } } + { } + { "#scomment" = " com" } + + test Xendconfsxp.lns get "(key value)" = + { "key" { "item" = "value" } } + + test Xendconfsxp.lns get "(key value)(key2 value2)" = + { "key" + { "item" = "value" } + } + { "key2" + { "item" = "value2" } + } + + test Xendconfsxp.lns get "( key value )( key2 value2 )" = + { "key" + { "item" = "value" } + } + { "key2" + { "item" = "value2" } + } + + let source_7 = "(key value)(key2 value2)" + test Xendconfsxp.lns get source_7 = + { "key" + { "item" = "value" } + } + { "key2" + { "item" = "value2" } + } + +(* 2 items? it is a key/item *) + + test Xendconfsxp.lns get "(key value)" = + { "key" + { "item" = "value" } + } + + test Xendconfsxp.lns get "( key value )" = + { "key" + { "item" = "value" } + } + +(* 3 items? Not allowed. 2nd item must be in ()'s *) + test Xendconfsxp.lns get "(key value value2)" = * + +(* key/list pairs. *) + +(* 0 item -- TODO: implement this. *) + + test Xendconfsxp.lns get "( key ())" = * + +(* 1 item *) + + test Xendconfsxp.lns get "(key (listitem1) )" = + { "key" + { "array" + { "item" = "listitem1" } + } + } + + test Xendconfsxp.lns get "(key ( (foo bar bar bat ) ) )" = + { "key" + { "array" + { "array" + { "item" = "foo" } + { "item" = "bar" } + { "item" = "bar" } + { "item" = "bat" } + } + } + } + + test Xendconfsxp.lns get "(key ((foo foo foo (bar bar bar))))" = + { "key" + { "array" + { "array" + { "item" = "foo" } + { "item" = "foo" } + { "item" = "foo" } + { "array" + { "item" = "bar" } + { "item" = "bar" } + { "item" = "bar" } + } + } + } + } + +(* 2 item *) + + test Xendconfsxp.lns get "(xen-api-server (foo bar))" = + { "xen-api-server" + { "array" + { "item" = "foo" } + { "item" = "bar" } + } + } + + test Xendconfsxp.lns get "( key ( value value2 ))" = + { "key" + { "array" + { "item" = "value" } + { "item" = "value2" } + } + } + +(* 3 item *) + + test Xendconfsxp.lns get "( key ( value value2 value3 ))" = + { "key" + { "array" + { "item" = "value" } + { "item" = "value2" } + { "item" = "value3" } + } + } + +(* quotes *) + test Xendconfsxp.lns get "(key \"foo\")" = { "key" { "item" = "\"foo\"" } } + test Xendconfsxp.lns get "(key \"\")" = { "key" { "item" = "\"\"" } } + test Xendconfsxp.lns get "( key \"foo\" )" = { "key" { "item" = "\"foo\"" } } + test Xendconfsxp.lns get "( key \"f oo\" )" = { "key" { "item" = "\"f oo\"" } } + test Xendconfsxp.lns get "( key \"f oo\" )" = { "key" { "item" = "\"f oo\"" } } + test Xendconfsxp.lns get "(foo \"this is \\\"quoted\\\" in quotes\")" = + { "foo" { "item" = "\"this is \\\"quoted\\\" in quotes\"" } } + + test Xendconfsxp.lns get "( key \"fo\\'\" )" = { "key" { "item" = "\"fo\\'\""} } + test Xendconfsxp.lns get "( key \"fo\\'\" )" = { "key" { "item" = "\"fo\\'\""} } + test Xendconfsxp.lns get "( key \"\")" = { "key" { "item" = "\"\"" } } + +(* Newlines in strange places *) + test Xendconfsxp.lns get "(\nkey\nbar\n)" = { "key" { "item" = "bar" } } + test Xendconfsxp.lns get "(\n\n\nkey\n\n\nbar\n\n\n)" = { "key" { "item" = "bar" } } + test Xendconfsxp.lns get "(\nkey\nbar\n)" = { "key" { "item" = "bar" } } + +(* Comments in strange places *) + test Xendconfsxp.lns get "(\nkey #aa\nbar)" = + { "key" + { "#comment" = "aa" } + { "item" = "bar" } + } + + test Xendconfsxp.lns get "(\nkey\n#aa\nbar)" = + { "key" + { "#comment" = "aa" } + { "item" = "bar" } + } + + test Xendconfsxp.lns get "(\nkey\n #aa\nbar)" = + { "key" + { "#comment" = "aa" } + { "item" = "bar" } + } + +(* Comments must have 1 space before the # *) + test Xendconfsxp.lns get "(\nkey# com\nbar\n)" = * + test Xendconfsxp.lns get "(\nkey#aa\nbar)" = * + +(* Comments may start a line *) + test Xendconfsxp.lns get "(\nkey\n# com\nbar)" = + { "key" + { "#comment" = "com" } + { "item" = "bar" } + } + test Xendconfsxp.lns get "(\nkey\n#aa\nbar)" = + { "key" + { "#comment" = "aa" } + { "item" = "bar" } + } + +(* Sub lists *) + test Xendconfsxp.lns get "(key ((foo foo) (bar bar)))" = + { "key" + { "array" + { "array" + { "item" = "foo" } + { "item" = "foo" } + } + { "array" + { "item" = "bar" } + { "item" = "bar" } + } + } + } + + + test Xendconfsxp.lns get "(aaa ((bbb ccc ddd) (eee fff)))" = + { "aaa" + { "array" + { "array" + { "item" = "bbb" } + { "item" = "ccc" } + { "item" = "ddd" } + } + { "array" + { "item" = "eee" } + { "item" = "fff" } + } + } + } + +(* Comments in strange places *) + test Xendconfsxp.lns get "(\nkey\nbar # bb\n)" = + { "key" + { "item" = "bar" } + { "#comment" = "bb" } + } + test Xendconfsxp.lns get "(\nkey\nbar \n#cc\n)" = + { "key" { "item" = "bar" } + { "#comment" = "cc" } } + test Xendconfsxp.lns get "(\nkey\nbar \n #cc\n)" = + { "key" { "item" = "bar" } + { "#comment" = "cc" } } + test Xendconfsxp.lns get "(\nkey\nbar \n #cc\n )" = + { "key" { "item" = "bar" } + { "#comment" = "cc" } } + test Xendconfsxp.lns get "(foo ((foo foo foo) (unix none)))" = + { "foo" + { "array" + { "array" + { "item" = "foo" } + { "item" = "foo" } + { "item" = "foo" } + } + { "array" + { "item" = "unix" } + { "item" = "none" } + } + } + } + + test Xendconfsxp.lns get "(foo ((foo foo 'foo') (unix none)))" = + { "foo" + { "array" + { "array" + { "item" = "foo" } + { "item" = "foo" } + { "item" = "'foo'" } + } + { "array" + { "item" = "unix" } + { "item" = "none" } + } + } + } + + test Xendconfsxp.lns get "(xen-api-server ((9363 pam '^localhost$ example\\.com$') (unix none)))" = + { "xen-api-server" + { "array" + { "array" + { "item" = "9363" } + { "item" = "pam" } + { "item" = "'^localhost$ example\.com$'" } + } + { "array" + { "item" = "unix" } + { "item" = "none" } + } + } + } + + test Xendconfsxp.lns get "# -*- sh -*-\n#foo\n#bar\n\n\n(foo bar)" = + { "#scomment" = " -*- sh -*-" } + { "#scomment" = "foo" } + { "#scomment" = "bar" } + { } + { } + { "foo" + { "item" = "bar" } + } + +(* Test whitespace before lparen *) + test Xendconfsxp.lns get " (network-script network-bridge)\n#\n" = + { "network-script" { "item" = "network-bridge" } } + { } + { "#scomment" = "" } + +(* Bugs: *) + +(* Note: It works if you change the last \n to \t *) + test Xendconfsxp.lns get "(\nkey\n# com\nbar\n)" = * diff --git a/Sharp.Augeas.Test/lens/tests/test_xinetd.aug b/Sharp.Augeas.Test/lens/tests/test_xinetd.aug new file mode 100644 index 0000000..ff69f29 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_xinetd.aug @@ -0,0 +1,90 @@ +module Test_xinetd = + +let eol_ws = "defaults \t \n{\n enabled = cvs echo \n}\n\n" + +let cvs = "# default: off +# description: The CVS service can record the history of your source +# files. CVS stores all the versions of a file in a single +# file in a clever way that only stores the differences +# between versions. +service cvspserver +{ + disable = yes + port = 2401 + socket_type = stream + protocol = tcp + wait = no + user = root + passenv = PATH + server = /usr/bin/cvs + env -= HOME=/var/cvs + server_args = -f --allow-root=/var/cvs pserver +# bind = 127.0.0.1 + log_on_failure += HOST + FLAGS = IPv6 IPv4 +} +" + +let lst_add = "service svc_add +{ + log_on_failure += HOST +} +" + +test Xinetd.lns get eol_ws = + { "defaults" { "enabled" + { "value" = "cvs" } + { "value" = "echo" } } } + {} + +test Xinetd.lns put eol_ws after rm "/defaults/enabled/value[last()]" = + "defaults \t \n{\n enabled = cvs \n}\n\n" + +test Xinetd.lns get cvs = + { "#comment" = "default: off" } + { "#comment" = "description: The CVS service can record the history of your source" } + { "#comment" = "files. CVS stores all the versions of a file in a single" } + { "#comment" = "file in a clever way that only stores the differences" } + { "#comment" = "between versions." } + { "service" = "cvspserver" + { "disable" = "yes" } + { "port" = "2401" } + { "socket_type" = "stream" } + { "protocol" = "tcp" } + { "wait" = "no" } + { "user" = "root" } + { "passenv" { "value" = "PATH" } } + { "server" = "/usr/bin/cvs" } + { "env" { "del" } { "value" = "HOME=/var/cvs" } } + { "server_args" + { "value" = "-f" } + { "value" = "--allow-root=/var/cvs" } + { "value" = "pserver" } } + { "#comment" = "bind = 127.0.0.1" } + { "log_on_failure" { "add" } { "value" = "HOST" } } + { "FLAGS" + { "value" = "IPv6" } + { "value" = "IPv4" } } } + +(* Switch the '+=' to a simple '=' *) +test Xinetd.lns put lst_add after rm "/service/log_on_failure/add" = + "service svc_add\n{\n log_on_failure = HOST\n}\n" + +test Xinetd.lns put "" after + set "/service" "svc"; + set "/service/instances" "UNLIMITED" = "service svc +{ +\tinstances = UNLIMITED +} +" + +(* Support missing values in lists *) +test Xinetd.lns get "service check_mk\n{\n log_on_success =\n server_args=\n}\n" = + { "service" = "check_mk" + { "log_on_success" } + { "server_args" } + } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/tests/test_xml.aug b/Sharp.Augeas.Test/lens/tests/test_xml.aug new file mode 100644 index 0000000..7156083 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_xml.aug @@ -0,0 +1,905 @@ +(* +Module: Test_Xml + Provides unit tests and examples for the <Xml> lens. +*) + +module Test_Xml = + +(* View: knode + A simple flag function + + Parameters: + r:regexp - the pattern for the flag +*) +let knode (r:regexp) = [ key r ] + +(************************************************************************ + * Group: Utilities lens + *************************************************************************) +(* +let _ = print_regexp(lens_ctype(Xml.text)) +let _ = print_endline "" +*) + +(* Group: Comments *) + +(* Test: Xml.comment + Comments get mapped into "#comment" nodes. *) +test Xml.comment get + "<!-- declarations for <head> & <body> -->" = + + { "#comment" = " declarations for <head> & <body> " } + +(* Test: Xml.comment + This syntax is not understood. *) +test Xml.comment get + "<!-- B+, B, or B--->" = * + +(* Group: Prolog and declarations *) + +(* Test: Xml.prolog + The XML prolog tag is mapped in a "#declaration" node, + which contains an "#attribute" node with various attributes of the tag. *) +test Xml.prolog get + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" = + + { "#declaration" + { "#attribute" + { "version" = "1.0" } + { "encoding" = "UTF-8" } + } + } + +(* Test: Xml.decl_def_item + !ELEMENT declaration tags are mapped in "!ELEMENT" nodes. + The associated declaration attribute is mapped in a "#decl" subnode. *) +test Xml.decl_def_item get + "<!ELEMENT greeting (#PCDATA)>" = + + { "!ELEMENT" = "greeting" + { "#decl" = "(#PCDATA)" } + } + +(* Test: Xml.decl_def_item + !ENTITY declaration tags are mapped in "!ENTITY" nodes. + The associated declaration attribute is mapped in a "#decl" subnode. *) +test Xml.decl_def_item get + "<!ENTITY da \" \">" = + + { "!ENTITY" = "da" + { "#decl" = " " } + } + +(* Test: Xml.doctype + !DOCTYPE tags are mapped in "!DOCTYPE" nodes. + The associated system attribute is mapped in a "SYSTEM" subnode. *) +test Xml.doctype get + "<!DOCTYPE greeting:foo SYSTEM \"hello.dtd\">" = + + { "!DOCTYPE" = "greeting:foo" + { "SYSTEM" = "hello.dtd" } + } + +(* Test: Xml.doctype + This is an example of a !DOCTYPE tag with !ELEMENT children tags. *) +test Xml.doctype get "<!DOCTYPE foo [ +<!ELEMENT bar (#PCDATA)> +<!ELEMENT baz (bar)* > +]>" = + + { "!DOCTYPE" = "foo" + { "!ELEMENT" = "bar" + { "#decl" = "(#PCDATA)" } + } + { "!ELEMENT" = "baz" + { "#decl" = "(bar)*" } + } + } + +(* Group: Attributes *) + +(* Variable: att_def1 *) +let att_def1 = "<!ATTLIST termdef +id ID #REQUIRED +name CDATA #IMPLIED>" +(* Variable: att_def2 *) +let att_def2 = "<!ATTLIST list +type (bullets|ordered|glossary) \"ordered\">" +(* Variable: att_def3 *) +let att_def3 = "<!ATTLIST form +method CDATA #FIXED \"POST\">" + +(* Test: Xml.att_list_def *) +test Xml.att_list_def get + att_def1 = + + { "!ATTLIST" = "termdef" + { "1" + { "#name" = "id" } + { "#type" = "ID" } + { "#REQUIRED" } + } + { "2" + { "#name" = "name" } + { "#type" = "CDATA" } + { "#IMPLIED" } + } + } + +(* Test: Xml.att_list_def *) +test Xml.att_list_def get + att_def2 = + + { "!ATTLIST" = "list" + { "1" + { "#name" = "type" } + { "#type" = "(bullets|ordered|glossary)" } + { "#FIXED" = "ordered" } + } + } + +(* Test: Xml.att_list_def *) +test Xml.att_list_def get + att_def3 = + + { "!ATTLIST" = "form" + { "1" + { "#name" = "method" } + { "#type" = "CDATA" } + { "#FIXED" = "POST" } + } + } + +(* Test: Xml.notation_def *) +test Xml.notation_def get + "<!NOTATION not3 SYSTEM \"\">" = + + { "!NOTATION" = "not3" + { "SYSTEM" = "" } + } + +(* Variable: cdata1 *) +let cdata1 = "<![CDATA[testing]]>" +(* Test: Xml.cdata *) +test Xml.cdata get cdata1 = { "#CDATA" = "testing" } + +(* Variable: attr1 *) +let attr1 = " attr1=\"value1\" attr2=\"value2\"" +(* Variable: attr2 *) +let attr2 = " attr2=\"foo\"" +(* Test: Xml.attributes *) +test Xml.attributes get attr1 = + { "#attribute" + { "attr1" = "value1" } + { "attr2" = "value2" } + } + +(* Test: Xml.attributes *) +test Xml.attributes get " refs=\"A1\nA2 A3\"" = + { "#attribute" + { "refs" = "A1\nA2 A3" } + } + +(* Test: Xml.attributes *) +test Xml.attributes put attr1 after rm "/#attribute[1]"; + set "/#attribute/attr2" "foo" = attr2 + +(* test quoting *) +(* well formed values *) +test Xml.attributes get " attr1=\"value1\"" = { "#attribute" { "attr1" = "value1" } } +test Xml.attributes get " attr1='value1'" = { "#attribute" { "attr1" = "value1" } } +test Xml.attributes get " attr1='va\"lue1'" = { "#attribute" { "attr1" = "va\"lue1" } } +test Xml.attributes get " attr1=\"va'lue1\"" = { "#attribute" { "attr1" = "va'lue1" } } + +(* illegal as per the XML standard *) +test Xml.attributes get " attr1=\"va\"lue1\"" = * +test Xml.attributes get " attr1='va'lue1'" = * + +(* malformed values *) +test Xml.attributes get " attr1=\"value1'" = * +test Xml.attributes get " attr1='value1\"" = * + +(* Group: empty *) + +(* Variable: empty1 *) +let empty1 = "<a/>" +(* Variable: empty2 *) +let empty2 = "<a foo=\"bar\"/>" +(* Variable: empty3 *) +let empty3 = "<a foo=\"bar\"></a>\n" +(* Variable: empty4 *) +let empty4 = "<a foo=\"bar\" far=\"baz\"/>" +(* Test: Xml.empty_element *) +test Xml.empty_element get empty1 = { "a" = "#empty" } +(* Test: Xml.empty_element *) +test Xml.empty_element get empty2 = + { "a" = "#empty" { "#attribute" { "foo" = "bar"} } } + +(* Test: Xml.empty_element *) +test Xml.empty_element put empty1 after set "/a/#attribute/foo" "bar" = empty2 + +(* Test: Xml.empty_element + The attribute node must be the first child of the element *) +test Xml.empty_element put empty1 after set "/a/#attribute/foo" "bar"; + set "/a/#attribute/far" "baz" = empty4 + +(* Test: Xml.content *) +test Xml.content put "<a><b/></a>" after clear "/a/b" = "<a><b></b>\n</a>" + + +(* Group: Full lens *) + +(* Test: Xml.lns *) +test Xml.lns put "<a></a >" after set "/a/#text[1]" "foo"; + set "/a/#text[2]" "bar" = "<a>foobar</a >" + +(* Test: Xml.lns *) +test Xml.lns get "<?xml version=\"1.0\"?> +<!DOCTYPE catalog PUBLIC \"-//OASIS//DTD XML Catalogs V1.0//EN\" + \"file:///usr/share/xml/schema/xml-core/catalog.dtd\"> + <doc/>" = + { "#declaration" + { "#attribute" + { "version" = "1.0" } + } + } + { "!DOCTYPE" = "catalog" + { "PUBLIC" + { "#literal" = "-//OASIS//DTD XML Catalogs V1.0//EN" } + { "#literal" = "file:///usr/share/xml/schema/xml-core/catalog.dtd" } + } + } + { "doc" = "#empty" } + +(* Test: Xml.lns *) +test Xml.lns get "<oor:component-data xmlns:oor=\"http://openoffice.org/2001/registry\"/> +" = + { "oor:component-data" = "#empty" + { "#attribute" + { "xmlns:oor" = "http://openoffice.org/2001/registry" } + } + } + +(* Variable: input1 *) +let input1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> +<html>\r + <head> + <title>Wiki + + +

Augeas

+

Augeas is now able to parse XML files!

+
    +
  • Translate from XML to a tree syntax
  • +
  • Translate from the tree back to XML
  • +
  • this
  • +
+ + +" + +(* Test: Xml.doc + Test with *) +test Xml.doc get input1 = + { "#declaration" + { "#attribute" + { "version" = "1.0" } + { "encoding" = "UTF-8" } + } + } + { "html" + { "#text" = "\r\n " } + { "head" + { "#text" = "\n " } + { "title" + { "#text" = "Wiki" } + } + { "#text" = " " } + } + { "#text" = " " } + { "body" + { "#text" = " + " } + { "h1" + { "#text" = "Augeas" } + } + { "#text" = " " } + { "p" + { "#attribute" + { "class" = "main" } + } + { "#text" = "Augeas is now able to parse XML files!" } + } + { "#text" = " " } + { "ul" + { "#text" = "\n " } + { "li" + { "#text" = "Translate from XML to a tree syntax" } + } + { "#text" = " " } + { "li" + { "#text" = "Translate from the tree back to XML" } + } + { "#text" = " " } + { "#comment" = " this is some comment " } + { "#text" = " + " } + { "li" + { "#text" = "this" } + } + { "#text" = " " } + } + { "#text" = " " } + } + } + +(* Test: Xml.doc + Modify with *) +test Xml.doc put input1 after rm "/html/body" = +" +\r + + Wiki + + +" + + +(* Variable: ul1 *) +let ul1 = " +
    +
  • test1
  • +
  • test2
  • +
  • test3
  • +
  • test4
  • +
+" + +test Xml.doc get ul1 = + { "ul" + { "#text" = " + " } + { "li" + { "#text" = "test1" } + } + { "#text" = " " } + { "li" + { "#text" = "test2" } + } + { "#text" = " " } + { "li" + { "#text" = "test3" } + } + { "#text" = " " } + { "li" + { "#text" = "test4" } + } + } + + +test Xml.doc put ul1 after set "/ul/li[3]/#text" "bidon" = " +
    +
  • test1
  • +
  • test2
  • +
  • bidon
  • +
  • test4
  • +
+" + +test Xml.doc put ul1 after rm "/ul/li[2]" = " +
    +
  • test1
  • +
  • test3
  • +
  • test4
  • +
+" + + +(* #text nodes don't move when inserting a node, the result depends on where the node is added *) +test Xml.doc put ul1 after insb "a" "/ul/li[2]" = " +
+" + +test Xml.doc put ul1 after insa "a" "/ul/li[1]" = " +
    +
  • test1
  • + +
  • test2
  • +
  • test3
  • +
  • test4
  • +
+" + +(* Attributes must be added before text nodes *) +test Xml.doc put ul1 after insb "#attribute" "/ul/li[2]/#text"; + set "/ul/li[2]/#attribute/bidon" "gazou"; + set "/ul/li[2]/#attribute/foo" "bar" = " +
    +
  • test1
  • +
  • test2
  • +
  • test3
  • +
  • test4
  • +
+" + +(* if empty element is allowed to be as root, this test triggers error *) +test Xml.lns get " + +" = + { "doc" + { "#text" = "\n" } + { "a" + { "c" = "#empty" } + { "b" + { "c" = "#empty" } + } + { "c" = "#empty" } + { "c" = "#empty" } + { "a" } + } + } + +let p01pass2 = " + + + + + + + + + + +]> + + + + + + + + + +" + +test Xml.lns get p01pass2 = + { "#pi" + { "#target" = "PI" } + { "#instruction" = "before document element" } + } + { "#comment" = " comment after document element" } + { "#pi" + { "#target" = "PI" } + { "#instruction" = "before document element" } + } + { "#comment" = " comment after document element" } + { "#pi" + { "#target" = "PI" } + { "#instruction" = "before document element" } + } + { "#comment" = " comment after document element" } + { "#pi" + { "#target" = "PI" } + { "#instruction" = "before document element" } + } + { "!DOCTYPE" = "doc" + { "!ELEMENT" = "doc" + { "#decl" = "ANY" } + } + { "!ELEMENT" = "a" + { "#decl" = "ANY" } + } + { "!ELEMENT" = "b" + { "#decl" = "ANY" } + } + { "!ELEMENT" = "c" + { "#decl" = "ANY" } + } + } + { "doc" + { "#text" = " +" } + { "a" + { "b" + { "c" = "#empty" } + } + } + } + { "#comment" = " comment after document element" } + { "#pi" + { "#target" = "PI" } + { "#instruction" = "after document element" } + } + { "#comment" = " comment after document element" } + { "#pi" + { "#target" = "PI" } + { "#instruction" = "after document element" } + } + { "#comment" = " comment after document element" } + { "#pi" + { "#target" = "PI" } + { "#instruction" = "after document element" } + } + + +(* various valid Name constructions *) +test Xml.lns get "\n\n<::._-0/>\n<_:._-0/>\n\n<_/>\n<:/>\n" = + { "doc" + { "#text" = "\n" } + { "A:._-0" = "#empty" } + { "::._-0" = "#empty" } + { "_:._-0" = "#empty" } + { "A" = "#empty" } + { "_" = "#empty" } + { ":" = "#empty" } + } + +test Xml.lns get " + + + + +" = + { "doc" + { "#text" = "\n" } + { "abcdefghijklmnopqrstuvwxyz" = "#empty" } + { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" = "#empty" } + { "A01234567890" = "#empty" } + { "A.-:" = "#empty" } + } + + +let p06fail1 = " + + + + + +]> + + + +" + +(* we accept this test because we do not verify XML references *) +test Xml.lns get p06fail1 = + { "#comment" = "non-validating processors may pass this instance because they don't check the IDREFS attribute type" } + { "!DOCTYPE" = "doc" + { "!ELEMENT" = "doc" + { "#decl" = "(a|refs)*" } + } + { "!ELEMENT" = "a" + { "#decl" = "EMPTY" } + } + { "!ELEMENT" = "refs" + { "#decl" = "EMPTY" } + } + { "!ATTLIST" = "refs" + { "1" + { "#name" = "refs" } + { "#type" = "IDREFS" } + { "#REQUIRED" } + } + } + { "!ATTLIST" = "a" + { "1" + { "#name" = "id" } + { "#type" = "ID" } + { "#REQUIRED" } + } + } + } + { "doc" + { "#text" = " +" } + { "a" = "#empty" + { "#attribute" + { "id" = "A1" } + } + } + { "a" = "#empty" + { "#attribute" + { "id" = "A2" } + } + } + { "a" = "#empty" + { "#attribute" + { "id" = "A3" } + } + } + { "refs" = "#empty" + { "#attribute" + { "refs" = "" } + } + } + } + +(* we accept dquote, but not single quotes, because of resulting ambiguity *) +let p10pass1_1 = "'">\nasdf\n ?>%\"/>" +let p10pass1_2 = "" + +test Xml.lns get p10pass1_1 = + { "doc" + { "A" = "#empty" + { "#attribute" + { "a" = "asdf>'">\nasdf\n ?>%" } + } + } + } + +test Xml.lns get p10pass1_2 = + { "doc" + { "A" = "#empty" + { "#attribute" + { "a" = "\"\">'"" } + } + } + } + +(* here again, test exclude single quote *) +let p11pass1 = " + +?>/\''\"> + +]> +" + +test Xml.lns get p11pass1 = + { "#comment" = "Inability to resolve a notation should not be reported as an error" } + { "!DOCTYPE" = "doc" + { "!ELEMENT" = "doc" + { "#decl" = "EMPTY" } + } + { "!NOTATION" = "not1" + { "SYSTEM" = "a%a&b�?>/\''" } + } + { "!NOTATION" = "not3" + { "SYSTEM" = "" } + } + } + { "doc" } + +test Xml.lns get "a%b%</doc></doc>]]<&" = + { "doc" + { "#text" = "a%b%</doc></doc>]]<&" } + } + +let p15pass1 = " + +" + +test Xml.lns get p15pass1 = + { "#comment" = "a +-<[ CDATA [ +\"- -'- +-" } + { "#comment" = "" } + { "doc" } + +let p22pass3 = " + +" + +test Xml.lns get p22pass3 = + { "#declaration" + { "#attribute" + { "version" = "1.0" } + } + } + { "#comment" = "comment" } + { "#pi" + { "#target" = "pi" } + { "#instruction" = "some instruction" } + } + { "doc" + { "#pi" + { "#target" = "pi" } + } + } + +let p25pass2 = " +" + +test Xml.lns get p25pass2 = + { "#declaration" + { "#attribute" + { "version" = "1.0" } + } + } + { "doc" } + + +test Xml.lns get " +]> +" = + { "!DOCTYPE" = "doc" + { "!ELEMENT" = "doc" + { "#decl" = "EMPTY" } + } + } + { "doc" } + +test Xml.lns get "" = { "doc" } + +test Xml.lns get "" = + { "a" + { "doc" = "#empty" + { "#attribute" + { "att" = "val" } + { "att2" = "val2" } + { "att3" = "val3" } + } + } + } + +test Xml.lns get "" = { "doc" = "#empty" } + +test Xml.lns get "" = + { "a" + { "#CDATA" = "Thu, 13 Feb 2014 12:22:35 +0000" } } + +(* failure tests *) +(* only one document element *) +test Xml.lns get "" = * + +(* document element must be complete *) +test Xml.lns get "" = * + +(* accept empty document *) +test Xml.lns get "\n" = {} + +(* malformed element *) +test Xml.lns get "" = * + +(* a Name cannot start with a digit *) +test Xml.lns get "<0A/>" = * + +(* no space before "CDATA" *) +test Xml.lns get "" = * + +(* no space after "CDATA" *) +test Xml.lns get "" = * + +(* FIXME: CDSect's can't nest *) +test Xml.lns get " + +]]> +" = + { "doc" + { "#text" = "\n" } + { "#CDATA" = "\n\n" } } + +(* Comment is illegal in VersionInfo *) +test Xml.lns get " =\"1.0\"?> +" = * + +(* only declarations in DTD *) +test Xml.lns get " + +]>" = * + +(* we do not support external entities *) +test Xml.lns get "\"> +%eldecl; +]> +" = * + +(* Escape character in attributes *) +test Xml.lns get "" = + { "a" = "#empty" + { "#attribute" { "password" = "my\!pass" } } } + +test Xml.lns put "" +after set "/a" "#empty" = "\n" + +(* Issue #142 *) +test Xml.entity_def get + "" = + { "!ENTITY" = "open-hatch" + { "SYSTEM" + { "#systemliteral" = "http://examplecom/OpenHatch.xml" } + } } + +test Xml.entity_def get + "" = + { "!ENTITY" = "open-hatch" + { "PUBLIC" + { "#pubidliteral" = + "-//Textuality//TEXT Standard open-hatch boilerplate//EN" } + { "#systemliteral" = + "http://www.textuality.com/boilerplate/OpenHatch.xml" } } } + +let dt_with_entities = +" + + ]>" + +test Xml.doctype get dt_with_entities = + { "!DOCTYPE" = "server-xml" + { "!ENTITY" = "sys-ent" + { "SYSTEM" + { "#systemliteral" = "sys-file.xml" } + } + } + { "!ENTITY" = "pub-ent" + { "PUBLIC" + { "#pubidliteral" = "-//something public//TEXT" } + { "#systemliteral" = "pub-file.xml" } + } + } + } + +test Xml.doctype put dt_with_entities after + rm "/\!DOCTYPE/\!ENTITY[2]"; + set "/\!DOCTYPE/\!ENTITY[. = \"sys-ent\"]/SYSTEM/#systemliteral" + "other-file.xml" + = +" + ]>" + +test Xml.lns get (dt_with_entities . "") = + { "!DOCTYPE" = "server-xml" + { "!ENTITY" = "sys-ent" + { "SYSTEM" + { "#systemliteral" = "sys-file.xml" } + } + } + { "!ENTITY" = "pub-ent" + { "PUBLIC" + { "#pubidliteral" = "-//something public//TEXT" } + { "#systemliteral" = "pub-file.xml" } + } + } + } + { "body" } + +test Xml.lns put " + +" + after + insa "!DOCTYPE" "#declaration"; + set "\\!DOCTYPE" "Server"; + set "\\!DOCTYPE/\\!ENTITY" "resourcesFile"; + set "\\!DOCTYPE/\\!ENTITY/SYSTEM/#systemliteral" "data.xml" + = +"]> +\n" diff --git a/Sharp.Augeas.Test/lens/tests/test_xorg.aug b/Sharp.Augeas.Test/lens/tests/test_xorg.aug new file mode 100644 index 0000000..86a2829 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_xorg.aug @@ -0,0 +1,94 @@ +(* Tests for the Xorg module *) + +module Test_xorg = + + let conf = " +# xorg.conf + +Section \"ServerLayout\" + Identifier \"single head configuration\" + Screen 0 \"Screen0\" 0 0 + InputDevice \"Generic Keyboard\" \"CoreKeyboard\" +EndSection + +Section \"InputDevice\" + Identifier \"Generic Keyboard\" + # that's a driver + Driver \"kbd\" + Option \"XkbOptions\" \"lv3:ralt_switch\" +EndSection + +Section \"Device\" + Identifier \"Configured Video Device\" + Option \"MonitorLayout\" \"LVDS,VGA\" + VideoRam 229376 + Option \"NoAccel\" + Option \"fbdev\" \"\" + Screen 0 +EndSection + +Section \"Screen\" + Identifier \"Screen0\" + Device \"Configured Video Device\" + DefaultDepth 24 + SubSection \"Display\" + Viewport 0 0 + Depth 24 + Modes \"1280x1024\" \"1280x960\" \"1280x800\" + EndSubSection +EndSection + +Section \"Module\" + SubSection \"extmod\" + Option \"omit XFree86-DGA\" + EndSubSection +EndSection +" + + test Xorg.lns get conf = + { } + { "#comment" = "xorg.conf" } + { } + { "ServerLayout" + { "Identifier" = "single head configuration" } + { "Screen" = "Screen0" + { "num" = "0" } + { "position" = "0 0" } } + { "InputDevice" = "Generic Keyboard" + { "option" = "CoreKeyboard" } } } + { } + { "InputDevice" + { "Identifier" = "Generic Keyboard" } + { "#comment" = "that's a driver" } + { "Driver" = "kbd" } + { "Option" = "XkbOptions" + { "value" = "lv3:ralt_switch" } } } + { } + { "Device" + { "Identifier" = "Configured Video Device" } + { "Option" = "MonitorLayout" + { "value" = "LVDS,VGA" } } + { "VideoRam" = "229376" } + { "Option" = "NoAccel" } + { "Option" = "fbdev" + { "value" = "" } } + { "Screen" + { "num" = "0" } } } + { } + { "Screen" + { "Identifier" = "Screen0" } + { "Device" = "Configured Video Device" } + { "DefaultDepth" = "24" } + { "Display" + { "ViewPort" + { "x" = "0" } + { "y" = "0" } } + { "Depth" = "24" } + { "Modes" + { "mode" = "1280x1024" } + { "mode" = "1280x960" } + { "mode" = "1280x800" } } } } + { } + { "Module" + { "extmod" + { "Option" = "omit XFree86-DGA" } } } diff --git a/Sharp.Augeas.Test/lens/tests/test_xymon.aug b/Sharp.Augeas.Test/lens/tests/test_xymon.aug new file mode 100644 index 0000000..837a288 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_xymon.aug @@ -0,0 +1,179 @@ +module Test_xymon = + +let conf = " +#atest comment + +title test title +page page1 'This is a test page' +1.1.1.1 testhost.localdomain # test1 test2 http:443 ldaps=testhost.localdomain http://testhost.localdomain +2.2.2.2 testhost2.local.domain # COMMENT:stuff apache=wow +#test comment + +page newpage +1.1.1.1 testhost.localdomain # test1 test2 http:443 ldaps=testhost.localdomain http://testhost.localdomain +2.2.2.2 testhost2.local.domain # COMMENT:stuff apache=wow + +title test title +group group1 +3.3.3.3 host1 # +4.4.4.4 host2 # + +group-sorted group2 +5.5.5.5 host3 # conn +6.6.6.6 host4 # ssh + +subparent page1 page2 This is after page 1 +10.0.0.1 router1.loni.org # +10.0.0.2 sw1.localdomain # + +" +test Xymon.lns get conf = + { } + { "#comment" = "atest comment" } + { } + { "title" = "test title" } + { "page" = "page1" + { "pagetitle" = "'This is a test page'" } + { "host" + { "ip" = "1.1.1.1" } + { "fqdn" = "testhost.localdomain" } + { "tag" = "test1" } + { "tag" = "test2" } + { "tag" = "http:443" } + { "tag" = "ldaps=testhost.localdomain" } + { "tag" = "http://testhost.localdomain" } + } + { "host" + { "ip" = "2.2.2.2" } + { "fqdn" = "testhost2.local.domain" } + { "tag" = "COMMENT:stuff" } + { "tag" = "apache=wow" } + } + { "#comment" = "test comment" } + { } + } + { "page" = "newpage" + { "host" + { "ip" = "1.1.1.1" } + { "fqdn" = "testhost.localdomain" } + { "tag" = "test1" } + { "tag" = "test2" } + { "tag" = "http:443" } + { "tag" = "ldaps=testhost.localdomain" } + { "tag" = "http://testhost.localdomain" } + } + { "host" + { "ip" = "2.2.2.2" } + { "fqdn" = "testhost2.local.domain" } + { "tag" = "COMMENT:stuff" } + { "tag" = "apache=wow" } + } + { } + { "title" = "test title" } + { "group" = "group1" + { "host" + { "ip" = "3.3.3.3" } + { "fqdn" = "host1" } + } + { "host" + { "ip" = "4.4.4.4" } + { "fqdn" = "host2" } + } + { } + } + { "group-sorted" = "group2" + { "host" + { "ip" = "5.5.5.5" } + { "fqdn" = "host3" } + { "tag" = "conn" } + } + { "host" + { "ip" = "6.6.6.6" } + { "fqdn" = "host4" } + { "tag" = "ssh" } + } + { } + } + } + { "subparent" = "page2" + { "parent" = "page1" } + { "pagetitle" = "This is after page 1" } + { "host" + { "ip" = "10.0.0.1" } + { "fqdn" = "router1.loni.org" } + } + { "host" + { "ip" = "10.0.0.2" } + { "fqdn" = "sw1.localdomain" } + } + { } + } + + + test Xymon.host get "192.168.1.1 server1.test.example.com # tag1 tag2 CLASS:classname CLIENT:clienthostname NOCOLUMNS:column1,column2\n" = + { "host" + { "ip" = "192.168.1.1" } + { "fqdn" = "server1.test.example.com" } + { "tag" = "tag1" } + { "tag" = "tag2" } + { "tag" = "CLASS:classname" } + { "tag" = "CLIENT:clienthostname" } + { "tag" = "NOCOLUMNS:column1,column2" } + } + + test Xymon.host get "192.168.1.1 test.example.com # \n" = + { "host" + { "ip" = "192.168.1.1" } + { "fqdn" = "test.example.com" } + } + + test Xymon.host get "192.168.1.1 test.example.com # http://google.com COMMENT:asdf\n" = + { "host" + { "ip" = "192.168.1.1" } + { "fqdn" = "test.example.com" } + { "tag" = "http://google.com" } + { "tag" = "COMMENT:asdf" } + } + + test Xymon.include get "include file1.txt\n" = + { "include" = "file1.txt" } + + test Xymon.include get "directory dir2\n" = + { "directory" = "dir2" } + + test Xymon.page get "page page1 page 1 title is here\n" = + { "page" = "page1" + { "pagetitle" = "page 1 title is here" } + } + + test Xymon.page get "page page2\n" = + { "page" = "page2" + } + + test Xymon.subparent get "subparent page1 page2 PAGETITLE 1\n1.1.1.1 host1.lan #\n2.2.2.2 host2.lan # \n" = + { "subparent" = "page2" + { "parent" = "page1" } + { "pagetitle" = "PAGETITLE 1" } + { "host" + { "ip" = "1.1.1.1" } + { "fqdn" = "host1.lan" } + } + { "host" + { "ip" = "2.2.2.2" } + { "fqdn" = "host2.lan" } + } + } + + test Xymon.title get "title title 1 goes here\n" = + { "title" = "title 1 goes here" } + + test Xymon.lns get "page page1\ninclude file1.cfg\nsubparent page1 page2\ninclude page2.cfg\n" = + { "page" = "page1" + { "include" = "file1.cfg" } + } + { "subparent" = "page2" + { "parent" = "page1" } + { "include" = "page2.cfg" } + } + + diff --git a/Sharp.Augeas.Test/lens/tests/test_xymon_alerting.aug b/Sharp.Augeas.Test/lens/tests/test_xymon_alerting.aug new file mode 100644 index 0000000..77525cb --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_xymon_alerting.aug @@ -0,0 +1,289 @@ +(* +Module: Test_Xymon_Alerting + Provides unit tests and examples for the lens. +*) + +module Test_Xymon_Alerting = + let macro_definition = "$NOTIF_LOCAL=SCRIPT /foo/xymonqpage.sh $PAGER SCRIPT /foo/xymonsms.sh $SMS FORMAT=SMS COLOR=!yellow\n" + test Xymon_Alerting.lns get macro_definition = + { "$NOTIF_LOCAL" = "SCRIPT /foo/xymonqpage.sh $PAGER SCRIPT /foo/xymonsms.sh $SMS FORMAT=SMS COLOR=!yellow" } + + let basic_syntax = "HOST=hostname IGNORE\n" + test Xymon_Alerting.lns get basic_syntax = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "IGNORE" { "filters" } } + } + } + + let two_filters = "HOST=hostname SERVICE=service IGNORE\n" + test Xymon_Alerting.lns get two_filters = + { "1" + { "filters" + { "HOST" = "hostname" } + { "SERVICE" = "service" } + } + { "recipients" + { "IGNORE" { "filters" } } + } + } + + let two_recipients = "HOST=hostname IGNORE STOP\n" + test Xymon_Alerting.lns get two_recipients = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "IGNORE" { "filters" } } + { "STOP" { "filters" } } + } + } + + let two_lines = "HOST=hostname SERVICE=service\n IGNORE\n" + test Xymon_Alerting.lns get two_lines = + { "1" + { "filters" + { "HOST" = "hostname" } + { "SERVICE" = "service" } + } + { "recipients" + { "IGNORE" { "filters" } } + } + } + + let two_lines_for_recipients = "HOST=hostname SERVICE=service\n IGNORE\nSTOP\n" + test Xymon_Alerting.lns get two_lines_for_recipients = + { "1" + { "filters" + { "HOST" = "hostname" } + { "SERVICE" = "service" } + } + { "recipients" + { "IGNORE" { "filters" } } + { "STOP" { "filters" } } + } + } + + let with_blanks_at_eol = "HOST=hostname SERVICE=service \n IGNORE \n" + test Xymon_Alerting.lns get with_blanks_at_eol = + { "1" + { "filters" + { "HOST" = "hostname" } + { "SERVICE" = "service" } + } + { "recipients" + { "IGNORE" { "filters" } } + } + } + + let several_rules = "HOST=hostname SERVICE=service\nIGNORE\nHOST=hostname2 SERVICE=svc\nIGNORE\nSTOP\n" + test Xymon_Alerting.lns get several_rules = + { "1" + { "filters" + { "HOST" = "hostname" } + { "SERVICE" = "service" } + } + { "recipients" + { "IGNORE" { "filters" } } + } + } + { "2" + { "filters" + { "HOST" = "hostname2" } + { "SERVICE" = "svc" } + } + { "recipients" + { "IGNORE" { "filters" } } + { "STOP" { "filters" } } + } + } + + + let duration = "HOST=hostname DURATION>20 SERVICE=service\nIGNORE\n" + test Xymon_Alerting.lns get duration = + { "1" + { "filters" + { "HOST" = "hostname" } + { "DURATION" + { "operator" = ">" } + { "value" = "20" } + } + { "SERVICE" = "service" } + } + { "recipients" + { "IGNORE" { "filters" } } + } + } + + let notice = "HOST=hostname NOTICE SERVICE=service\nIGNORE\n" + test Xymon_Alerting.lns get notice = + { "1" + { "filters" + { "HOST" = "hostname" } + { "NOTICE" } + { "SERVICE" = "service" } + } + { "recipients" + { "IGNORE" { "filters" } } + } + } + + let mail = "HOST=hostname MAIL astreinteMail\n" + test Xymon_Alerting.lns get mail = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "MAIL" = "astreinteMail" + { "filters" } + } + } + } + + let script = "HOST=hostname SCRIPT /foo/email.sh astreinteMail\n" + test Xymon_Alerting.lns get script = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "SCRIPT" + { "script" = "/foo/email.sh" } + { "recipient" = "astreinteMail" } + { "filters" } + } + } + } + + let repeat = "HOST=hostname REPEAT=15\n" + test Xymon_Alerting.lns get repeat = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "REPEAT" = "15" + { "filters" } + } + } + } + + let mail_with_filters = "HOST=hostname MAIL astreinteMail EXSERVICE=service\n" + test Xymon_Alerting.lns get mail_with_filters = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "MAIL" = "astreinteMail" + { "filters" + { "EXSERVICE" = "service" } + } + } + } + } + + let mail_with_several_filters = "HOST=hostname MAIL astreinteMail EXSERVICE=service DURATION>20\n" + test Xymon_Alerting.lns get mail_with_several_filters = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "MAIL" = "astreinteMail" + { "filters" + { "EXSERVICE" = "service" } + { "DURATION" + { "operator" = ">" } + { "value" = "20" } + } + } + } + } + } + + let script_with_several_filters = "HOST=hostname SCRIPT /foo/email.sh astreinteMail EXSERVICE=service DURATION>20\n" + test Xymon_Alerting.lns get script_with_several_filters = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "SCRIPT" + { "script" = "/foo/email.sh" } + { "recipient" = "astreinteMail" } + { "filters" + { "EXSERVICE" = "service" } + { "DURATION" + { "operator" = ">" } + { "value" = "20" } + } + } + } + } + } + + let repeat_with_several_filters = "HOST=hostname REPEAT=15 EXSERVICE=service DURATION>20\n" + test Xymon_Alerting.lns get repeat_with_several_filters = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "REPEAT" = "15" + { "filters" + { "EXSERVICE" = "service" } + { "DURATION" + { "operator" = ">" } + { "value" = "20" } + } + } + } + } + } + + let recipients_with_several_filters = "HOST=hostname\nREPEAT=15 EXSERVICE=service DURATION>20\nMAIL astreinteMail TIME=weirdtimeformat\n" + test Xymon_Alerting.lns get recipients_with_several_filters = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "REPEAT" = "15" + { "filters" + { "EXSERVICE" = "service" } + { "DURATION" + { "operator" = ">" } + { "value" = "20" } + } + } + } + { "MAIL" = "astreinteMail" + { "filters" + { "TIME" = "weirdtimeformat" } + } + } + } + } + + let recipient_macro = "HOST=hostname\n $NOTIF_LOCAL\n STOP\n" + test Xymon_Alerting.lns get recipient_macro = + { "1" + { "filters" + { "HOST" = "hostname" } + } + { "recipients" + { "$NOTIF_LOCAL" + { "filters" } + } + { "STOP" + { "filters" } + } + } + } + diff --git a/Sharp.Augeas.Test/lens/tests/test_yaml.aug b/Sharp.Augeas.Test/lens/tests/test_yaml.aug new file mode 100644 index 0000000..34eef08 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_yaml.aug @@ -0,0 +1,94 @@ +module Test_YAML = + +(* Inherit test *) +test YAML.lns get "host1: + <<: *production\n" = +{ "host1" + { "<<" = "production" } +} + +(* top level sequence *) +test YAML.lns get " +- foo: 1 + bar: 2 + +- baz: 3 + gee: 4 +" = +{ } +{ "@sequence" + { "foo" = "1" } + { "bar" = "2" } +} +{ } +{ "@sequence" + { "baz" = "3" } + { "gee" = "4" } +} + +test YAML.lns get " +defaults: &defaults + repo1: master + repo2: master + +# Live +production: &production + # repo3: dc89d7a + repo4: 2d39995 + # repo5: bc4a40d + +host1: + <<: *production + +host2: + <<: *defaults + repo6: branch1 + +host3: + <<: *defaults + # repo7: branch2 + repo8: branch3 +" = +{} +{ "defaults" = "defaults" + { "repo1" = "master" } + { "repo2" = "master" } +} +{} +{ "#comment" = "Live" } +{ "production" = "production" + { "#comment" = "repo3: dc89d7a" } + { "repo4" = "2d39995" } + { "#comment" = "repo5: bc4a40d" } +} +{} +{ "host1" + { "<<" = "production" } +} +{} +{ "host2" + { "<<" = "defaults" } + { "repo6" = "branch1" } +} +{} +{ "host3" + { "<<" = "defaults" } + { "#comment" = "repo7: branch2" } + { "repo8" = "branch3" } +} + +(* Ruby YAML header *) +test YAML.lns get "--- !ruby/object:Puppet::Node::Factspress RETURN)\n" = + { "@yaml" = "!ruby/object:Puppet::Node::Factspress RETURN)" } + + +(* Continued lines *) +test YAML.lns get "abc: + def: |- + ghi +\n" = + { "abc" + { "def" + { "@mval" + { "@line" = "ghi" } } } } + diff --git a/Sharp.Augeas.Test/lens/tests/test_yum.aug b/Sharp.Augeas.Test/lens/tests/test_yum.aug new file mode 100644 index 0000000..2688182 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tests/test_yum.aug @@ -0,0 +1,227 @@ +(* +Module: Test_Yum + Provides unit tests and examples for the lens. +*) + +module Test_yum = + + let yum_simple = "[sec1] +# comment +key=value +[sec-two] +key1=value1 +# comment +key2=value2 +" + + let yum_conf = "[main] +cachedir=/var/cache/yum +keepcache=0 +debuglevel=2 +logfile=/var/log/yum.log +exactarch=1 +obsoletes=1 +gpgcheck=1 +plugins=1 +metadata_expire=1800 + +installonly_limit=100 + +# PUT YOUR REPOS HERE OR IN separate files named file.repo +# in /etc/yum.repos.d +" + + let yum_repo1 = "[fedora] +name=Fedora $releasever - $basearch +failovermethod=priority +#baseurl=http://download.fedora.redhat.com/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/ +mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$releasever&arch=$basearch +enabled=1 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora file:///etc/pki/rpm-gpg/RPM-GPG-KEY + +[fedora-debuginfo] +name=Fedora $releasever - $basearch - Debug +failovermethod=priority +#baseurl=http://download.fedora.redhat.com/pub/fedora/linux/releases/$releasever/Everything/$basearch/debug/ +mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-debug-$releasever&arch=$basearch +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora file:///etc/pki/rpm-gpg/RPM-GPG-KEY + +[fedora-source] +name=Fedora $releasever - Source +failovermethod=priority +#baseurl=http://download.fedora.redhat.com/pub/fedora/linux/releases/$releasever/Everything/source/SRPMS/ +mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-source-$releasever&arch=$basearch +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora file:///etc/pki/rpm-gpg/RPM-GPG-KEY +" + let yum_repo2 = "[remi] +name=Les RPM de remi pour FC$releasever - $basearch +baseurl=http://remi.collet.free.fr/rpms/fc$releasever.$basearch/ + http://iut-info.ens.univ-reims.fr/remirpms/fc$releasever.$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi + +[remi-test] +name=Les RPM de remi en test pour FC$releasever - $basearch +baseurl=http://remi.collet.free.fr/rpms/test-fc$releasever.$basearch/ + http://iut-info.ens.univ-reims.fr/remirpms/test-fc$releasever.$basearch/ +enabled=0 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi +" + + let cont = "[main]\nbaseurl=url1\n url2 , url3\n \n" + + test Yum.lns get yum_simple = + { "sec1" + { "#comment" = "comment" } + { "key" = "value" } + } + { "sec-two" + { "key1" = "value1" } + { "#comment" = "comment" } + { "key2" = "value2" } + } + + test Yum.lns put yum_conf after + rm "main" + = "" + + test Yum.lns put yum_simple after + set "sec1/key" "othervalue" + = "[sec1]\n# comment\nkey=othervalue\n[sec-two]\nkey1=value1\n# comment\nkey2=value2\n" + + test Yum.lns put yum_simple after + rm "sec1" ; + rm "sec-two/key1" + = "[sec-two]\n# comment\nkey2=value2\n" + + test Yum.lns put yum_simple after + rm "sec1" ; + rm "sec-two/key1" ; + set "sec-two/newkey" "newvalue" + = "[sec-two]\n# comment\nkey2=value2\nnewkey=newvalue\n" + + test Yum.lns put yum_simple after + rm "sec1" ; + set "sec-two/key1" "newvalue" + = "[sec-two]\nkey1=newvalue\n# comment\nkey2=value2\n" + + test Yum.lns get cont = + { "main" + { "baseurl" = "url1" } + { "baseurl" = "url2" } + { "baseurl" = "url3" } + {} + } + + test Yum.lns put cont after + set "main/gpgcheck" "1" + = + cont . "gpgcheck=1\n" + + (* We are actually stricter than yum in checking syntax. The yum.conf *) + (* man page mentions that it is illegal to have multiple baseurl keys *) + (* in the same section, but yum will just carry on, usually with *) + (* results that surpise the unsuspecting user *) + test Yum.lns get "[repo]\nbaseurl=url1\nbaseurl=url2\n" = * + + (* This checks that we take the right branch in the section lens. *) + test Yum.record get "[repo]\nname=A name\nbaseurl=url1\n" = + { "repo" + { "name" = "A name" } + { "baseurl" = "url1" } } + + (* Handle continuation lines for gpgkey; bug #132 *) + test Yum.lns get "[main]\ngpgkey=key1\n key2\n" = + { "main" + { "gpgkey" = "key1" } + { "gpgkey" = "key2" } } + + test Yum.lns get yum_repo1 = + { "fedora" + { "name" = "Fedora $releasever - $basearch" } + { "failovermethod" = "priority" } + { "#comment" = "baseurl=http://download.fedora.redhat.com/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/" } + { "mirrorlist" = "http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$releasever&arch=$basearch" } + { "enabled" = "1" } + { "gpgcheck" = "1" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY" } + { } + } + { "fedora-debuginfo" + { "name" = "Fedora $releasever - $basearch - Debug" } + { "failovermethod" = "priority" } + { "#comment" = "baseurl=http://download.fedora.redhat.com/pub/fedora/linux/releases/$releasever/Everything/$basearch/debug/" } + { "mirrorlist" = "http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-debug-$releasever&arch=$basearch" } + { "enabled" = "0" } + { "gpgcheck" = "1" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY" } + { } + } + { "fedora-source" + { "name" = "Fedora $releasever - Source" } + { "failovermethod" = "priority" } + { "#comment" = "baseurl=http://download.fedora.redhat.com/pub/fedora/linux/releases/$releasever/Everything/source/SRPMS/" } + { "mirrorlist" = "http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-source-$releasever&arch=$basearch" } + { "enabled" = "0" } + { "gpgcheck" = "1" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY" } + } + + + test Yum.lns get yum_repo2 = + { "remi" + { "name" = "Les RPM de remi pour FC$releasever - $basearch" } + { "baseurl" = "http://remi.collet.free.fr/rpms/fc$releasever.$basearch/" } + { "baseurl" = "http://iut-info.ens.univ-reims.fr/remirpms/fc$releasever.$basearch/" } + { "enabled" = "0" } + { "gpgcheck" = "1" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi" } + { } + } + { "remi-test" + { "name" = "Les RPM de remi en test pour FC$releasever - $basearch" } + { "baseurl" = "http://remi.collet.free.fr/rpms/test-fc$releasever.$basearch/" } + { "baseurl" = "http://iut-info.ens.univ-reims.fr/remirpms/test-fc$releasever.$basearch/" } + { "enabled" = "0" } + { "gpgcheck" = "1" } + { "gpgkey" = "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi" } + } + + (* Test: Yum.lns + Check that we can parse an empty line, to fix test-save *) + test Yum.lns get "\n" = { } + + (* Test: Yum.lns + Issue #45: allow spaces around equals sign *) + test Yum.lns get "[rpmforge] +name = RHEL $releasever - RPMforge.net - dag +baseurl = http://apt.sw.be/redhat/el6/en/$basearch/rpmforge\n" = + { "rpmforge" + { "name" = "RHEL $releasever - RPMforge.net - dag" } + { "baseurl" = "http://apt.sw.be/redhat/el6/en/$basearch/rpmforge" } + } + + (* Test: Yum.lns + Issue #275: parse excludes as a list *) + test Yum.lns get "[epel] +name=Extra Packages for Enterprise Linux 6 - $basearch +exclude=ocs* clamav* +" = + { "epel" + { "name" = "Extra Packages for Enterprise Linux 6 - $basearch" } + { "exclude" = "ocs*" } + { "exclude" = "clamav*" } } + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/thttpd.aug b/Sharp.Augeas.Test/lens/thttpd.aug new file mode 100644 index 0000000..bf6c491 --- /dev/null +++ b/Sharp.Augeas.Test/lens/thttpd.aug @@ -0,0 +1,48 @@ +(* +Module: Thttpd + Parses Thttpd's configuration files + +Author: Marc Fournier + +About: Reference + This lens is based on Thttpd's default thttpd.conf file. + +About: Usage Example +(start code) + augtool> get /files/etc/thttpd/thttpd.conf/port + /files/etc/thttpd/thttpd.conf/port = 80 + + augtool> set /files/etc/thttpd/thttpd.conf/port 8080 + augtool> save + Saved 1 file(s) +(end code) + The file also contains various examples. + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Thttpd = +autoload xfm + +let comment = Util.comment +let comment_eol = Util.comment_generic /[ \t]*[#][ \t]*/ " # " +let empty = Util.empty +let eol = Util.del_str "\n" +let bol = Util.del_opt_ws "" + +let kvkey = /(port|dir|data_dir|user|cgipat|throttles|host|logfile|pidfile|charset|p3p|max_age)/ +let flag = /(no){0,1}(chroot|symlinks|vhost|globalpasswd)/ +let val = /[^\n# \t]*/ + +let kventry = key kvkey . Util.del_str "=" . store val +let flagentry = key flag + +let kvline = [ bol . kventry . (eol|comment_eol) ] +let flagline = [ bol . flagentry . (eol|comment_eol) ] + +let lns = (kvline|flagline|comment|empty)* + +let filter = incl "/etc/thttpd/thttpd.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/tinc.aug b/Sharp.Augeas.Test/lens/tinc.aug new file mode 100644 index 0000000..bd812f7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tinc.aug @@ -0,0 +1,37 @@ +(* +Module: Tinc + Parses Tinc VPN configuration files + +Author: Thomas Weißschuh + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Tinc = + +autoload xfm + +let no_spaces_no_equals = /[^ \t\r\n=]+/ +let assign = del (/[ \t]*[= ][ \t]*/) " = " +let del_str = Util.del_str + +let entry = Build.key_value_line /[A-Za-z]+/ assign (store no_spaces_no_equals) + +let key_section_start = "-----BEGIN RSA PUBLIC KEY-----\n" +let key_section_end = "\n-----END RSA PUBLIC KEY-----" + (* the last line does not include a newline *) +let base_64 = /[A-Za-z0-9+\/=\n]+[A-Za-z0-9+\/=]/ +let key_section = del_str key_section_start . + (label "#key" . store base_64) . + del_str key_section_end + +(* we only support a single key section *) +let lns = (Util.comment | Util.empty | entry) * . [(key_section . Util.empty *)]? + +let filter = incl "/etc/tinc.conf" + . incl "/etc/tinc/*/tinc.conf" + . incl "/etc/tinc/hosts/*" + . incl "/etc/tinc/*/hosts/*" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/tmpfiles.aug b/Sharp.Augeas.Test/lens/tmpfiles.aug new file mode 100644 index 0000000..01b3003 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tmpfiles.aug @@ -0,0 +1,107 @@ +(* +Module: Tmpfiles + Parses systemd tmpfiles.d files + +Author: Julien Pivotto + +About: Reference + This lens tries to keep as close as possible to `man 5 tmpfiles.d` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/tmpfiles.d/*.conf /usr/lib/tmpfiles.d/*.conf and + /run/tmpfiles.d/*.conf. See . + +About: Examples + The file contains various examples and tests. +*) + +module Tmpfiles = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Comments and empty lines *) + + (* View: sep_spc +Space *) + let sep_spc = Sep.space + + (* View: sep_opt_spc +Optional space (for the beginning of the lines) *) + let sep_opt_spc = Sep.opt_space + + (* View: comment +Comments *) + let comment = Util.comment + + (* View: empty +Empty lines *) + let empty = Util.empty + +(* Group: Lense-specific primitives *) + + (* View: type +One letter. Some of them can have a "+" and all can have an +exclamation mark ("!") and/or minus sign ("-"). + +Not all letters are valid. +*) + let type = /([fFwdDevqQpLcbCxXrRzZtThHaAm]|[fFwpLcbaA]\+)!?-?/ + + (* View: mode +"-", or 3-4 bytes. Optionally starts with a "~". *) + let mode = /(-|~?[0-7]{3,4})/ + + (* View: age +"-", or one of the formats seen in the manpage: 10d, 5seconds, 1y5days. +optionally starts with a "~'. *) + let age = /(-|(~?[0-9]+(s|m|min|h|d|w|ms|us|((second|minute|hour|day|week|millisecond|microsecond)s?))?)+)/ + + (* View: argument +The last field. It can contain spaces. *) + let argument = /([^# \t\n][^#\n]*[^# \t\n]|[^# \t\n])/ + + (* View: field +Applies to the other fields: path, gid and uid fields *) + let field = /[^# \t\n]+/ + + (* View: record +A valid record, one line in the file. +Only the two first fields are mandatory. *) + let record = [ seq "record" . sep_opt_spc . + [ label "type" . store type ] . sep_spc . + [ label "path" . store field ] . ( sep_spc . + [ label "mode" . store mode ] . ( sep_spc . + [ label "uid" . store field ] . ( sep_spc . + [ label "gid" . store field ] . ( sep_spc . + [ label "age" . store age ] . ( sep_spc . + [ label "argument" . store argument ] )? )? )? )? )? . + Util.comment_or_eol ] + +(************************************************************************ + * Group: THE TMPFILES LENSE + *************************************************************************) + + (* View: lns +The tmpfiles lens. +Each line can be a comment, a record or empty. *) + let lns = ( empty | comment | record ) * + + (* View: filter *) + let filter = incl "/etc/tmpfiles.d/*.conf" + . incl "/usr/lib/tmpfiles.d/*.conf" + . incl "/run/tmpfiles.d/*.conf" + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/toml.aug b/Sharp.Augeas.Test/lens/toml.aug new file mode 100644 index 0000000..9a7d1ba --- /dev/null +++ b/Sharp.Augeas.Test/lens/toml.aug @@ -0,0 +1,145 @@ +(* +Module: Toml + Parses TOML files + +Author: Raphael Pinson + +About: Reference + https://github.com/mojombo/toml/blob/master/README.md + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to TOML files. + +About: Examples + The file contains various examples and tests. +*) + +module Toml = + +(* Group: base definitions *) + +(* View: comment + A simple comment *) +let comment = IniFile.comment "#" "#" + +(* View: empty + An empty line *) +let empty = Util.empty_dos + +(* View: eol + An end of line *) +let eol = Util.doseol + + +(* Group: value entries *) + +let bare_re_noquot = (/[^][", \t\r\n]/ - "#") +let bare_re = (/[^][,\r=]/ - "#")+ +let no_quot = /[^]["\r\n]*/ +let bare = Quote.do_dquote_opt_nil (store (bare_re_noquot . (bare_re* . bare_re_noquot)?)) +let quoted = Quote.do_dquote (store (/[^"]/ . "#"* . /[^"]/)) + +let ws = del /[ \t\n]*/ "" + +let space_or_empty = [ del /[ \t\n]+/ " " ] + +let comma = Util.del_str "," . (space_or_empty | comment)? +let lbrace = Util.del_str "{" . (space_or_empty | comment)? +let rbrace = Util.del_str "}" +let lbrack = Util.del_str "[" . (space_or_empty | comment)? +let rbrack = Util.del_str "]" + +(* This follows the definition of 'string' at https://www.json.org/ + It's a little wider than what's allowed there as it would accept + nonsensical \u escapes *) +let triple_dquote = Util.del_str "\"\"\"" +let str_store = Quote.dquote . store /([^\\"]|\\\\["\/bfnrtu\\])*/ . Quote.dquote + +let str_store_multi = triple_dquote . eol + . store /([^\\"]|\\\\["\/bfnrtu\\])*/ + . del /\n[ \t]*/ "\n" . triple_dquote + +let str_store_literal = Quote.squote . store /([^\\']|\\\\['\/bfnrtu\\])*/ . Quote.squote + +let integer = + let base10 = /[+-]?[0-9_]+/ + in let hex = /0x[A-Za-z0-9]+/ + in let oct = /0o[0-7]+/ + in let bin = /0b[01]+/ + in [ label "integer" . store (base10 | hex | oct | bin) ] + +let float = + let n = /[0-9_]+/ + in let pm = /[+-]?/ + in let z = pm . n + in let decim = "." . n + in let exp = /[Ee]/ . z + in let num = z . decim | z . exp | z . decim . exp + in let inf = pm . "inf" + in let nan = pm . "nan" + in [ label "float" . store (num | inf | nan) ] + +let str = [ label "string" . str_store ] + +let str_multi = [ label "string_multi" . str_store_multi ] + +let str_literal = [ label "string_literal" . str_store_literal ] + +let bool (r:regexp) = [ label "bool" . store r ] + + +let date_re = /[0-9]{4}-[0-9]{2}-[0-9]{2}/ +let time_re = /[0-9]{1,2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?[A-Z]*/ + +let datetime = [ label "datetime" . store (date_re . /[T ]/ . time_re) ] +let date = [ label "date" . store date_re ] +let time = [ label "time" . store time_re ] + +let norec = str | str_multi | str_literal + | integer | float | bool /true|false/ + | datetime | date | time + +let array (value:lens) = [ label "array" . lbrack + . ( ( Build.opt_list value comma . space_or_empty? . rbrack ) + | rbrack ) ] + +let array_norec = array norec + +let rec array_rec = array (norec | array_rec) + +let entry_base (value:lens) = [ label "entry" . store Rx.word . Sep.space_equal . value ] + +let inline_table (value:lens) = [ label "inline_table" . lbrace + . ( (Build.opt_list (entry_base value) comma . space_or_empty? . rbrace) + | rbrace ) ] + +let entry = [ label "entry" . Util.indent . store Rx.word . Sep.space_equal + . (norec | array_rec | inline_table (norec|array_norec)) . (eol | comment) ] + +(* Group: tables *) + +(* View: table_gen + A generic table *) +let table_gen (name:string) (lbrack:string) (rbrack:string) = + let title = Util.indent . label name + . Util.del_str lbrack + . store /[^]\r\n.]+(\.[^]\r\n.]+)*/ + . Util.del_str rbrack . eol + in [ title . (entry|empty|comment)* ] + +(* View: table + A table or array of tables *) +let table = table_gen "table" "[" "]" + | table_gen "@table" "[[" "]]" + +(* Group: lens *) + +(* View: lns + The Toml lens *) +let lns = (entry | empty | comment)* . table* diff --git a/Sharp.Augeas.Test/lens/trapperkeeper.aug b/Sharp.Augeas.Test/lens/trapperkeeper.aug new file mode 100644 index 0000000..0c30493 --- /dev/null +++ b/Sharp.Augeas.Test/lens/trapperkeeper.aug @@ -0,0 +1,123 @@ +(* +Module: Trapperkeeper + Parses Trapperkeeper configuration files + +Author: Raphael Pinson + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to Trapperkeeper webservice configuration files. See . + +About: Examples + The file contains various examples and tests. +*) +module Trapperkeeper = + +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* View: empty *) +let empty = Util.empty + +(* View: comment *) +let comment = Util.comment + +(* View: sep *) +let sep = del /[ \t]*[:=]/ ":" + +(* View: sep_with_spc *) +let sep_with_spc = sep . Sep.opt_space + +(************************************************************************ + * Group: BLOCKS (FROM 1.2, FOR 0.10 COMPATIBILITY) + *************************************************************************) + +(* Variable: block_ldelim_newlines_re *) +let block_ldelim_newlines_re = /[ \t\n]+\{([ \t\n]*\n)?/ + +(* Variable: block_rdelim_newlines_re *) +let block_rdelim_newlines_re = /[ \t]*\}/ + +(* Variable: block_ldelim_newlines_default *) +let block_ldelim_newlines_default = "\n{\n" + +(* Variable: block_rdelim_newlines_default *) +let block_rdelim_newlines_default = "}" + +(************************************************************************ + * View: block_newline + * A block enclosed in brackets, with newlines forced + * and indentation defaulting to a tab. + * + * Parameters: + * entry:lens - the entry to be stored inside the block. + * This entry should not include , + * or , + * should be indented and finish with an eol. + ************************************************************************) +let block_newlines (entry:lens) (comment:lens) = + del block_ldelim_newlines_re block_ldelim_newlines_default + . ((entry | comment) . (Util.empty | entry | comment)*)? + . del block_rdelim_newlines_re block_rdelim_newlines_default + +(************************************************************************ + * Group: ENTRY TYPES + *************************************************************************) + +let opt_dquot (lns:lens) = del /"?/ "" . lns . del /"?/ "" + +(* View: simple *) +let simple = [ Util.indent . label "@simple" . opt_dquot (store /[A-Za-z0-9_.\/-]+/) . sep_with_spc + . [ label "@value" . opt_dquot (store /[^,"\[ \t\n]+/) ] + . Util.eol ] + +(* View: array *) +let array = + let lbrack = Util.del_str "[" + in let rbrack = Util.del_str "]" + in let opt_space = del /[ \t]*/ "" + in let comma = opt_space . Util.del_str "," . opt_space + in let elem = [ seq "elem" . opt_dquot (store /[^,"\[ \t\n]+/) ] + in let elems = counter "elem" . Build.opt_list elem comma + in [ Util.indent . label "@array" . store Rx.word + . sep_with_spc . lbrack . Sep.opt_space + . (elems . Sep.opt_space)? + . rbrack . Util.eol ] + +(* View: hash *) +let hash (lns:lens) = [ Util.indent . label "@hash" . store Rx.word . sep + . block_newlines lns Util.comment + . Util.eol ] + + +(************************************************************************ + * Group: ENTRY + *************************************************************************) + +(* Just for typechecking *) +let entry_no_rec = hash (simple|array) + +(* View: entry *) +let rec entry = hash (entry|simple|array) + +(************************************************************************ + * Group: LENS AND FILTER + *************************************************************************) + +(* View: lns *) +let lns = (empty|comment)* . (entry . (empty|comment)*)* + +(* Variable: filter *) +let filter = incl "/etc/puppetserver/conf.d/*" + . incl "/etc/puppetlabs/puppetserver/conf.d/*" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/tuned.aug b/Sharp.Augeas.Test/lens/tuned.aug new file mode 100644 index 0000000..506ed07 --- /dev/null +++ b/Sharp.Augeas.Test/lens/tuned.aug @@ -0,0 +1,21 @@ +(* +Module: Tuned + Parses Tuned's configuration files + +Author: Pat Riehecky + +About: Reference + This lens is based on tuned's tuned-main.conf + +About: License + This file is licensed under the LGPL v2+, like the rest of Augeas. +*) + +module Tuned = +autoload xfm + +let lns = Simplevars.lns + +let filter = incl "/etc/tuned/tuned-main.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/up2date.aug b/Sharp.Augeas.Test/lens/up2date.aug new file mode 100644 index 0000000..f1d9ab7 --- /dev/null +++ b/Sharp.Augeas.Test/lens/up2date.aug @@ -0,0 +1,84 @@ +(* +Module: Up2date + Parses /etc/sysconfig/rhn/up2date + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 up2date` where possible. + +About: License + This file is licenced under the LGPLv2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/sysconfig/rhn/up2date. See . + +About: Examples + The file contains various examples and tests. +*) + +module Up2date = + +autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Variable: key_re *) +let key_re = /[^=# \t\n]+/ + +(* Variable: value_re *) +let value_re = /[^ \t\n;][^\n;]*[^ \t\n;]|[^ \t\n;]/ + +(* View: sep_semi *) +let sep_semi = Sep.semicolon + +(************************************************************************ + * Group: ENTRIES + *************************************************************************) + +(* View: single_entry + key=foo *) +let single_entry = [ label "value" . store value_re ] + +(* View: multi_empty + key=; *) +let multi_empty = sep_semi + +(* View: multi_value + One value in a list setting *) +let multi_value = [ seq "multi" . store value_re ] + +(* View: multi_single + key=foo; (parsed as a list) *) +let multi_single = multi_value . sep_semi + +(* View: multi_values + key=foo;bar + key=foo;bar; *) +let multi_values = multi_value . ( sep_semi . multi_value )+ . del /;?/ ";" + +(* View: multi_entry + List settings go under a 'values' node *) +let multi_entry = [ label "values" . counter "multi" + . ( multi_single | multi_values | multi_empty ) ] + +(* View: entry *) +let entry = [ seq "entry" . store key_re . Sep.equal + . ( multi_entry | single_entry )? . Util.eol ] + +(************************************************************************ + * Group: LENS + *************************************************************************) + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry)* + +(* Variable: filter *) +let filter = incl "/etc/sysconfig/rhn/up2date" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/updatedb.aug b/Sharp.Augeas.Test/lens/updatedb.aug new file mode 100644 index 0000000..40cd26f --- /dev/null +++ b/Sharp.Augeas.Test/lens/updatedb.aug @@ -0,0 +1,49 @@ +(* +Module: UpdateDB + Parses /etc/updatedb.conf + +Author: Raphael Pinson + +About: Reference + This lens tries to keep as close as possible to `man 5 updatedb.conf` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/updatedb.conf. See . + +About: Examples + The file contains various examples and tests. +*) + +module UpdateDB = + +autoload xfm + +(* View: list + A list entry *) +let list = + let entry = [ label "entry" . store Rx.no_spaces ] + in let entry_list = Build.opt_list entry Sep.space + in [ key /PRUNE(FS|NAMES|PATHS)/ . Sep.space_equal + . Quote.do_dquote entry_list . Util.doseol ] + +(* View: bool + A boolean entry *) +let bool = [ key "PRUNE_BIND_MOUNTS" . Sep.space_equal + . Quote.do_dquote (store /[01]|no|yes/) + . Util.doseol ] + +(* View: lns + The lens *) +let lns = (Util.empty|Util.comment|list|bool)* + +(* Variable: filter + The filter *) +let filter = incl "/etc/updatedb.conf" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/util.aug b/Sharp.Augeas.Test/lens/util.aug new file mode 100644 index 0000000..72b79ec --- /dev/null +++ b/Sharp.Augeas.Test/lens/util.aug @@ -0,0 +1,198 @@ +(* +Module: Util + Generic module providing useful primitives + +Author: David Lutterkort + +About: License + This file is licensed under the LGPLv2+, like the rest of Augeas. +*) + + +module Util = + + +(* +Variable: del_str + Delete a string and default to it + + Parameters: + s:string - the string to delete and default to +*) + let del_str (s:string) = del s s + +(* +Variable: del_ws + Delete mandatory whitespace +*) + let del_ws = del /[ \t]+/ + +(* +Variable: del_ws_spc + Delete mandatory whitespace, default to single space +*) + let del_ws_spc = del_ws " " + +(* +Variable: del_ws_tab + Delete mandatory whitespace, default to single tab +*) + let del_ws_tab = del_ws "\t" + + +(* +Variable: del_opt_ws + Delete optional whitespace +*) + let del_opt_ws = del /[ \t]*/ + + +(* +Variable: eol + Delete end of line, including optional trailing whitespace +*) + let eol = del /[ \t]*\n/ "\n" + +(* +Variable: doseol + Delete end of line with optional carriage return, + including optional trailing whitespace +*) + let doseol = del /[ \t]*\r?\n/ "\n" + + +(* +Variable: indent + Delete indentation, including leading whitespace +*) + let indent = del /[ \t]*/ "" + +(* Group: Comment + This is a general definition of comment + It allows indentation for comments, removes the leading and trailing spaces + of comments and stores them in nodes, except for empty comments which are + ignored together with empty lines +*) + + +(* View: comment_generic_seteol + Map comments and set default comment sign +*) + + let comment_generic_seteol (r:regexp) (d:string) (eol:lens) = + [ label "#comment" . del r d + . store /([^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n])/ . eol ] + +(* View: comment_generic + Map comments and set default comment sign +*) + + let comment_generic (r:regexp) (d:string) = + comment_generic_seteol r d doseol + +(* View: comment + Map comments into "#comment" nodes +*) + let comment = comment_generic /[ \t]*#[ \t]*/ "# " + +(* View: comment_noindent + Map comments into "#comment" nodes, without indentation +*) + let comment_noindent = comment_generic /#[ \t]*/ "# " + +(* View: comment_eol + Map eol comments into "#comment" nodes + Add a space before # for end of line comments +*) + let comment_eol = comment_generic /[ \t]*#[ \t]*/ " # " + +(* View: comment_or_eol + A or , with an optional empty comment *) + let comment_or_eol = comment_eol | (del /[ \t]*(#[ \t]*)?\n/ "\n") + +(* View: comment_multiline + A C-style multiline comment *) + let comment_multiline = + let mline_re = (/[^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n]/ - /.*\*\/.*/) in + let mline = [ seq "mline" + . del /[ \t\r\n]*/ "\n" + . store mline_re ] in + [ label "#mcomment" . del /[ \t]*\/\*/ "/*" + . counter "mline" + . mline . (eol . mline)* + . del /[ \t\r\n]*\*\/[ \t]*\r?\n/ "\n*/\n" ] + +(* View: comment_c_style + A comment line, C-style *) + let comment_c_style = + comment_generic /[ \t]*\/\/[ \t]*/ "// " + +(* View: comment_c_style_or_hash + A comment line, C-style or hash *) + let comment_c_style_or_hash = + comment_generic /[ \t]*((\/\/)|#)[ \t]*/ "// " + +(* View: empty_generic + A generic definition of + Map empty lines, including empty comments *) + let empty_generic (r:regexp) = + [ del r "" . del_str "\n" ] + +(* Variable: empty_generic_re *) + let empty_generic_re = /[ \t]*#?[ \t]*/ + +(* View: empty + Map empty lines, including empty comments *) + let empty = empty_generic empty_generic_re + +(* Variable: empty_c_style_re *) + let empty_c_style_re = /[ \t]*((\/\/)|(\/\*[ \t]*\*\/))?[ \t]*/ + +(* View: empty_c_style + Map empty lines, including C-style empty comment *) + let empty_c_style = empty_generic empty_c_style_re + +(* View: empty_any + Either or *) + let empty_any = empty_generic (empty_generic_re | empty_c_style_re) + +(* View: empty_generic_dos + A generic definition of with dos newlines + Map empty lines, including empty comments *) + let empty_generic_dos (r:regexp) = + [ del r "" . del /\r?\n/ "\n" ] + +(* View: empty_dos *) + let empty_dos = + empty_generic_dos /[ \t]*#?[ \t]*/ + + +(* View: Split *) +(* Split (SEP . ELT)* into an array-like tree where each match for ELT *) +(* appears in a separate subtree. The labels for the subtrees are *) +(* consecutive numbers, starting at 0 *) + let split (elt:lens) (sep:lens) = + let sym = gensym "split" in + counter sym . ( [ seq sym . sep . elt ] ) * + +(* View: delim *) + let delim (op:string) = del (/[ \t]*/ . op . /[ \t]*/) + (" " . op . " ") + +(* Group: Exclusions + +Variable: stdexcl + Exclusion for files that are commonly not wanted/needed +*) + let stdexcl = (excl "*~") . + (excl "*.rpmnew") . + (excl "*.rpmsave") . + (excl "*.dpkg-old") . + (excl "*.dpkg-new") . + (excl "*.dpkg-bak") . + (excl "*.dpkg-dist") . + (excl "*.augsave") . + (excl "*.augnew") . + (excl "*.bak") . + (excl "*.old") . + (excl "#*#") diff --git a/Sharp.Augeas.Test/lens/vfstab.aug b/Sharp.Augeas.Test/lens/vfstab.aug new file mode 100644 index 0000000..f730329 --- /dev/null +++ b/Sharp.Augeas.Test/lens/vfstab.aug @@ -0,0 +1,67 @@ +(* +Module: Vfstab + Parses Solaris vfstab config file, based on Fstab lens + +Author: Dominic Cleal + +About: Reference + See vfstab(4) + +About: License + This file is licenced under the LGPLv2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/vfstab. + +About: Examples + The file contains various examples and tests. +*) + +module Vfstab = + autoload xfm + + let sep_tab = Sep.tab + let sep_spc = Sep.space + let comma = Sep.comma + let eol = Util.eol + + let comment = Util.comment + let empty = Util.empty + + let file = /[^# \t\n]+/ + + let int = Rx.integer + let bool = "yes" | "no" + + (* An option label can't contain comma, comment, equals, or space *) + let optlabel = /[^,#= \n\t]+/ - "-" + let spec = /[^-,# \n\t][^ \n\t]*/ + + let optional = Util.del_str "-" + + let comma_sep_list (l:string) = + let value = [ label "value" . Util.del_str "=" . store Rx.neg1 ] in + let lns = [ label l . store optlabel . value? ] in + Build.opt_list lns comma + + let record = [ seq "mntent" . + [ label "spec" . store spec ] . sep_tab . + ( [ label "fsck" . store spec ] | optional ). sep_tab . + [ label "file" . store file ] . sep_tab . + comma_sep_list "vfstype" . sep_tab . + ( [ label "passno" . store int ] | optional ) . sep_spc . + [ label "atboot" . store bool ] . sep_tab . + ( comma_sep_list "opt" | optional ) . + eol ] + + let lns = ( empty | comment | record ) * + let filter = incl "/etc/vfstab" + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/vmware_config.aug b/Sharp.Augeas.Test/lens/vmware_config.aug new file mode 100644 index 0000000..e7398d0 --- /dev/null +++ b/Sharp.Augeas.Test/lens/vmware_config.aug @@ -0,0 +1,34 @@ +(* +Module: VWware_Config + Parses /etc/vmware/config + +Author: Raphael Pinson + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Configuration files + This lens applies to /etc/vmware/config. See . + +About: Examples + The file contains various examples and tests. +*) +module VMware_Config = + +autoload xfm + +(* View: entry *) +let entry = + Build.key_value_line Rx.word Sep.space_equal Quote.double_opt + +(* View: lns *) +let lns = (Util.empty | Util.comment | entry)* + + +(* Variable: filter *) +let filter = incl "/etc/vmware/config" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/vsftpd.aug b/Sharp.Augeas.Test/lens/vsftpd.aug new file mode 100644 index 0000000..5b54d04 --- /dev/null +++ b/Sharp.Augeas.Test/lens/vsftpd.aug @@ -0,0 +1,31 @@ +(* Parse vsftpd.conf *) +module Vsftpd = + autoload xfm + +(* The code in parseconf.c does not seem to allow for trailing whitespace *) +(* in the config file *) +let eol = Util.del_str "\n" +let empty = Util.empty +let comment = Util.comment + +let bool_option_re = /anonymous_enable|isolate|isolate_network|local_enable|pasv_enable|port_enable|chroot_local_user|write_enable|anon_upload_enable|anon_mkdir_write_enable|anon_other_write_enable|chown_uploads|connect_from_port_20|xferlog_enable|dirmessage_enable|anon_world_readable_only|async_abor_enable|ascii_upload_enable|ascii_download_enable|one_process_model|xferlog_std_format|pasv_promiscuous|deny_email_enable|chroot_list_enable|setproctitle_enable|text_userdb_names|ls_recurse_enable|log_ftp_protocol|guest_enable|userlist_enable|userlist_deny|use_localtime|check_shell|hide_ids|listen|port_promiscuous|passwd_chroot_enable|no_anon_password|tcp_wrappers|use_sendfile|force_dot_files|listen_ipv6|dual_log_enable|syslog_enable|background|virtual_use_local_privs|session_support|download_enable|dirlist_enable|chmod_enable|secure_email_list_enable|run_as_launching_user|no_log_lock|ssl_enable|allow_anon_ssl|force_local_logins_ssl|force_local_data_ssl|ssl_sslv2|ssl_sslv3|ssl_tlsv1|tilde_user_enable|force_anon_logins_ssl|force_anon_data_ssl|mdtm_write|lock_upload_files|pasv_addr_resolve|debug_ssl|require_cert|validate_cert|require_ssl_reuse|allow_writeable_chroot|seccomp_sandbox/ + +let uint_option_re = /accept_timeout|connect_timeout|local_umask|anon_umask|ftp_data_port|idle_session_timeout|data_connection_timeout|pasv_min_port|pasv_max_port|anon_max_rate|local_max_rate|listen_port|max_clients|file_open_mode|max_per_ip|trans_chunk_size|delay_failed_login|delay_successful_login|max_login_fails|chown_upload_mode/ + +let str_option_re = /secure_chroot_dir|ftp_username|chown_username|xferlog_file|vsftpd_log_file|message_file|nopriv_user|ftpd_banner|banned_email_file|chroot_list_file|pam_service_name|guest_username|userlist_file|anon_root|local_root|banner_file|pasv_address|listen_address|user_config_dir|listen_address6|cmds_allowed|hide_file|deny_file|user_sub_token|email_password_file|rsa_cert_file|dsa_cert_file|ssl_ciphers|rsa_private_key_file|dsa_private_key_file|ca_certs_file/ + +let bool_value_re = /[yY][eE][sS]|[tT][rR][uU][eE]|1|[nN][oO]|[fF][aA][lL][sS][eE]|0/ + +let option (k:regexp) (v:regexp) = [ key k . Util.del_str "=" . store v . eol ] + +let bool_option = option bool_option_re bool_value_re + +let str_option = option str_option_re /[^\n]+/ + +let uint_option = option uint_option_re /[0-9]+/ + +let lns = (bool_option|str_option|uint_option|comment|empty)* + +let filter = (incl "/etc/vsftpd.conf") . (incl "/etc/vsftpd/vsftpd.conf") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/webmin.aug b/Sharp.Augeas.Test/lens/webmin.aug new file mode 100644 index 0000000..2bc4f3e --- /dev/null +++ b/Sharp.Augeas.Test/lens/webmin.aug @@ -0,0 +1,46 @@ +(* Webmin module for Augeas + Author: Free Ekanayaka + + Reference: + +*) + +module Webmin = + + autoload xfm + +(************************************************************************ + * USEFUL PRIMITIVES + *************************************************************************) + +let eol = Util.eol +let comment = Util.comment +let empty = Util.empty + +let sep_eq = del /=/ "=" + +let sto_to_eol = store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ + +let word = /[A-Za-z0-9_.-]+/ + +(************************************************************************ + * ENTRIES + *************************************************************************) + +let entry = [ key word + . sep_eq + . sto_to_eol? + . eol ] + +(************************************************************************ + * LENS + *************************************************************************) + +let lns = (comment|empty|entry) * + +let wm_incl (n:string) + = (incl ("/etc/webmin/" . n)) +let filter = wm_incl "miniserv.conf" + . wm_incl "ldap-useradmin/config" + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/wine.aug b/Sharp.Augeas.Test/lens/wine.aug new file mode 100644 index 0000000..bd43a17 --- /dev/null +++ b/Sharp.Augeas.Test/lens/wine.aug @@ -0,0 +1,46 @@ +(* Lens for the textual representation of Windows registry files, as used *) +(* by wine etc. *) +(* This is pretty quick and dirty, as it doesn't put a lot of finesse on *) +(* splitting up values that have structure, e.g. hex arrays or *) +(* collections of paths. *) +module Wine = + +(* We handle Unix and DOS line endings, though we can only add one or the *) +(* other to new lines. Maybe provide a function to gather that from the *) +(* current file ? *) +let eol = del /[ \t]*\r?\n/ "\n" +let comment = [ label "#comment" . del /[ \t]*;;[ \t]*/ ";; " + . store /([^ \t\r\n].*[^ \t\r\n]|[^ \t\r\n])/ . eol ] +let empty = [ eol ] +let dels = Util.del_str +let del_ws = Util.del_ws_spc + +let header = + [ label "registry" . store /[a-zA-Z0-9 \t]*[a-zA-Z0-9]/ ] . + del /[ \t]*Version[ \t]*/ " Version " . + [ label "version" . store /[0-9.]+/ ] . eol + +let qstr = + let re = /([^"\n]|\\\\.)*/ - /@|"@"/ in (* " Relax, emacs *) + dels "\"" . store re . dels "\"" + +let typed_val = + ([ label "type" . store /dword|hex(\\([0-9]+\\))?/ ] . dels ":" . + [ label "value" . store /[a-zA-Z0-9,()]+(\\\\\r?\n[ \t]*[a-zA-Z0-9,]+)*/]) + |([ label "type" . store /str\\([0-9]+\\)/ ] . dels ":" . + dels "\"" . [ label "value" . store /[^"\n]*/ ] . dels "\"") (* " Relax, emacs *) + +let entry = + let qkey = [ label "key" . qstr ] in + let eq = del /[ \t]*=[ \t]*/ "=" in + let qstore = [ label "value" . qstr ] in + [ label "entry" . qkey . eq . (qstore|typed_val) . eol ] + |[label "anon" . del /"?@"?/ "@" . eq . (qstore|typed_val) .eol ] + +let section = + let ts = [ label "timestamp" . store Rx.integer ] in + [ label "section" . del /[ \t]*\\[/ "[" . + store /[^]\n]+/ . dels "]" . (del_ws . ts)? . eol . + (entry|empty|comment)* ] + +let lns = header . (empty|comment)* . section* diff --git a/Sharp.Augeas.Test/lens/xendconfsxp.aug b/Sharp.Augeas.Test/lens/xendconfsxp.aug new file mode 100644 index 0000000..132e479 --- /dev/null +++ b/Sharp.Augeas.Test/lens/xendconfsxp.aug @@ -0,0 +1,37 @@ +module Xendconfsxp = + autoload xfm + +let spc1 = /[ \t\n]+/ +let ws = del spc1 " " + +let lbrack = del /[ \t]*\([ \t\n]*/ "(" +let rbrack = del /[ \t\n]*\)/ ")" + +let empty_line = [ del /[ \t]*\n/ "\n" ] + +let no_ws_comment = + [ label "#comment" . del /#[ \t]*/ "# " . store /[^ \t]+[^\n]*/ . del /\n/ "\n" ] + +let standalone_comment = [ label "#scomment" . del /#/ "#" . store /.*/ . del /\n/ "\n" ] +(* Minor bug: The initial whitespace is stored, not deleted. *) + +let ws_and_comment = ws . no_ws_comment + +(* Either a word or a quoted string *) +let str_store = store /[A-Za-z0-9_.\/-]+|\"([^\"\\\\]|(\\\\.))*\"|'([^'\\\\]|(\\\\.))*'/ + +let str = [ label "string" . str_store ] + +let var_name = key Rx.word + +let rec thing = + let array = [ label "array" . lbrack . Build.opt_list thing ws . ws_and_comment? . rbrack ] in + let str = [ label "item" . str_store ] in + str | array + +let sexpr = [ lbrack . var_name . ws . no_ws_comment? . thing . ws_and_comment? . rbrack ] + +let lns = ( empty_line | standalone_comment | sexpr ) * + +let filter = incl "xend-config.sxp" +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/xinetd.aug b/Sharp.Augeas.Test/lens/xinetd.aug new file mode 100644 index 0000000..072d768 --- /dev/null +++ b/Sharp.Augeas.Test/lens/xinetd.aug @@ -0,0 +1,108 @@ +(* + * Module: Xinetd + * Parses xinetd configuration files + * + * The structure of the lens and allowed attributes are ripped directly + * from xinetd's parser in xinetd/parse.c in xinetd's source checkout + * The downside of being so precise here is that if attributes are added + * they need to be added here, too. Writing a catchall entry, and getting + * to typecheck correctly would be a huge pain. + * + * A really enterprising soul could tighten this down even further by + * restricting the acceptable values for each attribute. + * + * Author: David Lutterkort + *) + +module Xinetd = + autoload xfm + + let opt_spc = Util.del_opt_ws " " + + let spc_equal = opt_spc . Sep.equal + + let op = ([ label "add" . opt_spc . Util.del_str "+=" ] + |[ label "del" . opt_spc . Util.del_str "-=" ] + | spc_equal) + + let value = store Rx.no_spaces + + let indent = del Rx.opt_space "\t" + + let attr_one (n:regexp) = + Build.key_value n Sep.space_equal value + + let attr_lst (n:regexp) (op_eq: lens) = + let value_entry = [ label "value" . value ] in + Build.key_value n op_eq (opt_spc . Build.opt_list value_entry Sep.space)? + + let attr_lst_eq (n:regexp) = attr_lst n spc_equal + + let attr_lst_op (n:regexp) = attr_lst n op + + (* Variable: service_attr + * Note: + * It is much faster to combine, for example, all the attr_one + * attributes into one regexp and pass that to a lens instead of + * using lens union (attr_one "a" | attr_one "b"|..) because the latter + * causes the type checker to work _very_ hard. + *) + let service_attr = + attr_one (/socket_type|protocol|wait|user|group|server|instances/i + |/rpc_version|rpc_number|id|port|nice|banner|bind|interface/i + |/per_source|groups|banner_success|banner_fail|disable|max_load/i + |/rlimit_as|rlimit_cpu|rlimit_data|rlimit_rss|rlimit_stack|v6only/i + |/deny_time|umask|mdns|libwrap/i) + (* redirect and cps aren't really lists, they take exactly two values *) + |attr_lst_eq (/server_args|log_type|access_times|type|flags|redirect|cps/i) + |attr_lst_op (/log_on_success|log_on_failure|only_from|no_access|env|passenv/i) + + let default_attr = + attr_one (/instances|banner|bind|interface|per_source|groups/i + |/banner_success|banner_fail|max_load|v6only|umask|mdns/i) + |attr_lst_eq /cps/i (* really only two values, not a whole list *) + |attr_lst_op (/log_type|log_on_success|log_on_failure|disabled/i + |/no_access|only_from|passenv|enabled/i) + + (* View: body + * Note: + * We would really like to say "the body can contain any of a list + * of a list of attributes, each of them at most once"; but that + * would require that we build a lens that matches the permutation + * of all attributes; with around 40 individual attributes, that's + * not computationally feasible, even if we didn't have to worry + * about how to write that down. The resulting regular expressions + * would simply be prohibitively large. + *) + let body (attr:lens) = Build.block_newlines_spc + (indent . attr . Util.eol) + Util.comment + + (* View: includes + * Note: + * It would be nice if we could use the directories given in include and + * includedir directives to parse additional files instead of hardcoding + * all the places where xinetd config files can be found; but that is + * currently not possible, and implementing that has a good amount of + * hairy corner cases to consider. + *) + let includes = + Build.key_value_line /include(dir)?/ Sep.space (store Rx.no_spaces) + + let service = + let sto_re = /[^# \t\n\/]+/ in + Build.key_value_line "service" Sep.space (store sto_re . body service_attr) + + let defaults = [ key "defaults" . body default_attr . Util.eol ] + + let lns = ( Util.empty | Util.comment | includes | defaults | service )* + + let filter = incl "/etc/xinetd.d/*" + . incl "/etc/xinetd.conf" + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas.Test/lens/xml.aug b/Sharp.Augeas.Test/lens/xml.aug new file mode 100644 index 0000000..342b13b --- /dev/null +++ b/Sharp.Augeas.Test/lens/xml.aug @@ -0,0 +1,168 @@ +(* XML lens for Augeas + Author: Francis Giraldeau + + Reference: http://www.w3.org/TR/2006/REC-xml11-20060816/ +*) + +module Xml = + +autoload xfm + +(************************************************************************ + * Utilities lens + *************************************************************************) + +let dels (s:string) = del s s +let spc = /[ \t\r\n]+/ +let osp = /[ \t\r\n]*/ +let sep_spc = del /[ \t\r\n]+/ " " +let sep_osp = del /[ \t\r\n]*/ "" +let sep_eq = del /[ \t\r\n]*=[ \t\r\n]*/ "=" + +let nmtoken = /[a-zA-Z:_][a-zA-Z0-9:_.-]*/ +let word = /[a-zA-Z][a-zA-Z0-9._-]*/ +let char = /.|(\r?\n)/ +(* if we hide the quotes, then we can only accept single or double quotes *) +(* otherwise a put ambiguity is raised *) +let sto_dquote = dels "\"" . store /[^"]*/ . dels "\"" (* " *) +let sto_squote = dels "'" . store /[^']*/ . dels "'" + +let comment = [ label "#comment" . + dels "" ] + +let pi_target = nmtoken - /[Xx][Mm][Ll]/ +let empty = Util.empty +let del_end = del />[\r?\n]?/ ">\n" +let del_end_simple = dels ">" + +(* This is siplified version of processing instruction + * pi has to not start or end with a white space and the string + * must not contain "?>". We restrict too much by not allowing any + * "?" nor ">" in PI + *) +let pi = /[^ \r\n\t]|[^ \r\n\t][^?>]*[^ \r\n\t]/ + +(************************************************************************ + * Attributes + *************************************************************************) + + +let decl = [ label "#decl" . sep_spc . + store /[^> \t\n\r]|[^> \t\n\r][^>\t\n\r]*[^> \t\n\r]/ ] + +let decl_def (r:regexp) (b:lens) = [ dels "<" . key r . + sep_spc . store nmtoken . + b . sep_osp . del_end_simple ] + +let elem_def = decl_def /!ELEMENT/ decl + +let enum = "(" . osp . nmtoken . ( osp . "|" . osp . nmtoken )* . osp . ")" + +let att_type = /CDATA|ID|IDREF|IDREFS|ENTITY|ENTITIES|NMTOKEN|NMTOKENS/ | + enum + +let id_def = [ sep_spc . key /PUBLIC/ . + [ label "#literal" . sep_spc . sto_dquote ]* ] | + [ sep_spc . key /SYSTEM/ . sep_spc . sto_dquote ] + +let notation_def = decl_def /!NOTATION/ id_def + +let att_def = counter "att_id" . + [ sep_spc . seq "att_id" . + [ label "#name" . store word . sep_spc ] . + [ label "#type" . store att_type . sep_spc ] . + ([ key /#REQUIRED|#IMPLIED/ ] | + [ label "#FIXED" . del /#FIXED[ \r\n\t]*|/ "" . sto_dquote ]) ]* + +let att_list_def = decl_def /!ATTLIST/ att_def + +let entity_def = + let literal (lbl:string) = [ sep_spc . label lbl . sto_dquote ] in + decl_def /!ENTITY/ + ( literal "#decl" + | [ sep_spc . key /SYSTEM/ . literal "#systemliteral" ] + | [ sep_spc . key /PUBLIC/ . literal "#pubidliteral" + . literal "#systemliteral" ] ) + +let decl_def_item = elem_def | entity_def | att_list_def | notation_def + +let decl_outer = sep_osp . del /\[[ \n\t\r]*/ "[\n" . + (decl_def_item . sep_osp )* . dels "]" + +(* let dtd_def = [ sep_spc . key "SYSTEM" . sep_spc . sto_dquote ] *) + +let doctype = decl_def /!DOCTYPE/ (decl_outer|id_def) + +(* General shape of an attribute + * q is the regexp matching the quote character for the value + * qd is the default quote character + * brx is what the actual attribute value must match *) +let attval (q:regexp) (qd:string) (brx:regexp) = + let quote = del q qd in + let body = store brx in + [ sep_spc . key nmtoken . sep_eq . square quote body quote ] + +(* We treat attributes according to one of the following three patterns: + attval1 : values that must be quoted with single quotes + attval2 : values that must be quoted with double quotes + attval3 : values that can be quoted with either *) +let attributes = + let attval1 = attval "'" "'" /[^']*"[^']*/ in (* " *) + let attval2 = attval "\"" "\"" /[^"]*'[^"]*/ in + let attval3 = attval /['"]/ "\"" /(\\\\|[^'\"])*/ in (* " *) + [ label "#attribute" . (attval1|attval2|attval3)+ ] + +let prolog = [ label "#declaration" . + dels "" ] + + +(************************************************************************ + * Tags + *************************************************************************) + +(* we consider entities as simple text *) +let text_re = /[^<]+/ - /([^<]*\]\]>[^<]*)/ +let text = [ label "#text" . store text_re ] +let cdata = [ label "#CDATA" . dels "" . char*)) . dels "]]>" ] + +(* the value of nmtoken_del is always the nmtoken_key string *) +let nmtoken_key = key nmtoken +let nmtoken_del = del nmtoken "a" + +let element (body:lens) = + let h = attributes? . sep_osp . dels ">" . body* . dels "[\r?\n]?/ "/>\n" ] + +let pi_instruction = [ dels "/ "?>" ] + +(* Typecheck is weaker on rec lens, detected by unfolding *) +(* +let content1 = element text +let rec content2 = element (content1|text|comment) +*) + +let rec content = element (text|comment|content|empty_element|pi_instruction|cdata) + +(* Constraints are weaker here, but it's better than being too strict *) +let doc = (sep_osp . (prolog | comment | doctype | pi_instruction))* . + ((sep_osp . content) | (sep_osp . empty_element)) . + (sep_osp . (comment | pi_instruction ))* . sep_osp + +let lns = doc | Util.empty? + +let filter = (incl "/etc/xml/*.xml") + . (incl "/etc/xml/catalog") + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/xorg.aug b/Sharp.Augeas.Test/lens/xorg.aug new file mode 100644 index 0000000..1c87c22 --- /dev/null +++ b/Sharp.Augeas.Test/lens/xorg.aug @@ -0,0 +1,319 @@ +(* +Module: Xorg + Parses /etc/X11/xorg.conf + +Authors: Raphael Pinson + Matthew Booth + +About: Reference + This lens tries to keep as close as possible to `man xorg.conf` where + possible. + +The definitions from `man xorg.conf` are put as commentaries for reference +throughout the file. More information can be found in the manual. + +About: License + This file is licensed under the LGPLv2+, like the rest of Augeas. + +About: Lens Usage + Sample usage of this lens in augtool + + * Get the identifier of the devices with a "Clone" option: + > match "/files/etc/X11/xorg.conf/Device[Option = 'Clone']/Identifier" + +About: Configuration files + This lens applies to /etc/X11/xorg.conf. See . +*) + +module Xorg = + autoload xfm + +(************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + +(* Group: Generic primitives *) + +(* Variable: eol *) +let eol = Util.eol + +(* Variable: to_eol + * Match everything from here to eol, cropping whitespace at both ends + *) +let to_eol = /[^ \t\n](.*[^ \t\n])?/ + +(* Variable: indent *) +let indent = Util.indent + +(* Variable: comment *) +let comment = Util.comment + +(* Variable: empty *) +let empty = Util.empty + + +(* Group: Separators *) + +(* Variable: sep_spc *) +let sep_spc = Util.del_ws_spc + +(* Variable: sep_dquote *) +let sep_dquote = Util.del_str "\"" + + +(* Group: Fields and values *) + +(* Variable: entries_re + * This is a list of all patterns which have specific handlers, and should + * therefore not be matched by the generic handler + *) +let entries_re = /([oO]ption|[sS]creen|[iI]nput[dD]evice|[dD]river|[sS]ub[sS]ection|[dD]isplay|[iI]dentifier|[vV]ideo[rR]am|[dD]efault[dD]epth|[dD]evice)/ + +(* Variable: generic_entry_re *) +let generic_entry_re = /[^# \t\n\/]+/ - entries_re + +(* Variable: quoted_non_empty_string_val *) +let quoted_non_empty_string_val = del "\"" "\"" . store /[^"\n]+/ + . del "\"" "\"" + (* " relax, emacs *) + +(* Variable: quoted_string_val *) +let quoted_string_val = del "\"" "\"" . store /[^"\n]*/ . del "\"" "\"" + (* " relax, emacs *) + +(* Variable: int *) +let int = /[0-9]+/ + + +(************************************************************************ + * Group: ENTRIES AND OPTIONS + *************************************************************************) + + +(* View: entry_int + * This matches an entry which takes a single integer for an argument + *) +let entry_int (canon:string) (re:regexp) = + [ indent . del re canon . label canon . sep_spc . store int . eol ] + +(* View: entry_rgb + * This matches an entry which takes 3 integers as arguments representing red, + * green and blue components + *) +let entry_rgb (canon:string) (re:regexp) = + [ indent . del re canon . label canon + . [ label "red" . sep_spc . store int ] + . [ label "green" . sep_spc . store int ] + . [ label "blue" . sep_spc . store int ] + . eol ] + +(* View: entry_xy + * This matches an entry which takes 2 integers as arguments representing X and + * Y coordinates + *) +let entry_xy (canon:string) (re:regexp) = + [ indent . del re canon . label canon + . [ label "x" . sep_spc . store int ] + . [ label "y" . sep_spc . store int ] + . eol ] + +(* View: entry_str + * This matches an entry which takes a single quoted string + *) +let entry_str (canon:string) (re:regexp) = + [ indent . del re canon . label canon + . sep_spc . quoted_non_empty_string_val . eol ] + +(* View: entry_generic + * An entry without a specific handler. Store everything after the keyword, + * cropping whitespace at both ends. + *) +let entry_generic = [ indent . key generic_entry_re + . sep_spc . store to_eol . eol ] + +(* View: option *) +let option = [ indent . del /[oO]ption/ "Option" . label "Option" . sep_spc + . quoted_non_empty_string_val + . [ label "value" . sep_spc . quoted_string_val ]* + . eol ] + +(* View: screen + * The Screen entry of ServerLayout + *) +let screen = [ indent . del /[sS]creen/ "Screen" . label "Screen" + . [ sep_spc . label "num" . store int ]? + . ( sep_spc . quoted_non_empty_string_val + . [ sep_spc . label "position" . store to_eol ]? )? + . eol ] + +(* View: input_device *) +let input_device = [ indent . del /[iI]nput[dD]evice/ "InputDevice" + . label "InputDevice" . sep_spc + . quoted_non_empty_string_val + . [ label "option" . sep_spc + . quoted_non_empty_string_val ]* + . eol ] + +(* View: driver *) +let driver = entry_str "Driver" /[dD]river/ + +(* View: identifier *) +let identifier = entry_str "Identifier" /[iI]dentifier/ + +(* View: videoram *) +let videoram = entry_int "VideoRam" /[vV]ideo[rR]am/ + +(* View: default_depth *) +let default_depth = entry_int "DefaultDepth" /[dD]efault[dD]epth/ + +(* View: device *) +let device = entry_str "Device" /[dD]evice/ + +(************************************************************************ + * Group: DISPLAY SUBSECTION + *************************************************************************) + + +(* View: display_modes *) +let display_modes = [ indent . del /[mM]odes/ "Modes" . label "Modes" + . [ label "mode" . sep_spc + . quoted_non_empty_string_val ]+ + . eol ] + +(************************************************************************* + * View: display_entry + * Known values for entries in the Display subsection + * + * Definition: + * > Depth depth + * > FbBpp bpp + * > Weight red-weight green-weight blue-weight + * > Virtual xdim ydim + * > ViewPort x0 y0 + * > Modes "mode-name" ... + * > Visual "visual-name" + * > Black red green blue + * > White red green blue + * > Options + *) + +let display_entry = entry_int "Depth" /[dD]epth/ | + entry_int "FbBpp" /[fF]b[bB]pp/ | + entry_rgb "Weight" /[wW]eight/ | + entry_xy "Virtual" /[vV]irtual/ | + entry_xy "ViewPort" /[vV]iew[pP]ort/ | + display_modes | + entry_str "Visual" /[vV]isual/ | + entry_rgb "Black" /[bB]lack/ | + entry_rgb "White" /[wW]hite/ | + entry_str "Options" /[oO]ptions/ | + empty | + comment + +(* View: display *) +let display = [ indent . del "SubSection" "SubSection" . sep_spc + . sep_dquote . key "Display" . sep_dquote + . eol + . display_entry* + . indent . del "EndSubSection" "EndSubSection" . eol ] + +(************************************************************************ + * Group: EXTMOD SUBSECTION + *************************************************************************) + +let extmod_entry = entry_str "Option" /[oO]ption/ | + empty | + comment + +let extmod = [ indent . del "SubSection" "SubSection" . sep_spc + . sep_dquote . key "extmod" . sep_dquote + . eol + . extmod_entry* + . indent . del "EndSubSection" "EndSubSection" . eol ] + +(************************************************************************ + * Group: SECTIONS + *************************************************************************) + + +(************************************************************************ + * Variable: section_re + * Known values for Section names + * + * Definition: + * > The section names are: + * > + * > Files File pathnames + * > ServerFlags Server flags + * > Module Dynamic module loading + * > Extensions Extension Enabling + * > InputDevice Input device description + * > InputClass Input Class description + * > Device Graphics device description + * > VideoAdaptor Xv video adaptor description + * > Monitor Monitor description + * > Modes Video modes descriptions + * > Screen Screen configuration + * > ServerLayout Overall layout + * > DRI DRI-specific configuration + * > Vendor Vendor-specific configuration + *************************************************************************) +let section_re = /(Extensions|Files|ServerFlags|Module|InputDevice|InputClass|Device|VideoAdaptor|Monitor|Modes|Screen|ServerLayout|DRI|Vendor)/ + + +(************************************************************************ + * Variable: secton_re_obsolete + * The following obsolete section names are still recognised for + * compatibility purposes. In new config files, the InputDevice + * section should be used instead. + * + * Definition: + * > Keyboard Keyboard configuration + * > Pointer Pointer/mouse configuration + *************************************************************************) +let section_re_obsolete = /(Keyboard|Pointer)/ + +(* View: section_entry *) +let section_entry = option | + screen | + display | + extmod | + input_device | + driver | + identifier | + videoram | + default_depth | + device | + entry_generic | + empty | comment + +(************************************************************************ + * View: section + * A section in xorg.conf + * + * Definition: + * > Section "SectionName" + * > SectionEntry + * > ... + * > EndSection + *************************************************************************) +let section = [ indent . del "Section" "Section" + . sep_spc . sep_dquote + . key (section_re|section_re_obsolete) . sep_dquote + . eol + . section_entry* + . indent . del "EndSection" "EndSection" . eol ] + +(* + * View: lns + * The xorg.conf lens + *) +let lns = ( empty | comment | section )* + + +(* Variable: filter *) +let filter = incl "/etc/X11/xorg.conf" + . incl "/etc/X11/xorg.conf.d/*.conf" + . Util.stdexcl + +let xfm = transform lns filter diff --git a/Sharp.Augeas.Test/lens/xymon.aug b/Sharp.Augeas.Test/lens/xymon.aug new file mode 100644 index 0000000..da372b8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/xymon.aug @@ -0,0 +1,56 @@ +(* +Xymon configuration +By Jason Kincl - 2012 +*) + +module Xymon = + autoload xfm + +let empty = Util.empty +let eol = Util.eol +let word = Rx.word +let space = Rx.space +let ip = Rx.ip +let del_ws_spc = Util.del_ws_spc +let value_to_eol = store /[^ \t][^\n]+/ +let eol_no_spc = Util.del_str "\n" + +let comment = Util.comment_generic /[ \t]*[;#][ \t]*/ "# " +let include = [ key /include|dispinclude|netinclude|directory/ . del_ws_spc . value_to_eol . eol_no_spc ] +let title = [ key "title" . del_ws_spc . value_to_eol . eol_no_spc ] + +(* Define host *) +let tag = del_ws_spc . [ label "tag" . store /[^ \n\t]+/ ] +let host_ip = [ label "ip" . store ip ] +let host_hostname = [ label "fqdn" . store word ] +let host_colon = del /[ \t]*#/ " #" +let host = [ label "host" . host_ip . del space " " . host_hostname . host_colon . tag* . eol ] + +(* Define group-compress and group-only *) +let group_extra = del_ws_spc . value_to_eol . eol_no_spc . (comment | empty | host | title)* +let group = [ key "group" . group_extra ] +let group_compress = [ key "group-compress" . group_extra ] +let group_sorted = [ key "group-sorted" . group_extra ] + +let group_only_col = [ label "col" . store Rx.word ] +let group_only_cols = del_ws_spc . group_only_col . ( Util.del_str "|" . group_only_col )* +let group_only = [ key "group-only" . group_only_cols . group_extra ] + +(* Have to use namespacing because page's title overlaps plain title tag *) +let page_name = store word +let page_title = [ label "pagetitle" . del_ws_spc . value_to_eol . eol_no_spc ] +let page_extra = del_ws_spc . page_name . (page_title | eol_no_spc) . (comment | empty | title | include | host)* + . (group | group_compress | group_sorted | group_only)* +let page = [ key /page|subpage/ . page_extra ] + +let subparent_parent = [ label "parent" . store word ] +let subparent = [ key "subparent" . del_ws_spc . subparent_parent . page_extra ] + +let ospage = [ key "ospage" . del_ws_spc . store word . del_ws_spc . [ label "ospagetitle" . value_to_eol . eol_no_spc ] ] + +let lns = (empty | comment | include | host | title | ospage )* . (group | group_compress | group_sorted | group_only)* . (page | subparent)* + +let filter = incl "/etc/xymon/hosts.cfg" . incl "/etc/xymon/pages.cfg" + +let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/xymon_alerting.aug b/Sharp.Augeas.Test/lens/xymon_alerting.aug new file mode 100644 index 0000000..d4265a8 --- /dev/null +++ b/Sharp.Augeas.Test/lens/xymon_alerting.aug @@ -0,0 +1,199 @@ +(* +Module: Xymon_Alerting + Parses xymon alerting files + +Author: Francois Maillard + +About: Reference + This lens tries to keep as close as possible to `man 5 alerts.cfg` where possible. + +About: License + This file is licenced under the LGPL v2+, like the rest of Augeas. + +About: Lens Usage + To be documented + +About: Not supported + File inclusion are not followed + +About: Configuration files + This lens applies to /etc/xymon/alerts.d/*.cfg and /etc/xymon/alerts.cfg. See . + +About: Examples + The file contains various examples and tests. +*) + +module Xymon_Alerting = + autoload xfm + + (************************************************************************ + * Group: USEFUL PRIMITIVES + *************************************************************************) + + (* View: store_word *) + let store_word = store /[^ =\t\n#]+/ + + (* View: comparison The greater and lesser than operators *) + let comparison = store /[<>]/ + + (* View: equal *) + let equal = Sep.equal + + (* View: ws *) + let ws = Sep.space + + (* View: eol *) + let eol = Util.eol + + (* View: ws_or_eol *) + let ws_or_eol = del /([ \t]+|[ \t]*\n[ \t]*)/ " " + + (* View: comment *) + let comment = Util.comment + + (* View: empty *) + let empty = Util.empty + + (* View: include *) + let include = [ key "include" . ws . store_word . eol ] + + (************************************************************************ + * Group: MACRO DEFINITION + *************************************************************************) + + (* View: macrodefinition + A string that starts with $ and that is assigned something *) + let macrodefinition = [ key /\$[^ =\t\n#\/]+/ . Sep.space_equal . store Rx.space_in . eol ] + + + (* View: flag + A flag value *) + let flag (kw:string) = Build.flag kw + + (* View: kw_word + A key=value value *) + let kw_word (kw:regexp) = Build.key_value kw equal store_word + + (************************************************************************ + * Group: FILTERS + *************************************************************************) + + (* View: page + The (ex)?page filter definition *) + let page = kw_word /(EX)?PAGE/ + + (* View: group + The (ex)?group filter definition *) + let group = kw_word /(EX)?GROUP/ + + (* View: host + The (ex)?host filter definition *) + let host = kw_word /(EX)?HOST/ + + (* View: service + The (ex)?service filter definition *) + let service = kw_word /(EX)?SERVICE/ + + (* View: color + The color filter definition *) + let color = kw_word "COLOR" + + (* View: time + The time filter definition *) + let time = kw_word "TIME" + + (* View: duration + The duration filter definition *) + let duration = [ key "DURATION" . [ label "operator" . comparison ] . [ label "value" . store_word ] ] + (* View: recover + The recover filter definition *) + let recover = flag "RECOVER" + (* View: notice + The notice filter definition *) + let notice = flag "NOTICE" + + (* View: rule_filter + Filters are made out of any of the above filter definitions *) + let rule_filter = page | group | host | service + | color | time | duration | recover | notice + + (* View: filters + One or more filters *) + let filters = [ label "filters" . Build.opt_list rule_filter ws ] + + (* View: filters_opt + Zero, one or more filters *) + let filters_opt = [ label "filters" . (ws . Build.opt_list rule_filter ws)? ] + + (* View: kw_word_filters_opt + A entry with optional filters *) + let kw_word_filters_opt (kw:string) = [ key kw . equal . store_word . filters_opt ] + + (* View: flag_filters_opt + A with optional filters *) + let flag_filters_opt (kw:string) = [ key kw . filters_opt ] + + (************************************************************************ + * Group: RECIPIENTS + *************************************************************************) + + (* View: mail + The mail recipient definition *) + let mail = [ key "MAIL" . ws . store_word . filters_opt ] + + (* View: script + The script recipient definition *) + let script = [ key "SCRIPT" . ws . [ label "script" . store_word ] + . ws . [ label "recipient" . store_word ] . filters_opt ] + + (* View: ignore + The ignore recipient definition *) + let ignore = flag_filters_opt "IGNORE" + + (* View: format + The format recipient definition *) + let format = kw_word_filters_opt "FORMAT" + + (* View: repeat + The repeat recipient definition *) + let repeat = kw_word_filters_opt "REPEAT" + + (* View: unmatched + The unmatched recipient definition *) + let unmatched = flag_filters_opt "UNMATCHED" + + (* View: stop + The stop recipient definition *) + let stop = flag_filters_opt "STOP" + + (* View: macro + The macro recipient definition *) + let macro = [ key /\$[^ =\t\n#\/]+/ . filters_opt ] + + (* View: recipient + Recipients are made out of any of the above recipient definitions *) + let recipient = mail | script | ignore | format | repeat | unmatched + | stop | macro + + let recipients = [ label "recipients" . Build.opt_list recipient ws_or_eol ] + + + (************************************************************************ + * Group: RULES + *************************************************************************) + + (* View: rule + Rules are made of rule_filter and then recipients sperarated by a whitespace *) + let rule = [ seq "rules" . filters . ws_or_eol . recipients . eol ] + + (* View: lns + The Xymon_Alerting lens *) + let lns = ( rule | macrodefinition | include | empty | comment )* + + (* Variable: filter *) + let filter = incl "/etc/xymon/alerts.d/*.cfg" + . incl "/etc/xymon/alerts.cfg" + . Util.stdexcl + + let xfm = transform lns filter + diff --git a/Sharp.Augeas.Test/lens/yaml.aug b/Sharp.Augeas.Test/lens/yaml.aug new file mode 100644 index 0000000..e54b110 --- /dev/null +++ b/Sharp.Augeas.Test/lens/yaml.aug @@ -0,0 +1,78 @@ +(* +Module: Yaml + Only valid for the following subset: + +> defaults: &anchor +> repo1: master +> +> host: +> # Inheritance +> <<: *anchor +> repo2: branch + +Author: Dimitar Dimitrov +*) +module YAML = + +(* Group: helpers *) +let dash = Util.del_str "-" +let colon = Sep.colon +let space = Sep.space +let val = store Rx.word +let eol = Util.eol +let empty = Util.empty +let comment = Util.comment_noindent + +(* +View: indent + the imposed indent is 2 spaces +*) +let indent = del /[ \t]+/ " " + +let mval = [ label "@mval" . Util.del_str "|-" . eol + . [ label "@line" . indent . store Rx.space_in . eol ]+ ] + +(* +View: inherit +> <<: *anchor +*) +let _inherit = [ key "<<" . colon . space . Util.del_str "*" . val . eol ] +let inherit = indent . _inherit . (indent . comment)* + +(* +View: repo +> { "repo" = "branch" } +*) +let _repo = [ key Rx.word . colon . space . (val | mval) . eol ] +let repo = indent . _repo . (indent . comment)* + +(* +View: anchor +> &anchor +*) +let anchor = Util.del_str "&" . val + +(* +View: entry +> host: +> # Inheritance +> <<: *anchor +> repo2: branch +*) +let entry = [ key Rx.word . colon . (space . anchor)? . eol + . (indent . comment)* + . ((inherit . (repo+)?) | repo+) + ] + +(* View: top level sequence *) +let sequence = [ label "@sequence" . counter "sequence" . dash . repo+ ] + +(* View: header *) +let header = [ label "@yaml" . Util.del_str "---" + . (Sep.space . store Rx.space_in)? . eol ] + +(* +View: lns + The yaml lens +*) +let lns = ((empty|comment)* . header)? . (sequence | entry | comment | empty)* diff --git a/Sharp.Augeas.Test/lens/yum.aug b/Sharp.Augeas.Test/lens/yum.aug new file mode 100644 index 0000000..9c9019f --- /dev/null +++ b/Sharp.Augeas.Test/lens/yum.aug @@ -0,0 +1,65 @@ +(* Parsing yum's config files *) +module Yum = + autoload xfm + +(************************************************************************ + * INI File settings + *************************************************************************) + +let comment = IniFile.comment "#" "#" +let sep = IniFile.sep "=" "=" +let empty = Util.empty +let eol = IniFile.eol + +(************************************************************************ + * ENTRY + *************************************************************************) + +let list_entry (list_key:string) = + let list_value = store /[^# \t\r\n,][^ \t\r\n,]*[^# \t\r\n,]|[^# \t\r\n,]/ in + let list_sep = del /([ \t]*(,[ \t]*|\r?\n[ \t]+))|[ \t]+/ "\n\t" in + [ key list_key . sep . Sep.opt_space . list_value ] + . (list_sep . Build.opt_list [ label list_key . list_value ] list_sep)? + . eol + +let entry_re = IniFile.entry_re - ("baseurl" | "gpgkey" | "exclude") + +let entry = IniFile.entry entry_re sep comment + | empty + +let entries = + let list_entry_elem (k:string) = list_entry k . entry* + in entry* + | entry* . Build.combine_three_opt + (list_entry_elem "baseurl") + (list_entry_elem "gpgkey") + (list_entry_elem "exclude") + + +(***********************************************************************a + * TITLE + *************************************************************************) +let title = IniFile.title IniFile.record_re +let record = [ title . entries ] + + +(************************************************************************ + * LENS & FILTER + *************************************************************************) +let lns = (empty | comment)* . record* + + let filter = (incl "/etc/yum.conf") + . (incl "/etc/yum.repos.d/*.repo") + . (incl "/etc/yum/yum-cron*.conf") + . (incl "/etc/yum/pluginconf.d/*") + . (excl "/etc/yum/pluginconf.d/versionlock.list") + . (incl "/etc/dnf/dnf.conf") + . (incl "/etc/dnf/automatic.conf") + . (incl "/etc/dnf/plugins/*.conf") + . Util.stdexcl + + let xfm = transform lns filter + +(* Local Variables: *) +(* mode: caml *) +(* End: *) diff --git a/Sharp.Augeas/root/boot/grub/grub.conf b/Sharp.Augeas.Test/root/boot/grub/grub.conf similarity index 100% rename from Sharp.Augeas/root/boot/grub/grub.conf rename to Sharp.Augeas.Test/root/boot/grub/grub.conf diff --git a/Sharp.Augeas/root/boot/grub/menu.lst b/Sharp.Augeas.Test/root/boot/grub/menu.lst similarity index 100% rename from Sharp.Augeas/root/boot/grub/menu.lst rename to Sharp.Augeas.Test/root/boot/grub/menu.lst diff --git a/Sharp.Augeas/root/etc/aliases b/Sharp.Augeas.Test/root/etc/aliases similarity index 100% rename from Sharp.Augeas/root/etc/aliases rename to Sharp.Augeas.Test/root/etc/aliases diff --git a/Sharp.Augeas/root/etc/apache2/apache2.conf b/Sharp.Augeas.Test/root/etc/apache2/apache2.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/apache2.conf rename to Sharp.Augeas.Test/root/etc/apache2/apache2.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-available/charset.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-available/charset.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-available/charset.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-available/charset.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-available/localized-error-pages.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-available/localized-error-pages.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-available/localized-error-pages.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-available/localized-error-pages.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-available/other-vhosts-access-log.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-available/other-vhosts-access-log.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-available/other-vhosts-access-log.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-available/other-vhosts-access-log.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-available/security.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-available/security.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-available/security.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-available/security.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-available/serve-cgi-bin.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-available/serve-cgi-bin.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-available/serve-cgi-bin.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-available/serve-cgi-bin.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-enabled/charset.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-enabled/charset.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-enabled/charset.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-enabled/charset.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-enabled/localized-error-pages.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-enabled/localized-error-pages.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-enabled/localized-error-pages.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-enabled/localized-error-pages.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-enabled/other-vhosts-access-log.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-enabled/other-vhosts-access-log.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-enabled/other-vhosts-access-log.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-enabled/other-vhosts-access-log.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-enabled/security.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-enabled/security.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-enabled/security.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-enabled/security.conf diff --git a/Sharp.Augeas/root/etc/apache2/conf-enabled/serve-cgi-bin.conf b/Sharp.Augeas.Test/root/etc/apache2/conf-enabled/serve-cgi-bin.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/conf-enabled/serve-cgi-bin.conf rename to Sharp.Augeas.Test/root/etc/apache2/conf-enabled/serve-cgi-bin.conf diff --git a/Sharp.Augeas/root/etc/apache2/envvars b/Sharp.Augeas.Test/root/etc/apache2/envvars similarity index 100% rename from Sharp.Augeas/root/etc/apache2/envvars rename to Sharp.Augeas.Test/root/etc/apache2/envvars diff --git a/Sharp.Augeas/root/etc/apache2/magic b/Sharp.Augeas.Test/root/etc/apache2/magic similarity index 100% rename from Sharp.Augeas/root/etc/apache2/magic rename to Sharp.Augeas.Test/root/etc/apache2/magic diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/access_compat.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/access_compat.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/access_compat.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/access_compat.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/actions.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/actions.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/actions.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/actions.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/actions.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/actions.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/actions.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/actions.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/alias.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/alias.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/alias.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/alias.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/alias.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/alias.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/alias.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/alias.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/allowmethods.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/allowmethods.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/allowmethods.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/allowmethods.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/asis.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/asis.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/asis.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/asis.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/auth_basic.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/auth_basic.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/auth_basic.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/auth_basic.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/auth_digest.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/auth_digest.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/auth_digest.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/auth_digest.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/auth_form.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/auth_form.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/auth_form.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/auth_form.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authn_anon.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_anon.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authn_anon.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_anon.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authn_core.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_core.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authn_core.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_core.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authn_dbd.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_dbd.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authn_dbd.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_dbd.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authn_dbm.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_dbm.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authn_dbm.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_dbm.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authn_file.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_file.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authn_file.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_file.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authn_socache.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_socache.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authn_socache.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authn_socache.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authnz_fcgi.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authnz_fcgi.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authnz_fcgi.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authnz_fcgi.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authnz_ldap.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authnz_ldap.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authnz_ldap.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authnz_ldap.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authz_core.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_core.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authz_core.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_core.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authz_dbd.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_dbd.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authz_dbd.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_dbd.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authz_dbm.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_dbm.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authz_dbm.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_dbm.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authz_groupfile.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_groupfile.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authz_groupfile.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_groupfile.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authz_host.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_host.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authz_host.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_host.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authz_owner.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_owner.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authz_owner.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_owner.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/authz_user.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_user.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/authz_user.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/authz_user.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/autoindex.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/autoindex.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/autoindex.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/autoindex.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/autoindex.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/autoindex.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/autoindex.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/autoindex.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/brotli.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/brotli.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/brotli.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/brotli.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/buffer.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/buffer.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/buffer.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/buffer.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cache.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cache.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cache.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cache.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cache_disk.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cache_disk.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cache_disk.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cache_disk.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cache_disk.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cache_disk.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cache_disk.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cache_disk.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cache_socache.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cache_socache.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cache_socache.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cache_socache.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cern_meta.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cern_meta.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cern_meta.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cern_meta.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cgi.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cgi.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cgi.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cgi.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cgid.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cgid.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cgid.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cgid.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/cgid.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/cgid.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/cgid.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/cgid.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/charset_lite.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/charset_lite.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/charset_lite.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/charset_lite.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/data.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/data.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/data.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/data.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dav.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dav.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dav.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dav.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dav_fs.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dav_fs.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dav_fs.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dav_fs.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dav_fs.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dav_fs.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dav_fs.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dav_fs.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dav_lock.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dav_lock.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dav_lock.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dav_lock.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dbd.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dbd.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dbd.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dbd.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/deflate.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/deflate.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/deflate.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/deflate.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/deflate.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/deflate.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/deflate.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/deflate.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dialup.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dialup.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dialup.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dialup.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dir.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dir.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dir.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dir.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dir.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dir.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dir.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dir.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/dump_io.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/dump_io.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/dump_io.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/dump_io.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/echo.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/echo.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/echo.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/echo.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/env.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/env.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/env.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/env.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/expires.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/expires.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/expires.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/expires.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/ext_filter.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/ext_filter.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/ext_filter.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/ext_filter.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/file_cache.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/file_cache.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/file_cache.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/file_cache.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/filter.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/filter.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/filter.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/filter.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/headers.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/headers.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/headers.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/headers.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/heartbeat.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/heartbeat.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/heartbeat.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/heartbeat.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/heartmonitor.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/heartmonitor.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/heartmonitor.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/heartmonitor.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/http2.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/http2.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/http2.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/http2.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/http2.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/http2.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/http2.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/http2.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/ident.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/ident.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/ident.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/ident.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/imagemap.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/imagemap.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/imagemap.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/imagemap.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/include.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/include.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/include.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/include.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/info.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/info.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/info.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/info.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/info.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/info.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/info.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/info.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_bybusyness.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_bybusyness.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_bybusyness.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_bybusyness.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_byrequests.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_byrequests.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_byrequests.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_byrequests.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_bytraffic.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_bytraffic.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_bytraffic.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_bytraffic.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_heartbeat.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_heartbeat.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/lbmethod_heartbeat.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/lbmethod_heartbeat.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/ldap.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/ldap.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/ldap.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/ldap.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/ldap.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/ldap.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/ldap.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/ldap.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/log_debug.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/log_debug.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/log_debug.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/log_debug.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/log_forensic.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/log_forensic.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/log_forensic.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/log_forensic.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/lua.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/lua.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/lua.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/lua.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/macro.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/macro.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/macro.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/macro.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/md.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/md.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/md.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/md.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mime.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mime.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mime.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mime.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mime.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mime.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mime.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mime.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mime_magic.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mime_magic.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mime_magic.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mime_magic.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mime_magic.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mime_magic.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mime_magic.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mime_magic.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mpm_event.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_event.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mpm_event.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_event.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mpm_event.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_event.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mpm_event.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_event.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mpm_prefork.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_prefork.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mpm_prefork.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_prefork.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mpm_prefork.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_prefork.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mpm_prefork.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_prefork.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mpm_worker.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_worker.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mpm_worker.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_worker.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/mpm_worker.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_worker.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/mpm_worker.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/mpm_worker.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/negotiation.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/negotiation.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/negotiation.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/negotiation.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/negotiation.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/negotiation.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/negotiation.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/negotiation.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_ajp.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_ajp.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_ajp.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_ajp.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_balancer.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_balancer.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_balancer.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_balancer.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_balancer.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_balancer.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_balancer.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_balancer.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_connect.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_connect.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_connect.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_connect.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_express.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_express.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_express.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_express.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_fcgi.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_fcgi.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_fcgi.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_fcgi.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_fdpass.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_fdpass.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_fdpass.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_fdpass.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_ftp.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_ftp.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_ftp.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_ftp.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_ftp.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_ftp.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_ftp.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_ftp.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_hcheck.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_hcheck.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_hcheck.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_hcheck.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_html.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_html.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_html.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_html.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_html.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_html.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_html.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_html.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_http.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_http.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_http.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_http.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_http2.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_http2.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_http2.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_http2.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_scgi.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_scgi.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_scgi.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_scgi.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_uwsgi.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_uwsgi.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_uwsgi.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_uwsgi.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/proxy_wstunnel.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_wstunnel.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/proxy_wstunnel.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/proxy_wstunnel.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/ratelimit.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/ratelimit.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/ratelimit.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/ratelimit.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/reflector.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/reflector.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/reflector.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/reflector.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/remoteip.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/remoteip.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/remoteip.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/remoteip.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/reqtimeout.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/reqtimeout.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/reqtimeout.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/reqtimeout.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/reqtimeout.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/reqtimeout.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/reqtimeout.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/reqtimeout.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/request.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/request.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/request.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/request.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/rewrite.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/rewrite.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/rewrite.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/rewrite.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/sed.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/sed.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/sed.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/sed.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/session.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/session.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/session.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/session.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/session_cookie.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/session_cookie.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/session_cookie.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/session_cookie.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/session_crypto.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/session_crypto.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/session_crypto.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/session_crypto.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/session_dbd.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/session_dbd.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/session_dbd.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/session_dbd.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/setenvif.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/setenvif.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/setenvif.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/setenvif.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/setenvif.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/setenvif.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/setenvif.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/setenvif.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/slotmem_plain.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/slotmem_plain.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/slotmem_plain.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/slotmem_plain.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/slotmem_shm.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/slotmem_shm.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/slotmem_shm.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/slotmem_shm.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/socache_dbm.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_dbm.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/socache_dbm.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_dbm.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/socache_memcache.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_memcache.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/socache_memcache.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_memcache.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/socache_redis.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_redis.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/socache_redis.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_redis.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/socache_shmcb.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_shmcb.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/socache_shmcb.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/socache_shmcb.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/speling.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/speling.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/speling.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/speling.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/ssl.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/ssl.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/ssl.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/ssl.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/ssl.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/ssl.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/ssl.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/ssl.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/status.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/status.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/status.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/status.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/status.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/status.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/status.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/status.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/substitute.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/substitute.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/substitute.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/substitute.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/suexec.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/suexec.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/suexec.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/suexec.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/unique_id.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/unique_id.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/unique_id.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/unique_id.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/userdir.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-available/userdir.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/userdir.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/userdir.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/userdir.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/userdir.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/userdir.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/userdir.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/usertrack.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/usertrack.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/usertrack.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/usertrack.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/vhost_alias.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/vhost_alias.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/vhost_alias.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/vhost_alias.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-available/xml2enc.load b/Sharp.Augeas.Test/root/etc/apache2/mods-available/xml2enc.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-available/xml2enc.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-available/xml2enc.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/access_compat.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/access_compat.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/access_compat.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/access_compat.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/alias.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/alias.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/alias.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/alias.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/alias.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/alias.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/alias.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/alias.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/auth_basic.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/auth_basic.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/auth_basic.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/auth_basic.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/authn_core.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authn_core.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/authn_core.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authn_core.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/authn_file.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authn_file.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/authn_file.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authn_file.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/authz_core.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authz_core.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/authz_core.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authz_core.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/authz_host.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authz_host.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/authz_host.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authz_host.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/authz_user.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authz_user.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/authz_user.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/authz_user.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/autoindex.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/autoindex.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/autoindex.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/autoindex.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/autoindex.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/autoindex.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/autoindex.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/autoindex.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/deflate.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/deflate.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/deflate.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/deflate.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/deflate.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/deflate.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/deflate.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/deflate.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/dir.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/dir.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/dir.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/dir.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/dir.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/dir.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/dir.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/dir.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/env.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/env.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/env.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/env.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/filter.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/filter.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/filter.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/filter.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/headers.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/headers.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/headers.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/headers.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/lbmethod_byrequests.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/lbmethod_byrequests.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/lbmethod_byrequests.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/lbmethod_byrequests.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/mime.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mime.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/mime.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mime.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/mime.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mime.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/mime.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mime.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/mpm_event.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mpm_event.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/mpm_event.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mpm_event.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/mpm_event.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mpm_event.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/mpm_event.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/mpm_event.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/negotiation.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/negotiation.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/negotiation.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/negotiation.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/negotiation.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/negotiation.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/negotiation.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/negotiation.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_balancer.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_balancer.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_balancer.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_balancer.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_balancer.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_balancer.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_balancer.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_balancer.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_connect.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_connect.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_connect.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_connect.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_ftp.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_ftp.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_ftp.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_ftp.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_ftp.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_ftp.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_ftp.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_ftp.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_html.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_html.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_html.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_html.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_html.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_html.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_html.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_html.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_http.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_http.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/proxy_http.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/proxy_http.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/reqtimeout.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/reqtimeout.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/reqtimeout.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/reqtimeout.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/reqtimeout.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/reqtimeout.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/reqtimeout.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/reqtimeout.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/rewrite.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/rewrite.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/rewrite.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/rewrite.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/setenvif.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/setenvif.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/setenvif.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/setenvif.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/setenvif.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/setenvif.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/setenvif.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/setenvif.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/slotmem_shm.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/slotmem_shm.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/slotmem_shm.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/slotmem_shm.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/socache_shmcb.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/socache_shmcb.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/socache_shmcb.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/socache_shmcb.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/ssl.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/ssl.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/ssl.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/ssl.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/ssl.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/ssl.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/ssl.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/ssl.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/status.conf b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/status.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/status.conf rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/status.conf diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/status.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/status.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/status.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/status.load diff --git a/Sharp.Augeas/root/etc/apache2/mods-enabled/xml2enc.load b/Sharp.Augeas.Test/root/etc/apache2/mods-enabled/xml2enc.load similarity index 100% rename from Sharp.Augeas/root/etc/apache2/mods-enabled/xml2enc.load rename to Sharp.Augeas.Test/root/etc/apache2/mods-enabled/xml2enc.load diff --git a/Sharp.Augeas/root/etc/apache2/ports.conf b/Sharp.Augeas.Test/root/etc/apache2/ports.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/ports.conf rename to Sharp.Augeas.Test/root/etc/apache2/ports.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-available/00-ci.codeliturgy.com-le-ssl.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-available/00-ci.codeliturgy.com-le-ssl.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-available/00-ci.codeliturgy.com-le-ssl.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-available/00-ci.codeliturgy.com-le-ssl.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-available/00-ci.codeliturgy.com.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-available/00-ci.codeliturgy.com.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-available/00-ci.codeliturgy.com.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-available/00-ci.codeliturgy.com.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-available/000-default.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-available/000-default.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-available/000-default.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-available/000-default.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-available/01-git.codeliturgy.com.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-available/01-git.codeliturgy.com.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-available/01-git.codeliturgy.com.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-available/01-git.codeliturgy.com.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-available/02-codeliturgy.com.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-available/02-codeliturgy.com.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-available/02-codeliturgy.com.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-available/02-codeliturgy.com.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-available/default-ssl.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-available/default-ssl.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-available/default-ssl.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-available/default-ssl.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-available/sample_dotnet_apache_config.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-available/sample_dotnet_apache_config.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-available/sample_dotnet_apache_config.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-available/sample_dotnet_apache_config.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-enabled/00-ci.codeliturgy.com-le-ssl.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-enabled/00-ci.codeliturgy.com-le-ssl.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-enabled/00-ci.codeliturgy.com-le-ssl.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-enabled/00-ci.codeliturgy.com-le-ssl.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-enabled/01-git.codeliturgy.com.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-enabled/01-git.codeliturgy.com.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-enabled/01-git.codeliturgy.com.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-enabled/01-git.codeliturgy.com.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-enabled/02-codeliturgy.com.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-enabled/02-codeliturgy.com.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-enabled/02-codeliturgy.com.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-enabled/02-codeliturgy.com.conf diff --git a/Sharp.Augeas/root/etc/apache2/sites-enabled/default-ssl.conf b/Sharp.Augeas.Test/root/etc/apache2/sites-enabled/default-ssl.conf similarity index 100% rename from Sharp.Augeas/root/etc/apache2/sites-enabled/default-ssl.conf rename to Sharp.Augeas.Test/root/etc/apache2/sites-enabled/default-ssl.conf diff --git a/Sharp.Augeas/root/etc/apt/apt.conf.d/01autoremove b/Sharp.Augeas.Test/root/etc/apt/apt.conf.d/01autoremove similarity index 100% rename from Sharp.Augeas/root/etc/apt/apt.conf.d/01autoremove rename to Sharp.Augeas.Test/root/etc/apt/apt.conf.d/01autoremove diff --git a/Sharp.Augeas/root/etc/apt/apt.conf.d/01autoremove-kernels b/Sharp.Augeas.Test/root/etc/apt/apt.conf.d/01autoremove-kernels similarity index 100% rename from Sharp.Augeas/root/etc/apt/apt.conf.d/01autoremove-kernels rename to Sharp.Augeas.Test/root/etc/apt/apt.conf.d/01autoremove-kernels diff --git a/Sharp.Augeas/root/etc/apt/apt.conf.d/50unattended-upgrades b/Sharp.Augeas.Test/root/etc/apt/apt.conf.d/50unattended-upgrades similarity index 100% rename from Sharp.Augeas/root/etc/apt/apt.conf.d/50unattended-upgrades rename to Sharp.Augeas.Test/root/etc/apt/apt.conf.d/50unattended-upgrades diff --git a/Sharp.Augeas/root/etc/apt/apt.conf.d/70debconf b/Sharp.Augeas.Test/root/etc/apt/apt.conf.d/70debconf similarity index 100% rename from Sharp.Augeas/root/etc/apt/apt.conf.d/70debconf rename to Sharp.Augeas.Test/root/etc/apt/apt.conf.d/70debconf diff --git a/Sharp.Augeas/root/etc/apt/apt.conf.d/90cloud-init-pipelining b/Sharp.Augeas.Test/root/etc/apt/apt.conf.d/90cloud-init-pipelining similarity index 100% rename from Sharp.Augeas/root/etc/apt/apt.conf.d/90cloud-init-pipelining rename to Sharp.Augeas.Test/root/etc/apt/apt.conf.d/90cloud-init-pipelining diff --git a/Sharp.Augeas/root/etc/apt/sources.list b/Sharp.Augeas.Test/root/etc/apt/sources.list similarity index 100% rename from Sharp.Augeas/root/etc/apt/sources.list rename to Sharp.Augeas.Test/root/etc/apt/sources.list diff --git a/Sharp.Augeas/root/etc/ceph/ceph.conf b/Sharp.Augeas.Test/root/etc/ceph/ceph.conf similarity index 100% rename from Sharp.Augeas/root/etc/ceph/ceph.conf rename to Sharp.Augeas.Test/root/etc/ceph/ceph.conf diff --git a/Sharp.Augeas/root/etc/crontab b/Sharp.Augeas.Test/root/etc/crontab similarity index 100% rename from Sharp.Augeas/root/etc/crontab rename to Sharp.Augeas.Test/root/etc/crontab diff --git a/Sharp.Augeas/root/etc/default/im-config b/Sharp.Augeas.Test/root/etc/default/im-config similarity index 100% rename from Sharp.Augeas/root/etc/default/im-config rename to Sharp.Augeas.Test/root/etc/default/im-config diff --git a/Sharp.Augeas/root/etc/dput.cf b/Sharp.Augeas.Test/root/etc/dput.cf similarity index 100% rename from Sharp.Augeas/root/etc/dput.cf rename to Sharp.Augeas.Test/root/etc/dput.cf diff --git a/Sharp.Augeas/root/etc/exports b/Sharp.Augeas.Test/root/etc/exports similarity index 100% rename from Sharp.Augeas/root/etc/exports rename to Sharp.Augeas.Test/root/etc/exports diff --git a/Sharp.Augeas/root/etc/fstab b/Sharp.Augeas.Test/root/etc/fstab similarity index 100% rename from Sharp.Augeas/root/etc/fstab rename to Sharp.Augeas.Test/root/etc/fstab diff --git a/Sharp.Augeas/root/etc/group b/Sharp.Augeas.Test/root/etc/group similarity index 100% rename from Sharp.Augeas/root/etc/group rename to Sharp.Augeas.Test/root/etc/group diff --git a/Sharp.Augeas/root/etc/grub.conf b/Sharp.Augeas.Test/root/etc/grub.conf similarity index 100% rename from Sharp.Augeas/root/etc/grub.conf rename to Sharp.Augeas.Test/root/etc/grub.conf diff --git a/Sharp.Augeas/root/etc/gshadow b/Sharp.Augeas.Test/root/etc/gshadow similarity index 100% rename from Sharp.Augeas/root/etc/gshadow rename to Sharp.Augeas.Test/root/etc/gshadow diff --git a/Sharp.Augeas/root/etc/hosts b/Sharp.Augeas.Test/root/etc/hosts similarity index 100% rename from Sharp.Augeas/root/etc/hosts rename to Sharp.Augeas.Test/root/etc/hosts diff --git a/Sharp.Augeas/root/etc/httpd/conf.d/ssl.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.d/ssl.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.d/ssl.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.d/ssl.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/00-base.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-base.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/00-base.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-base.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/00-dav.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-dav.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/00-dav.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-dav.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/00-lua.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-lua.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/00-lua.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-lua.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/00-mpm.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-mpm.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/00-mpm.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-mpm.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/00-optional.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-optional.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/00-optional.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-optional.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/00-proxy.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-proxy.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/00-proxy.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-proxy.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/00-systemd.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-systemd.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/00-systemd.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/00-systemd.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/01-cgi.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/01-cgi.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/01-cgi.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/01-cgi.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/10-h2.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/10-h2.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/10-h2.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/10-h2.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/10-mod_dnssd.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/10-mod_dnssd.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/10-mod_dnssd.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/10-mod_dnssd.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/10-proxy_h2.conf b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/10-proxy_h2.conf similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/10-proxy_h2.conf rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/10-proxy_h2.conf diff --git a/Sharp.Augeas/root/etc/httpd/conf.modules.d/README b/Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/README similarity index 100% rename from Sharp.Augeas/root/etc/httpd/conf.modules.d/README rename to Sharp.Augeas.Test/root/etc/httpd/conf.modules.d/README diff --git a/Sharp.Augeas/root/etc/inittab b/Sharp.Augeas.Test/root/etc/inittab similarity index 100% rename from Sharp.Augeas/root/etc/inittab rename to Sharp.Augeas.Test/root/etc/inittab diff --git a/Sharp.Augeas/root/etc/kdump.conf b/Sharp.Augeas.Test/root/etc/kdump.conf similarity index 100% rename from Sharp.Augeas/root/etc/kdump.conf rename to Sharp.Augeas.Test/root/etc/kdump.conf diff --git a/Sharp.Augeas/root/etc/krb5.conf b/Sharp.Augeas.Test/root/etc/krb5.conf similarity index 100% rename from Sharp.Augeas/root/etc/krb5.conf rename to Sharp.Augeas.Test/root/etc/krb5.conf diff --git a/Sharp.Augeas/root/etc/logrotate.d/acpid b/Sharp.Augeas.Test/root/etc/logrotate.d/acpid similarity index 100% rename from Sharp.Augeas/root/etc/logrotate.d/acpid rename to Sharp.Augeas.Test/root/etc/logrotate.d/acpid diff --git a/Sharp.Augeas/root/etc/logrotate.d/rpm b/Sharp.Augeas.Test/root/etc/logrotate.d/rpm similarity index 100% rename from Sharp.Augeas/root/etc/logrotate.d/rpm rename to Sharp.Augeas.Test/root/etc/logrotate.d/rpm diff --git a/Sharp.Augeas/root/etc/modules.conf b/Sharp.Augeas.Test/root/etc/modules.conf similarity index 100% rename from Sharp.Augeas/root/etc/modules.conf rename to Sharp.Augeas.Test/root/etc/modules.conf diff --git a/Sharp.Augeas/root/etc/multipath.conf b/Sharp.Augeas.Test/root/etc/multipath.conf similarity index 100% rename from Sharp.Augeas/root/etc/multipath.conf rename to Sharp.Augeas.Test/root/etc/multipath.conf diff --git a/Sharp.Augeas/root/etc/network/interfaces b/Sharp.Augeas.Test/root/etc/network/interfaces similarity index 100% rename from Sharp.Augeas/root/etc/network/interfaces rename to Sharp.Augeas.Test/root/etc/network/interfaces diff --git a/Sharp.Augeas/root/etc/nginx/nginx.conf b/Sharp.Augeas.Test/root/etc/nginx/nginx.conf similarity index 100% rename from Sharp.Augeas/root/etc/nginx/nginx.conf rename to Sharp.Augeas.Test/root/etc/nginx/nginx.conf diff --git a/Sharp.Augeas/root/etc/nrpe.cfg b/Sharp.Augeas.Test/root/etc/nrpe.cfg similarity index 100% rename from Sharp.Augeas/root/etc/nrpe.cfg rename to Sharp.Augeas.Test/root/etc/nrpe.cfg diff --git a/Sharp.Augeas/root/etc/nslcd.conf b/Sharp.Augeas.Test/root/etc/nslcd.conf similarity index 100% rename from Sharp.Augeas/root/etc/nslcd.conf rename to Sharp.Augeas.Test/root/etc/nslcd.conf diff --git a/Sharp.Augeas/root/etc/ntp.conf b/Sharp.Augeas.Test/root/etc/ntp.conf similarity index 100% rename from Sharp.Augeas/root/etc/ntp.conf rename to Sharp.Augeas.Test/root/etc/ntp.conf diff --git a/Sharp.Augeas/root/etc/pam.d/login b/Sharp.Augeas.Test/root/etc/pam.d/login similarity index 100% rename from Sharp.Augeas/root/etc/pam.d/login rename to Sharp.Augeas.Test/root/etc/pam.d/login diff --git a/Sharp.Augeas/root/etc/pam.d/newrole b/Sharp.Augeas.Test/root/etc/pam.d/newrole similarity index 100% rename from Sharp.Augeas/root/etc/pam.d/newrole rename to Sharp.Augeas.Test/root/etc/pam.d/newrole diff --git a/Sharp.Augeas/root/etc/pam.d/postgresql b/Sharp.Augeas.Test/root/etc/pam.d/postgresql similarity index 100% rename from Sharp.Augeas/root/etc/pam.d/postgresql rename to Sharp.Augeas.Test/root/etc/pam.d/postgresql diff --git a/Sharp.Augeas/root/etc/passwd b/Sharp.Augeas.Test/root/etc/passwd similarity index 100% rename from Sharp.Augeas/root/etc/passwd rename to Sharp.Augeas.Test/root/etc/passwd diff --git a/Sharp.Augeas/root/etc/php.ini b/Sharp.Augeas.Test/root/etc/php.ini similarity index 100% rename from Sharp.Augeas/root/etc/php.ini rename to Sharp.Augeas.Test/root/etc/php.ini diff --git a/Sharp.Augeas/root/etc/puppet/puppet.conf b/Sharp.Augeas.Test/root/etc/puppet/puppet.conf similarity index 100% rename from Sharp.Augeas/root/etc/puppet/puppet.conf rename to Sharp.Augeas.Test/root/etc/puppet/puppet.conf diff --git a/Sharp.Augeas/root/etc/resolv.conf b/Sharp.Augeas.Test/root/etc/resolv.conf similarity index 100% rename from Sharp.Augeas/root/etc/resolv.conf rename to Sharp.Augeas.Test/root/etc/resolv.conf diff --git a/Sharp.Augeas/root/etc/samba/smb.conf b/Sharp.Augeas.Test/root/etc/samba/smb.conf similarity index 100% rename from Sharp.Augeas/root/etc/samba/smb.conf rename to Sharp.Augeas.Test/root/etc/samba/smb.conf diff --git a/Sharp.Augeas/root/etc/security/limits.conf b/Sharp.Augeas.Test/root/etc/security/limits.conf similarity index 100% rename from Sharp.Augeas/root/etc/security/limits.conf rename to Sharp.Augeas.Test/root/etc/security/limits.conf diff --git a/Sharp.Augeas/root/etc/selinux/semanage.conf b/Sharp.Augeas.Test/root/etc/selinux/semanage.conf similarity index 100% rename from Sharp.Augeas/root/etc/selinux/semanage.conf rename to Sharp.Augeas.Test/root/etc/selinux/semanage.conf diff --git a/Sharp.Augeas/root/etc/services b/Sharp.Augeas.Test/root/etc/services similarity index 100% rename from Sharp.Augeas/root/etc/services rename to Sharp.Augeas.Test/root/etc/services diff --git a/Sharp.Augeas/root/etc/shadow b/Sharp.Augeas.Test/root/etc/shadow similarity index 100% rename from Sharp.Augeas/root/etc/shadow rename to Sharp.Augeas.Test/root/etc/shadow diff --git a/Sharp.Augeas/root/etc/squid/squid.conf b/Sharp.Augeas.Test/root/etc/squid/squid.conf similarity index 100% rename from Sharp.Augeas/root/etc/squid/squid.conf rename to Sharp.Augeas.Test/root/etc/squid/squid.conf diff --git a/Sharp.Augeas/root/etc/ssh/ssh_config b/Sharp.Augeas.Test/root/etc/ssh/ssh_config similarity index 100% rename from Sharp.Augeas/root/etc/ssh/ssh_config rename to Sharp.Augeas.Test/root/etc/ssh/ssh_config diff --git a/Sharp.Augeas/root/etc/ssh/sshd_config b/Sharp.Augeas.Test/root/etc/ssh/sshd_config similarity index 100% rename from Sharp.Augeas/root/etc/ssh/sshd_config rename to Sharp.Augeas.Test/root/etc/ssh/sshd_config diff --git a/Sharp.Augeas/root/etc/sudoers b/Sharp.Augeas.Test/root/etc/sudoers similarity index 100% rename from Sharp.Augeas/root/etc/sudoers rename to Sharp.Augeas.Test/root/etc/sudoers diff --git a/Sharp.Augeas/root/etc/sysconfig/anaconda b/Sharp.Augeas.Test/root/etc/sysconfig/anaconda similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/anaconda rename to Sharp.Augeas.Test/root/etc/sysconfig/anaconda diff --git a/Sharp.Augeas/root/etc/sysconfig/atd b/Sharp.Augeas.Test/root/etc/sysconfig/atd similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/atd rename to Sharp.Augeas.Test/root/etc/sysconfig/atd diff --git a/Sharp.Augeas/root/etc/sysconfig/authconfig b/Sharp.Augeas.Test/root/etc/sysconfig/authconfig similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/authconfig rename to Sharp.Augeas.Test/root/etc/sysconfig/authconfig diff --git a/Sharp.Augeas/root/etc/sysconfig/autofs b/Sharp.Augeas.Test/root/etc/sysconfig/autofs similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/autofs rename to Sharp.Augeas.Test/root/etc/sysconfig/autofs diff --git a/Sharp.Augeas/root/etc/sysconfig/clock b/Sharp.Augeas.Test/root/etc/sysconfig/clock similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/clock rename to Sharp.Augeas.Test/root/etc/sysconfig/clock diff --git a/Sharp.Augeas/root/etc/sysconfig/cpuspeed b/Sharp.Augeas.Test/root/etc/sysconfig/cpuspeed similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/cpuspeed rename to Sharp.Augeas.Test/root/etc/sysconfig/cpuspeed diff --git a/Sharp.Augeas/root/etc/sysconfig/crond b/Sharp.Augeas.Test/root/etc/sysconfig/crond similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/crond rename to Sharp.Augeas.Test/root/etc/sysconfig/crond diff --git a/Sharp.Augeas/root/etc/sysconfig/crontab b/Sharp.Augeas.Test/root/etc/sysconfig/crontab similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/crontab rename to Sharp.Augeas.Test/root/etc/sysconfig/crontab diff --git a/Sharp.Augeas/root/etc/sysconfig/firstboot b/Sharp.Augeas.Test/root/etc/sysconfig/firstboot similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/firstboot rename to Sharp.Augeas.Test/root/etc/sysconfig/firstboot diff --git a/Sharp.Augeas/root/etc/sysconfig/grub b/Sharp.Augeas.Test/root/etc/sysconfig/grub similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/grub rename to Sharp.Augeas.Test/root/etc/sysconfig/grub diff --git a/Sharp.Augeas/root/etc/sysconfig/hsqldb b/Sharp.Augeas.Test/root/etc/sysconfig/hsqldb similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/hsqldb rename to Sharp.Augeas.Test/root/etc/sysconfig/hsqldb diff --git a/Sharp.Augeas/root/etc/sysconfig/httpd b/Sharp.Augeas.Test/root/etc/sysconfig/httpd similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/httpd rename to Sharp.Augeas.Test/root/etc/sysconfig/httpd diff --git a/Sharp.Augeas/root/etc/sysconfig/hw-uuid b/Sharp.Augeas.Test/root/etc/sysconfig/hw-uuid similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/hw-uuid rename to Sharp.Augeas.Test/root/etc/sysconfig/hw-uuid diff --git a/Sharp.Augeas/root/etc/sysconfig/hwconf b/Sharp.Augeas.Test/root/etc/sysconfig/hwconf similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/hwconf rename to Sharp.Augeas.Test/root/etc/sysconfig/hwconf diff --git a/Sharp.Augeas/root/etc/sysconfig/i18n b/Sharp.Augeas.Test/root/etc/sysconfig/i18n similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/i18n rename to Sharp.Augeas.Test/root/etc/sysconfig/i18n diff --git a/Sharp.Augeas/root/etc/sysconfig/init b/Sharp.Augeas.Test/root/etc/sysconfig/init similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/init rename to Sharp.Augeas.Test/root/etc/sysconfig/init diff --git a/Sharp.Augeas/root/etc/sysconfig/iptables b/Sharp.Augeas.Test/root/etc/sysconfig/iptables similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/iptables rename to Sharp.Augeas.Test/root/etc/sysconfig/iptables diff --git a/Sharp.Augeas/root/etc/sysconfig/iptables-config b/Sharp.Augeas.Test/root/etc/sysconfig/iptables-config similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/iptables-config rename to Sharp.Augeas.Test/root/etc/sysconfig/iptables-config diff --git a/Sharp.Augeas/root/etc/sysconfig/irda b/Sharp.Augeas.Test/root/etc/sysconfig/irda similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/irda rename to Sharp.Augeas.Test/root/etc/sysconfig/irda diff --git a/Sharp.Augeas/root/etc/sysconfig/irqbalance b/Sharp.Augeas.Test/root/etc/sysconfig/irqbalance similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/irqbalance rename to Sharp.Augeas.Test/root/etc/sysconfig/irqbalance diff --git a/Sharp.Augeas/root/etc/sysconfig/kdump b/Sharp.Augeas.Test/root/etc/sysconfig/kdump similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/kdump rename to Sharp.Augeas.Test/root/etc/sysconfig/kdump diff --git a/Sharp.Augeas/root/etc/sysconfig/kernel b/Sharp.Augeas.Test/root/etc/sysconfig/kernel similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/kernel rename to Sharp.Augeas.Test/root/etc/sysconfig/kernel diff --git a/Sharp.Augeas/root/etc/sysconfig/keyboard b/Sharp.Augeas.Test/root/etc/sysconfig/keyboard similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/keyboard rename to Sharp.Augeas.Test/root/etc/sysconfig/keyboard diff --git a/Sharp.Augeas/root/etc/sysconfig/kudzu b/Sharp.Augeas.Test/root/etc/sysconfig/kudzu similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/kudzu rename to Sharp.Augeas.Test/root/etc/sysconfig/kudzu diff --git a/Sharp.Augeas/root/etc/sysconfig/libvirtd b/Sharp.Augeas.Test/root/etc/sysconfig/libvirtd similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/libvirtd rename to Sharp.Augeas.Test/root/etc/sysconfig/libvirtd diff --git a/Sharp.Augeas/root/etc/sysconfig/lircd b/Sharp.Augeas.Test/root/etc/sysconfig/lircd similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/lircd rename to Sharp.Augeas.Test/root/etc/sysconfig/lircd diff --git a/Sharp.Augeas/root/etc/sysconfig/lm_sensors b/Sharp.Augeas.Test/root/etc/sysconfig/lm_sensors similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/lm_sensors rename to Sharp.Augeas.Test/root/etc/sysconfig/lm_sensors diff --git a/Sharp.Augeas/root/etc/sysconfig/nasd b/Sharp.Augeas.Test/root/etc/sysconfig/nasd similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/nasd rename to Sharp.Augeas.Test/root/etc/sysconfig/nasd diff --git a/Sharp.Augeas/root/etc/sysconfig/netconsole b/Sharp.Augeas.Test/root/etc/sysconfig/netconsole similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/netconsole rename to Sharp.Augeas.Test/root/etc/sysconfig/netconsole diff --git a/Sharp.Augeas/root/etc/sysconfig/netdump_id_dsa.pub b/Sharp.Augeas.Test/root/etc/sysconfig/netdump_id_dsa.pub similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/netdump_id_dsa.pub rename to Sharp.Augeas.Test/root/etc/sysconfig/netdump_id_dsa.pub diff --git a/Sharp.Augeas/root/etc/sysconfig/network b/Sharp.Augeas.Test/root/etc/sysconfig/network similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/network rename to Sharp.Augeas.Test/root/etc/sysconfig/network diff --git a/Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-br0 b/Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-br0 similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-br0 rename to Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-br0 diff --git a/Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-eth0 b/Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-eth0 similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-eth0 rename to Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-eth0 diff --git a/Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-lo b/Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-lo similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-lo rename to Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-lo diff --git a/Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-lo.rpmsave b/Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-lo.rpmsave similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-lo.rpmsave rename to Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-lo.rpmsave diff --git a/Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-weird [!] (used to fail) b/Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-weird [!] (used to fail) similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-weird [!] (used to fail) rename to Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-weird [!] (used to fail) diff --git a/Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-wlan0 b/Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-wlan0 similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/network-scripts/ifcfg-wlan0 rename to Sharp.Augeas.Test/root/etc/sysconfig/network-scripts/ifcfg-wlan0 diff --git a/Sharp.Augeas/root/etc/sysconfig/nfs b/Sharp.Augeas.Test/root/etc/sysconfig/nfs similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/nfs rename to Sharp.Augeas.Test/root/etc/sysconfig/nfs diff --git a/Sharp.Augeas/root/etc/sysconfig/ntpd b/Sharp.Augeas.Test/root/etc/sysconfig/ntpd similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/ntpd rename to Sharp.Augeas.Test/root/etc/sysconfig/ntpd diff --git a/Sharp.Augeas/root/etc/sysconfig/prelink b/Sharp.Augeas.Test/root/etc/sysconfig/prelink similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/prelink rename to Sharp.Augeas.Test/root/etc/sysconfig/prelink diff --git a/Sharp.Augeas/root/etc/sysconfig/puppet b/Sharp.Augeas.Test/root/etc/sysconfig/puppet similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/puppet rename to Sharp.Augeas.Test/root/etc/sysconfig/puppet diff --git a/Sharp.Augeas/root/etc/sysconfig/readonly-root b/Sharp.Augeas.Test/root/etc/sysconfig/readonly-root similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/readonly-root rename to Sharp.Augeas.Test/root/etc/sysconfig/readonly-root diff --git a/Sharp.Augeas/root/etc/sysconfig/rsyslog b/Sharp.Augeas.Test/root/etc/sysconfig/rsyslog similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/rsyslog rename to Sharp.Augeas.Test/root/etc/sysconfig/rsyslog diff --git a/Sharp.Augeas/root/etc/sysconfig/samba b/Sharp.Augeas.Test/root/etc/sysconfig/samba similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/samba rename to Sharp.Augeas.Test/root/etc/sysconfig/samba diff --git a/Sharp.Augeas/root/etc/sysconfig/saslauthd b/Sharp.Augeas.Test/root/etc/sysconfig/saslauthd similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/saslauthd rename to Sharp.Augeas.Test/root/etc/sysconfig/saslauthd diff --git a/Sharp.Augeas/root/etc/sysconfig/smartmontools b/Sharp.Augeas.Test/root/etc/sysconfig/smartmontools similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/smartmontools rename to Sharp.Augeas.Test/root/etc/sysconfig/smartmontools diff --git a/Sharp.Augeas/root/etc/sysconfig/spamassassin b/Sharp.Augeas.Test/root/etc/sysconfig/spamassassin similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/spamassassin rename to Sharp.Augeas.Test/root/etc/sysconfig/spamassassin diff --git a/Sharp.Augeas/root/etc/sysconfig/sysstat b/Sharp.Augeas.Test/root/etc/sysconfig/sysstat similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/sysstat rename to Sharp.Augeas.Test/root/etc/sysconfig/sysstat diff --git a/Sharp.Augeas/root/etc/sysconfig/sysstat.ioconf b/Sharp.Augeas.Test/root/etc/sysconfig/sysstat.ioconf similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/sysstat.ioconf rename to Sharp.Augeas.Test/root/etc/sysconfig/sysstat.ioconf diff --git a/Sharp.Augeas/root/etc/sysconfig/system-config-firewall b/Sharp.Augeas.Test/root/etc/sysconfig/system-config-firewall similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/system-config-firewall rename to Sharp.Augeas.Test/root/etc/sysconfig/system-config-firewall diff --git a/Sharp.Augeas/root/etc/sysconfig/system-config-securitylevel b/Sharp.Augeas.Test/root/etc/sysconfig/system-config-securitylevel similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/system-config-securitylevel rename to Sharp.Augeas.Test/root/etc/sysconfig/system-config-securitylevel diff --git a/Sharp.Augeas/root/etc/sysconfig/system-config-users b/Sharp.Augeas.Test/root/etc/sysconfig/system-config-users similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/system-config-users rename to Sharp.Augeas.Test/root/etc/sysconfig/system-config-users diff --git a/Sharp.Augeas/root/etc/sysconfig/vncservers b/Sharp.Augeas.Test/root/etc/sysconfig/vncservers similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/vncservers rename to Sharp.Augeas.Test/root/etc/sysconfig/vncservers diff --git a/Sharp.Augeas/root/etc/sysconfig/wpa_supplicant b/Sharp.Augeas.Test/root/etc/sysconfig/wpa_supplicant similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/wpa_supplicant rename to Sharp.Augeas.Test/root/etc/sysconfig/wpa_supplicant diff --git a/Sharp.Augeas/root/etc/sysconfig/xend b/Sharp.Augeas.Test/root/etc/sysconfig/xend similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/xend rename to Sharp.Augeas.Test/root/etc/sysconfig/xend diff --git a/Sharp.Augeas/root/etc/sysconfig/xendomains b/Sharp.Augeas.Test/root/etc/sysconfig/xendomains similarity index 100% rename from Sharp.Augeas/root/etc/sysconfig/xendomains rename to Sharp.Augeas.Test/root/etc/sysconfig/xendomains diff --git a/Sharp.Augeas/root/etc/sysctl.conf b/Sharp.Augeas.Test/root/etc/sysctl.conf similarity index 100% rename from Sharp.Augeas/root/etc/sysctl.conf rename to Sharp.Augeas.Test/root/etc/sysctl.conf diff --git a/Sharp.Augeas/root/etc/syslog.conf b/Sharp.Augeas.Test/root/etc/syslog.conf similarity index 100% rename from Sharp.Augeas/root/etc/syslog.conf rename to Sharp.Augeas.Test/root/etc/syslog.conf diff --git a/Sharp.Augeas/root/etc/vsftpd.conf b/Sharp.Augeas.Test/root/etc/vsftpd.conf similarity index 100% rename from Sharp.Augeas/root/etc/vsftpd.conf rename to Sharp.Augeas.Test/root/etc/vsftpd.conf diff --git a/Sharp.Augeas/root/etc/xinetd.conf b/Sharp.Augeas.Test/root/etc/xinetd.conf similarity index 100% rename from Sharp.Augeas/root/etc/xinetd.conf rename to Sharp.Augeas.Test/root/etc/xinetd.conf diff --git a/Sharp.Augeas/root/etc/xinetd.d/cvs b/Sharp.Augeas.Test/root/etc/xinetd.d/cvs similarity index 100% rename from Sharp.Augeas/root/etc/xinetd.d/cvs rename to Sharp.Augeas.Test/root/etc/xinetd.d/cvs diff --git a/Sharp.Augeas/root/etc/xinetd.d/rsync b/Sharp.Augeas.Test/root/etc/xinetd.d/rsync similarity index 100% rename from Sharp.Augeas/root/etc/xinetd.d/rsync rename to Sharp.Augeas.Test/root/etc/xinetd.d/rsync diff --git a/Sharp.Augeas/root/etc/yum.conf b/Sharp.Augeas.Test/root/etc/yum.conf similarity index 100% rename from Sharp.Augeas/root/etc/yum.conf rename to Sharp.Augeas.Test/root/etc/yum.conf diff --git a/Sharp.Augeas/root/etc/yum.repos.d/fedora-updates.repo b/Sharp.Augeas.Test/root/etc/yum.repos.d/fedora-updates.repo similarity index 100% rename from Sharp.Augeas/root/etc/yum.repos.d/fedora-updates.repo rename to Sharp.Augeas.Test/root/etc/yum.repos.d/fedora-updates.repo diff --git a/Sharp.Augeas/root/etc/yum.repos.d/fedora.repo b/Sharp.Augeas.Test/root/etc/yum.repos.d/fedora.repo similarity index 100% rename from Sharp.Augeas/root/etc/yum.repos.d/fedora.repo rename to Sharp.Augeas.Test/root/etc/yum.repos.d/fedora.repo diff --git a/Sharp.Augeas/root/etc/yum.repos.d/remi.repo b/Sharp.Augeas.Test/root/etc/yum.repos.d/remi.repo similarity index 100% rename from Sharp.Augeas/root/etc/yum.repos.d/remi.repo rename to Sharp.Augeas.Test/root/etc/yum.repos.d/remi.repo diff --git a/Sharp.Augeas/root/pairs.txt b/Sharp.Augeas.Test/root/pairs.txt similarity index 100% rename from Sharp.Augeas/root/pairs.txt rename to Sharp.Augeas.Test/root/pairs.txt diff --git a/Sharp.Augeas/root/var/spool/cron/root b/Sharp.Augeas.Test/root/var/spool/cron/root similarity index 100% rename from Sharp.Augeas/root/var/spool/cron/root rename to Sharp.Augeas.Test/root/var/spool/cron/root diff --git a/Sharp.Augeas.sln b/Sharp.Augeas.sln index 336a1f2..65f024a 100644 --- a/Sharp.Augeas.sln +++ b/Sharp.Augeas.sln @@ -2,6 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharp.Augeas", "Sharp.Augeas\Sharp.Augeas.csproj", "{EF5B5D3E-325C-4C43-AFF7-851873E76B46}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharp.Augeas.Test", "Sharp.Augeas.Test\Sharp.Augeas.Test.csproj", "{64051CE5-219E-41A7-A3D0-091693464EBE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +14,9 @@ Global {EF5B5D3E-325C-4C43-AFF7-851873E76B46}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF5B5D3E-325C-4C43-AFF7-851873E76B46}.Release|Any CPU.ActiveCfg = Release|Any CPU {EF5B5D3E-325C-4C43-AFF7-851873E76B46}.Release|Any CPU.Build.0 = Release|Any CPU + {64051CE5-219E-41A7-A3D0-091693464EBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64051CE5-219E-41A7-A3D0-091693464EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64051CE5-219E-41A7-A3D0-091693464EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64051CE5-219E-41A7-A3D0-091693464EBE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Sharp.Augeas/.dockerignore b/Sharp.Augeas/.dockerignore deleted file mode 100644 index 38bece4..0000000 --- a/Sharp.Augeas/.dockerignore +++ /dev/null @@ -1,25 +0,0 @@ -**/.dockerignore -**/.env -**/.git -**/.gitignore -**/.project -**/.settings -**/.toolstarget -**/.vs -**/.vscode -**/.idea -**/*.*proj.user -**/*.dbmdl -**/*.jfm -**/azds.yaml -**/bin -**/charts -**/docker-compose* -**/Dockerfile* -**/node_modules -**/npm-debug.log -**/obj -**/secrets.dev.yaml -**/values.dev.yaml -LICENSE -README.md \ No newline at end of file diff --git a/Sharp.Augeas/Augeas.cs b/Sharp.Augeas/Augeas.cs index d476bbf..2b2b5ba 100644 --- a/Sharp.Augeas/Augeas.cs +++ b/Sharp.Augeas/Augeas.cs @@ -1,7 +1,4 @@ -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; -using Sharp.Augeas.Test; +using System.Runtime.InteropServices;using Sharp.Augeas.Test; using static Sharp.Augeas.AugeasExtern; using static Sharp.Augeas.AugFlags; @@ -11,11 +8,11 @@ namespace Sharp.Augeas /// Augeas Core containing the settings of this instance. /// We can have multiple augeas cores during the execution. /// - public unsafe partial class Augeas + public sealed class Augeas { private readonly IntPtr _augeas; - private HashSet _loadedFiles = new HashSet(); + private HashSet _loadedFiles = new(); #region Constructor / Destructor @@ -40,6 +37,31 @@ namespace Sharp.Augeas } } + /// + /// Constructor that reads AUG_LENS_PATH. + /// + /// + /// AUG_LENS_PATH environment variable is not set with the augeas lens path. + public Augeas(string root) + { + var lensPath = Environment.GetEnvironmentVariable("AUG_LENS_PATH"); + + if (string.IsNullOrEmpty(lensPath)) + { + throw new InvalidOperationException( + "Can't use root only ctor without a valid AUG_LENS_PATH environment variable."); + } + + var augSettings = new AugSettings(root, lensPath); + + _augeas = init_aug(augSettings, NO_STDINC | NO_LOAD); + + if (_augeas == IntPtr.Zero) + { + throw new InvalidOperationException("Augeas is not a valid instance."); + } + } + #endregion @@ -92,7 +114,7 @@ namespace Sharp.Augeas /// /// /// - public void PrintAugTree(string matchPath) + private void PrintTree(string matchPath) { print_tree(_augeas, matchPath); } @@ -103,7 +125,7 @@ namespace Sharp.Augeas /// /// configuration path. /// Dictionary with the Tree - public Dictionary GetTree(string matchPath) + private Dictionary GetTree(string matchPath) { var result = new Dictionary(); var raw = get_tree(_augeas, matchPath); @@ -123,10 +145,31 @@ namespace Sharp.Augeas return result; } - #endregion + + public void PrintVirtualHostTree(string apacheSitePath) + { + LoadFile(apacheSitePath); + string virtualHostTree = $"/files{apacheSitePath}/VirtualHost/*"; + PrintTree(virtualHostTree); + } - + public Dictionary GetVirtualHostTree(string apacheSitePath) + { + LoadFile(apacheSitePath); + string virtualHostTree = $"/files{apacheSitePath}/VirtualHost/*"; + return GetTree(virtualHostTree); + } + + + void PrintVirtualHostProxyTree(string configFilePath) + { + LoadFile(configFilePath); + string virtualHostProxyMatchPath = $"/files{configFilePath}/VirtualHost/Proxy/*"; + PrintTree(virtualHostProxyMatchPath); + } + + } } diff --git a/Sharp.Augeas/AugeasExtern.cs b/Sharp.Augeas/AugeasExtern.cs index 17a1ad9..8904bce 100644 --- a/Sharp.Augeas/AugeasExtern.cs +++ b/Sharp.Augeas/AugeasExtern.cs @@ -36,7 +36,7 @@ namespace Sharp.Augeas [DllImport(_libName)] public static extern IntPtr get_node(IntPtr augeas, [MarshalAs(UnmanagedType.LPStr)] string matchPath); - [DllImport(_libName)] - public static extern bool load_file(IntPtr augeas, [MarshalAs(UnmanagedType.LPStr)] string filePath); + [DllImport(_libName)] public static extern bool load_file(IntPtr augeas, [MarshalAs(UnmanagedType.LPStr)] string filePath); + } } \ No newline at end of file diff --git a/Sharp.Augeas/Platform/Linux/libclAugeas.so b/Sharp.Augeas/Platform/Linux/libclAugeas.so new file mode 100644 index 0000000000000000000000000000000000000000..6903728a71a84b450f82cc63c3e38c903c029f67 GIT binary patch literal 209256 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%0D{Q{3mB){&g`Wfc?9 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 literal 0 HcmV?d00001 diff --git a/Sharp.Augeas/Program.cs b/Sharp.Augeas/Program.cs deleted file mode 100644 index 9569977..0000000 --- a/Sharp.Augeas/Program.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Runtime.InteropServices; -using Sharp.Augeas; -using Sharp.Augeas.Test; - -var path = Environment.CurrentDirectory; -var root = $"{path}/root/"; - -var lensPath = ""; - -if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) -{ - lensPath = "/usr/share/augeas/lenses/dist"; -} -if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) -{ - lensPath = "/opt/homebrew/share/augeas/lenses/dist"; -} - -AugSettings augSettings = new AugSettings(root, lensPath); - -var augeas = new Augeas(augSettings); - -var virtualHostConfig = "/etc/apache2/sites-available/00-ci.codeliturgy.com.conf"; - -augeas.LoadFile(virtualHostConfig); - -void PrintVirtualHostTree(string configFilePath) -{ - string virtualHostTree = $"/files{configFilePath}/VirtualHost/*"; - augeas.PrintAugTree(virtualHostTree); -} - -void PrintVirtualHostProxyTree(string configFilePath) -{ - string virtualHostProxyMatchPath = $"/files{configFilePath}/VirtualHost/Proxy/*"; - augeas.PrintAugTree(virtualHostProxyMatchPath); -} - -PrintVirtualHostTree(virtualHostConfig); - - - - diff --git a/Sharp.Augeas/Sharp.Augeas.csproj b/Sharp.Augeas/Sharp.Augeas.csproj index e43a7c7..9676111 100644 --- a/Sharp.Augeas/Sharp.Augeas.csproj +++ b/Sharp.Augeas/Sharp.Augeas.csproj @@ -1,7 +1,6 @@ - Exe net6.0 enable disable diff --git a/Sharp.Augeas/VirtualHost/ApacheConfigExtensions.cs b/Sharp.Augeas/VirtualHost/ApacheConfigExtensions.cs new file mode 100644 index 0000000..76e6819 --- /dev/null +++ b/Sharp.Augeas/VirtualHost/ApacheConfigExtensions.cs @@ -0,0 +1,6 @@ +namespace Sharp.Augeas; + +public static class ApacheConfigExtensions +{ + +} \ No newline at end of file