]> git.openstreetmap.org Git - chef.git/commitdiff
Disable unreliable DNSSEC in test-kitchen master
authorGrant Slater <github@firefishy.com>
Sat, 11 May 2024 00:05:12 +0000 (01:05 +0100)
committerGrant Slater <github@firefishy.com>
Sat, 11 May 2024 00:05:12 +0000 (01:05 +0100)
1303 files changed:
.github/dependabot.yml [new file with mode: 0644]
.github/workflows/cookstyle.yml [new file with mode: 0644]
.github/workflows/test-kitchen.yml [new file with mode: 0644]
.gitignore
.kitchen.provision.rb [deleted file]
.kitchen.yml
.mailmap
.rubocop.yml
.rubocop_todo.yml
.ruby-version
.travis.yml [deleted file]
CONTRIBUTING.md
Dockerfile
Gemfile
Gemfile.lock
README.md
cookbooks/accounts/attributes/default.rb
cookbooks/accounts/files/default/contrapunctus/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/dmlu/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/gmoncrieff/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/grant/.selected_editor [new file with mode: 0644]
cookbooks/accounts/files/default/grant/.ssh/authorized_keys
cookbooks/accounts/files/default/jeslop/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/ligfietser/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/matt/.ssh/authorized_keys
cookbooks/accounts/files/default/mikel/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/milliams/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/msbarry/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/pnorman/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/rtnf/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/files/default/tomh/.zshrc
cookbooks/accounts/files/default/zander/.ssh/authorized_keys [new file with mode: 0644]
cookbooks/accounts/recipes/default.rb
cookbooks/apache/attributes/default.rb
cookbooks/apache/metadata.rb
cookbooks/apache/recipes/default.rb
cookbooks/apache/resources/conf.rb
cookbooks/apache/resources/module.rb
cookbooks/apache/resources/site.rb
cookbooks/apache/templates/default/apache.prom.erb [new file with mode: 0644]
cookbooks/apache/templates/default/brotli.conf.erb [new file with mode: 0644]
cookbooks/apache/templates/default/deflate.conf.erb
cookbooks/apache/templates/default/evasive.conf.erb [new file with mode: 0644]
cookbooks/apache/templates/default/httpd.conf.erb
cookbooks/apache/templates/default/info.conf.erb
cookbooks/apache/templates/default/ssl.erb
cookbooks/apache/templates/default/status.conf.erb
cookbooks/apt/attributes/default.rb
cookbooks/apt/recipes/default.rb
cookbooks/apt/recipes/docker.rb [new file with mode: 0644]
cookbooks/apt/recipes/elasticsearch6.rb [new file with mode: 0644]
cookbooks/apt/recipes/elasticsearch7.rb [new file with mode: 0644]
cookbooks/apt/recipes/elasticsearch8.rb [new file with mode: 0644]
cookbooks/apt/recipes/grafana.rb [new file with mode: 0644]
cookbooks/apt/recipes/hwraid.rb [new file with mode: 0644]
cookbooks/apt/recipes/management-component-pack.rb [new file with mode: 0644]
cookbooks/apt/recipes/maxmind.rb [new file with mode: 0644]
cookbooks/apt/recipes/nginx.rb [new file with mode: 0644]
cookbooks/apt/recipes/nodesource.rb [new file with mode: 0644]
cookbooks/apt/recipes/passenger.rb [new file with mode: 0644]
cookbooks/apt/recipes/postgresql.rb [new file with mode: 0644]
cookbooks/apt/recipes/yarn.rb [new file with mode: 0644]
cookbooks/apt/templates/default/apt.conf.erb
cookbooks/apt/templates/default/preferences.erb [deleted file]
cookbooks/apt/templates/default/sources.list.erb
cookbooks/awscli/README.md [new file with mode: 0644]
cookbooks/awscli/attributes/default.rb [new file with mode: 0644]
cookbooks/awscli/metadata.rb [moved from cookbooks/cgiirc/metadata.rb with 63% similarity]
cookbooks/awscli/recipes/default.rb [new file with mode: 0644]
cookbooks/backup/attributes/default.rb
cookbooks/backup/files/default/expire-backups
cookbooks/backup/metadata.rb
cookbooks/backup/recipes/default.rb
cookbooks/backup/templates/default/expire.cron.erb
cookbooks/bind/attributes/default.rb [deleted file]
cookbooks/bind/recipes/default.rb
cookbooks/bind/templates/default/db.10.erb
cookbooks/bind/templates/default/named.options.erb
cookbooks/blog/recipes/birthday.rb [new file with mode: 0644]
cookbooks/blog/recipes/default.rb
cookbooks/blog/recipes/staging.rb [new file with mode: 0644]
cookbooks/blog/templates/default/backup-birthday20.cron.erb [new file with mode: 0644]
cookbooks/blog/templates/default/backup-staging.cron.erb [new file with mode: 0644]
cookbooks/blog/templates/default/backup.cron.erb
cookbooks/blog/templates/default/opengeodata.erb [deleted file]
cookbooks/blogs/metadata.rb
cookbooks/blogs/recipes/default.rb
cookbooks/blogs/templates/default/apache.erb
cookbooks/blogs/templates/default/backup.cron.erb [new file with mode: 0644]
cookbooks/blogs/templates/default/blogs-update.erb [new file with mode: 0644]
cookbooks/blogs/templates/default/cron.erb [deleted file]
cookbooks/cgiirc/README.md [deleted file]
cookbooks/cgiirc/templates/default/apache.erb [deleted file]
cookbooks/cgiirc/templates/default/cgiirc.config.erb [deleted file]
cookbooks/cgiirc/templates/default/ipaccess.erb [deleted file]
cookbooks/chef/attributes/default.rb
cookbooks/chef/libraries/cpu.rb [new file with mode: 0644]
cookbooks/chef/libraries/edit_file.rb
cookbooks/chef/libraries/git.rb [new file with mode: 0644]
cookbooks/chef/libraries/persistent_token.rb [new file with mode: 0644]
cookbooks/chef/libraries/random_password.rb [deleted file]
cookbooks/chef/libraries/subversion.rb
cookbooks/chef/metadata.rb
cookbooks/chef/recipes/default.rb
cookbooks/chef/recipes/knife.rb [new file with mode: 0644]
cookbooks/chef/recipes/repository.rb
cookbooks/chef/recipes/server.rb
cookbooks/chef/templates/default/apache.erb
cookbooks/chef/templates/default/chef-client.conf.erb [deleted file]
cookbooks/chef/templates/default/client.rb.erb
cookbooks/chef/templates/default/post-receive.erb
cookbooks/chef/templates/default/report.rb.erb
cookbooks/chef/templates/default/server-backup.cron.erb
cookbooks/chef/templates/default/verisign.pem.erb [deleted file]
cookbooks/civicrm/README.md
cookbooks/civicrm/attributes/default.rb
cookbooks/civicrm/recipes/default.rb
cookbooks/civicrm/templates/default/apache.erb [new file with mode: 0644]
cookbooks/civicrm/templates/default/backup.cron.erb
cookbooks/civicrm/templates/default/cron.erb [deleted file]
cookbooks/clamav/metadata.rb
cookbooks/clamav/recipes/default.rb
cookbooks/community/README.md [new file with mode: 0644]
cookbooks/community/attributes/default.rb [new file with mode: 0644]
cookbooks/community/metadata.rb [new file with mode: 0644]
cookbooks/community/recipes/default.rb [new file with mode: 0644]
cookbooks/community/templates/default/backup.cron.erb [new file with mode: 0644]
cookbooks/community/templates/default/data.yml.erb [new file with mode: 0644]
cookbooks/community/templates/default/mail-receiver.yml.erb [new file with mode: 0644]
cookbooks/community/templates/default/update-feeds.atom.erb [new file with mode: 0644]
cookbooks/community/templates/default/web_only.yml.erb [new file with mode: 0644]
cookbooks/db/attributes/default.rb [new file with mode: 0644]
cookbooks/db/files/default/monthly-reindex.sql [new file with mode: 0644]
cookbooks/db/files/default/yearly-reindex.sql [new file with mode: 0644]
cookbooks/db/metadata.rb
cookbooks/db/recipes/backup.rb
cookbooks/db/recipes/base.rb
cookbooks/db/recipes/master.rb
cookbooks/db/recipes/slave.rb
cookbooks/db/templates/default/backup-db.erb
cookbooks/db/templates/default/backup.cron.erb [deleted file]
cookbooks/db/templates/default/sql_rails.yml.erb [new file with mode: 0644]
cookbooks/db/templates/default/wal-e.erb
cookbooks/db/templates/default/wal-g.erb [new file with mode: 0644]
cookbooks/dev/files/default/ooc/index.html
cookbooks/dev/metadata.rb
cookbooks/dev/recipes/default.rb
cookbooks/dev/templates/default/apache.apis.erb
cookbooks/dev/templates/default/apache.dev.erb
cookbooks/dev/templates/default/apache.ooc.erb
cookbooks/dev/templates/default/apache.phppgadmin.erb
cookbooks/dev/templates/default/apache.rails.erb
cookbooks/dev/templates/default/apache.user.erb
cookbooks/dev/templates/default/cgimap.environment.erb
cookbooks/dev/templates/default/dev.html.erb
cookbooks/dev/templates/default/fpm-default.conf.erb [deleted file]
cookbooks/dev/templates/default/fpm.conf.erb [deleted file]
cookbooks/dev/templates/default/rails.environment.erb [new file with mode: 0644]
cookbooks/dev/templates/default/rails.setup.rb.erb
cookbooks/dev/templates/default/user-slice.conf.erb [new file with mode: 0644]
cookbooks/devices/recipes/default.rb
cookbooks/devices/templates/default/nvme.conf.erb [moved from cookbooks/munin/templates/default/ipmi.erb with 67% similarity]
cookbooks/devices/templates/default/udev.rules.erb
cookbooks/dhcpd/metadata.rb
cookbooks/dhcpd/recipes/default.rb
cookbooks/dhcpd/templates/default/default.erb [new file with mode: 0644]
cookbooks/dhcpd/templates/default/dhcpd.conf.erb
cookbooks/dmca/files/default/html/HTML/Common.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/DHTMLRulesTableless.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/PageDHTMLRulesTableless.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Array.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ArraySmarty.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Default.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ITDynamic.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ITStatic.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Object.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ObjectFlexy.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/QuickHtml.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Tableless.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Rule.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Callback.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Compare.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Email.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Range.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Regex.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Required.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/RuleRegistry.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/advcheckbox.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/autocomplete.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/button.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/checkbox.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/date.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/element.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/file.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/group.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/header.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/hidden.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/hiddenselect.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/hierselect.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/html.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/image.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/input.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/link.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/password.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/radio.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/reset.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/select.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/static.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/submit.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/text.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/textarea.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/utils.php [deleted file]
cookbooks/dmca/files/default/html/HTML/QuickForm/xbutton.php [deleted file]
cookbooks/dmca/files/default/html/favicon.ico [deleted file]
cookbooks/dmca/files/default/html/index.php [deleted file]
cookbooks/dmca/files/default/html/robots.txt [deleted file]
cookbooks/dmca/files/default/html/style.css [deleted file]
cookbooks/dmca/metadata.rb
cookbooks/dmca/recipes/default.rb
cookbooks/dns/attributes/default.rb [new file with mode: 0644]
cookbooks/dns/metadata.rb
cookbooks/dns/recipes/default.rb
cookbooks/dns/templates/default/apache.erb
cookbooks/dns/templates/default/creds.json.erb [new file with mode: 0644]
cookbooks/dns/templates/default/dns-check.erb
cookbooks/dns/templates/default/dns-update.erb
cookbooks/dns/templates/default/geo.js.erb [new file with mode: 0644]
cookbooks/dns/templates/default/zone.html.erb
cookbooks/docker/metadata.rb [new file with mode: 0644]
cookbooks/docker/recipes/default.rb [new file with mode: 0644]
cookbooks/docker/templates/default/daemon.json.erb [new file with mode: 0644]
cookbooks/donate/README.md [deleted file]
cookbooks/donate/recipes/default.rb [deleted file]
cookbooks/donate/templates/default/apache.erb [deleted file]
cookbooks/donate/templates/default/backup.cron.erb [deleted file]
cookbooks/donate/templates/default/cron.erb [deleted file]
cookbooks/donate/templates/default/db-connect.inc.php.erb [deleted file]
cookbooks/elasticsearch/attributes/default.rb
cookbooks/elasticsearch/metadata.rb
cookbooks/elasticsearch/recipes/default.rb
cookbooks/exim/attributes/default.rb
cookbooks/exim/files/default/noreply/community [moved from cookbooks/exim/files/default/noreply/forum with 52% similarity]
cookbooks/exim/files/default/noreply/web
cookbooks/exim/metadata.rb
cookbooks/exim/recipes/default.rb
cookbooks/exim/templates/default/apache-mta-sts.erb [new file with mode: 0644]
cookbooks/exim/templates/default/apache.erb
cookbooks/exim/templates/default/default.erb [new file with mode: 0644]
cookbooks/exim/templates/default/dkim-domains.erb [new file with mode: 0644]
cookbooks/exim/templates/default/dkim-selectors.erb [new file with mode: 0644]
cookbooks/exim/templates/default/exim4.conf.erb
cookbooks/exim/templates/default/mail.rc.erb [moved from cookbooks/munin/templates/default/diskstats.erb with 63% similarity]
cookbooks/exim/templates/default/mta-sts.erb [new file with mode: 0644]
cookbooks/fail2ban/metadata.rb
cookbooks/fail2ban/recipes/default.rb
cookbooks/fail2ban/resources/filter.rb
cookbooks/fail2ban/resources/jail.rb
cookbooks/fail2ban/templates/default/jail.default.erb
cookbooks/fail2ban/templates/default/jail.erb
cookbooks/fail2ban/templates/default/paths-overrides.local.erb [moved from cookbooks/munin/templates/default/df.erb with 62% similarity]
cookbooks/forum/README.md [deleted file]
cookbooks/forum/recipes/default.rb [deleted file]
cookbooks/forum/templates/default/apache.erb [deleted file]
cookbooks/forum/templates/default/backup.cron.erb [deleted file]
cookbooks/forum/templates/default/config.php.erb [deleted file]
cookbooks/foundation/metadata.rb
cookbooks/foundation/recipes/board.rb
cookbooks/foundation/recipes/dwg.rb
cookbooks/foundation/recipes/mastodon.rb [new file with mode: 0644]
cookbooks/foundation/recipes/mwg.rb
cookbooks/foundation/recipes/owg.rb
cookbooks/foundation/recipes/welcome.rb [new file with mode: 0644]
cookbooks/foundation/recipes/wiki.rb
cookbooks/foundation/templates/default/apache.owg.erb [deleted file]
cookbooks/foundation/templates/default/robots.txt.erb [new file with mode: 0644]
cookbooks/ftp/recipes/default.rb
cookbooks/geodns/metadata.rb
cookbooks/geodns/recipes/default.rb
cookbooks/geodns/templates/default/config.erb
cookbooks/geodns/templates/default/geo.erb
cookbooks/geodns/templates/default/zone.map.erb [new file with mode: 0644]
cookbooks/geodns/templates/default/zone.resource.erb [new file with mode: 0644]
cookbooks/geodns/templates/default/zone.weighted.erb [new file with mode: 0644]
cookbooks/geoipupdate/README.md [new file with mode: 0644]
cookbooks/geoipupdate/attributes/default.rb [new file with mode: 0644]
cookbooks/geoipupdate/metadata.rb [moved from cookbooks/munin/metadata.rb with 56% similarity]
cookbooks/geoipupdate/recipes/default.rb [new file with mode: 0644]
cookbooks/geoipupdate/templates/default/GeoIP.conf.erb [new file with mode: 0644]
cookbooks/git/attributes/default.rb
cookbooks/git/metadata.rb
cookbooks/git/recipes/server.rb
cookbooks/git/recipes/web.rb
cookbooks/git/templates/default/apache.erb
cookbooks/git/templates/default/backup.cron.erb
cookbooks/git/templates/default/gitconfig.erb [new file with mode: 0644]
cookbooks/git/templates/default/gitweb.conf.erb
cookbooks/git/templates/default/indextext.html.erb [new file with mode: 0644]
cookbooks/gps-tile/attributes/default.rb [new file with mode: 0644]
cookbooks/gps-tile/files/default/html/index.html
cookbooks/gps-tile/metadata.rb
cookbooks/gps-tile/recipes/default.rb
cookbooks/gps-tile/templates/default/apache.erb
cookbooks/hardware/attributes/default.rb
cookbooks/hardware/metadata.rb
cookbooks/hardware/recipes/default.rb
cookbooks/hardware/templates/default/cciss-vol-statusd.erb [deleted file]
cookbooks/hardware/templates/default/ilo-defaults.xml.erb [new file with mode: 0644]
cookbooks/hardware/templates/default/ipmi_local.yml.erb [new file with mode: 0644]
cookbooks/hardware/templates/default/irqbalance.erb [deleted file]
cookbooks/hardware/templates/default/lldp.rb.erb [new file with mode: 0644]
cookbooks/hardware/templates/default/mcelog-trigger.erb [deleted file]
cookbooks/hardware/templates/default/modules.erb [deleted file]
cookbooks/hardware/templates/default/munin.hddtemp.erb [deleted file]
cookbooks/hardware/templates/default/munin.smart.erb [deleted file]
cookbooks/hardware/templates/default/ohai.rb.erb
cookbooks/hardware/templates/default/raid.default.erb [deleted file]
cookbooks/hardware/templates/default/smart.devices.erb [new file with mode: 0644]
cookbooks/hardware/templates/default/update-smart-drivedb.erb [new file with mode: 0644]
cookbooks/hardware/templates/default/watchdog.conf.erb [moved from cookbooks/munin/templates/default/if.erb with 61% similarity]
cookbooks/hardware/templates/default/watchdog.erb [deleted file]
cookbooks/hot/metadata.rb
cookbooks/hot/recipes/default.rb
cookbooks/hot/templates/default/apache.erb [deleted file]
cookbooks/ideditor/metadata.rb [moved from cookbooks/incron/metadata.rb with 62% similarity]
cookbooks/ideditor/recipes/default.rb [new file with mode: 0644]
cookbooks/imagery/files/default/os-openmap-local-palette.txt [new file with mode: 0644]
cookbooks/imagery/metadata.rb
cookbooks/imagery/recipes/default.rb
cookbooks/imagery/recipes/gb_ea.rb
cookbooks/imagery/recipes/gb_os_sv.rb
cookbooks/imagery/recipes/lu_lidar_hillshade.rb [new file with mode: 0644]
cookbooks/imagery/recipes/lu_ngl_dtm.rb [new file with mode: 0644]
cookbooks/imagery/recipes/tiler.rb [new file with mode: 0644]
cookbooks/imagery/recipes/za_ngi_aerial.rb [new file with mode: 0644]
cookbooks/imagery/recipes/za_ngi_topo.rb
cookbooks/imagery/resources/layer.rb
cookbooks/imagery/resources/site.rb
cookbooks/imagery/templates/default/imagery.js.erb
cookbooks/imagery/templates/default/index.html.erb
cookbooks/imagery/templates/default/mapserver.map.erb
cookbooks/imagery/templates/default/nginx_default.conf.erb
cookbooks/imagery/templates/default/nginx_imagery.conf.erb
cookbooks/imagery/templates/default/nginx_imagery_layer_fragment.conf.erb
cookbooks/imagery/templates/default/nginx_titiler.conf.erb [new file with mode: 0644]
cookbooks/incron/README.md [deleted file]
cookbooks/incron/attributes/default.rb [deleted file]
cookbooks/incron/recipes/default.rb [deleted file]
cookbooks/irc/README.md [new file with mode: 0644]
cookbooks/irc/metadata.rb [moved from cookbooks/openvpn/metadata.rb with 63% similarity]
cookbooks/irc/recipes/default.rb [moved from cookbooks/cgiirc/recipes/default.rb with 50% similarity]
cookbooks/kibana/attributes/default.rb
cookbooks/kibana/metadata.rb
cookbooks/kibana/recipes/default.rb
cookbooks/kibana/templates/default/apache.erb
cookbooks/letsencrypt/attributes/default.rb [new file with mode: 0644]
cookbooks/letsencrypt/files/default/bin/check-certificate
cookbooks/letsencrypt/files/default/bin/renew-hook
cookbooks/letsencrypt/files/default/bin/upload
cookbooks/letsencrypt/metadata.rb
cookbooks/letsencrypt/recipes/default.rb
cookbooks/letsencrypt/templates/default/apache.erb
cookbooks/letsencrypt/templates/default/cron.erb [deleted file]
cookbooks/letsencrypt/templates/default/logrotate.erb [new file with mode: 0644]
cookbooks/logstash/attributes/default.rb
cookbooks/logstash/metadata.rb
cookbooks/logstash/recipes/default.rb
cookbooks/logstash/recipes/forwarder.rb
cookbooks/mailman/metadata.rb
cookbooks/mailman/recipes/default.rb
cookbooks/mailman/templates/default/apache.erb
cookbooks/mailman/templates/default/backup.cron.erb
cookbooks/mailman/templates/default/mm_cfg.py.erb
cookbooks/matomo/README.md [new file with mode: 0644]
cookbooks/matomo/attributes/default.rb [new file with mode: 0644]
cookbooks/matomo/metadata.rb [moved from cookbooks/donate/metadata.rb with 58% similarity]
cookbooks/matomo/recipes/default.rb [new file with mode: 0644]
cookbooks/matomo/templates/default/apache.erb [new file with mode: 0644]
cookbooks/matomo/templates/default/config.erb [moved from cookbooks/piwik/templates/default/config.erb with 72% similarity]
cookbooks/mediawiki/attributes/default.rb
cookbooks/mediawiki/metadata.rb
cookbooks/mediawiki/recipes/default.rb
cookbooks/mediawiki/resources/extension.rb
cookbooks/mediawiki/resources/site.rb
cookbooks/mediawiki/resources/skin.rb
cookbooks/mediawiki/templates/default/LocalSettings.php.erb
cookbooks/mediawiki/templates/default/apache.erb
cookbooks/mediawiki/templates/default/composer.local.json.erb
cookbooks/mediawiki/templates/default/mediawiki-backup.cron.erb
cookbooks/mediawiki/templates/default/mediawiki.cron.erb [deleted file]
cookbooks/mediawiki/templates/default/mw-ext-AbuseFilter.inc.php.erb
cookbooks/mediawiki/templates/default/mw-ext-CirrusSearch.inc.php.erb
cookbooks/mediawiki/templates/default/mw-ext-ConfirmEdit.inc.php.erb
cookbooks/mediawiki/templates/default/mw-ext-SimpleMap.inc.php.erb [deleted file]
cookbooks/mediawiki/templates/default/mw-ext-SlippyMap.inc.php.erb [deleted file]
cookbooks/mediawiki/templates/default/mw-ext-SpamBlacklist.inc.php.erb
cookbooks/mediawiki/templates/default/mw-ext-TitleBlacklist.inc.php.erb
cookbooks/mediawiki/templates/default/mw-ext-VisualEditor.inc.php.erb
cookbooks/mediawiki/templates/default/mw-ext-osmtaginfo.inc.php.erb [deleted file]
cookbooks/mediawiki/templates/default/parsoid-config.yaml.erb [deleted file]
cookbooks/memcached/metadata.rb
cookbooks/memcached/recipes/default.rb
cookbooks/memcached/templates/default/memcached.conf.erb
cookbooks/memcached/templates/default/munin.erb [deleted file]
cookbooks/munin/README.md [deleted file]
cookbooks/munin/attributes/default.rb [deleted file]
cookbooks/munin/files/default/plugin-conf.d/api [deleted file]
cookbooks/munin/files/default/plugin-conf.d/chef [deleted file]
cookbooks/munin/files/default/plugin-conf.d/hpasmcli2 [deleted file]
cookbooks/munin/files/default/plugins/api_calls_ [deleted file]
cookbooks/munin/files/default/plugins/api_calls_num [deleted file]
cookbooks/munin/files/default/plugins/api_calls_status [deleted file]
cookbooks/munin/files/default/plugins/api_waits_ [deleted file]
cookbooks/munin/files/default/plugins/chef_status [deleted file]
cookbooks/munin/files/default/plugins/chrony [deleted file]
cookbooks/munin/files/default/plugins/fw_conntrack [deleted file]
cookbooks/munin/files/default/plugins/fw_forwarded_local [deleted file]
cookbooks/munin/files/default/plugins/hpasmcli2_ [deleted file]
cookbooks/munin/files/default/plugins/memcached_ [deleted file]
cookbooks/munin/files/default/plugins/memcached_multi_ [deleted file]
cookbooks/munin/files/default/plugins/munin_rrdcached [deleted file]
cookbooks/munin/files/default/plugins/mysql_ [deleted file]
cookbooks/munin/files/default/plugins/passenger_memory [deleted file]
cookbooks/munin/files/default/plugins/passenger_processes [deleted file]
cookbooks/munin/files/default/plugins/passenger_queues [deleted file]
cookbooks/munin/files/default/plugins/passenger_requests [deleted file]
cookbooks/munin/files/default/plugins/planet_age [deleted file]
cookbooks/munin/files/default/plugins/postgres_replication [deleted file]
cookbooks/munin/files/default/plugins/replication_delay [deleted file]
cookbooks/munin/files/default/plugins/rrdcached [deleted file]
cookbooks/munin/files/default/plugins/snmp__apcpdu_current [deleted file]
cookbooks/munin/files/default/plugins/snmp__apcpdu_humidity [deleted file]
cookbooks/munin/files/default/plugins/snmp__apcpdu_power [deleted file]
cookbooks/munin/files/default/plugins/snmp__apcpdu_temperature [deleted file]
cookbooks/munin/files/default/plugins/snmp__apcpdu_voltage [deleted file]
cookbooks/munin/files/default/plugins/squid_delay_pools [deleted file]
cookbooks/munin/files/default/plugins/squid_delay_pools_noreferer [deleted file]
cookbooks/munin/files/default/plugins/squid_icp [deleted file]
cookbooks/munin/files/default/plugins/squid_times [deleted file]
cookbooks/munin/files/default/www/favicon.ico [deleted file]
cookbooks/munin/files/default/www/robots.txt [deleted file]
cookbooks/munin/libraries/expand.rb [deleted file]
cookbooks/munin/recipes/default.rb [deleted file]
cookbooks/munin/recipes/server.rb [deleted file]
cookbooks/munin/resources/plugin.rb [deleted file]
cookbooks/munin/resources/plugin_conf.rb [deleted file]
cookbooks/munin/templates/default/apache.erb [deleted file]
cookbooks/munin/templates/default/backup.cron.erb [deleted file]
cookbooks/munin/templates/default/munin-node.conf.erb [deleted file]
cookbooks/munin/templates/default/munin.conf.erb [deleted file]
cookbooks/munin/templates/default/rrdcached.erb [deleted file]
cookbooks/munin/templates/default/sensors_volt.erb [deleted file]
cookbooks/mysql/libraries/mysql.rb
cookbooks/mysql/metadata.rb
cookbooks/mysql/recipes/default.rb
cookbooks/mysql/resources/database.rb
cookbooks/mysql/resources/user.rb
cookbooks/mysql/templates/default/apparmor.erb [new file with mode: 0644]
cookbooks/networking/attributes/default.rb
cookbooks/networking/definitions/firewall_rule.rb [deleted file]
cookbooks/networking/libraries/interfaces.rb
cookbooks/networking/libraries/ipaddresses.rb
cookbooks/networking/metadata.rb
cookbooks/networking/recipes/default.rb
cookbooks/networking/resources/firewall_rule.rb [new file with mode: 0644]
cookbooks/networking/templates/default/bond.netdev.erb [new file with mode: 0644]
cookbooks/networking/templates/default/dokken.network.erb [new file with mode: 0644]
cookbooks/networking/templates/default/hostname.erb [deleted file]
cookbooks/networking/templates/default/network.erb [new file with mode: 0644]
cookbooks/networking/templates/default/nftables.conf.erb [new file with mode: 0644]
cookbooks/networking/templates/default/nftables.erb [new file with mode: 0644]
cookbooks/networking/templates/default/resolved.conf.erb
cookbooks/networking/templates/default/shorewall-conntrack.erb [deleted file]
cookbooks/networking/templates/default/shorewall-default.erb [deleted file]
cookbooks/networking/templates/default/shorewall-hosts.erb [deleted file]
cookbooks/networking/templates/default/shorewall-interfaces.erb [deleted file]
cookbooks/networking/templates/default/shorewall-masq.erb [deleted file]
cookbooks/networking/templates/default/shorewall-policy.erb [deleted file]
cookbooks/networking/templates/default/shorewall-rules.erb [deleted file]
cookbooks/networking/templates/default/shorewall-zones.erb [deleted file]
cookbooks/networking/templates/default/shorewall.conf.erb [deleted file]
cookbooks/networking/templates/default/shorewall6-hosts.erb [deleted file]
cookbooks/networking/templates/default/shorewall6-interfaces.erb [deleted file]
cookbooks/networking/templates/default/shorewall6.conf.erb [deleted file]
cookbooks/networking/templates/default/slave.network.erb [new file with mode: 0644]
cookbooks/networking/templates/default/vlan.netdev.erb [new file with mode: 0644]
cookbooks/networking/templates/default/wireguard.netdev.erb [new file with mode: 0644]
cookbooks/networking/templates/default/wireguard.network.erb [new file with mode: 0644]
cookbooks/nfs/README.md [deleted file]
cookbooks/nfs/recipes/default.rb [deleted file]
cookbooks/nfs/recipes/server.rb [deleted file]
cookbooks/nfs/templates/default/exports.erb [deleted file]
cookbooks/nginx/attributes/default.rb
cookbooks/nginx/metadata.rb
cookbooks/nginx/recipes/default.rb
cookbooks/nginx/resources/site.rb
cookbooks/nginx/templates/default/munin.erb [deleted file]
cookbooks/nginx/templates/default/nginx.conf.erb
cookbooks/nodejs/metadata.rb
cookbooks/nodejs/recipes/default.rb
cookbooks/nodejs/resources/package.rb
cookbooks/nominatim/README.md
cookbooks/nominatim/attributes/default.rb
cookbooks/nominatim/files/default/website/403.html [new file with mode: 0644]
cookbooks/nominatim/files/default/website/509.html [new file with mode: 0644]
cookbooks/nominatim/files/default/website/crossdomain.xml [new file with mode: 0644]
cookbooks/nominatim/files/default/website/favicon.ico [new file with mode: 0644]
cookbooks/nominatim/files/default/website/nominatim.xml [new file with mode: 0644]
cookbooks/nominatim/files/default/website/robots.txt [new file with mode: 0644]
cookbooks/nominatim/files/default/website/taginfo.json [new file with mode: 0644]
cookbooks/nominatim/metadata.rb
cookbooks/nominatim/recipes/default.rb
cookbooks/nominatim/templates/default/apache.erb [deleted file]
cookbooks/nominatim/templates/default/fpm.conf.erb [deleted file]
cookbooks/nominatim/templates/default/git-post-merge-hook.erb [deleted file]
cookbooks/nominatim/templates/default/ipblocks.erb [deleted file]
cookbooks/nominatim/templates/default/logrotate.apache.erb [deleted file]
cookbooks/nominatim/templates/default/logrotate.nginx.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/logrotate.nominatim.erb
cookbooks/nominatim/templates/default/munin.erb [deleted file]
cookbooks/nominatim/templates/default/nginx-qa-tiles.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/nginx.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/nominatim-daily-maintenance.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/nominatim-update-data.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/nominatim-update-refresh-db.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/nominatim-update-source.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/nominatim-update.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/nominatim.cron.erb [deleted file]
cookbooks/nominatim/templates/default/nominatim.env.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/qa_config.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/settings.erb [deleted file]
cookbooks/nominatim/templates/default/ui-config.js.erb [new file with mode: 0644]
cookbooks/nominatim/templates/default/updater.erb [deleted file]
cookbooks/nominatim/templates/default/updater.init.erb [deleted file]
cookbooks/nominatim/templates/default/vacuum-db-nominatim.erb
cookbooks/ntp/metadata.rb
cookbooks/ntp/recipes/default.rb
cookbooks/ntp/templates/default/chrony.conf.erb
cookbooks/ohai/resources/plugin.rb
cookbooks/openssh/attributes/default.rb
cookbooks/openssh/recipes/default.rb
cookbooks/openssh/templates/default/ssh_config.erb [deleted file]
cookbooks/openssh/templates/default/ssh_known_hosts.erb
cookbooks/openssh/templates/default/sshd_config.conf.erb [new file with mode: 0644]
cookbooks/openvpn/README.md [deleted file]
cookbooks/openvpn/attributes/default.rb [deleted file]
cookbooks/openvpn/recipes/default.rb [deleted file]
cookbooks/openvpn/templates/default/tunnel.conf.erb [deleted file]
cookbooks/osmosis/attributes/default.rb
cookbooks/osmosis/metadata.rb
cookbooks/osmosis/recipes/default.rb
cookbooks/osqa/attributes/default.rb
cookbooks/osqa/metadata.rb
cookbooks/osqa/recipes/default.rb
cookbooks/osqa/templates/default/apache.erb
cookbooks/osqa/templates/default/backup.cron.erb
cookbooks/otrs/attributes/default.rb
cookbooks/otrs/metadata.rb
cookbooks/otrs/recipes/debian.rb [new file with mode: 0644]
cookbooks/otrs/recipes/default.rb
cookbooks/otrs/templates/default/apache-debian.erb [new file with mode: 0644]
cookbooks/otrs/templates/default/apache.erb
cookbooks/otrs/templates/default/backup.cron.erb
cookbooks/otrs/templates/default/dbconfig.config.erb [new file with mode: 0644]
cookbooks/otrs/templates/default/sudoers.erb [deleted file]
cookbooks/overpass/README.md [new file with mode: 0644]
cookbooks/overpass/attributes/default.rb [new file with mode: 0644]
cookbooks/overpass/metadata.rb [new file with mode: 0644]
cookbooks/overpass/recipes/default.rb [new file with mode: 0644]
cookbooks/overpass/templates/default/apache.erb [new file with mode: 0644]
cookbooks/overpass/templates/default/logrotate.erb [moved from cookbooks/dns/templates/default/cron.erb with 51% similarity]
cookbooks/overpass/templates/default/overpass-import-db.erb [new file with mode: 0644]
cookbooks/overpass/templates/default/overpass-update-areas.erb [new file with mode: 0644]
cookbooks/overpass/templates/default/overpass-update-db.erb [new file with mode: 0644]
cookbooks/overpass/templates/default/totp-filter.erb [new file with mode: 0644]
cookbooks/oxidized/README.md [new file with mode: 0644]
cookbooks/oxidized/attributes/default.rb [new file with mode: 0644]
cookbooks/oxidized/metadata.rb [moved from cookbooks/forum/metadata.rb with 56% similarity]
cookbooks/oxidized/recipes/default.rb [new file with mode: 0644]
cookbooks/oxidized/templates/default/config.erb [new file with mode: 0644]
cookbooks/oxidized/templates/default/logrotate.erb [moved from cookbooks/networking/templates/default/logrotate.shorewall.erb with 61% similarity]
cookbooks/oxidized/templates/default/routers.db.erb [new file with mode: 0644]
cookbooks/passenger/attributes/default.rb
cookbooks/passenger/metadata.rb
cookbooks/passenger/recipes/default.rb
cookbooks/passenger/resources/application.rb
cookbooks/passenger/templates/default/munin.erb [deleted file]
cookbooks/passenger/templates/default/passenger.conf.erb
cookbooks/passenger/templates/default/ruby.erb
cookbooks/php/README.md [new file with mode: 0644]
cookbooks/php/attributes/default.rb [new file with mode: 0644]
cookbooks/php/metadata.rb [moved from cookbooks/roundup/metadata.rb with 66% similarity]
cookbooks/php/recipes/apache.rb [new file with mode: 0644]
cookbooks/php/recipes/default.rb [moved from cookbooks/roundup/recipes/default.rb with 83% similarity]
cookbooks/php/recipes/fpm.rb [new file with mode: 0644]
cookbooks/php/resources/fpm.rb [new file with mode: 0644]
cookbooks/php/templates/default/php-fpm.ini.erb [new file with mode: 0644]
cookbooks/php/templates/default/pool.conf.erb [new file with mode: 0644]
cookbooks/piwik/README.md [deleted file]
cookbooks/piwik/attributes/default.rb [deleted file]
cookbooks/piwik/metadata.rb [deleted file]
cookbooks/piwik/recipes/default.rb [deleted file]
cookbooks/piwik/templates/default/apache.erb [deleted file]
cookbooks/piwik/templates/default/cron.erb [deleted file]
cookbooks/planet/attributes/default.rb
cookbooks/planet/files/default/ccbysa_cgi/HEADER.cgi [new file with mode: 0644]
cookbooks/planet/files/default/ccbysa_history_cgi/HEADER.cgi
cookbooks/planet/files/default/cgi/HEADER.cgi
cookbooks/planet/files/default/history_cgi/HEADER.cgi
cookbooks/planet/files/default/html/robots.txt
cookbooks/planet/files/default/html/style.css
cookbooks/planet/files/default/replication-bin/replicate-changesets
cookbooks/planet/files/default/replication-bin/replicate-cleanup [new file with mode: 0755]
cookbooks/planet/files/default/replication-bin/replicate-day [new file with mode: 0644]
cookbooks/planet/files/default/replication-bin/replicate-hour [new file with mode: 0644]
cookbooks/planet/files/default/replication-bin/replicate-minute [new file with mode: 0755]
cookbooks/planet/files/default/replication-bin/streaming-replicator [deleted file]
cookbooks/planet/files/default/replication-bin/streaming-server [deleted file]
cookbooks/planet/files/default/replication-cgi/HEADER.cgi
cookbooks/planet/metadata.rb
cookbooks/planet/recipes/aws.rb [new file with mode: 0644]
cookbooks/planet/recipes/current.rb
cookbooks/planet/recipes/default.rb
cookbooks/planet/recipes/dump.rb
cookbooks/planet/recipes/notes.rb
cookbooks/planet/recipes/replication.rb
cookbooks/planet/templates/default/apache-latest-planet-filename.erb
cookbooks/planet/templates/default/apache-s3-ip2region.erb [new file with mode: 0644]
cookbooks/planet/templates/default/apache.erb
cookbooks/planet/templates/default/aws-config.erb [new file with mode: 0644]
cookbooks/planet/templates/default/aws-credentials.erb [new file with mode: 0644]
cookbooks/planet/templates/default/changesets.conf.erb
cookbooks/planet/templates/default/old-planet-file-cleanup.cron.erb [deleted file]
cookbooks/planet/templates/default/planet-dump-mirror-cron.erb [deleted file]
cookbooks/planet/templates/default/planet-file-cleanup.erb [moved from cookbooks/planet/templates/default/old-planet-file-cleanup.erb with 100% similarity]
cookbooks/planet/templates/default/planet-mirror-redirect-update.erb [deleted file]
cookbooks/planet/templates/default/planet-notes-cleanup.erb [new file with mode: 0644]
cookbooks/planet/templates/default/planet-notes-dump.cron.erb [deleted file]
cookbooks/planet/templates/default/planet-notes-dump.erb
cookbooks/planet/templates/default/planet-update-file.erb [deleted file]
cookbooks/planet/templates/default/planet-update.cron.erb [deleted file]
cookbooks/planet/templates/default/planet-update.erb
cookbooks/planet/templates/default/planet-update.logrotate.erb [deleted file]
cookbooks/planet/templates/default/planetdump-trigger.erb [new file with mode: 0644]
cookbooks/planet/templates/default/planetdump.erb
cookbooks/planet/templates/default/replication.cron.erb [deleted file]
cookbooks/planet/templates/default/streaming.init.erb [deleted file]
cookbooks/planet/templates/default/users-agreed.erb
cookbooks/podman/attributes/default.rb [new file with mode: 0644]
cookbooks/podman/metadata.rb [moved from cookbooks/squid/metadata.rb with 66% similarity]
cookbooks/podman/recipes/apache.rb [new file with mode: 0644]
cookbooks/podman/recipes/default.rb [new file with mode: 0644]
cookbooks/podman/resources/service.rb [new file with mode: 0644]
cookbooks/podman/resources/site.rb [new file with mode: 0644]
cookbooks/podman/templates/default/apache.erb [moved from cookbooks/dmca/templates/default/apache.erb with 76% similarity]
cookbooks/postgresql/README.md
cookbooks/postgresql/attributes/default.rb
cookbooks/postgresql/libraries/postgresql.rb
cookbooks/postgresql/metadata.rb
cookbooks/postgresql/recipes/default.rb
cookbooks/postgresql/resources/database.rb
cookbooks/postgresql/resources/execute.rb
cookbooks/postgresql/resources/extension.rb
cookbooks/postgresql/resources/munin.rb [deleted file]
cookbooks/postgresql/resources/sequence.rb [new file with mode: 0644]
cookbooks/postgresql/resources/table.rb
cookbooks/postgresql/resources/tablespace.rb
cookbooks/postgresql/resources/user.rb
cookbooks/postgresql/templates/default/munin.erb [deleted file]
cookbooks/postgresql/templates/default/pg_hba.conf.erb
cookbooks/postgresql/templates/default/postgresql.conf.erb
cookbooks/postgresql/templates/default/sql_exporter.yml.erb [new file with mode: 0644]
cookbooks/prometheus/README.md [new file with mode: 0644]
cookbooks/prometheus/attributes/default.rb [new file with mode: 0644]
cookbooks/prometheus/files/default/id_rsa.pub [new file with mode: 0644]
cookbooks/prometheus/metadata.rb [new file with mode: 0644]
cookbooks/prometheus/recipes/default.rb [new file with mode: 0644]
cookbooks/prometheus/recipes/server.rb [new file with mode: 0644]
cookbooks/prometheus/recipes/smokeping.rb [new file with mode: 0644]
cookbooks/prometheus/resources/collector.rb [new file with mode: 0644]
cookbooks/prometheus/resources/exporter.rb [new file with mode: 0644]
cookbooks/prometheus/templates/default/alert_rules.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/alertmanager.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/amtool.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/apache.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/aws-credentials.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/backup-data.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/backup.cron.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/chef.prom.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/cloudwatch.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/filestat.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/grafana.ini.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/karma.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/prometheus.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/smokeping.yml.erb [new file with mode: 0644]
cookbooks/prometheus/templates/default/ssl.yml.erb [new file with mode: 0644]
cookbooks/python/recipes/default.rb
cookbooks/python/resources/package.rb
cookbooks/python/resources/virtualenv.rb
cookbooks/roundup/README.md [deleted file]
cookbooks/rsyncd/metadata.rb
cookbooks/rsyncd/recipes/default.rb
cookbooks/ruby/README.md [new file with mode: 0644]
cookbooks/ruby/attributes/default.rb [new file with mode: 0644]
cookbooks/ruby/metadata.rb [moved from cookbooks/nfs/metadata.rb with 70% similarity]
cookbooks/ruby/recipes/default.rb [new file with mode: 0644]
cookbooks/ruby/resources/bundle_exec.rb [new file with mode: 0644]
cookbooks/ruby/resources/bundle_install.rb [new file with mode: 0644]
cookbooks/serverinfo/README.md
cookbooks/serverinfo/metadata.rb
cookbooks/serverinfo/recipes/default.rb
cookbooks/serverinfo/templates/default/apache.erb
cookbooks/snmpd/attributes/default.rb
cookbooks/snmpd/recipes/default.rb
cookbooks/snmpd/templates/default/snmpd.conf.erb
cookbooks/spamassassin/metadata.rb
cookbooks/spamassassin/recipes/default.rb
cookbooks/spamassassin/templates/default/spamassassin.erb
cookbooks/squid/README.md [deleted file]
cookbooks/squid/attributes/default.rb [deleted file]
cookbooks/squid/recipes/default.rb [deleted file]
cookbooks/squid/resources/fragment.rb [deleted file]
cookbooks/squid/templates/default/squid.conf.erb [deleted file]
cookbooks/ssl/attributes/default.rb
cookbooks/ssl/files/default/dhparam.pem [new file with mode: 0644]
cookbooks/ssl/files/default/letsencrypt.pem [deleted file]
cookbooks/ssl/recipes/default.rb
cookbooks/ssl/resources/certificate.rb
cookbooks/stateofthemap/metadata.rb
cookbooks/stateofthemap/recipes/container.rb [new file with mode: 0644]
cookbooks/stateofthemap/recipes/default.rb
cookbooks/stateofthemap/recipes/wordpress.rb [new file with mode: 0644]
cookbooks/stateofthemap/templates/default/apache.erb [deleted file]
cookbooks/stateofthemap/templates/default/apache.jekyll.erb [deleted file]
cookbooks/stateofthemap/templates/default/apache.static.erb [deleted file]
cookbooks/stateofthemap/templates/default/backup.cron.erb
cookbooks/subversion/files/default/hooks/post-commit [deleted file]
cookbooks/subversion/files/default/hooks/post-revprop-change [deleted file]
cookbooks/subversion/metadata.rb
cookbooks/subversion/recipes/default.rb
cookbooks/subversion/templates/default/apache.erb [deleted file]
cookbooks/subversion/templates/default/backup.cron.erb [deleted file]
cookbooks/supybot/attributes/default.rb [new file with mode: 0644]
cookbooks/supybot/metadata.rb
cookbooks/supybot/recipes/default.rb
cookbooks/supybot/templates/default/channels.conf.erb
cookbooks/supybot/templates/default/git.conf.erb
cookbooks/supybot/templates/default/supybot.conf.erb
cookbooks/switch2osm/metadata.rb
cookbooks/switch2osm/recipes/default.rb
cookbooks/switch2osm/templates/default/apache.erb [deleted file]
cookbooks/sysctl/attributes/default.rb [new file with mode: 0644]
cookbooks/sysctl/recipes/default.rb
cookbooks/sysctl/templates/default/chef.conf.erb [deleted file]
cookbooks/sysfs/recipes/default.rb
cookbooks/systemd/resources/path.rb
cookbooks/systemd/resources/service.rb
cookbooks/systemd/resources/socket.rb [new file with mode: 0644]
cookbooks/systemd/resources/timer.rb
cookbooks/systemd/resources/tmpfile.rb
cookbooks/systemd/templates/default/service.erb
cookbooks/systemd/templates/default/socket.erb [new file with mode: 0644]
cookbooks/taginfo/attributes/default.rb
cookbooks/taginfo/metadata.rb
cookbooks/taginfo/recipes/default.rb
cookbooks/taginfo/templates/default/apache.erb
cookbooks/taginfo/templates/default/taginfo-update.erb [deleted file]
cookbooks/taginfo/templates/default/update.erb
cookbooks/tile/attributes/default.rb
cookbooks/tile/files/default/bin/expire-tiles-single [deleted file]
cookbooks/tile/files/default/html/abuse.png [deleted file]
cookbooks/tile/files/default/html/abuse2.png [deleted file]
cookbooks/tile/files/default/html/abuse3.png [deleted file]
cookbooks/tile/files/default/html/crossdomain.xml
cookbooks/tile/files/default/html/favicon.ico
cookbooks/tile/files/default/html/robots.txt
cookbooks/tile/files/default/html/tilejson.json [new file with mode: 0644]
cookbooks/tile/files/default/html/update-url-tile.png [deleted file]
cookbooks/tile/files/default/ruby/expire.rb [deleted file]
cookbooks/tile/metadata.rb
cookbooks/tile/recipes/default.rb
cookbooks/tile/templates/default/apache.erb
cookbooks/tile/templates/default/cleanup-tiles.cron.erb [deleted file]
cookbooks/tile/templates/default/cleanup-tiles.erb
cookbooks/tile/templates/default/debug.erb
cookbooks/tile/templates/default/expire-tiles.erb
cookbooks/tile/templates/default/export.cron.erb [deleted file]
cookbooks/tile/templates/default/export.erb
cookbooks/tile/templates/default/logrotate.apache.erb
cookbooks/tile/templates/default/render-lowzoom.erb
cookbooks/tile/templates/default/renderd.conf.erb
cookbooks/tile/templates/default/replicate-post.erb [new file with mode: 0644]
cookbooks/tile/templates/default/replicate.erb
cookbooks/tile/templates/default/replicate.logrotate.erb [deleted file]
cookbooks/tile/templates/default/update-lowzoom.erb
cookbooks/tilecache/README.md [deleted file]
cookbooks/tilecache/attributes/default.rb [deleted file]
cookbooks/tilecache/metadata.rb [deleted file]
cookbooks/tilecache/recipes/default.rb [deleted file]
cookbooks/tilecache/templates/default/cron.erb [deleted file]
cookbooks/tilecache/templates/default/logrotate.nginx.erb [deleted file]
cookbooks/tilecache/templates/default/logrotate.squid.erb [deleted file]
cookbooks/tilecache/templates/default/munin.ping.erb [deleted file]
cookbooks/tilecache/templates/default/nginx_generate_tilecache_qos_map.erb [deleted file]
cookbooks/tilecache/templates/default/nginx_tile.conf.erb [deleted file]
cookbooks/tilecache/templates/default/squid.conf.erb [deleted file]
cookbooks/tilelog/attributes/default.rb
cookbooks/tilelog/metadata.rb
cookbooks/tilelog/recipes/default.rb
cookbooks/tilelog/templates/default/tilelog.cron.erb [deleted file]
cookbooks/tilelog/templates/default/tilelog.erb
cookbooks/tools/attributes/default.rb [new file with mode: 0644]
cookbooks/tools/recipes/default.rb
cookbooks/tools/templates/default/motd-news.erb [new file with mode: 0644]
cookbooks/trac/files/default/htdocs/osm.ico [deleted file]
cookbooks/trac/files/default/htdocs/osm.png [deleted file]
cookbooks/trac/files/default/htdocs/robots.txt [deleted file]
cookbooks/trac/files/default/templates/site.html [deleted file]
cookbooks/trac/files/default/trac-authenticate [deleted file]
cookbooks/trac/metadata.rb
cookbooks/trac/recipes/default.rb
cookbooks/trac/templates/default/apache.erb [deleted file]
cookbooks/trac/templates/default/backup.cron.erb [deleted file]
cookbooks/trac/templates/default/sudoers.erb [deleted file]
cookbooks/trac/templates/default/trac.ini.erb [deleted file]
cookbooks/web/README.md
cookbooks/web/attributes/default.rb
cookbooks/web/files/default/static/openlayers/OpenLayers.js [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/OpenStreetMap.js [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/404.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/blank.gif [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/cloud-popup-relative.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/drag-rectangle-off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/drag-rectangle-on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/east-mini.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/layer-switcher-maximize.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/layer-switcher-minimize.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/marker-blue.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/marker-gold.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/marker-green.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/marker.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/measuring-stick-off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/measuring-stick-on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/north-mini.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/panning-hand-off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/panning-hand-on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/slider.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/south-mini.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/west-mini.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/zoom-minus-mini.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/zoom-plus-mini.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/zoom-world-mini.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/img/zoombar.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/google.css [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/ie6-style.css [new file with mode: 0755]
cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/blank.gif [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/close.gif [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/editing_tool_bar.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/navigation_history.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/overview_replacement.gif [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel-NOALPHA.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/pan_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/pan_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/ruler.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_off.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_on.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel-NOALPHA.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel.png [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/style.css [new file with mode: 0644]
cookbooks/web/files/default/static/openlayers/theme/default/style.mobile.css [new file with mode: 0644]
cookbooks/web/metadata.rb
cookbooks/web/recipes/backend.rb [deleted file]
cookbooks/web/recipes/base.rb
cookbooks/web/recipes/cgimap.rb
cookbooks/web/recipes/cleanup.rb
cookbooks/web/recipes/frontend.rb
cookbooks/web/recipes/rails.rb
cookbooks/web/recipes/statistics.rb
cookbooks/web/resources/rails_port.rb
cookbooks/web/templates/default/apache.backend.erb [deleted file]
cookbooks/web/templates/default/apache.frontend.erb
cookbooks/web/templates/default/api-statistics.erb
cookbooks/web/templates/default/deliver-message.erb [new file with mode: 0644]
cookbooks/web/templates/default/logrotate.web.erb
cookbooks/web/templates/default/passenger.cron.erb [deleted file]
cookbooks/web/templates/default/statistics.cron.erb [deleted file]
cookbooks/web/templates/default/statistics.erb
cookbooks/wiki/metadata.rb
cookbooks/wiki/recipes/default.rb
cookbooks/wiki/templates/default/mw-ext-JsonConfig.inc.php.erb [new file with mode: 0644]
cookbooks/wiki/templates/default/mw-ext-Kartographer.inc.php.erb [new file with mode: 0644]
cookbooks/wiki/templates/default/mw-ext-MultiMaps.inc.php.erb [deleted file]
cookbooks/wiki/templates/default/mw-ext-Wikibase.inc.php.erb
cookbooks/wiki/templates/default/robots.txt.erb
cookbooks/wiki/templates/default/squid.conf.erb [deleted file]
cookbooks/wiki/templates/default/wiki-dump.erb [deleted file]
cookbooks/wordpress/attributes/default.rb
cookbooks/wordpress/libraries/wordpress.rb
cookbooks/wordpress/metadata.rb
cookbooks/wordpress/recipes/default.rb
cookbooks/wordpress/resources/plugin.rb
cookbooks/wordpress/resources/site.rb
cookbooks/wordpress/resources/theme.rb
cookbooks/wordpress/templates/default/apache.erb
hooks/pre-commit
roles/aarnet.rb
roles/albi.rb [new file with mode: 0644]
roles/altavoz.rb [deleted file]
roles/angor.rb
roles/appliwave.rb [new file with mode: 0644]
roles/ar.rb [new file with mode: 0644]
roles/ascalon.rb
roles/aws-us-east-2.rb [new file with mode: 0644]
roles/aws.rb
roles/backup.rb
roles/balerion.rb
roles/base.rb
roles/birthday20.rb [new file with mode: 0644]
roles/blix-nl.rb [deleted file]
roles/blix-no.rb [deleted file]
roles/blix.rb [deleted file]
roles/blog-staging.rb [new file with mode: 0644]
roles/blogs.rb [new file with mode: 0644]
roles/boitata.rb [deleted file]
roles/bowser.rb
roles/bytemark.rb
roles/c3sl.rb [deleted file]
roles/carnet.rb
roles/catalyst.rb [deleted file]
roles/chef-server.rb
roles/cherufe.rb [deleted file]
roles/chrysophylax.rb [deleted file]
roles/clifford.rb [deleted file]
roles/cmok.rb [deleted file]
roles/co.rb [new file with mode: 0644]
roles/community.rb [new file with mode: 0644]
roles/crm.rb
roles/culebre.rb
roles/datahata.rb [deleted file]
roles/db-master.rb
roles/db-slave.rb
roles/db.rb
roles/delta.rb [deleted file]
roles/dev.rb
roles/dns.rb
roles/donate.rb [deleted file]
roles/dotsrc.rb [deleted file]
roles/draco.rb [deleted file]
roles/dribble.rb [new file with mode: 0644]
roles/drogon.rb [deleted file]
roles/dulcy.rb
roles/eddie.rb
roles/epix.rb [new file with mode: 0644]
roles/equinix-ams.rb [moved from roles/equinix.rb with 52% similarity]
roles/equinix-dub.rb [new file with mode: 0644]
roles/errol.rb [deleted file]
roles/euserv.rb [deleted file]
roles/eustace.rb [deleted file]
roles/exonetric.rb
roles/faffy.rb [new file with mode: 0644]
roles/fafnir.rb
roles/ffrl.rb [deleted file]
roles/firefishynet.rb
roles/forum.rb [deleted file]
roles/foundation.rb
roles/fullsave.rb [deleted file]
roles/fume.rb
roles/g5solutions.rb [deleted file]
roles/gandi.rb [new file with mode: 0644]
roles/gateway.rb
roles/geodns.rb
roles/git.rb
roles/gorynych.rb [deleted file]
roles/gp-dl360e-g8.rb [new file with mode: 0644]
roles/gps-tile.rb
roles/grifon.rb [deleted file]
roles/grindtooth.rb [deleted file]
roles/grisu.rb
roles/grnet.rb [deleted file]
roles/hetzner.rb [deleted file]
roles/horntail.rb [new file with mode: 0644]
roles/hostedinnz.rb [deleted file]
roles/hp-dl180-g6.rb
roles/hp-dl360-g6.rb
roles/hp-g9.rb
roles/idris.rb [new file with mode: 0644]
roles/imagery.rb
roles/inxza.rb
roles/irc.rb
roles/ironbelly.rb
roles/iway.rb [deleted file]
roles/jakelong.rb
roles/jump.rb [deleted file]
roles/kalessin.rb [deleted file]
roles/karm.rb
roles/katie.rb [deleted file]
roles/katla.rb [deleted file]
roles/keizer.rb [deleted file]
roles/kessie.rb
roles/kibana.rb
roles/konqi.rb
roles/ladon.rb [deleted file]
roles/letsencrypt.rb
roles/lists.rb
roles/logstash-forwarder.rb
roles/logstash.rb
roles/longma.rb
roles/lu.rb [new file with mode: 0644]
roles/lyonix.rb
roles/lysator.rb [deleted file]
roles/mail.rb
roles/matomo.rb [new file with mode: 0644]
roles/meraxes.rb [new file with mode: 0644]
roles/milkywan.rb [deleted file]
roles/muirdris.rb [new file with mode: 0644]
roles/munin.rb [deleted file]
roles/naga.rb
roles/nchc.rb [deleted file]
roles/necrosan.rb
roles/nepomuk.rb [deleted file]
roles/netalerts.rb
roles/nidhogg.rb
roles/nominatim.rb
roles/noomoahk.rb [deleted file]
roles/noquiklos.rb [deleted file]
roles/norbert.rb
roles/odin.rb
roles/orm.rb [deleted file]
roles/osqa.rb
roles/osuosl.rb
roles/otrs.rb
roles/overpass-query.rb [new file with mode: 0644]
roles/ovh.rb
roles/oxidized.rb [new file with mode: 0644]
roles/palulukon.rb [new file with mode: 0644]
roles/paulla.rb
roles/piasa.rb [new file with mode: 0644]
roles/piwik.rb [deleted file]
roles/pl.rb [new file with mode: 0644]
roles/planet-current.rb [deleted file]
roles/planet.rb
roles/prgmr.rb [deleted file]
roles/prometheus.rb [new file with mode: 0644]
roles/pummelzacken.rb [deleted file]
roles/pyrene.rb [deleted file]
roles/ramoth.rb [deleted file]
roles/rhaegal.rb
roles/ridgeback.rb [deleted file]
roles/ridley.rb
roles/rimfaxe.rb [deleted file]
roles/roundup.rb [deleted file]
roles/saphira.rb [deleted file]
roles/sarel.rb [deleted file]
roles/sarkany.rb [deleted file]
roles/scaleway.rb [new file with mode: 0644]
roles/scorch.rb
roles/shenron.rb
roles/simurgh.rb [deleted file]
roles/smaug.rb [new file with mode: 0644]
roles/snap-01.rb [new file with mode: 0644]
roles/snap-02.rb [new file with mode: 0644]
roles/snap-03.rb [new file with mode: 0644]
roles/spike-01.rb [new file with mode: 0644]
roles/spike-02.rb [new file with mode: 0644]
roles/spike-03.rb [new file with mode: 0644]
roles/spike-04.rb [deleted file]
roles/spike-05.rb [deleted file]
roles/spike-06.rb
roles/spike-07.rb
roles/spike-08.rb
roles/stateofthemap.rb
roles/stormfly-01.rb [deleted file]
roles/stormfly-02.rb [deleted file]
roles/stormfly-03.rb [new file with mode: 0644]
roles/stormfly-04.rb [new file with mode: 0644]
roles/supermicro-x8dtt-h.rb [deleted file]
roles/supybot.rb
roles/szerverem.rb [deleted file]
roles/tabaluga.rb [deleted file]
roles/taginfo.rb
roles/teleservice.rb
roles/teraswitch.rb [deleted file]
roles/tetaneutral.rb [deleted file]
roles/thorn-01.rb [deleted file]
roles/thorn-02.rb [deleted file]
roles/thorn-03.rb [deleted file]
roles/thorn-04.rb [deleted file]
roles/thorn-05.rb [deleted file]
roles/tiamat-00.rb [deleted file]
roles/tiamat-01.rb [deleted file]
roles/tiamat-02.rb [deleted file]
roles/tiamat-03.rb [deleted file]
roles/tiamat-10.rb [deleted file]
roles/tiamat-11.rb [deleted file]
roles/tiamat-12.rb [deleted file]
roles/tiamat-13.rb [deleted file]
roles/tiamat-20.rb [deleted file]
roles/tiamat-21.rb [deleted file]
roles/tiamat-22.rb [deleted file]
roles/tiamat-23.rb [deleted file]
roles/tile.rb
roles/tilecache.rb [deleted file]
roles/toothless.rb [deleted file]
roles/trac.rb
roles/trogdor.rb [deleted file]
roles/tuatara.rb [deleted file]
roles/tyan-s7010.rb [deleted file]
roles/ucl.rb
roles/umu.rb
roles/unizar.rb [deleted file]
roles/urmel.rb [deleted file]
roles/utelecom.rb [deleted file]
roles/vhagar.rb [new file with mode: 0644]
roles/vipertooth.rb [deleted file]
roles/viserion.rb [deleted file]
roles/waima.rb [deleted file]
roles/web-backend.rb [deleted file]
roles/web-db.rb
roles/web-frontend.rb
roles/web-storage.rb [deleted file]
roles/web.rb
roles/wiki.rb
roles/yandex.rb [deleted file]
roles/ysera.rb
roles/zcu.rb [deleted file]
test/data_bags/accounts/community.json [new file with mode: 0644]
test/data_bags/accounts/forum.json [deleted file]
test/data_bags/accounts/git.json [new file with mode: 0644]
test/data_bags/accounts/gpstile.json [new file with mode: 0644]
test/data_bags/accounts/kibana.json [new file with mode: 0644]
test/data_bags/accounts/lonvia.json [new file with mode: 0644]
test/data_bags/accounts/nominatim.json [new file with mode: 0644]
test/data_bags/accounts/osmbackup.json [new file with mode: 0644]
test/data_bags/accounts/osqa.json [new file with mode: 0644]
test/data_bags/accounts/overpass.json [new file with mode: 0644]
test/data_bags/accounts/planet.json [new file with mode: 0644]
test/data_bags/accounts/rails.json [new file with mode: 0644]
test/data_bags/accounts/supybot.json [new file with mode: 0644]
test/data_bags/accounts/taginfo.json [new file with mode: 0644]
test/data_bags/accounts/tile.json [new file with mode: 0644]
test/data_bags/accounts/trac.json [new file with mode: 0644]
test/data_bags/accounts/wiki.json [new file with mode: 0644]
test/data_bags/accounts/wordpress.json [new file with mode: 0644]
test/data_bags/blog/passwords.json [new file with mode: 0644]
test/data_bags/blog/wp2fa_encrypt_keys.json [new file with mode: 0644]
test/data_bags/civicrm/passwords.json [new file with mode: 0644]
test/data_bags/civicrm/wp2fa_encrypt_keys.json [new file with mode: 0644]
test/data_bags/community/passwords.json [new file with mode: 0644]
test/data_bags/db/passwords.json [new file with mode: 0644]
test/data_bags/db/wal-secrets.json [new file with mode: 0644]
test/data_bags/dns/passwords.json [new file with mode: 0644]
test/data_bags/donate/passwords.json [new file with mode: 0644]
test/data_bags/exim/aliases.json [new file with mode: 0644]
test/data_bags/exim/dkim.json [new file with mode: 0644]
test/data_bags/foundation/passwords.json [new file with mode: 0644]
test/data_bags/geoipupdate/license-keys.json [new file with mode: 0644]
test/data_bags/letsencrypt/.gitkeep [new file with mode: 0644]
test/data_bags/logstash/keys.json [new file with mode: 0644]
test/data_bags/matomo/passwords.json [new file with mode: 0644]
test/data_bags/networking/keys.json [new file with mode: 0644]
test/data_bags/otrs-debian/passwords.json [new file with mode: 0644]
test/data_bags/planet/aws.json [new file with mode: 0644]
test/data_bags/postgresql/passwords.json [new file with mode: 0644]
test/data_bags/prometheus/passwords.json [new file with mode: 0644]
test/data_bags/prometheus/tokens.json [new file with mode: 0644]
test/data_bags/snmpd/communities.json [new file with mode: 0644]
test/data_bags/stateofthemap/passwords.json [new file with mode: 0644]
test/data_bags/stateofthemap/wp2fa_encrypt_keys.json [new file with mode: 0644]
test/data_bags/supybot/passwords.json [new file with mode: 0644]
test/data_bags/supybot/users.json [new file with mode: 0644]
test/data_bags/tile/blocks.json [new file with mode: 0644]
test/data_bags/tilelog/passwords.json [new file with mode: 0644]
test/data_bags/web/matomo.json [new file with mode: 0644]
test/data_bags/web/passwords.json [new file with mode: 0644]
test/data_bags/wiki/passwords.json [new file with mode: 0644]
test/integration/apache/inspec/apache_spec.rb [moved from test/integration/forum/serverspec/apache_spec.rb with 76% similarity]
test/integration/apache/serverspec/apache_spec.rb [deleted file]
test/integration/awscli/inspec/awscli_spec.rb [new file with mode: 0644]
test/integration/bind/inspec/bind_spec.rb [moved from test/integration/bind/serverspec/bind_spec.rb with 75% similarity]
test/integration/blog/inspec/apache_spec.rb [moved from test/integration/apache-ssl/serverspec/apache_spec.rb with 76% similarity]
test/integration/blog/inspec/wordpress_spec.rb [new file with mode: 0644]
test/integration/blogs/inspec/apache_spec.rb [moved from test/integration/otrs/serverspec/apache_spec.rb with 76% similarity]
test/integration/chef/inspec/chef_spec.rb [new file with mode: 0644]
test/integration/civicrm/inspec/apache_spec.rb [moved from test/integration/blogs/serverspec/apache_spec.rb with 76% similarity]
test/integration/clamav/inspec/clamav_spec.rb [new file with mode: 0644]
test/integration/community/inspec/docker_spec.rb [new file with mode: 0644]
test/integration/community/inspec/http_spec.rb [new file with mode: 0644]
test/integration/db-backup/inspec/backup_spec.rb [new file with mode: 0644]
test/integration/db-base/inspec/postgresql_spec.rb [new file with mode: 0644]
test/integration/db-master/inspec/postgresql_spec.rb [new file with mode: 0644]
test/integration/db-slave/inspec/postgresql_spec.rb [new file with mode: 0644]
test/integration/dhcpd/inspec/dhcpd_spec.rb [new file with mode: 0644]
test/integration/dmca/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/dns/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/dns/inspec/dnscontrol_spec.rb [new file with mode: 0644]
test/integration/docker/inspec/docker_spec.rb [new file with mode: 0644]
test/integration/elasticsearch/inspec/elasticsearch_spec.rb [new file with mode: 0644]
test/integration/exim/inspec/exim_spec.rb [new file with mode: 0644]
test/integration/fail2ban/inspec/fail2ban_spec.rb [new file with mode: 0644]
test/integration/forum/serverspec/mysql_spec.rb [deleted file]
test/integration/foundation-board/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/foundation-dwg/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/foundation-mastodon/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/foundation-mwg/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/foundation-owg/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/foundation-welcome/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/foundation-wiki/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/ftp/inspec/vsftpd_spec.rb [new file with mode: 0644]
test/integration/geodns/inspec/gdsnd_spec.rb [new file with mode: 0644]
test/integration/git-web/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/git-web/inspec/gitweb_spec.rb [new file with mode: 0644]
test/integration/git/inspec/git_spec.rb [new file with mode: 0644]
test/integration/gps-tile/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/gps-tile/inspec/gpsupdate_spec.rb [new file with mode: 0644]
test/integration/hot/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/ideditor/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/imagery-tiler/inspec/nginx_spec.rb [new file with mode: 0644]
test/integration/imagery-tiler/inspec/tiler_spec.rb [new file with mode: 0644]
test/integration/irc/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/kibana/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/logstash-forwarder/inspec/filebeat_spec.rb [new file with mode: 0644]
test/integration/logstash/inspec/elasticsearch_spec.rb [new file with mode: 0644]
test/integration/logstash/inspec/logstash_spec.rb [new file with mode: 0644]
test/integration/mail/inspec/clamav_spec.rb [new file with mode: 0644]
test/integration/mail/inspec/exim_spec.rb [new file with mode: 0644]
test/integration/mail/inspec/spamassassin_spec.rb [new file with mode: 0644]
test/integration/mailman/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/mailman/inspec/mailman_spec.rb [new file with mode: 0644]
test/integration/matomo/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/memcached/inspec/memcached_spec.rb [new file with mode: 0644]
test/integration/munin-server/serverspec/apache_spec.rb [deleted file]
test/integration/munin-server/serverspec/munin_spec.rb [deleted file]
test/integration/munin-server/serverspec/rrdcached_spec.rb [deleted file]
test/integration/munin/serverspec/munin_node_spec.rb [deleted file]
test/integration/mysql/inspec/mysql_spec.rb [new file with mode: 0644]
test/integration/mysql/serverspec/mysql_spec.rb [deleted file]
test/integration/networking/inspec/nftables_spec.rb [new file with mode: 0644]
test/integration/networking/serverspec/shorewall_spec.rb [deleted file]
test/integration/nginx/inspec/nginx_spec.rb [new file with mode: 0644]
test/integration/nodejs/inspec/nodejs_spec.rb [new file with mode: 0644]
test/integration/nominatim/inspec/nginx_spec.rb [new file with mode: 0644]
test/integration/ntp/inspec/chronyd_spec.rb [new file with mode: 0644]
test/integration/openssh/inspec/openssh_spec.rb [new file with mode: 0644]
test/integration/osmosis/inspec/osmosis_spec.rb [new file with mode: 0644]
test/integration/osqa/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/otrs-debian/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/otrs/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/overpass/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/php-apache/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/planet-dump/inspec/planetdump_spec.rb [new file with mode: 0644]
test/integration/planet-notes/inspec/planetdump_spec.rb [new file with mode: 0644]
test/integration/planet/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/postgresql/inspec/postgresql_spec.rb [new file with mode: 0644]
test/integration/prometheus-server/inspec/alertmanager_spec.rb [new file with mode: 0644]
test/integration/prometheus-server/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/prometheus-server/inspec/grafana_spec.rb [new file with mode: 0644]
test/integration/prometheus-server/inspec/karma_spec.rb [new file with mode: 0644]
test/integration/prometheus-server/inspec/prometheus_spec.rb [new file with mode: 0644]
test/integration/prometheus/inspec/prometheus_node_exporter_spec.rb [new file with mode: 0644]
test/integration/rsyncd/inspec/rsync_spec.rb [new file with mode: 0644]
test/integration/serverinfo/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/snmpd/inspec/snmpd_spec.rb [new file with mode: 0644]
test/integration/spamassassin/inspec/spamassassin_spec.rb [new file with mode: 0644]
test/integration/stateofthemap-container/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/stateofthemap-wordpress/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/subversion/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/supybot/inspec/supybot_spec.rb [new file with mode: 0644]
test/integration/switch2osm/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/sysfs/inspec/sysfsutils_spec.rb [new file with mode: 0644]
test/integration/taginfo/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/tile/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/trac/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/web-cgimap/inspec/cgimap_spec.rb [new file with mode: 0644]
test/integration/web-frontend/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/web-frontend/inspec/cgimap_spec.rb [new file with mode: 0644]
test/integration/web-frontend/inspec/memcached_spec.rb [new file with mode: 0644]
test/integration/web-frontend/inspec/rails_spec.rb [new file with mode: 0644]
test/integration/web-rails/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/web-rails/inspec/rails_spec.rb [new file with mode: 0644]
test/integration/wiki/inspec/apache_spec.rb [new file with mode: 0644]
test/integration/wordpress/inspec/apache_spec.rb [new file with mode: 0644]

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644 (file)
index 0000000..9f77688
--- /dev/null
@@ -0,0 +1,10 @@
+version: 2
+updates:
+  - package-ecosystem: "bundler"
+    directory: "/"
+    schedule:
+      interval: "daily"
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "daily"
diff --git a/.github/workflows/cookstyle.yml b/.github/workflows/cookstyle.yml
new file mode 100644 (file)
index 0000000..b9332e2
--- /dev/null
@@ -0,0 +1,24 @@
+name: Cookstyle
+
+on:
+  - push
+  - pull_request
+  - workflow_dispatch
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  cookstyle:
+    name: Cookstyle
+    runs-on: ubuntu-latest
+    steps:
+    - name: Check out code
+      uses: actions/checkout@v4
+    - name: Setup ruby
+      uses: ruby/setup-ruby@v1
+      with:
+        bundler-cache: true
+    - name: Run cookstyle
+      run: bundle exec cookstyle --format fuubar
diff --git a/.github/workflows/test-kitchen.yml b/.github/workflows/test-kitchen.yml
new file mode 100644 (file)
index 0000000..bbcae2b
--- /dev/null
@@ -0,0 +1,153 @@
+name: Test Kitchen
+
+on:
+  - push
+  - pull_request
+  - workflow_dispatch
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  kitchen:
+    name: Test Kitchen
+    runs-on: ubuntu-22.04
+    permissions:
+      packages: read
+    strategy:
+      matrix:
+        suite:
+          - accounts
+          - apache
+          - apt
+          - backup
+          - bind
+          - blog
+          - blogs
+          - chef
+          - civicrm
+          - clamav
+          - community
+          - db-backup
+          - db-base
+          - db-master
+          - db-slave
+          - devices
+          - dhcpd
+          - dmca
+          - dns
+          - docker
+          - elasticsearch
+          - exim
+          - fail2ban
+          - foundation-board
+          - foundation-dwg
+          - foundation-mastodon
+          - foundation-mwg
+          - foundation-owg
+          - foundation-welcome
+          - foundation-wiki
+          - ftp
+          - geodns
+          - geoipupdate
+          - git
+          - git-server
+          - git-web
+          - gps-tile
+          - hardware
+          - hot
+          - ideditor
+          - irc
+          - kibana
+          - letsencrypt
+          - logstash
+          - logstash-forwarder
+          - mail
+          - mailman
+          - matomo
+          - memcached
+          - mysql
+          - networking
+          - nginx
+          - nodejs
+          - nominatim
+          - ntp
+          - openssh
+          - osmosis
+          - osqa
+          - otrs
+          - overpass
+          - passenger
+          - php
+          - php-apache
+          - php-fpm
+          - planet
+          - planet-aws
+          - planet-current
+          - planet-dump
+          - planet-notes
+          - planet-replication
+          - postgresql
+          - prometheus
+          - prometheus-server
+          - python
+          - rsyncd
+          - serverinfo
+          - snmpd
+          - spamassassin
+          - ssl
+          - stateofthemap-container
+          - stateofthemap-wordpress
+          - subversion
+          - supybot
+          - switch2osm
+          - sysctl
+          - sysfs
+          - taginfo
+          - tile
+          - tilelog
+          - tools
+          - trac
+          - web-cgimap
+          - web-frontend
+          - web-rails
+          - wordpress
+          - wiki
+        os:
+          - ubuntu-2204
+        include:
+          - os: ubuntu-2004
+            suite: mailman
+          - os: ubuntu-2004
+            suite: osqa
+          - os: debian-12
+            suite: imagery-tiler
+        exclude:
+          - suite: mailman
+            os: ubuntu-2204
+          - suite: osqa
+            os: ubuntu-2204
+      fail-fast: false
+    steps:
+    - name: Login to GitHub Container Registry
+      uses: docker/login-action@v3
+      with:
+        registry: ghcr.io
+        username: ${{ github.actor }}
+        password: ${{ secrets.GITHUB_TOKEN }}
+    - name: Check out code
+      uses: actions/checkout@v4
+    - name: Setup ruby
+      uses: ruby/setup-ruby@v1
+      with:
+        ruby-version: 3.1
+        bundler-cache: true
+    - name: Run kitchen test ${{ matrix.suite }}-${{ matrix.os }}
+      run: bundle exec kitchen test ${{ matrix.suite }}-${{ matrix.os }}
+    - name: Gather journal output
+      run: |
+        bundle exec kitchen exec ${{ matrix.suite }}-${{ matrix.os }} -c "journalctl --since=yesterday"
+        bundle exec kitchen exec ${{ matrix.suite }}-${{ matrix.os }} -c "networkctl status --all"
+        bundle exec kitchen exec ${{ matrix.suite }}-${{ matrix.os }} -c "resolvectl status" || true
+      if: ${{ failure() }}
index 82d1b5caa3af3d2a880e01e105742b24fff0a22a..b31363aa4261a906fae966c5edcd8217fea66a57 100644 (file)
@@ -1,2 +1,3 @@
+.DS_Store
 .kitchen/
 .kitchen.local.yml
diff --git a/.kitchen.provision.rb b/.kitchen.provision.rb
deleted file mode 100644 (file)
index 8398bd5..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Vagrant.configure(2) do |config|
-  config.vm.provision "shell", :inline => <<-SHELL
-    apt-get update -y
-  SHELL
-end
index 1b49363e6b13698d9dc3108e01e4596527ccb2b2..f439c27944ddc46e6fda45b31f64d7ad58102aa7 100644 (file)
@@ -1,16 +1,65 @@
 ---
 driver:
-  name: vagrant
-  provision: true
-  vagrantfiles:
-    - .kitchen.provision.rb
+  name: dokken
+  chef_version: 18
+  volumes:
+    - /var/lib/docker
+  env:
+    - container=dokken
+  ipv6: true
+  ipv6_subnet: "fd95:8552:964c::/64"
+  dns:
+    - 8.8.8.8
+    - 8.8.4.4
+    - 1.1.1.1
+    - 1.0.0.1
+
+transport:
+  name: dokken
 
 provisioner:
-  name: chef_zero
+  name: dokken
+  chef_license: accept
   data_bags_path: test/data_bags
+  slow_resource_report: true
+  clean_dokken_sandbox: true
+  attributes:
+    networking:
+      dnssec: "false" # Disable DNSSEC as occasionally unreliable in GitHub Actions
+
+verifier:
+  name: inspec
+  root_path: /opt/verifier
+  sudo: false
 
 platforms:
-  - name: ubuntu-16.04
+  - name: ubuntu-20.04
+    driver:
+      image: ghcr.io/test-kitchen/dokken/ubuntu-20.04
+      privileged: true
+      pid_one_command: /bin/systemd
+      intermediate_instructions:
+        - RUN /usr/bin/apt-get update -y
+        - RUN /usr/bin/apt-get install -y eatmydata
+        - RUN echo /usr/lib/$(uname -m)-linux-gnu/libeatmydata.so >>/etc/ld.so.preload
+  - name: ubuntu-22.04
+    driver:
+      image: ghcr.io/test-kitchen/dokken/ubuntu-22.04
+      privileged: true
+      pid_one_command: /bin/systemd
+      intermediate_instructions:
+        - RUN /usr/bin/apt-get update -y
+        - RUN /usr/bin/apt-get install -y eatmydata
+        - RUN echo /usr/lib/$(uname -m)-linux-gnu/libeatmydata.so >>/etc/ld.so.preload
+  - name: debian-12
+    driver:
+      image: ghcr.io/test-kitchen/dokken/debian-12
+      privileged: true
+      pid_one_command: /bin/systemd
+      intermediate_instructions:
+        - RUN /usr/bin/apt-get update -y
+        - RUN /usr/bin/apt-get install -y eatmydata
+        - RUN echo /usr/lib/$(uname -m)-linux-gnu/libeatmydata.so >>/etc/ld.so.preload
 
 suites:
   - name: accounts
@@ -19,52 +68,356 @@ suites:
   - name: apache
     run_list:
       - recipe[apache::default]
-  - name: apache-ssl
-    run_list:
-      - recipe[apache::ssl]
   - name: apt
     run_list:
       - recipe[apt::default]
+  - name: awscli
+    run_list:
+      - recipe[awscli::default]
+  - name: backup
+    run_list:
+      - recipe[backup::default]
   - name: bind
     run_list:
       - recipe[bind::default]
+    attributes:
+      bind:
+        clients: none
+  - name: blog
+    run_list:
+      - recipe[blog::default]
   - name: blogs
     run_list:
-      - recipe[accounts::default]
       - recipe[blogs::default]
-  - name: forum
+  - name: chef
     run_list:
-      - recipe[accounts::default]
-      - role[forum]
+      - recipe[chef::default]
+  - name: civicrm
+    run_list:
+      - recipe[civicrm::default]
+  - name: clamav
+    run_list:
+      - recipe[clamav::default]
+  - name: community
+    run_list:
+      - recipe[community::default]
+  - name: db-backup
+    run_list:
+      - recipe[db::backup]
+  - name: db-base
+    run_list:
+      - recipe[db::base]
+  - name: db-master
+    run_list:
+      - recipe[db::master]
+  - name: db-slave
+    run_list:
+      - recipe[db::slave]
+  - name: devices
+    run_list:
+      - recipe[devices::default]
+  - name: dhcpd
+    run_list:
+      - recipe[dhcpd::default]
+    attributes:
+      dhcpd:
+        first_address: 172.18.100.1
+        last_address: 172.18.100.254
+      networking:
+        interfaces:
+          test:
+            interface: eth0
+            role: internal
+            inet:
+              address: 172.18.0.2
+              prefix: 16
+              gateway: 172.18.0.1
+        roles:
+          external:
+            zone: test
+  - name: dmca
+    run_list:
+      - recipe[dmca::default]
+  - name: dns
+    run_list:
+      - recipe[dns::default]
+  - name: docker
+    run_list:
+      - recipe[docker::default]
+  - name: elasticsearch
+    run_list:
+      - recipe[elasticsearch::default]
+  - name: exim
+    run_list:
+      - recipe[exim::default]
+  - name: fail2ban
+    run_list:
+      - recipe[fail2ban::default]
+  - name: foundation-board
+    run_list:
+      - recipe[foundation::board]
+  - name: foundation-dwg
+    run_list:
+      - recipe[foundation::dwg]
+  - name: foundation-mastodon
+    run_list:
+      - recipe[foundation::mastodon]
+  - name: foundation-mwg
+    run_list:
+      - recipe[foundation::mwg]
+  - name: foundation-owg
+    run_list:
+      - recipe[foundation::owg]
+  - name: foundation-welcome
+    run_list:
+      - recipe[foundation::welcome]
+  - name: foundation-wiki
+    run_list:
+      - recipe[foundation::wiki]
+  - name: ftp
+    run_list:
+      - recipe[ftp::default]
+  - name: geodns
+    run_list:
+      - recipe[geodns::default]
+    attributes:
+      networking:
+        interfaces:
+          test:
+            role: external
+            inet:
+              address: 172.18.0.2
+              prefix: 16
+  - name: geoipupdate
+    run_list:
+      - recipe[geoipupdate::default]
+  - name: git
+    run_list:
+      - recipe[git::default]
+  - name: git-server
+    run_list:
+      - recipe[git::server]
+  - name: git-web
+    run_list:
+      - recipe[git::web]
+  - name: gps-tile
+    run_list:
+      - recipe[gps-tile::default]
+  - name: hardware
+    run_list:
+      - recipe[hardware::default]
+  - name: hot
+    run_list:
+      - recipe[hot::default]
+  - name: ideditor
+    run_list:
+      - recipe[ideditor::default]
+  - name: imagery-tiler
+    run_list:
+      - recipe[imagery::tiler]
+  - name: irc
+    run_list:
+      - recipe[irc::default]
+  - name: kibana
+    run_list:
+      - recipe[kibana::default]
   - name: letsencrypt
     run_list:
-      - recipe[accounts::default]
-      - recipe[apt::default]
-      - role[letsencrypt]
+      - recipe[letsencrypt::default]
+  - name: logstash
+    run_list:
+      - recipe[logstash::default]
+  - name: logstash-forwarder
+    run_list:
+      - recipe[logstash::forwarder]
     attributes:
-      apt:
-        sources:
-          - openstreetmap
-  - name: munin
+      logstash:
+        forwarder:
+          filebeat.inputs:
+            - type: filestream
+              id: apache
+              paths:
+                - /var/log/apache2/access.log
+              fields:
+                type: apache
+              fields_under_root: true
+  - name: mail
+    run_list:
+      - role[mail]
+  - name: mailman
     run_list:
-      - recipe[munin::default]
-  - name: munin-server
+      - recipe[mailman::default]
+  - name: matomo
     run_list:
-      - recipe[munin::server]
+      - recipe[matomo::default]
+  - name: memcached
+    run_list:
+      - recipe[memcached::default]
   - name: mysql
     run_list:
       - recipe[mysql::default]
   - name: networking
     run_list:
       - recipe[networking::default]
+  - name: nginx
+    run_list:
+      - recipe[nginx::default]
+  - name: nodejs
+    run_list:
+      - recipe[nodejs::default]
+  - name: nominatim
+    run_list:
+      - recipe[nominatim::default]
+  - name: ntp
+    run_list:
+      - recipe[ntp::default]
+  - name: openssh
+    run_list:
+      - recipe[openssh::default]
+  - name: osmosis
+    run_list:
+      - recipe[osmosis::default]
+  - name: osqa
+    run_list:
+      - recipe[osqa::default]
   - name: otrs
     run_list:
-      - recipe[accounts::default]
-      - recipe[chef::default]
-      - role[otrs]
+      - recipe[otrs::default]
+  - name: otrs-debian
+    run_list:
+      - recipe[otrs::debian]
+  - name: overpass
+    run_list:
+      - recipe[overpass::default]
+  - name: passenger
+    run_list:
+      - recipe[passenger::default]
+  - name: php
+    run_list:
+      - recipe[php::default]
+  - name: php-apache
+    run_list:
+      - recipe[php::apache]
+  - name: php-fpm
+    run_list:
+      - recipe[php::fpm]
+  - name: planet
+    run_list:
+      - recipe[planet::default]
+  - name: planet-aws
+    run_list:
+      - recipe[planet::aws]
+  - name: planet-current
+    run_list:
+      - recipe[planet::current]
+  - name: planet-dump
+    run_list:
+      - recipe[planet::dump]
+  - name: planet-notes
+    run_list:
+      - recipe[planet::notes]
+    attributes:
+      web:
+        readonly_database_host: readonly
+  - name: planet-replication
+    run_list:
+      - recipe[planet::replication]
+    attributes:
+      web:
+        readonly_database_host: readonly
+  - name: postgresql
+    run_list:
+      - recipe[postgresql::default]
+    attributes:
+      postgresql:
+        versions:
+          - 15
+  - name: prometheus
+    run_list:
+      - recipe[prometheus::default]
+    attributes:
+      networking:
+        interfaces:
+          test:
+            interface: eth0
+            role: internal
+            inet:
+              address: 172.18.0.2
+              prefix: 16
+              gateway: 172.18.0.1
+  - name: prometheus-server
+    run_list:
+      - recipe[prometheus::server]
   - name: python
     run_list:
       - recipe[python::default]
+  - name: rsyncd
+    run_list:
+      - recipe[rsyncd::default]
+  - name: serverinfo
+    run_list:
+      - recipe[serverinfo::default]
+  - name: snmpd
+    run_list:
+      - recipe[snmpd::default]
+  - name: spamassassin
+    run_list:
+      - recipe[spamassassin::default]
+  - name: ssl
+    run_list:
+      - recipe[ssl::default]
+  - name: stateofthemap-container
+    run_list:
+      - recipe[stateofthemap::container]
+  - name: stateofthemap-wordpress
+    run_list:
+      - recipe[stateofthemap::wordpress]
+  - name: subversion
+    run_list:
+      - recipe[subversion::default]
+  - name: supybot
+    run_list:
+      - recipe[supybot::default]
+  - name: switch2osm
+    run_list:
+      - recipe[switch2osm::default]
+  - name: sysctl
+    run_list:
+      - recipe[sysctl::default]
+  - name: sysfs
+    run_list:
+      - recipe[sysfs::default]
+  - name: taginfo
+    run_list:
+      - recipe[taginfo::default]
+    attributes:
+      taginfo:
+        sites:
+          - name: taginfo.example.com
+  - name: tile
+    run_list:
+      - recipe[tile::default]
+  - name: tilelog
+    run_list:
+      - recipe[tilelog::default]
   - name: tools
     run_list:
       - recipe[tools::default]
+  - name: trac
+    run_list:
+      - recipe[trac::default]
+  - name: web-cgimap
+    run_list:
+      - recipe[web::cgimap]
+  - name: web-frontend
+    run_list:
+      - recipe[web::frontend]
+  - name: web-rails
+    run_list:
+      - recipe[web::rails]
+  - name: wiki
+    run_list:
+      - recipe[wiki::default]
+  - name: wordpress
+    run_list:
+      - recipe[wordpress::default]
index 90f166d5b9fab3b4f4b2d6ad5fc35d92eea916da..15718e51933286e21d1edb4d70fac5f8d649b42f 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -1,3 +1,3 @@
-Grant Slater <openstreetmap@firefishy.com> <git@firefishy.com>
+Grant Slater <openstreetmap@firefishy.com> <git@firefishy.com> <grant.slater@wearefriday.com> <github@firefishy.com>
 Guillaume Rischard <git@stereo.lu> <github@stereo.lu>
 Jochen Topf <jochen@topf.org> <jochen@remote.org>
index 5db1a31045524667dabbea1a6aaf55863ffa3ed4..d3e607a069bb15bf76870686de76ac7f54dd2cbc 100644 (file)
@@ -1,17 +1,26 @@
 inherit_from: .rubocop_todo.yml
 
 AllCops:
-  TargetRubyVersion: 2.3
+  TargetRubyVersion: 3.1
+
+Chef/Modernize/IncludingAptDefaultRecipe:
+  Enabled: false
+  
+Chef/Modernize/CronDFileOrTemplate:
+  Enabled: false
 
 Layout/ExtraSpacing:
   AllowForAlignment: true
 
-Layout/IndentHeredoc:
-  EnforcedStyle: squiggly
+Layout/HeredocIndentation:
+  Enabled: true
 
-Naming/UncommunicativeMethodParamName:
+Naming/MethodParameterName:
   Enabled: false
 
+Style/CommandLiteral:
+  EnforcedStyle: percent_x
+
 Style/HashSyntax:
   EnforcedStyle: hash_rockets
 
index 03f9944def5692d31fb2985bad578fbb945a157a..a92cef294acfb249ea45ca0dde559e5fc631b239 100644 (file)
@@ -1,45 +1,14 @@
 # This configuration was generated by
 # `rubocop --auto-gen-config`
-# on 2019-11-26 22:24:47 +0000 using RuboCop version 0.75.1.
+# on 2021-05-11 07:26:15 UTC using RuboCop version 1.14.0.
 # The point is for the user to remove these configuration records
 # one by one as the offenses are removed from the code base.
 # Note that changes in the inspected code, or installation of new
 # versions of RuboCop, may require this file to be generated again.
 
-# Offense count: 14
-ChefCorrectness/NodeNormal:
-  Exclude:
-    - '**/metadata.rb'
-    - 'cookbooks/dev/recipes/default.rb'
-    - 'cookbooks/mediawiki/resources/site.rb'
-    - 'cookbooks/networking/recipes/default.rb'
-    - 'cookbooks/openvpn/recipes/default.rb'
-    - 'cookbooks/web/recipes/backend.rb'
-    - 'cookbooks/wordpress/resources/site.rb'
-
-# Offense count: 12
-ChefCorrectness/NodeNormalUnless:
-  Exclude:
-    - '**/metadata.rb'
-    - 'cookbooks/mailman/recipes/default.rb'
-    - 'cookbooks/mediawiki/resources/site.rb'
-    - 'cookbooks/wordpress/resources/site.rb'
-
-# Offense count: 1
-# Configuration parameters: Include.
-# Include: **/definitions/*.rb
-ChefModernize/Definitions:
-  Exclude:
-    - 'cookbooks/networking/definitions/firewall_rule.rb'
-
-# Offense count: 951
+# Offense count: 1124
 # Cop supports --auto-correct.
 # Configuration parameters: .
 # SupportedStyles: strings, symbols
-ChefStyle/AttributeKeys:
+Chef/Style/AttributeKeys:
   EnforcedStyle: symbols
-
-# Offense count: 468
-# Cop supports --auto-correct.
-ChefStyle/FileMode:
-  Enabled: false
index 7bf4b6a8aeff6ff21de600580d06d0047d6a34f0..0aec50e6ede78cfcb00d159fc0932ce35a80cb87 100644 (file)
@@ -1 +1 @@
-2.4.6
+3.1.4
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644 (file)
index 87e77d6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-sudo: false
-language: ruby
-cache: bundler
-script:
-  - bundle exec cookstyle -f fuubar
index 256d0ae6abb8fe9291eb1880f264d8fe5e358bc9..5345a078628ee051e9047c8e2dc256dfde2adc30 100644 (file)
@@ -9,3 +9,69 @@ https://help.github.com/articles/using-pull-requests
 You should fork the project into your own repo, create a topic branch
 there and then make one or more pull requests back to the openstreetmap/chef repository.
 Your pull requests will then be reviewed and discussed.
+
+## Running the Infrastructure Tests locally
+
+- **[Cookstyle](https://docs.chef.io/workstation/cookstyle/)** is used for linting, ensuring that our Chef recipes follow style guidelines and best practices.
+- **[Test Kitchen](https://kitchen.ci/)** combined with **InSpec** and [Dokken](https://github.com/test-kitchen/kitchen-dokken) is used to verify the functionality of our Chef code, ensuring it behaves as expected.
+
+The following guidelines are to help set up and run these checks locally:
+
+#### **1. Install Docker**
+- Visit [Docker's official site](https://www.docker.com/products/docker-desktop) to download and install Docker.
+
+#### **2. Install Homebrew (Apple MacOS only)**
+- Install Homebrew by following the instructions [here](https://brew.sh/).
+
+#### **3. Install rbenv (recommended)**
+- Install rbenv by following the instructions [here](https://github.com/rbenv/rbenv#installation).
+
+rbenv is a ruby version manager. rbenv allows projects to use a different version of ruby than the version of install with your operating system.
+
+> *Note on rbenv: While we recommend using rbenv for managing Ruby versions, it's not strictly necessary. If you have Ruby already installed feel free to use that. If you're not using rbenv, simply omit the `rbenv exec` prefix from the commands below.*
+
+#### **4. Increase File Limit (Important for MacOS)**
+
+To avoid errors when running tests on MacOS, you might need to increase the number of files your system can open at once. Here's how:
+
+1. Run the command:
+```bash
+ulimit -n 1024
+```
+2. To make the change permanent, add the above line to either `~/.zshrc` or `~/.bash_profile`, depending on your shell.
+
+**Note:** MacOS has a low default limit of just 256 open files. If you exceed this while testing, you'll see an error like: `Too many open files - getcwd (Errno::EMFILE)`. This step helps prevent that.
+
+#### **5. Install Required Ruby Version (recommended)**
+Navigate to the git checkout of the OpenStreetMap chef repo and run:
+```bash
+rbenv install
+```
+This will install the recommended version of ruby for running the tests. The recommended version of ruby is defined in the [.ruby-version](.ruby-version) file.
+
+#### **6. Install Dependencies with Bundler**
+```bash
+rbenv exec gem install bundler
+rbenv exec bundler install
+```
+This will install the [bundler](https://bundler.io/), the ruby gem packages manager, and then uses `bundler`` to install the required gem packages for the tests.
+
+#### **7. Run Cookstyle for Linting and Style Checks**
+```bash
+rbenv exec bundle exec cookstyle
+```
+This will run [cookstyle](https://docs.chef.io/workstation/cookstyle/) a linting tool which reports on any linting issues.
+
+> *Automatically run cookstyle lint: We have a sample [git pre-commit hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) in the `hooks/pre-commit` file which can be copied to the local checkout of this repo to the file `.git/hooks/pre-commit`  to ensure the lint passes when running a git commit.*
+
+#### **8. List Available Tests**
+```bash
+rbenv exec bundler exec kitchen list
+```
+This lists the [Test Kitchen](https://kitchen.ci/) tests which are available. The list of tests is generated from the definitions in the [.kitchen.yml](.kitchen.yml) file. The individual tests are written in [InSpec](https://docs.chef.io/inspec/) and are stored in the `test/integration/` directory.
+
+#### **9. Run an Example Test**
+```bash
+rbenv exec bundler exec kitchen test dns-ubuntu-2204
+```
+This runs the [Test Kitchen](https://kitchen.ci/) [InSpec](https://docs.chef.io/inspec/) `dns` tests using the `Ubuntu 22.04` platform. The tests are run inside a Docker container using the Test Kitchen [Dokken driver](https://github.com/test-kitchen/kitchen-dokken).
index a09077debd49e040018c165fec84dfcd8eaa13c1..fa0ad5960af0f072b55c489cdb7713e6a8629096 100644 (file)
@@ -1,6 +1,6 @@
 # Basic Dockerfile to run cookstyle linting
-# run: docker build -t test .
-FROM ruby:2.6-alpine as build
+# run: docker build -t chef-test .
+FROM ruby:3.1-alpine as build
 
 # Add Gem build requirements
 RUN apk add --no-cache build-base
diff --git a/Gemfile b/Gemfile
index ddf1c6b1cab9ab4372204993ddcb4570689bc5e1..ec9eb03b0c0f47c6449890a17e1b0db94df0b0b8 100644 (file)
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
 source "https://rubygems.org"
 
 gem "cookstyle"
-gem "kitchen-vagrant"
-gem "serverspec"
+gem "kitchen-dokken"
+gem "kitchen-inspec"
 gem "test-kitchen"
index 2744ce864ec5a338239f5ec0aadeca72faf021d5..91643f30aa61faef946b00e3a4ea98da1fdc925d 100644 (file)
 GEM
   remote: https://rubygems.org/
   specs:
-    ast (2.4.0)
-    bcrypt_pbkdf (1.0.1)
-    builder (3.2.3)
-    cookstyle (5.13.7)
-      rubocop (= 0.75.1)
-    diff-lcs (1.3)
-    ed25519 (1.2.4)
-    equatable (0.6.1)
-    erubi (1.9.0)
-    ffi (1.11.3)
-    gssapi (1.3.0)
+    activesupport (7.1.3.2)
+      base64
+      bigdecimal
+      concurrent-ruby (~> 1.0, >= 1.0.2)
+      connection_pool (>= 2.2.5)
+      drb
+      i18n (>= 1.6, < 2)
+      minitest (>= 5.1)
+      mutex_m
+      tzinfo (~> 2.0)
+    addressable (2.8.6)
+      public_suffix (>= 2.0.2, < 6.0)
+    ast (2.4.2)
+    aws-eventstream (1.3.0)
+    aws-partitions (1.863.0)
+    aws-sdk-accessanalyzer (1.44.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-account (1.20.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-alexaforbusiness (1.67.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-amplify (1.54.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-apigateway (1.90.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-apigatewayv2 (1.53.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-applicationautoscaling (1.79.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-athena (1.79.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-autoscaling (1.102.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-batch (1.79.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-budgets (1.62.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudformation (1.97.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudfront (1.86.1)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudhsm (1.50.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudhsmv2 (1.53.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudtrail (1.74.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudwatch (1.83.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudwatchevents (1.69.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cloudwatchlogs (1.77.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-codecommit (1.62.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-codedeploy (1.62.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-codepipeline (1.67.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cognitoidentity (1.51.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-cognitoidentityprovider (1.85.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-configservice (1.103.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-core (3.190.3)
+      aws-eventstream (~> 1, >= 1.3.0)
+      aws-partitions (~> 1, >= 1.651.0)
+      aws-sigv4 (~> 1.8)
+      jmespath (~> 1, >= 1.6.1)
+    aws-sdk-costandusagereportservice (1.53.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-databasemigrationservice (1.91.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-dynamodb (1.98.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-ec2 (1.429.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-ecr (1.68.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-ecrpublic (1.25.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-ecs (1.135.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-efs (1.71.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-eks (1.95.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-elasticache (1.95.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-elasticbeanstalk (1.63.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-elasticloadbalancing (1.51.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-elasticloadbalancingv2 (1.96.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-elasticsearchservice (1.79.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-emr (1.81.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-eventbridge (1.54.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-firehose (1.60.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-glue (1.165.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-guardduty (1.85.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-iam (1.92.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-kafka (1.67.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-kinesis (1.54.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-kms (1.76.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-lambda (1.113.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-macie2 (1.64.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-mq (1.58.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-networkfirewall (1.39.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-networkmanager (1.40.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-organizations (1.83.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-ram (1.52.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-rds (1.208.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-redshift (1.107.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-route53 (1.83.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-route53domains (1.54.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-route53resolver (1.51.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-s3 (1.141.0)
+      aws-sdk-core (~> 3, >= 3.189.0)
+      aws-sdk-kms (~> 1)
+      aws-sigv4 (~> 1.8)
+    aws-sdk-s3control (1.74.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-secretsmanager (1.87.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-securityhub (1.98.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-servicecatalog (1.90.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-ses (1.58.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-shield (1.60.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-signer (1.50.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-simpledb (1.42.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv2 (~> 1.0)
+    aws-sdk-sms (1.52.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-sns (1.70.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-sqs (1.69.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-ssm (1.162.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-states (1.63.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-synthetics (1.39.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-transfer (1.86.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-waf (1.58.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sdk-wafv2 (1.74.0)
+      aws-sdk-core (~> 3, >= 3.188.0)
+      aws-sigv4 (~> 1.1)
+    aws-sigv2 (1.2.0)
+    aws-sigv4 (1.8.0)
+      aws-eventstream (~> 1, >= 1.0.2)
+    azure_graph_rbac (0.17.2)
+      ms_rest_azure (~> 0.12.0)
+    azure_mgmt_key_vault (0.17.7)
+      ms_rest_azure (~> 0.12.0)
+    azure_mgmt_resources (0.18.2)
+      ms_rest_azure (~> 0.12.0)
+    azure_mgmt_security (0.19.0)
+      ms_rest_azure (~> 0.12.0)
+    azure_mgmt_storage (0.23.0)
+      ms_rest_azure (~> 0.12.0)
+    base64 (0.2.0)
+    bcrypt_pbkdf (1.1.0)
+    bigdecimal (3.1.7)
+    bson (4.15.0)
+    builder (3.2.4)
+    chef-config (18.4.12)
+      addressable
+      chef-utils (= 18.4.12)
+      fuzzyurl
+      mixlib-config (>= 2.2.12, < 4.0)
+      mixlib-shellout (>= 2.0, < 4.0)
+      tomlrb (~> 1.2)
+    chef-telemetry (1.1.1)
+      chef-config
+      concurrent-ruby (~> 1.0)
+    chef-utils (18.4.12)
+      concurrent-ruby
+    coderay (1.1.3)
+    concurrent-ruby (1.2.3)
+    connection_pool (2.4.1)
+    cookstyle (7.32.8)
+      rubocop (= 1.25.1)
+    declarative (0.0.20)
+    diff-lcs (1.5.1)
+    docker-api (2.2.0)
+      excon (>= 0.47.0)
+      multi_json
+    domain_name (0.6.20240107)
+    drb (2.2.1)
+    dry-configurable (1.1.0)
+      dry-core (~> 1.0, < 2)
+      zeitwerk (~> 2.6)
+    dry-core (1.0.1)
+      concurrent-ruby (~> 1.0)
+      zeitwerk (~> 2.6)
+    dry-inflector (1.0.0)
+    dry-logic (1.5.0)
+      concurrent-ruby (~> 1.0)
+      dry-core (~> 1.0, < 2)
+      zeitwerk (~> 2.6)
+    dry-struct (1.6.0)
+      dry-core (~> 1.0, < 2)
+      dry-types (>= 1.7, < 2)
+      ice_nine (~> 0.11)
+      zeitwerk (~> 2.6)
+    dry-types (1.7.2)
+      bigdecimal (~> 3.0)
+      concurrent-ruby (~> 1.0)
+      dry-core (~> 1.0)
+      dry-inflector (~> 1.0)
+      dry-logic (~> 1.4)
+      zeitwerk (~> 2.6)
+    ed25519 (1.3.0)
+    erubi (1.12.0)
+    excon (0.110.0)
+    faraday (1.10.3)
+      faraday-em_http (~> 1.0)
+      faraday-em_synchrony (~> 1.0)
+      faraday-excon (~> 1.1)
+      faraday-httpclient (~> 1.0)
+      faraday-multipart (~> 1.0)
+      faraday-net_http (~> 1.0)
+      faraday-net_http_persistent (~> 1.0)
+      faraday-patron (~> 1.0)
+      faraday-rack (~> 1.0)
+      faraday-retry (~> 1.0)
+      ruby2_keywords (>= 0.0.4)
+    faraday-cookie_jar (0.0.7)
+      faraday (>= 0.8.0)
+      http-cookie (~> 1.0.0)
+    faraday-em_http (1.0.0)
+    faraday-em_synchrony (1.0.0)
+    faraday-excon (1.1.0)
+    faraday-follow_redirects (0.3.0)
+      faraday (>= 1, < 3)
+    faraday-httpclient (1.0.1)
+    faraday-multipart (1.0.4)
+      multipart-post (~> 2)
+    faraday-net_http (1.0.1)
+    faraday-net_http_persistent (1.2.0)
+    faraday-patron (1.0.0)
+    faraday-rack (1.0.0)
+    faraday-retry (1.0.3)
+    faraday_middleware (1.2.0)
+      faraday (~> 1.0)
+    ffi (1.16.3)
+    fuzzyurl (0.9.0)
+    google-api-client (0.52.0)
+      addressable (~> 2.5, >= 2.5.1)
+      googleauth (~> 0.9)
+      httpclient (>= 2.8.1, < 3.0)
+      mini_mime (~> 1.0)
+      representable (~> 3.0)
+      retriable (>= 2.0, < 4.0)
+      rexml
+      signet (~> 0.12)
+    googleauth (0.14.0)
+      faraday (>= 0.17.3, < 2.0)
+      jwt (>= 1.4, < 3.0)
+      memoist (~> 0.16)
+      multi_json (~> 1.11)
+      os (>= 0.9, < 2.0)
+      signet (~> 0.14)
+    gssapi (1.3.1)
       ffi (>= 1.0.1)
-    gyoku (1.3.1)
+    gyoku (1.4.0)
       builder (>= 2.1.2)
+      rexml (~> 3.0)
+    hashdiff (1.0.1)
+    hashie (5.0.0)
+    highline (2.1.0)
+    http-cookie (1.0.5)
+      domain_name (~> 0.5)
     httpclient (2.8.3)
-    jaro_winkler (1.5.4)
-    kitchen-vagrant (1.6.0)
-      test-kitchen (>= 1.4, < 3)
-    license-acceptance (1.0.13)
+    i18n (1.14.4)
+      concurrent-ruby (~> 1.0)
+    ice_nine (0.11.2)
+    inifile (3.0.0)
+    inspec (5.22.40)
+      cookstyle
+      faraday_middleware (>= 0.12.2, < 1.3)
+      inspec-core (= 5.22.40)
+      mongo (= 2.13.2)
+      progress_bar (~> 1.3.3)
+      rake
+      train (~> 3.10)
+      train-aws (~> 0.2)
+      train-habitat (~> 0.1)
+      train-kubernetes (~> 0.1)
+      train-winrm (~> 0.2)
+    inspec-core (5.22.40)
+      addressable (~> 2.4)
+      chef-telemetry (~> 1.0, >= 1.0.8)
+      faraday (>= 1, < 3)
+      faraday-follow_redirects (~> 0.3)
+      hashie (>= 3.4, < 6.0)
+      license-acceptance (>= 0.2.13, < 3.0)
+      method_source (>= 0.8, < 2.0)
+      mixlib-log (~> 3.0)
+      multipart-post (~> 2.0)
+      parallel (~> 1.9)
+      parslet (>= 1.5, < 3.0)
+      pry (~> 0.13)
+      rspec (>= 3.9, <= 3.12)
+      rspec-its (~> 1.2)
+      rubyzip (>= 1.2.2, < 3.0)
+      semverse (~> 3.0)
+      sslshake (~> 1.2)
+      thor (>= 0.20, < 1.3.0)
+      tomlrb (>= 1.2, < 2.1)
+      train-core (~> 3.10)
+      tty-prompt (~> 0.17)
+      tty-table (~> 0.10)
+    jmespath (1.6.2)
+    json (2.7.1)
+    jsonpath (1.1.5)
+      multi_json
+    jwt (2.8.1)
+      base64
+    k8s-ruby (0.16.0)
+      dry-configurable
+      dry-struct
+      dry-types
+      excon (~> 0.71)
+      hashdiff (~> 1.0.0)
+      jsonpath (~> 1.1)
+      recursive-open-struct (~> 1.1.3)
+      yajl-ruby (~> 1.4.0)
+      yaml-safe_load_stream3
+    kitchen-dokken (2.20.4)
+      docker-api (>= 1.33, < 3)
+      lockfile (~> 2.1)
+      test-kitchen (>= 1.15, < 4)
+    kitchen-inspec (2.6.2)
+      hashie (>= 3.4, <= 5.0)
+      inspec (>= 2.2.64, < 6.0)
+      test-kitchen (>= 2.7, < 4)
+    license-acceptance (2.1.13)
       pastel (~> 0.7)
-      tomlrb (~> 1.2)
-      tty-box (~> 0.3)
-      tty-prompt (~> 0.18)
+      tomlrb (>= 1.2, < 3.0)
+      tty-box (~> 0.6)
+      tty-prompt (~> 0.20)
     little-plugger (1.1.4)
-    logging (2.2.2)
+    lockfile (2.1.3)
+    logging (2.3.1)
       little-plugger (~> 1.1)
-      multi_json (~> 1.10)
-    mixlib-install (3.11.21)
+      multi_json (~> 1.14)
+    memoist (0.16.2)
+    method_source (1.0.0)
+    mini_mime (1.1.5)
+    minitest (5.22.3)
+    mixlib-config (3.0.27)
+      tomlrb
+    mixlib-install (3.12.30)
       mixlib-shellout
       mixlib-versioning
       thor
-    mixlib-shellout (3.0.7)
-    mixlib-versioning (1.2.7)
-    multi_json (1.14.1)
-    necromancer (0.5.1)
-    net-scp (2.0.0)
-      net-ssh (>= 2.6.5, < 6.0.0)
-    net-ssh (5.2.0)
+    mixlib-log (3.0.9)
+    mixlib-shellout (3.2.7)
+      chef-utils
+    mixlib-versioning (1.2.12)
+    mongo (2.13.2)
+      bson (>= 4.8.2, < 5.0.0)
+    ms_rest (0.7.6)
+      concurrent-ruby (~> 1.0)
+      faraday (>= 0.9, < 2.0.0)
+      timeliness (~> 0.3.10)
+    ms_rest_azure (0.12.0)
+      concurrent-ruby (~> 1.0)
+      faraday (>= 0.9, < 2.0.0)
+      faraday-cookie_jar (~> 0.0.6)
+      ms_rest (~> 0.7.6)
+    multi_json (1.15.0)
+    multipart-post (2.4.0)
+    mutex_m (0.2.0)
+    net-scp (4.0.0)
+      net-ssh (>= 2.6.5, < 8.0.0)
+    net-ssh (7.2.3)
     net-ssh-gateway (2.0.0)
       net-ssh (>= 4.0.0)
-    net-telnet (0.1.1)
-    nori (2.6.0)
-    parallel (1.19.1)
-    parser (2.6.5.0)
-      ast (~> 2.4.0)
-    pastel (0.7.3)
-      equatable (~> 0.6)
+    nori (2.7.0)
+      bigdecimal
+    options (2.3.2)
+    os (1.1.4)
+    parallel (1.24.0)
+    parser (3.3.0.5)
+      ast (~> 2.4.1)
+      racc
+    parslet (2.0.0)
+    pastel (0.8.0)
       tty-color (~> 0.5)
-    rainbow (3.0.0)
-    rspec (3.9.0)
-      rspec-core (~> 3.9.0)
-      rspec-expectations (~> 3.9.0)
-      rspec-mocks (~> 3.9.0)
-    rspec-core (3.9.0)
-      rspec-support (~> 3.9.0)
-    rspec-expectations (3.9.0)
+    progress_bar (1.3.3)
+      highline (>= 1.6, < 3)
+      options (~> 2.3.0)
+    pry (0.14.2)
+      coderay (~> 1.1)
+      method_source (~> 1.0)
+    public_suffix (5.0.4)
+    racc (1.7.3)
+    rainbow (3.1.1)
+    rake (13.1.0)
+    recursive-open-struct (1.1.3)
+    regexp_parser (2.9.0)
+    representable (3.2.0)
+      declarative (< 0.1.0)
+      trailblazer-option (>= 0.1.1, < 0.2.0)
+      uber (< 0.2.0)
+    retriable (3.1.2)
+    rexml (3.2.6)
+    rspec (3.12.0)
+      rspec-core (~> 3.12.0)
+      rspec-expectations (~> 3.12.0)
+      rspec-mocks (~> 3.12.0)
+    rspec-core (3.12.3)
+      rspec-support (~> 3.12.0)
+    rspec-expectations (3.12.4)
       diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.9.0)
+      rspec-support (~> 3.12.0)
     rspec-its (1.3.0)
       rspec-core (>= 3.0.0)
       rspec-expectations (>= 3.0.0)
-    rspec-mocks (3.9.0)
+    rspec-mocks (3.12.7)
       diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.9.0)
-    rspec-support (3.9.0)
-    rubocop (0.75.1)
-      jaro_winkler (~> 1.5.1)
+      rspec-support (~> 3.12.0)
+    rspec-support (3.12.2)
+    rubocop (1.25.1)
       parallel (~> 1.10)
-      parser (>= 2.6)
+      parser (>= 3.1.0.0)
       rainbow (>= 2.2.2, < 4.0)
+      regexp_parser (>= 1.8, < 3.0)
+      rexml
+      rubocop-ast (>= 1.15.1, < 2.0)
       ruby-progressbar (~> 1.7)
-      unicode-display_width (>= 1.4.0, < 1.7)
-    ruby-progressbar (1.10.1)
-    rubyntlm (0.6.2)
-    rubyzip (2.0.0)
-    serverspec (2.41.5)
-      multi_json
-      rspec (~> 3.0)
-      rspec-its
-      specinfra (~> 2.72)
-    sfl (2.3)
-    specinfra (2.82.4)
-      net-scp
-      net-ssh (>= 2.7)
-      net-telnet (= 0.1.1)
-      sfl
-    strings (0.1.8)
-      strings-ansi (~> 0.1)
-      unicode-display_width (~> 1.5)
+      unicode-display_width (>= 1.4.0, < 3.0)
+    rubocop-ast (1.31.2)
+      parser (>= 3.3.0.4)
+    ruby-progressbar (1.13.0)
+    ruby2_keywords (0.0.5)
+    rubyntlm (0.6.3)
+    rubyzip (2.3.2)
+    semverse (3.0.2)
+    signet (0.19.0)
+      addressable (~> 2.8)
+      faraday (>= 0.17.5, < 3.a)
+      jwt (>= 1.5, < 3.0)
+      multi_json (~> 1.10)
+    sslshake (1.3.1)
+    strings (0.2.1)
+      strings-ansi (~> 0.2)
+      unicode-display_width (>= 1.5, < 3.0)
       unicode_utils (~> 1.4)
     strings-ansi (0.2.0)
-    test-kitchen (2.3.4)
+    test-kitchen (3.6.0)
       bcrypt_pbkdf (~> 1.0)
+      chef-utils (>= 16.4.35)
       ed25519 (~> 1.2)
-      license-acceptance (~> 1.0, >= 1.0.11)
+      license-acceptance (>= 1.0.11, < 3.0)
       mixlib-install (~> 3.6)
       mixlib-shellout (>= 1.2, < 4.0)
-      net-scp (>= 1.1, < 3.0)
-      net-ssh (>= 2.9, < 6.0)
+      net-scp (>= 1.1, < 5.0)
+      net-ssh (>= 2.9, < 8.0)
       net-ssh-gateway (>= 1.2, < 3.0)
-      thor (~> 0.19)
+      thor (>= 0.19, < 2.0)
       winrm (~> 2.0)
       winrm-elevated (~> 1.0)
       winrm-fs (~> 1.1)
-    thor (0.20.3)
-    tomlrb (1.2.9)
-    tty-box (0.5.0)
-      pastel (~> 0.7.2)
-      strings (~> 0.1.6)
+    thor (1.2.2)
+    timeliness (0.3.10)
+    tomlrb (1.3.0)
+    trailblazer-option (0.1.2)
+    train (3.11.0)
+      activesupport (>= 6.0.3.1)
+      azure_graph_rbac (~> 0.16)
+      azure_mgmt_key_vault (~> 0.17)
+      azure_mgmt_resources (~> 0.15)
+      azure_mgmt_security (~> 0.18)
+      azure_mgmt_storage (~> 0.18)
+      docker-api (>= 1.26, < 3.0)
+      google-api-client (>= 0.23.9, <= 0.52.0)
+      googleauth (>= 0.6.6, <= 0.14.0)
+      inifile (~> 3.0)
+      train-core (= 3.11.0)
+      train-winrm (~> 0.2)
+    train-aws (0.2.41)
+      aws-partitions (~> 1.863.0)
+      aws-sdk-accessanalyzer (~> 1.44.0)
+      aws-sdk-account (~> 1.20.0)
+      aws-sdk-alexaforbusiness (~> 1.67.0)
+      aws-sdk-amplify (~> 1.54.0)
+      aws-sdk-apigateway (~> 1.90.0)
+      aws-sdk-apigatewayv2 (~> 1.53.0)
+      aws-sdk-applicationautoscaling (~> 1.79.0)
+      aws-sdk-athena (>= 1.78, < 1.80)
+      aws-sdk-autoscaling (= 1.102.0)
+      aws-sdk-batch (~> 1.79.0)
+      aws-sdk-budgets (~> 1.62.0)
+      aws-sdk-cloudformation (>= 1.96, < 1.98)
+      aws-sdk-cloudfront (~> 1.86.0)
+      aws-sdk-cloudhsm (~> 1.50.0)
+      aws-sdk-cloudhsmv2 (~> 1.53.0)
+      aws-sdk-cloudtrail (~> 1.74.0)
+      aws-sdk-cloudwatch (~> 1.83.0)
+      aws-sdk-cloudwatchevents (~> 1.69.0)
+      aws-sdk-cloudwatchlogs (~> 1.75)
+      aws-sdk-codecommit (~> 1.62.0)
+      aws-sdk-codedeploy (~> 1.62.0)
+      aws-sdk-codepipeline (~> 1.67.0)
+      aws-sdk-cognitoidentity (~> 1.51.0)
+      aws-sdk-cognitoidentityprovider (~> 1.84)
+      aws-sdk-configservice (~> 1.103.0)
+      aws-sdk-core (~> 3.190.0)
+      aws-sdk-costandusagereportservice (~> 1.53.0)
+      aws-sdk-databasemigrationservice (~> 1.91.0)
+      aws-sdk-dynamodb (~> 1.98.0)
+      aws-sdk-ec2 (>= 1.427, < 1.430)
+      aws-sdk-ecr (~> 1.68.0)
+      aws-sdk-ecrpublic (~> 1.25.0)
+      aws-sdk-ecs (~> 1.135.0)
+      aws-sdk-efs (~> 1.71.0)
+      aws-sdk-eks (~> 1.95.0)
+      aws-sdk-elasticache (~> 1.95.0)
+      aws-sdk-elasticbeanstalk (~> 1.63.0)
+      aws-sdk-elasticloadbalancing (~> 1.51.0)
+      aws-sdk-elasticloadbalancingv2 (~> 1.96.0)
+      aws-sdk-elasticsearchservice (~> 1.79.0)
+      aws-sdk-emr (~> 1.81.0)
+      aws-sdk-eventbridge (~> 1.54.0)
+      aws-sdk-firehose (~> 1.60.0)
+      aws-sdk-glue (~> 1.164)
+      aws-sdk-guardduty (~> 1.85.0)
+      aws-sdk-iam (~> 1.92.0)
+      aws-sdk-kafka (~> 1.67.0)
+      aws-sdk-kinesis (~> 1.54.0)
+      aws-sdk-kms (~> 1.74)
+      aws-sdk-lambda (~> 1.113.0)
+      aws-sdk-macie2 (~> 1.64.0)
+      aws-sdk-mq (~> 1.58.0)
+      aws-sdk-networkfirewall (~> 1.39.0)
+      aws-sdk-networkmanager (~> 1.40.0)
+      aws-sdk-organizations (~> 1.83.0)
+      aws-sdk-ram (~> 1.52.0)
+      aws-sdk-rds (~> 1.208.0)
+      aws-sdk-redshift (~> 1.107.0)
+      aws-sdk-route53 (~> 1.83.0)
+      aws-sdk-route53domains (~> 1.54.0)
+      aws-sdk-route53resolver (~> 1.51.0)
+      aws-sdk-s3 (~> 1.141.0)
+      aws-sdk-s3control (~> 1.74.0)
+      aws-sdk-secretsmanager (~> 1.87.0)
+      aws-sdk-securityhub (~> 1.98.0)
+      aws-sdk-servicecatalog (~> 1.90.0)
+      aws-sdk-ses (~> 1.58.0)
+      aws-sdk-shield (~> 1.60.0)
+      aws-sdk-signer (~> 1.50.0)
+      aws-sdk-simpledb (~> 1.42.0)
+      aws-sdk-sms (~> 1.52.0)
+      aws-sdk-sns (~> 1.70.0)
+      aws-sdk-sqs (~> 1.69.0)
+      aws-sdk-ssm (~> 1.162.0)
+      aws-sdk-states (~> 1.63.0)
+      aws-sdk-synthetics (~> 1.39.0)
+      aws-sdk-transfer (~> 1.86.0)
+      aws-sdk-waf (~> 1.58.0)
+      aws-sdk-wafv2 (~> 1.74.0)
+    train-core (3.11.0)
+      addressable (~> 2.5)
+      ffi (!= 1.13.0)
+      json (>= 1.8, < 3.0)
+      mixlib-shellout (>= 2.0, < 4.0)
+      net-scp (>= 1.2, < 5.0)
+      net-ssh (>= 2.9, < 8.0)
+    train-habitat (0.2.22)
+    train-kubernetes (0.2.1)
+      k8s-ruby (~> 0.16.0)
+      train (~> 3.0)
+    train-winrm (0.2.13)
+      winrm (>= 2.3.6, < 3.0)
+      winrm-elevated (~> 1.2.2)
+      winrm-fs (~> 1.0)
+    tty-box (0.7.0)
+      pastel (~> 0.8)
+      strings (~> 0.2.0)
       tty-cursor (~> 0.7)
-    tty-color (0.5.0)
-    tty-cursor (0.7.0)
-    tty-prompt (0.20.0)
-      necromancer (~> 0.5.0)
-      pastel (~> 0.7.0)
-      tty-reader (~> 0.7.0)
-    tty-reader (0.7.0)
+    tty-color (0.6.0)
+    tty-cursor (0.7.1)
+    tty-prompt (0.23.1)
+      pastel (~> 0.8)
+      tty-reader (~> 0.8)
+    tty-reader (0.9.0)
       tty-cursor (~> 0.7)
-      tty-screen (~> 0.7)
-      wisper (~> 2.0.0)
-    tty-screen (0.7.0)
-    unicode-display_width (1.6.0)
+      tty-screen (~> 0.8)
+      wisper (~> 2.0)
+    tty-screen (0.8.2)
+    tty-table (0.12.0)
+      pastel (~> 0.8)
+      strings (~> 0.2.0)
+      tty-screen (~> 0.8)
+    tzinfo (2.0.6)
+      concurrent-ruby (~> 1.0)
+    uber (0.1.0)
+    unicode-display_width (2.5.0)
     unicode_utils (1.4.0)
-    winrm (2.3.3)
+    winrm (2.3.6)
       builder (>= 2.1.2)
       erubi (~> 1.8)
       gssapi (~> 1.2)
@@ -132,26 +719,29 @@ GEM
       httpclient (~> 2.2, >= 2.2.0.2)
       logging (>= 1.6.1, < 3.0)
       nori (~> 2.0)
-      rubyntlm (~> 0.6.0, >= 0.6.1)
-    winrm-elevated (1.1.2)
+      rubyntlm (~> 0.6.0, >= 0.6.3)
+    winrm-elevated (1.2.3)
       erubi (~> 1.8)
       winrm (~> 2.0)
       winrm-fs (~> 1.0)
-    winrm-fs (1.3.4)
+    winrm-fs (1.3.5)
       erubi (~> 1.8)
       logging (>= 1.6.1, < 3.0)
       rubyzip (~> 2.0)
       winrm (~> 2.0)
     wisper (2.0.1)
+    yajl-ruby (1.4.3)
+    yaml-safe_load_stream3 (0.1.2)
+    zeitwerk (2.6.13)
 
 PLATFORMS
   ruby
 
 DEPENDENCIES
   cookstyle
-  kitchen-vagrant
-  serverspec
+  kitchen-dokken
+  kitchen-inspec
   test-kitchen
 
 BUNDLED WITH
-   1.17.2
+   2.2.16
index 8707c7b461c18a3d46329c097cf8d7a692fd4f26..86145db1765475d9ed7c6d07bcd1fa0c4750f76e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
 # OpenStreetMap chef cookbooks
 
-[![Build Status](https://travis-ci.org/openstreetmap/chef.svg?branch=master)](https://travis-ci.org/openstreetmap/chef)
+[![Cookstyle](https://github.com/openstreetmap/chef/workflows/Cookstyle/badge.svg?branch=master&event=push)](https://github.com/openstreetmap/chef/actions?query=workflow%3ACookstyle%20branch%3Amaster%20event%3Apush)
+[![Test Kitchen](https://github.com/openstreetmap/chef/workflows/Test%20Kitchen/badge.svg?branch=master&event=push)](https://github.com/openstreetmap/chef/actions?query=workflow%3A%22Test+Kitchen%22%20branch%3Amaster%20event%3Apush)
 
 This repository manages the configuration of all the servers run by the
 OpenStreetMap Foundation's Operations Working Group. We use
@@ -13,16 +14,16 @@ servers.
 
 We make extensive use of roles to configure the servers. In general we have:
 
-## Server-specific roles (e.g. [katla.rb](roles/katla.rb))
+## Server-specific roles (e.g. [faffy.rb](roles/faffy.rb))
 
 These deal with particular setup or quirks of a server, such as its IP address. They also include roles representing the service they are performing, and the location they are in and any particular hardware they have that needs configuration.
 All our servers are [named after dragons](https://wiki.openstreetmap.org/wiki/Servers/Name_Ideas).
 
-## Hardware-specific roles (e.g. [tyan-s7010.rb](roles/tyan-s7010.rb))
+## Hardware-specific roles (e.g. [hp-g9.rb](roles/hp-g9.rb))
 
 Covers anything specific to a certain piece of hardware, like a motherboard, that could apply to multiple machines.
 
-## Location-specific roles (e.g. [equinix.rb](roles/equinix.rb))
+## Location-specific roles (e.g. [equinix-dub.rb](roles/equinix-dub.rb))
 
 These form a hierarchy of datacentres, organisations, and countries where our servers are located.
 
@@ -36,9 +37,10 @@ We use the 'Organization Repository' approach, where we have all our cookbooks i
 
 # Contributing
 
-Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
+Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more details. The guide also includes details on how to run the tests locally.
 
 # Contact Us
 
 * Twitter: [@OSM_Tech](https://twitter.com/OSM_Tech)
+* Mastodon / Fediverse: [@OSM_Tech](https://en.osm.town/@osm_tech)
 * IRC: [#OSM-Dev on irc.oftc.net](https://irc.openstreetmap.org/)
index 8535ee403c98bb4f8d9787095d24b88d848e63a1..e529fe2fd857b4367e3fd18e7155123d21185b82 100644 (file)
@@ -4,3 +4,4 @@ default[:accounts][:manage_home] = true
 
 default[:accounts][:groups] = {}
 default[:accounts][:users] = {}
+default[:accounts][:administrators] = []
diff --git a/cookbooks/accounts/files/default/contrapunctus/.ssh/authorized_keys b/cookbooks/accounts/files/default/contrapunctus/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..032adbf
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwUG1hL4maYavu5UE8O/6N/O7BWQPoRR42IzWKx1tncf4BKbyf7ck5vP0fPYGDR54FsaZEOjCAQ+TwsozpGVBcxbWTo2ApxKM4MH3t/UHclRvmgj38wSQPc57hIBiWfkukKYq5vGPvw9Avd5LSyTKB5Sm9H0jYgVel5QtbGLIN1l/Liwc91T8hbk47vJ1NEy2WVvnPglQI/jZff0ZOc85O/bHxrtt6Nv/03p2BYPoObrCiGJkDO4mBQyUf/9FRoZ1ZcEyINTAgd1nS0CVLEMjMeYsqcRf1NEhY2ai1tZ0kHEOBia4cTlCiJhNUOgf/hz3HbIwTiTv04NmhpVZzOESnsaW9T6Wvb4/6G9JS+ZDZK54r4Ht0bsGt61IyhdPATKKHTzyktHQ/89K4YWppHhlzt4FZ3gyslpBv5lhagIXCjGN8+UP8295pKdBMknefbQfSsjYlxdCPZhI2XtyKDjmRTJRn78eKfrwdo/om0t6GHlDE+r259QvX98rSXOdUJjdbbITk+nS6cn5WK5O5RjMo1+e8EAOmC9vdE4zgeFJyNwxeCRUpIpv/233Cd2qG73r3czbhtLJji27vSLXomfeSBfiEfjBGi69VI07dwECwW31hdDUAAHL50HD53nJgRkxHDJHIPVmHBB2MA09etnUZ+24gzpAx/w5QnA2tYWRGZw== contrapunctus@disroot.org
diff --git a/cookbooks/accounts/files/default/dmlu/.ssh/authorized_keys b/cookbooks/accounts/files/default/dmlu/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..2170df5
--- /dev/null
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAqX90M2sP8AYuO7pdH8yHwu6T2RtuLFG7vzgVTiDSaEq8XvgRdaRRIECXbotwDONaOUgjlFHLo7bKc6aj1sWq21rP6FO+nL0TrzpirdspmIeCDDzkGzCRJSIIOLOzVCY8E8+JLqosrpIzScnLmDFopVpvhzBDIVF9LzYaKZc8s+kiB74Q28qKFKAzBi4mfxxkSUXSIQ3UA/CchRUef6UtSJjl04b4vnnnCG+DVO4HzCurwZq/47VIe1xwAIFavTuHniBd/iaoc2tGtclD9Je5T1ja5NaWoh3pf8hPxNpTZmGc3fex3xkHkF1x5FMu2sscgB3R0fdRaNZ9vPqu4WyY2Q== dmlu
diff --git a/cookbooks/accounts/files/default/gmoncrieff/.ssh/authorized_keys b/cookbooks/accounts/files/default/gmoncrieff/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..dbf638d
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEYfJbizJ99jRXzyNcIbPYFH874Qj2YM7FVqbomq/hDB github-key
diff --git a/cookbooks/accounts/files/default/grant/.selected_editor b/cookbooks/accounts/files/default/grant/.selected_editor
new file mode 100644 (file)
index 0000000..c85d073
--- /dev/null
@@ -0,0 +1,2 @@
+# Generated by /usr/bin/select-editor
+SELECTED_EDITOR="/usr/bin/vim.basic"
index 26a4f44a99dfaa21612e82663a01a5af8bf0dbcd..fa33091a6cc20199374fc238a0f58b9ce7259622 100644 (file)
@@ -1,3 +1,5 @@
 # DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6Hw67b4cRzXDvs88XSuKpXTJmFyietVqaQvJRedQflurHay5lGdFyzfPF0P+mG9l5O/qlKzXo5xvZNe6YOGcMCuxzOYiw/bAkEd7oHYVXVJr8jWL2zqusBmf5dLZDEjMtUX9w6IQWiuSvm3To3Fsohn2UjUqEi5aULu6h39O1JtcdtmIvjB4iTmIO4Eme8FxubktDImyCvwOAJVsYQASljeaTDa+31ANqMDehXZSRjFKaVECw1RNyvYclmkbj8rLiw648/IV9xRi/SMtZlNyxrcIKQ6hKmmiyaBA6a5QEqWj7OMVYCECAoNwlWKhBmkMx7fwOh1eKKOLFeFz2kdSt grant@home-desktop-key
 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDuVegqS8l8WgH1T1LMGyJ4OvPeI5Kek5f5bYsHy62DLOhd4aDHCjJPegfiKCdpYde/b2kOQuwG90cl1a+6DDvNXvIDarQvfNzNWGONOtb+NM0/+IuAfSeonh8ROWRLW5ciOQi0PuPGnjD9vYdFMKtCh1lyi9KOq9DJNR0HFqEJgoZg8BoclAUdtgPzYU/fVpgwAS5mdBUTIQga3CbVsRcTWLPFKNlgY46eWYEKb9XqZIoa5AlxqH6AtYjaUQBdGzRpo/PW71VZzpZMP/dhf6illQBUyFJXL+PyVZGsckq94fkb6j3E5OkuGT55o4fEVLQaIDh2sIUB5n2emnP5On44kNTCPZiAMAC2weLv9PD7RFgTuxVTa1WsxbDqqaTueHJH1P+K4TNx2w0wfTfxqXjXKQPwGED1+xHWwOQoWT9eSarvUQF1jtQdseNsljPkJtpTiD2CHIUuCohYm0DxGYbQSl7uTLDK5HfuMMhAfBry/kNDb7CFTWKzN98Zbam8fx7e9TnCoL4MOMR8GOZyw/ITMbjmWRV5JGFfNUvqrteb9DLh99ZNDrcAawoESFLQTaXGPNYwCMcsxHxZAo8obfRGM/RbGvS+njfib6tkMwh6H/7uA1MPVLEbLejosMUzylDcfaoqGB5SryzZSVO0f7lx4JadQDCAimGBb0N3Fem8Rw== grant.slater@FRIDAY
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGW+K3RYYU26wSOp0DWA4OA94UeX9AZdk8aaaiV1KopY grant@home
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG+dY7nSVDShpfzDrgs1UaDeFbQUlXVWl4eECFu0Zo3a grant.slater@LONGS22-M
diff --git a/cookbooks/accounts/files/default/jeslop/.ssh/authorized_keys b/cookbooks/accounts/files/default/jeslop/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..379ff19
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAB9jIwQu1TmXcQH6FXEz53fkTX3abCgjflwdESnaR5qKw6hUcvAIjPXiGLFGdl+nR56aCbQrbXQVF3Hug2+057xcAEAhFj0aIOoDhgEkZ0uK4GIElZjCUugYLt3AbQXTRpEXtXaL1wzyBmFqbTMOxDOzaif+PYWwDHC1yo1C5jhSlRmRg== jesus@Mac-mini-de-Jesus.local
diff --git a/cookbooks/accounts/files/default/ligfietser/.ssh/authorized_keys b/cookbooks/accounts/files/default/ligfietser/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..b4cde51
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCYd3z5L8YQXRw3JHXwD0KyTdfWncom7UPAP3BcrfUK/oJXFAE6w4w4nsYHk4axRddIKLXYXl5guine/hd7uBk77mqVYSi4JpCDhYt8cIvAd6xHOmWEQwU3Yjvov3XcKOz304sD93pcynBXwpUxih4k3UifgUJz7Ire0f99FaOQ5+yI6qVMEcOReNGgtR3k7vbZXJhzNanKaZoUVeA/PAZx+Zv9cOXvmfgsYSmU6Thrf78dMBH+4GkXSodXC5iliQTepWFQxQ0hHSxndP3UkxVLQdi426jsceG4bXjkmh+cv3q6ue3e/hAU5BZmAzyT/NOGrC92FYlqTYfqNKv+RqVZ rsa-key-20240327
index a5f67e78a2ac26650a84124e7e74ca7aabd09ab6..de66ccbbc370fd30d3d4c1f19a623ccdcac586a3 100644 (file)
@@ -1,2 +1,3 @@
 # DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAyBrnrkjzAJqXtRP0MFKlc3v4fTnrRzzebIFH8YpFRCaLKpIXWVbg5BqXuxHB/vqf/1Gknycb7bgLPbhWr+b50D+nnodiJ35HPqrQVLG6nsqxnbbVXO1IR7KsctL+Wr3GW5pBeWct9GAALn8ACAR8zZ/4V6qXDgUvh0inefcqpks1YgdPdyAGLMFy7hzI5lY8kGh58kVPXMpyJLVnGX0yUjrip9IkPrGBvMDiGDiPwLOfKGDR0s1An1GK2i4k2rPxkZzdQSbqZXaaCw3MNJkDvwSmQNQp4Rprfy5BqptwJg4PLnGGePfYbzsqYA0/Pq4ccO+NPCDxZxb2XuVjgXEg8Q== matt@horntail.openstreetmap.org
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDntpfnmWsP/9nh3JvT/AuNz3t4azrH54vKLrdtovYQ14QC66GA9EyAJel2eamyhevHQw5JU3Ic6H0ycXZus6QNn5vZKBn72/HXc/mvfRO2F5PvWVVF5LROoe1YBmYJugqpRwFekt9pIs49bbu3lZolnmmVT/uQP3sTFgErc/eqBtzgB+0OYijddQl3otzOZaZh1o4YaUvyutVb8ND3D1xgPxavWKW8B3BTDLF/Lr0wyh+CTWc1LtXVifIWpe9Muv+l+iww8AScyryLdMfcrUY+k76HwmkLbNV01hWMbfnB+4KoshFHnpmFN/Q4maoEXQpwP1II3iEKVs6QWFc4dImREtpiUJm5XeznlmfBuMac2gZPyPqSQPoUmxDTV7+umbcpw5IMGKFom6GJJJN2Az40TqNoQBAwnrJrmxzvLU8POpfYdZZfPLUB8l9nELGvIMhbRTBVpq6t99AxqvHlk3hc6yPTBFfltiBDB62QyOIEggbecnMaD1VvAkrthRITNJ9h0zdvrXM+X0pMo1QM8dBqRvrbBD7fr3gy2Oo+/XMsxf6Q8Fd7iu8oU8HYCwDexqZ8y9Nb54dOglWzSEPsTBAWf6PtBtZaXZ/VnNy3zjnJuOA99STQmqH5OPCY0eg6yRE6TILj9J4wWAXytXL9lF5YAW8JIT4+8pa4WhJoUGQz1w== zerebubuth@gmail.com
diff --git a/cookbooks/accounts/files/default/mikel/.ssh/authorized_keys b/cookbooks/accounts/files/default/mikel/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..e52e3ae
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCmMyloQ+2+9Din4JPv11cu8EHgHREz3zljaxUDcU/zh2XoZIZn5jm9+qev+ga2ewX2gS8HflIIY5LG3sHCxhzUAvv5vFUha1qZVOA6CIi4WEqJfNkkyBuPFwYQDFwMgxQV/tOIAc/94lJ1DT/BrfJmeayh08OKgEpLLFTUDdlSA79sbQoT4JwTQM46H1s6r1adYjjZmz6vdyJ2yq3ODGWz356ad7hCch4AzK79MVkitaY2v17Zy+gKLkT75G1Fy4J0wBsDszNZHbNO95Exyqld4L4AvTGsz6JHglceMb/r7ma/Od0T+VT5TI5cQwZUqXOEOWRf2VptYQ7RrgSPKRq7 mikel_maron
diff --git a/cookbooks/accounts/files/default/milliams/.ssh/authorized_keys b/cookbooks/accounts/files/default/milliams/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..a1fa1cf
--- /dev/null
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEVkoOPte6R6jN5w7yny+YLtoZGl/XLQL2aSjhgyNHrh matt@HEX
diff --git a/cookbooks/accounts/files/default/msbarry/.ssh/authorized_keys b/cookbooks/accounts/files/default/msbarry/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..6ef49ee
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8FAjmvszUAHdZROboaVvTDniabLELeMe1WXHL55XelxAN3kZEmXLNbCXzLuYYQ5ASgrSVC5jX52bvPPJXeCR1NJXEfYNPyxfioMfAF298yNNap7Hkt2fmpjDleOJYK2gvJ7mHJjsTodno4j1Nm8pkr60r3n3ecYV9dMSk2ee37heYEZK9/Swcn8m79fCR0SBZ3JdsKeC+uMZxz9BXNF3COwgyO8C+/8+gwPGpqOMjQMLpHmuefGxGAINAV6CBes9N9g0ky8OiGjg1XQq9kMp+bihcAT8UKqc2+v9uH73eK9ZL3FYTcJwNO1IWofoU/eUT6hcrWnahPcVW5O5NBgRZ github
diff --git a/cookbooks/accounts/files/default/pnorman/.ssh/authorized_keys b/cookbooks/accounts/files/default/pnorman/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..31eafc8
--- /dev/null
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCYxvvG3WcrofBviPhEhKuEBiej3WcLMEhYloJB0pOGF1DaK8kD6QRlH4mZaNmm4mZCQIUv2KfgxDyPmp8byGZniVQzx74dlFDozFY+q9beokQA/f5RjtWs2G8gO+V4UdNXxo9q3cvfjiK9eXtjLjYyMkwb8n6Y3jrpt7CDflb7Pa+yJF9C1ugPooa739YNw5M8qPWdP1QVK8M7zZTeUbGh1xWReGCwcKFNDtoOSyj1XXkKSvfGd+spKqfwKOHOqVXQYNtSm+nnIuGilLp8caFa3lOvcGnlXgSKExeiMq/zG7vlvierkuwz00yOxF6h6BgjLztLCsknt3mD92vhUqQz
diff --git a/cookbooks/accounts/files/default/rtnf/.ssh/authorized_keys b/cookbooks/accounts/files/default/rtnf/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..1696cac
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCZmRTAN92TeqR9iIFsPFGmNdC7fGoH112eoY3D4JskfnezgdF+knA5qRf62VGnoa3oHfDZKGNaMexLZmyFLycyqFUln+TjzUpBLO3Ni7GykmIoxpTvzbs7iCtY9YChUUHz4qq7LP9W7QBRYYhgGMfa8IZUqTE3ogAG8uyKl+jn20PyVkkQabwePfCEm6WhcqKWA86u6R7SuE3O4YJsXIq9uaUZJVBomg+ORNcD90UcyTGzJ8hlqk9RBPvc4q2eTN3A9+/j/CDxiKAUFIqFeZ3nCZ/YFcS6Cxzl5+q4+NfFWe2zgFdw3YTWIdLsarMLJm55E9LHKhCedjel4P1tjqVr rtnf
index 20211c3c89d8f3b77452892b6fd09deff9ad42a0..1eae8a39221227e7573e98df2817068ffaad31fd 100644 (file)
@@ -28,6 +28,8 @@ unset zle_bracketed_paste
 # Keep tramp happy
 if [[ "$TERM" = "dumb" ]]
 then
+    unsetopt PROMPT_SP
+    unsetopt PROMPT_CR
     unsetopt ZLE
 fi
 
diff --git a/cookbooks/accounts/files/default/zander/.ssh/authorized_keys b/cookbooks/accounts/files/default/zander/.ssh/authorized_keys
new file mode 100644 (file)
index 0000000..c6e54b3
--- /dev/null
@@ -0,0 +1,2 @@
+# DO NOT EDIT - This file is being maintained by Chef - use authorized_keys2 instead
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMnMNgIczCZtRuvd75FWGaTFD4xZSQ+EWAlR+CcMWDXM slack-key
index 7eb760f3cc7c8c2990903d81356e39e922f5b4a5..b395aeca615c44f3bb46546c2610e27f076fb031 100644 (file)
@@ -19,7 +19,7 @@
 
 package "zsh"
 
-administrators = []
+administrators = node[:accounts][:administrators].to_a
 
 search(:accounts, "*:*").each do |account|
   name = account["id"]
@@ -39,9 +39,15 @@ search(:accounts, "*:*").each do |account|
       user_shell = details[:shell] || account["shell"] || node[:accounts][:shell]
     end
 
+    available_users = if node[:etc]
+                        node[:etc][:passwd].keys
+                      else
+                        []
+                      end
+
     group name.to_s do
       gid account["uid"].to_i
-      members group_members & node[:etc][:passwd].keys
+      members group_members & available_users
     end
 
     user name.to_s do
@@ -58,18 +64,16 @@ search(:accounts, "*:*").each do |account|
       source name.to_s
       owner name.to_s
       group name.to_s
-      mode 0o755
+      mode "755"
       files_owner name.to_s
       files_group name.to_s
-      files_mode 0o644
+      files_mode "644"
       only_if do
-        begin
-          cookbook = run_context.cookbook_collection[cookbook_name]
-          files = cookbook.relative_filenames_in_preferred_directory(node, :files, name.to_s)
-          !files.empty?
-        rescue Chef::Exceptions::FileNotFound
-          false
-        end
+        cookbook = run_context.cookbook_collection[cookbook_name]
+        files = cookbook.relative_filenames_in_preferred_directory(node, :files, name.to_s)
+        !files.empty?
+      rescue Chef::Exceptions::FileNotFound
+        false
       end
     end
 
index cff5e5b839c1b5fb0af59eed4b16e1d32b2feb73..075e4c86f2d443e3f18aa86ecac03cec38f39437 100644 (file)
@@ -1,4 +1,4 @@
-default[:apache][:mpm] = "worker"
+default[:apache][:mpm] = "event"
 
 default[:apache][:timeout] = 300
 
@@ -30,4 +30,11 @@ default[:apache][:listen_address] = "*"
 
 default[:apache][:buffered_logs] = true
 
-default[:apache][:reqtimeout] = false
+default[:apache][:evasive][:enable] = true
+default[:apache][:evasive][:hash_table_size] = 65536
+# page_count is misnomer as it can match backends in some cases
+default[:apache][:evasive][:page_count] = 150
+default[:apache][:evasive][:site_count] = 250
+default[:apache][:evasive][:page_interval] = 1
+default[:apache][:evasive][:site_interval] = 1
+default[:apache][:evasive][:blocking_period] = 60
index 06b231a1c3c2e01c896ac84a032c198b46cf9c31..2323547f7e3eb6a90bec66f403b5117dc24b80e9 100644 (file)
@@ -6,5 +6,7 @@ description       "Installs and configures apache"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "munin"
+depends           "fail2ban"
+depends           "prometheus"
 depends           "ssl"
+depends           "systemd"
index ffa03c34cbfbdae28b2c7649ab6da7281f3bd4b1..d1a0aac1dd45c70e56a30b071c64ebcfde31b864 100644 (file)
@@ -17,6 +17,8 @@
 # limitations under the License.
 #
 
+include_recipe "fail2ban"
+include_recipe "prometheus"
 include_recipe "ssl"
 
 package %w[
@@ -49,12 +51,14 @@ template "/etc/apache2/ports.conf" do
   source "ports.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
-service "apache2" do
-  action [:enable, :start]
-  supports :status => true, :restart => true, :reload => true
+systemd_service "apache2" do
+  dropin "chef"
+  memory_high "50%"
+  memory_max "75%"
+  notifies :restart, "service[apache2]"
 end
 
 apache_module "info" do
@@ -67,20 +71,24 @@ apache_module "status" do
   variables :hosts => admins["hosts"]
 end
 
-apache_module "deflate" do
-  conf "deflate.conf.erb"
-end
-
-if node[:apache][:reqtimeout]
-  apache_module "reqtimeout" do
-    action [:enable]
+if node[:apache][:evasive][:enable]
+  apache_module "evasive" do
+    conf "evasive.conf.erb"
   end
 else
-  apache_module "reqtimeout" do
-    action [:disable]
+  apache_module "evasive" do
+    action :disable
   end
 end
 
+apache_module "brotli" do
+  conf "brotli.conf.erb"
+end
+
+apache_module "deflate" do
+  conf "deflate.conf.erb"
+end
+
 apache_module "headers"
 apache_module "ssl"
 
@@ -88,6 +96,43 @@ apache_conf "ssl" do
   template "ssl.erb"
 end
 
-munin_plugin "apache_accesses"
-munin_plugin "apache_processes"
-munin_plugin "apache_volume"
+# Apache should only be started after modules enabled
+service "apache2" do
+  action [:enable, :start]
+  retries 2
+  retry_delay 10
+  supports :status => true, :restart => true, :reload => true
+end
+
+fail2ban_filter "apache-forbidden" do
+  action :delete
+end
+
+fail2ban_jail "apache-forbidden" do
+  action :delete
+end
+
+fail2ban_filter "apache-evasive" do
+  failregex ": Blacklisting address <ADDR>: possible DoS attack\.$"
+end
+
+fail2ban_jail "apache-evasive" do
+  filter "apache-evasive"
+  backend "systemd"
+  journalmatch "_SYSTEMD_UNIT=apache2.service SYSLOG_IDENTIFIER=mod_evasive"
+  ports [80, 443]
+  findtime "10m"
+  maxretry 3
+end
+
+template "/var/lib/prometheus/node-exporter/apache.prom" do
+  source "apache.prom.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+prometheus_exporter "apache" do
+  port 9117
+  options "--scrape_uri=http://localhost/server-status?auto"
+end
index 0ac19b0c795f9b64283754a900c4f74cb36a9d64..9f1efb24f284f6b8d4c725b925f1946c3927418b 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action [:create, :enable]
 
-property :conf, :kind_of => String, :name_attribute => true
+property :conf, :kind_of => String, :name_property => true
 property :cookbook, :kind_of => String
-property :template, :kind_of => String, :required => true
+property :template, :kind_of => String, :required => [:create]
 property :variables, :kind_of => Hash, :default => {}
 property :reload_apache, :kind_of => [TrueClass, FalseClass], :default => true
 
@@ -48,7 +50,7 @@ action_class do
       source new_resource.template
       owner "root"
       group "root"
-      mode 0o644
+      mode "644"
       variables new_resource.variables
     end
   end
index 0ac0f8f01471cd161811c8a537155d6f774b7535..5de2bfcaade352b9623842a44031b02e297e1799 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action [:install, :enable]
 
-property :module, :kind_of => String, :name_attribute => true
+property :module, :kind_of => String, :name_property => true
 property :package, :kind_of => String
 property :conf, :kind_of => String
 property :variables, :kind_of => Hash, :default => {}
@@ -33,7 +35,7 @@ action :install do
       source new_resource.conf
       owner "root"
       group "root"
-      mode 0o644
+      mode "644"
       variables new_resource.variables
     end
   end
index 5b52304251b8dfae2609155b340c1b6b85b6f70b..598f841ff86e131abea1546c3370e38b56577342 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action [:create, :enable]
 
-property :site, :kind_of => String, :name_attribute => true
+property :site, :kind_of => String, :name_property => true
 property :directory, :kind_of => String
 property :cookbook, :kind_of => String
-property :template, :kind_of => String, :required => true
+property :template, :kind_of => String, :required => [:create]
 property :variables, :kind_of => Hash, :default => {}
 property :reload_apache, :kind_of => [TrueClass, FalseClass], :default => true
 
@@ -32,7 +34,7 @@ action :create do
     source new_resource.template
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables new_resource.variables.merge(:name => new_resource.site, :directory => site_directory)
   end
 end
diff --git a/cookbooks/apache/templates/default/apache.prom.erb b/cookbooks/apache/templates/default/apache.prom.erb
new file mode 100644 (file)
index 0000000..8c0b5b0
--- /dev/null
@@ -0,0 +1,27 @@
+# HELP apache_server_limit Value of ServerLimit directive
+# TYPE apache_server_limit gauge
+<% if node[:apache][:mpm] == "prefork" -%>
+apache_server_limit{} <%= node[:apache][:prefork][:server_limit] || 256 %>
+<% elsif node[:apache][:mpm] == "worker" -%>
+apache_server_limit{} <%= node[:apache][:worker][:server_limit] || 16 %>
+<% elsif node[:apache][:mpm] == "event" -%>
+apache_server_limit{} <%= node[:apache][:event][:server_limit] || 16 %>
+<% end -%>
+# HELP apache_threads_per_child Value of ThreadsPerChild directive
+# TYPE apache_threads_per_child gauge
+<% if node[:apache][:mpm] == "prefork" -%>
+apache_threads_per_child{} 1
+<% elsif node[:apache][:mpm] == "worker" -%>
+apache_threads_per_child{} <%= node[:apache][:worker][:threads_per_child] || 25 %>
+<% elsif node[:apache][:mpm] == "event" -%>
+apache_threads_per_child{} <%= node[:apache][:event][:threads_per_child] || 25 %>
+<% end -%>
+# HELP apache_async_request_worker_factor Value of AsyncRequestWorkerFactor directive
+# TYPE apache_async_request_worker_factor gauge
+<% if node[:apache][:mpm] == "prefork" -%>
+apache_async_request_worker_factor{} 0
+<% elsif node[:apache][:mpm] == "worker" -%>
+apache_async_request_worker_factor{} 0
+<% elsif node[:apache][:mpm] == "event" -%>
+apache_async_request_worker_factor{} <%= node[:apache][:event][:async_request_worker_factor] || 2 %>
+<% end -%>
diff --git a/cookbooks/apache/templates/default/brotli.conf.erb b/cookbooks/apache/templates/default/brotli.conf.erb
new file mode 100644 (file)
index 0000000..3bf3dfc
--- /dev/null
@@ -0,0 +1,14 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<IfModule mod_brotli.c>
+       <IfModule mod_filter.c>
+               AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css text/javascript
+               AddOutputFilterByType BROTLI_COMPRESS application/x-javascript application/javascript application/ecmascript
+               AddOutputFilterByType BROTLI_COMPRESS application/rss+xml
+               AddOutputFilterByType BROTLI_COMPRESS application/wasm
+               AddOutputFilterByType BROTLI_COMPRESS application/xml
+               AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
+       </IfModule>
+</IfModule>
+
+# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
index a418736e71cad7b34f38dcaf1a9ad96d411e0d86..9f9bda5f9aabde23551f341edbbe6bef8e58a99e 100644 (file)
@@ -1,15 +1,14 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
 <IfModule mod_deflate.c>
-        <IfModule mod_filter.c>
-                # these are known to be safe with MSIE 6
-                AddOutputFilterByType DEFLATE text/html text/plain text/xml
-
-                # everything else may cause problems with MSIE 6
-                AddOutputFilterByType DEFLATE text/css
-                AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
-                AddOutputFilterByType DEFLATE application/rss+xml
-                AddOutputFilterByType DEFLATE application/xml
-                AddOutputFilterByType DEFLATE image/svg+xml
-        </IfModule>
+       <IfModule mod_filter.c>
+               AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
+               AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
+               AddOutputFilterByType DEFLATE application/rss+xml
+               AddOutputFilterByType DEFLATE application/wasm
+               AddOutputFilterByType DEFLATE application/xml
+               AddOutputFilterByType DEFLATE image/svg+xml
+       </IfModule>
 </IfModule>
+
+# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
diff --git a/cookbooks/apache/templates/default/evasive.conf.erb b/cookbooks/apache/templates/default/evasive.conf.erb
new file mode 100644 (file)
index 0000000..0f6b37b
--- /dev/null
@@ -0,0 +1,10 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<IfModule mod_evasive20.c>
+    DOSHashTableSize <%= node[:apache][:evasive][:hash_table_size] %>
+    DOSPageCount <%= node[:apache][:evasive][:page_count] %>
+    DOSSiteCount <%= node[:apache][:evasive][:site_count] %>
+    DOSPageInterval <%= node[:apache][:evasive][:page_interval] %>
+    DOSSiteInterval <%= node[:apache][:evasive][:site_interval] %>
+    DOSBlockingPeriod <%= node[:apache][:evasive][:blocking_period] %>
+</IfModule>
index 62533efae0512bee01b91b50e0f8e432591ab6d6..3f78187f8b540d37e878184e440b09d138964515 100644 (file)
@@ -63,3 +63,6 @@ AddType application/x-xz .xz
 
 # Configure logging
 BufferedLogs <%= node[:apache][:buffered_logs] ? "On" : "Off" %>
+
+# Define an extended log format that includes request time and SSL details
+LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %Dus %{SSL_PROTOCOL}x %{SSL_CIPHER}x" combined_extended
index f983b9991da32f96eafd5f56268e1095f590333a..a8a303a9fe61e25b697b035c0972d421817cfcd2 100644 (file)
@@ -4,7 +4,7 @@
 
 <Location /server-info>
     SetHandler server-info
-<% node.ipaddresses do |address| -%>
+<% node.ipaddresses.sort.each do |address| -%>
     Require ip <%= address %>
 <% end -%>
     Require ip 127.0.1.1
index 80735c9cb51d3d0a53e6b18a878301f635f87b52..81afb3de55cff8182aa3a33a7361c5d6150bd6ba 100644 (file)
@@ -13,4 +13,3 @@ SSLStaplingFakeTryLater off
 SSLStaplingCache shmcb:${APACHE_RUN_DIR}/ssl_ocspcache(512000)
 
 Header always set Strict-Transport-Security "<%= node[:ssl][:strict_transport_security] %>" "expr=%{HTTPS} == 'on'"
-Header always set Expect-CT "max-age=0, report-uri=\"https://openstreetmap.report-uri.com/r/d/ct/reportOnly\"" "expr=%{HTTPS} == 'on'
index 6b8b98ee7f8e19b13b2f6cab289ae46fd2a665b9..f78aa9402b3eecf3aab18c18418baeef8640f962 100644 (file)
@@ -6,7 +6,7 @@ ExtendedStatus On
 
 <Location /server-status>
     SetHandler server-status
-<% node.ipaddresses do |address| -%>
+<% node.ipaddresses.sort.each do |address| -%>
     Require ip <%= address %>
 <% end -%>
     Require ip 127.0.1.1
index f75ed9e34abe5f4a77f1591ceea00011136f4b61..6ec384b5d7e90c2a42f12f2516794325d4dd4e8a 100644 (file)
@@ -1,4 +1,2 @@
-default_unless[:apt][:sources] = []
-
 default[:apt][:unattended_upgrades][:enable] = true
 default[:apt][:unattended_upgrades][:remove_unused_dependencies] = true
index 9aa2f7a827760dc54dc5d70c5275c9d42479b496..9627bf4d409d91f0a511b6bb783ac642d633fe19 100644 (file)
@@ -21,139 +21,73 @@ package %w[
   apt
   apt-transport-https
   gnupg
-  update-notifier-common
 ]
 
+package "update-notifier-common" if platform?("ubuntu")
+
 file "/etc/motd.tail" do
   action :delete
 end
 
-template "/etc/apt/preferences.d/99-chef" do
-  source "preferences.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+# FIXME: cleanup old package pin method for cciss-vol-status
+file "/etc/apt/preferences.d/99-chef" do
+  action :delete
+end
+
+apt_preference "cciss-vol-status" do
+  pin          "origin *.ubuntu.com"
+  pin_priority "1100"
 end
 
 apt_update "/etc/apt/sources.list" do
   action :nothing
 end
 
-archive_host = if node[:country]
-                 "#{node[:country]}.archive.ubuntu.com"
-               else
-                 "archive.ubuntu.com"
-               end
+if platform?("debian")
+  archive_host = "deb.debian.org"
+  archive_security_host = archive_host
+  archive_distro = "debian"
+  archive_security_distro = "debian-security"
+  archive_suites = %w[main updates backports security]
+  archive_components = %w[main contrib non-free non-free-firmware]
+elsif intel?
+  archive_host = if node[:country]
+                   "#{node[:country]}.archive.ubuntu.com"
+                 else
+                   "archive.ubuntu.com"
+                 end
+  archive_security_host = "security.ubuntu.com"
+  archive_distro = "ubuntu"
+  archive_security_distro = archive_distro
+  archive_suites = %w[main updates backports security]
+  archive_components = %w[main restricted universe multiverse]
+else
+  archive_host = "ports.ubuntu.com"
+  archive_security_host = archive_host
+  archive_distro = "ubuntu-ports"
+  archive_security_distro = archive_distro
+  archive_suites = %w[main updates backports security]
+  archive_components = %w[main restricted universe multiverse]
+end
 
 template "/etc/apt/sources.list" do
   source "sources.list.erb"
   owner "root"
   group "root"
-  mode 0o644
-  variables :archive_host => archive_host, :codename => node[:lsb][:codename]
+  mode "644"
+  variables :archive_host => archive_host,
+            :archive_security_host => archive_security_host,
+            :archive_distro => archive_distro,
+            :archive_security_distro => archive_security_distro,
+            :archive_suites => archive_suites,
+            :archive_components => archive_components,
+            :codename => node[:lsb][:codename]
   notifies :update, "apt_update[/etc/apt/sources.list]", :immediately
 end
 
-repository_actions = Hash.new do |_, repository|
-  node[:apt][:sources].include?(repository) ? :add : :remove
-end
-
-apt_repository "brightbox-ruby-ng" do
-  action repository_actions["brightbox-ruby-ng"]
-  uri "ppa:brightbox/ruby-ng"
-end
-
-apt_repository "ubuntugis-stable" do
-  action repository_actions["ubuntugis-stable"]
-  uri "ppa:ubuntugis/ppa"
-end
-
-apt_repository "ubuntugis-unstable" do
-  action repository_actions["ubuntugis-unstable"]
-  uri "ppa:ubuntugis/ubuntugis-unstable"
-end
-
 apt_repository "openstreetmap" do
-  action repository_actions["openstreetmap"]
   uri "ppa:osmadmins/ppa"
-end
-
-apt_repository "squid2" do
-  action repository_actions["squid2"]
-  uri "ppa:osmadmins/squid2"
-end
-
-apt_repository "squid3" do
-  action repository_actions["squid3"]
-  uri "ppa:osmadmins/squid3"
-end
-
-apt_repository "squid4" do
-  action repository_actions["squid4"]
-  uri "ppa:osmadmins/squid4"
-end
-
-apt_repository "management-component-pack" do
-  action repository_actions["management-component-pack"]
-  uri "https://downloads.linux.hpe.com/SDR/repo/mcp"
-  distribution "#{node[:lsb][:codename]}/current-gen9"
-  components ["non-free"]
-  key "C208ADDE26C2B797"
-end
-
-apt_repository "hwraid" do
-  action repository_actions["hwraid"]
-  uri "https://hwraid.le-vert.net/ubuntu"
-  distribution "precise"
-  components ["main"]
-  key "6005210E23B3D3B4"
-end
-
-apt_repository "nginx" do
-  action repository_actions["nginx"]
-  arch "amd64"
-  uri "https://nginx.org/packages/ubuntu"
-  components ["nginx"]
-  key "ABF5BD827BD9BF62"
-end
-
-apt_repository "elasticsearch5.x" do
-  action repository_actions["elasticsearch5.x"]
-  uri "https://artifacts.elastic.co/packages/5.x/apt"
-  distribution "stable"
-  components ["main"]
-  key "D27D666CD88E42B4"
-end
-
-apt_repository "elasticsearch6.x" do
-  action repository_actions["elasticsearch6.x"]
-  uri "https://artifacts.elastic.co/packages/6.x/apt"
-  distribution "stable"
-  components ["main"]
-  key "D27D666CD88E42B4"
-end
-
-apt_repository "passenger" do
-  action repository_actions["passenger"]
-  uri "https://oss-binaries.phusionpassenger.com/apt/passenger"
-  components ["main"]
-  key "561F9B9CAC40B2F7"
-end
-
-apt_repository "postgresql" do
-  action repository_actions["postgresql"]
-  uri "https://apt.postgresql.org/pub/repos/apt"
-  distribution "#{node[:lsb][:codename]}-pgdg"
-  components ["main"]
-  key "7FCC7D46ACCC4CF8"
-end
-
-apt_repository "mediawiki" do
-  action repository_actions["mediawiki"]
-  uri "https://releases.wikimedia.org/debian"
-  distribution "jessie-mediawiki"
-  components ["main"]
-  key "90E9F83F22250DD7"
+  only_if { platform?("ubuntu") }
 end
 
 package "unattended-upgrades"
@@ -168,7 +102,7 @@ if Dir.exist?("/usr/share/unattended-upgrades")
   file "/etc/apt/apt.conf.d/20auto-upgrades" do
     user "root"
     group "root"
-    mode 0o644
+    mode "644"
     content auto_upgrades
   end
 end
@@ -177,5 +111,5 @@ template "/etc/apt/apt.conf.d/60chef" do
   source "apt.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
diff --git a/cookbooks/apt/recipes/docker.rb b/cookbooks/apt/recipes/docker.rb
new file mode 100644 (file)
index 0000000..2aeb832
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Cookbook:: apt
+# Recipe:: docker
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+docker_platform = if platform?("debian")
+                    "debian"
+                  else
+                    "ubuntu"
+                  end
+
+docker_arch = if arm?
+                "arm64"
+              else
+                "amd64"
+              end
+
+apt_repository "docker" do
+  uri "https://download.docker.com/linux/#{docker_platform}"
+  arch docker_arch
+  components ["stable"]
+  key "https://download.docker.com/linux/#{docker_platform}/gpg"
+end
diff --git a/cookbooks/apt/recipes/elasticsearch6.rb b/cookbooks/apt/recipes/elasticsearch6.rb
new file mode 100644 (file)
index 0000000..74c02a3
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Cookbook:: apt
+# Recipe:: elasticsearch6
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "elasticsearch6.x" do
+  uri "https://artifacts.elastic.co/packages/6.x/apt"
+  distribution "stable"
+  components ["main"]
+  key "D27D666CD88E42B4"
+end
diff --git a/cookbooks/apt/recipes/elasticsearch7.rb b/cookbooks/apt/recipes/elasticsearch7.rb
new file mode 100644 (file)
index 0000000..6dc8241
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# Cookbook:: apt
+# Recipe:: elasticsearch7
+#
+# Copyright:: 2022, Grant Slater
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "elasticsearch7.x" do
+  uri "https://artifacts.elastic.co/packages/7.x/apt"
+  distribution "stable"
+  components ["main"]
+  key "D27D666CD88E42B4"
+end
+
+# Workaround for mediawiki 1.39.x which ONLY supports elasticsearch 7.10.2
+# elasticsearch 7.10.2 is the final Apache 2.0 licensed version of elasticsearch
+apt_preference "elasticsearch" do
+  pin          "version 7.10.2"
+  pin_priority "1100"
+end
diff --git a/cookbooks/apt/recipes/elasticsearch8.rb b/cookbooks/apt/recipes/elasticsearch8.rb
new file mode 100644 (file)
index 0000000..61a94f7
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Cookbook:: apt
+# Recipe:: elasticsearch8
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "elasticsearch8.x" do
+  uri "https://artifacts.elastic.co/packages/8.x/apt"
+  distribution "stable"
+  components ["main"]
+  key "D27D666CD88E42B4"
+end
diff --git a/cookbooks/apt/recipes/grafana.rb b/cookbooks/apt/recipes/grafana.rb
new file mode 100644 (file)
index 0000000..ef6531c
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# Cookbook:: apt
+# Recipe:: grafana
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+remote_file "/etc/apt/trusted.gpg.d/grafana.asc" do
+  source "https://packages.grafana.com/gpg.key"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+apt_repository "grafana" do
+  uri "https://packages.grafana.com/enterprise/deb"
+  distribution "stable"
+  components ["main"]
+end
diff --git a/cookbooks/apt/recipes/hwraid.rb b/cookbooks/apt/recipes/hwraid.rb
new file mode 100644 (file)
index 0000000..fa5d9e1
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Cookbook:: apt
+# Recipe:: hwraid
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+platform_name = if platform?("debian")
+                  "debian"
+                else
+                  "ubuntu"
+                end
+
+distribution_name = if platform?("debian")
+                      "buster"
+                    else
+                      "precise"
+                    end
+
+apt_repository "hwraid" do
+  uri "https://hwraid.le-vert.net/#{platform_name}"
+  distribution distribution_name
+  components ["main"]
+  key "6005210E23B3D3B4"
+end
diff --git a/cookbooks/apt/recipes/management-component-pack.rb b/cookbooks/apt/recipes/management-component-pack.rb
new file mode 100644 (file)
index 0000000..700ac02
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# Cookbook:: apt
+# Recipe:: management-component-pack
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "management-component-pack" do
+  action :remove
+end
+
+if platform?("debian")
+  apt_repository "mcp" do
+    uri "https://downloads.linux.hpe.com/SDR/repo/mcp"
+    distribution "#{node[:lsb][:codename]}/current"
+    components ["non-free"]
+    key "C208ADDE26C2B797"
+  end
+elsif platform?("ubuntu")
+  if node[:dmi][:system][:product_name].end_with?("Gen10")
+    apt_repository "mcp-jammy" do
+      uri "https://downloads.linux.hpe.com/SDR/repo/mcp"
+      distribution "jammy/current"
+      components ["non-free"]
+      key "C208ADDE26C2B797"
+    end
+
+    apt_repository "mcp-focal-gen10" do
+      uri "https://downloads.linux.hpe.com/SDR/repo/mcp"
+      distribution "focal/current-gen10"
+      components ["non-free"]
+      key "C208ADDE26C2B797"
+    end
+  else
+    apt_repository "mcp-bionic-gen9" do
+      uri "https://downloads.linux.hpe.com/SDR/repo/mcp"
+      distribution "bionic/current-gen9"
+      components ["non-free"]
+      key "C208ADDE26C2B797"
+    end
+  end
+end
diff --git a/cookbooks/apt/recipes/maxmind.rb b/cookbooks/apt/recipes/maxmind.rb
new file mode 100644 (file)
index 0000000..dbe0fc8
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# Cookbook:: apt
+# Recipe:: maxmind
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "maxmind" do
+  uri "ppa:maxmind/ppa"
+  only_if { platform?("ubuntu") }
+end
diff --git a/cookbooks/apt/recipes/nginx.rb b/cookbooks/apt/recipes/nginx.rb
new file mode 100644 (file)
index 0000000..b80b8bb
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# Cookbook:: apt
+# Recipe:: nginx
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+platform_name = if platform?("debian")
+                  "debian"
+                else
+                  "ubuntu"
+                end
+
+apt_repository "nginx" do
+  arch "amd64"
+  uri "https://nginx.org/packages/#{platform_name}"
+  components ["nginx"]
+  key "ABF5BD827BD9BF62"
+end
diff --git a/cookbooks/apt/recipes/nodesource.rb b/cookbooks/apt/recipes/nodesource.rb
new file mode 100644 (file)
index 0000000..3e4fb94
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Cookbook:: apt
+# Recipe:: nodesource
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "nodesource" do
+  uri "https://deb.nodesource.com/node_20.x"
+  distribution "nodistro"
+  components ["main"]
+  key "https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key"
+end
diff --git a/cookbooks/apt/recipes/passenger.rb b/cookbooks/apt/recipes/passenger.rb
new file mode 100644 (file)
index 0000000..136175b
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Cookbook:: apt
+# Recipe:: passenger
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "passenger" do
+  uri "https://oss-binaries.phusionpassenger.com/apt/passenger"
+  components ["main"]
+  key "561F9B9CAC40B2F7"
+end
diff --git a/cookbooks/apt/recipes/postgresql.rb b/cookbooks/apt/recipes/postgresql.rb
new file mode 100644 (file)
index 0000000..66e4c1c
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Cookbook:: apt
+# Recipe:: postgresql
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "postgresql" do
+  uri "https://apt.postgresql.org/pub/repos/apt"
+  distribution "#{node[:lsb][:codename]}-pgdg"
+  components ["main"]
+  key "7FCC7D46ACCC4CF8"
+end
diff --git a/cookbooks/apt/recipes/yarn.rb b/cookbooks/apt/recipes/yarn.rb
new file mode 100644 (file)
index 0000000..7451e96
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Cookbook:: apt
+# Recipe:: yarn
+#
+# Copyright:: 2022, Tom Hughes
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt"
+
+apt_repository "yarn" do
+  uri "https://dl.yarnpkg.com/debian"
+  distribution "stable"
+  components ["main"]
+  key "1646B01B86E50310"
+end
index b0552bbc1907ebfcdacffde4f7ab9c3dedfe5925..8943458e9359229907fe6e1b25b30de3f4012fb0 100644 (file)
@@ -3,3 +3,11 @@
 // Do automatic removal of new unused dependencies after the upgrade
 // (equivalent to apt-get autoremove)
 Unattended-Upgrade::Remove-Unused-Dependencies "<%= node[:apt][:unattended_upgrades][:remove_unused_dependencies] ? 'true' : 'false' %>";
+
+// Don't install recommended packages as we don't want to get
+// new postgres versions automatically
+APT::Install-Recommends "false";
+
+// Briefly wait for lock on dpkg/apt
+// to avoid concurrent issues with unattended-upgrades and apt daily
+DPkg::lock::timeout 90;
diff --git a/cookbooks/apt/templates/default/preferences.erb b/cookbooks/apt/templates/default/preferences.erb
deleted file mode 100644 (file)
index 6f89c16..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-Package: cciss-vol-status
-Pin: origin "*.ubuntu.com"
-Pin-Priority: 1100
index e572f7ced598e41f2b10d3607940ecab14d46dfb..d514279b76f5f4af6813bb41aacaf5791676c9d9 100644 (file)
@@ -1,51 +1,21 @@
 # DO NOT EDIT - This file is being maintained by Chef
+<% if @archive_suites.include?("main") -%>
 
-deb http://<%= @archive_host %>/ubuntu/ <%= @codename %> main restricted
-deb-src http://<%= @archive_host %>/ubuntu/ <%= @codename %> main restricted
+deb http://<%= @archive_host %>/<%= @archive_distro %>/ <%= @codename %> <%= @archive_components.join(" ") %>
+# deb-src http://<%= @archive_host %>/<%= @archive_distro %>/ <%= @codename %> <%= @archive_components.join(" ") %>
+<% end -%>
+<% if @archive_suites.include?("updates") -%>
 
-## Major bug fix updates produced after the final release of the
-## distribution.
-deb http://<%= @archive_host %>/ubuntu/ <%= @codename %>-updates main restricted
-deb-src http://<%= @archive_host %>/ubuntu/ <%= @codename %>-updates main restricted
+deb http://<%= @archive_host %>/<%= @archive_distro %>/ <%= @codename %>-updates <%= @archive_components.join(" ") %>
+# deb-src http://<%= @archive_host %>/<%= @archive_distro %>/ <%= @codename %>-updates <%= @archive_components.join(" ") %>
+<% end -%>
+<% if @archive_suites.include?("backports") -%>
 
-## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
-## team. Also, please note that software in universe WILL NOT receive any
-## review or updates from the Ubuntu security team.
-deb http://<%= @archive_host %>/ubuntu/ <%= @codename %> universe
-deb-src http://<%= @archive_host %>/ubuntu/ <%= @codename %> universe
-deb http://<%= @archive_host %>/ubuntu/ <%= @codename %>-updates universe
-deb-src http://<%= @archive_host %>/ubuntu/ <%= @codename %>-updates universe
+deb http://<%= @archive_host %>/<%= @archive_distro %>/ <%= @codename %>-backports <%= @archive_components.join(" ") %>
+# deb-src http://<%= @archive_host %>/<%= @archive_distro %>/ <%= @codename %>-backports <%= @archive_components.join(" ") %>
+<% end -%>
+<% if @archive_suites.include?("security") -%>
 
-## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu 
-## team, and may not be under a free licence. Please satisfy yourself as to 
-## your rights to use the software. Also, please note that software in 
-## multiverse WILL NOT receive any review or updates from the Ubuntu
-## security team.
-deb http://<%= @archive_host %>/ubuntu/ <%= @codename %> multiverse
-deb-src http://<%= @archive_host %>/ubuntu/ <%= @codename %> multiverse
-deb http://<%= @archive_host %>/ubuntu/ <%= @codename %>-updates multiverse
-deb-src http://<%= @archive_host %>/ubuntu/ <%= @codename %>-updates multiverse
-
-## Uncomment the following two lines to add software from the 'backports'
-## repository.
-## N.B. software from this repository may not have been tested as
-## extensively as that contained in the main release, although it includes
-## newer versions of some applications which may provide useful features.
-## Also, please note that software in backports WILL NOT receive any review
-## or updates from the Ubuntu security team.
-deb http://<%= @archive_host %>/ubuntu/ <%= @codename %>-backports main restricted universe multiverse
-deb-src http://<%= @archive_host %>/ubuntu/ <%= @codename %>-backports main restricted universe multiverse
-
-## Uncomment the following two lines to add software from Canonical's
-## 'partner' repository. This software is not part of Ubuntu, but is
-## offered by Canonical and the respective vendors as a service to Ubuntu
-## users.
-# deb http://archive.canonical.com/ubuntu <%= @codename %> partner
-# deb-src http://archive.canonical.com/ubuntu <%= @codename %> partner
-
-deb http://security.ubuntu.com/ubuntu <%= @codename %>-security main restricted
-deb-src http://security.ubuntu.com/ubuntu <%= @codename %>-security main restricted
-deb http://security.ubuntu.com/ubuntu <%= @codename %>-security universe
-deb-src http://security.ubuntu.com/ubuntu <%= @codename %>-security universe
-deb http://security.ubuntu.com/ubuntu <%= @codename %>-security multiverse
-deb-src http://security.ubuntu.com/ubuntu <%= @codename %>-security multiverse
+deb http://<%= @archive_security_host %>/<%= @archive_security_distro %>/ <%= @codename %>-security <%= @archive_components.join(" ") %>
+# deb-src http://<%= @archive_security_host %>/<%= @archive_security_distro %>/ <%= @codename %>-security <%= @archive_components.join(" ") %>
+<% end -%>
diff --git a/cookbooks/awscli/README.md b/cookbooks/awscli/README.md
new file mode 100644 (file)
index 0000000..9009059
--- /dev/null
@@ -0,0 +1,3 @@
+# awscli Cookbook
+
+This cookbook installs and configures awscli
diff --git a/cookbooks/awscli/attributes/default.rb b/cookbooks/awscli/attributes/default.rb
new file mode 100644 (file)
index 0000000..09d356d
--- /dev/null
@@ -0,0 +1,2 @@
+# Set the default awscli version
+default[:awscli][:version] = "latest"
similarity index 63%
rename from cookbooks/cgiirc/metadata.rb
rename to cookbooks/awscli/metadata.rb
index 3b4b8207171a401ec66b0e8ea592af207e52ca81..56be15b3c37edcdbb30429611312cd0b42f8f754 100644 (file)
@@ -1,9 +1,9 @@
-name              "cgiirc"
+name              "awscli"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures cgiirc"
+description       "Installs and configures awscli"
 
 version           "1.0.0"
+supports          "debian"
 supports          "ubuntu"
-depends           "apache"
diff --git a/cookbooks/awscli/recipes/default.rb b/cookbooks/awscli/recipes/default.rb
new file mode 100644 (file)
index 0000000..2268486
--- /dev/null
@@ -0,0 +1,89 @@
+#
+# Cookbook:: awscli
+# Recipe:: default
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+cache_dir = Chef::Config[:file_cache_path]
+
+# Determine architecture of system for the AWS CLI download
+awscli_arch = if arm?
+                "aarch64"
+              else
+                "x86_64"
+              end
+
+awscli_version_suffix = if node[:awscli][:version] == "latest"
+                          "" # latest version does not have a suffix
+                        else
+                          "-#{node[:awscli][:version]}"
+                        end
+
+awscli_zip = "awscliv2#{awscli_version_suffix}.zip"
+
+# Ensure unpack directory is removed
+directory "#{cache_dir}/awscli" do
+  action :delete
+  recursive true
+end
+
+# Remove any existing AWS CLI zip files, unless it's the one we're downloading
+Dir.glob("#{cache_dir}/awscliv2*.zip").each do |zip|
+  next if zip == "#{cache_dir}/#{awscli_zip}"
+
+  file zip do
+    action :delete
+    backup false
+  end
+end
+
+# Download the AWS CLI zip file
+remote_file "#{cache_dir}/#{awscli_zip}" do
+  source "https://awscli.amazonaws.com/awscli-exe-linux-#{awscli_arch}#{awscli_version_suffix}.zip"
+  owner "root"
+  group "root"
+  mode "644"
+  backup false
+  ignore_failure true
+end
+
+# Extract the AWS CLI zip file
+archive_file "#{cache_dir}/#{awscli_zip}" do
+  path "#{cache_dir}/#{awscli_zip}"
+  destination "#{cache_dir}/awscli"
+  strip_components 1
+  action :nothing
+  subscribes :extract, "remote_file[#{cache_dir}/#{awscli_zip}]", :immediately
+end
+
+# Find the version of the AWS CLI we just downloaded
+# Example version string: aws-cli/2.12.6 Python/3.11.4 Linux/5.15.49-linuxkit-pr exe/aarch64.ubuntu.22 prompt/off
+# Install CLI to path: /opt/awscli/v2/current/bin/aws
+ruby_block "install-awscli" do
+  block do
+    require "fileutils"
+    awscli_version_string = shell_out("#{cache_dir}/awscli/dist/aws", "--version")
+    awscli_version = awscli_version_string.stdout.split(" ").first.split("/").last
+    FileUtils.mkdir_p("/opt/awscli/v2/#{awscli_version}/bin/", :mode => 0755)
+    FileUtils.mv("#{cache_dir}/awscli/dist", "/opt/awscli/v2/#{awscli_version}/dist", :force => true)
+    FileUtils.ln_sf("/opt/awscli/v2/#{awscli_version}/dist/aws", "/opt/awscli/v2/#{awscli_version}/bin/aws")
+    FileUtils.ln_sf("/opt/awscli/v2/#{awscli_version}/dist/aws_completer", "/opt/awscli/v2/#{awscli_version}/bin/aws_completer")
+    FileUtils.rm("/opt/awscli/v2/current") if File.exist?("/opt/awscli/v2/current")
+    FileUtils.ln_sf("/opt/awscli/v2/#{awscli_version}", "/opt/awscli/v2/current")
+  end
+  action :nothing
+  subscribes :run, "archive_file[#{cache_dir}/#{awscli_zip}]", :immediately
+end
index c0b8de57fac80d3d0e113116f78e07e7fc643d08..2773238abd6b254b931ad86345fafb1fda49502d 100644 (file)
@@ -1 +1,3 @@
 default[:stats][:sites] = []
+
+default[:accounts][:users][:osmbackup][:status] = :role
index 0cd75a5029dba6cbafceb5effec5f58f4be775ab..9d82c384a620c656115fd75d2c749a62e265c1e7 100644 (file)
@@ -43,19 +43,23 @@ for my $month (0 .. $months - 1)
 }
 
 my $dates = join("|", @dates);
-my $match = qr/^${prefix}\d{4}-\d{2}-\d{2}\./;
-my $keep = qr/^${prefix}(?:${dates})\./;
+my $match = qr/^\Q${prefix}\E\d{4}-\d{2}-\d{2}\./;
+my $keep = qr/^\Q${prefix}\E(?:${dates})\./;
 
 opendir(DIR, "$dir") || die "Can't open ${dir}: $!";
 
-while (my $file = readdir(DIR))
-{
-#    print "Expiring $file\n" if $file =~ $match && $file !~ $keep;
-    unlink("${dir}/${file}") if $file =~ $match && $file !~ $keep;
-}
+my @files = sort(grep(/$match/, readdir(DIR)));
 
 closedir(DIR);
 
+pop @files;
+
+for my $file (@files)
+{
+#    print "Expiring $file\n" if $file !~ $keep;
+    unlink("${dir}/${file}") if $file !~ $keep;
+}
+
 exit 0;
 
 sub Monday
index c4f1bdabd113dd2fc0e7c9f346a8208e496a84ae..d5baa16641ad1dcb8a721fef4628ca37ac3b96b8 100644 (file)
@@ -6,3 +6,4 @@ description       "Installs and configures backup.openstreetmap.org"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
index 0204f56f294f6b558c22a26c59f2147687ccef85..0999231ef4a9ca7322960a18c732318719cefe71 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
+
 package %w[
   perl
   libdate-calc-perl
+  awscli
 ]
 
 directory "/store/backup" do
   owner "osmbackup"
   group "osmbackup"
-  mode 0o2755
+  mode "2755"
+  recursive true
 end
 
 cookbook_file "/usr/local/bin/expire-backups" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 template "/etc/cron.daily/expire-backups" do
   source "expire.cron.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
index 9f80b24c06a36e62a2b23efdd62cb63b04dd70c8..e1ec74a08a36aec5305ef367324d17cc4bf326d6 100644 (file)
@@ -2,7 +2,7 @@
 
 # DO NOT EDIT - This file is being maintained by Chef
 
-for prefix in chef-server chef-repository chef-git forum git lists munin osm-blog osm-donate osmf-crm osmf-ledgersmb wiki-wiki.osmfoundation.org osqa otrs sotm svn switch2osm trac wiki-board.osmfoundation.org wiki-dwg.osmfoundation.org wiki-wiki.openstreetmap.org
+for prefix in blogs chef-server chef-repository chef-git community forum git lists osm-blog osmf-crm osmf-ledgersmb wiki-wiki.osmfoundation.org osqa otrs prometheus sotm svn switch2osm trac wiki-board.osmfoundation.org wiki-dwg.osmfoundation.org wiki-mwg.osmfoundation.org wiki-wiki.openstreetmap.org
 do
   /usr/local/bin/expire-backups --days=3 --weeks=3 --months=3 /store/backup $prefix
 done
diff --git a/cookbooks/bind/attributes/default.rb b/cookbooks/bind/attributes/default.rb
deleted file mode 100644 (file)
index 9ebc921..0000000
+++ /dev/null
@@ -1 +0,0 @@
-default[:bind] = {}
index 087ef5802f4db2ff5eaac454f40f41675adcde8d..39f0ba2fddb1753170f151395c009272f748fdd6 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "networking"
-
-clients = search(:node, "roles:#{node[:bind][:clients]}")
-
-ipv4_clients = clients.collect do |client|
-  client.ipaddresses(:family => :inet)
-end.flatten
-
-ipv6_clients = clients.collect do |client|
-  client.ipaddresses(:family => :inet6)
-end.flatten
-
 package "bind9"
 
-service "bind9" do
+service "named" do
   action [:enable, :start]
-  supports :status => true, :restart => true, :reload => true
 end
 
 template "/etc/bind/named.conf.local" do
   source "named.local.erb"
   owner "root"
   group "root"
-  mode 0o644
-  notifies :restart, "service[bind9]"
+  mode "644"
+  notifies :restart, "service[named]"
 end
 
 template "/etc/bind/named.conf.options" do
   source "named.options.erb"
   owner "root"
   group "root"
-  mode 0o644
-  variables :ipv4_clients => ipv4_clients, :ipv6_clients => ipv6_clients
-  notifies :restart, "service[bind9]"
+  mode "644"
+  notifies :restart, "service[named]"
 end
 
 template "/etc/bind/db.10" do
   source "db.10.erb"
   owner "root"
   group "root"
-  mode 0o644
-  notifies :reload, "service[bind9]"
+  mode "644"
+  notifies :reload, "service[named]"
 end
 
 firewall_rule "accept-dns-udp" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "udp"
+  context :incoming
+  protocol :udp
   dest_ports "domain"
-  source_ports "-"
 end
 
 firewall_rule "accept-dns-tcp" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "tcp:syn"
+  context :incoming
+  protocol :tcp
   dest_ports "domain"
-  source_ports "-"
 end
index 05dc9d618caed69aac6bf684102624a036fdb8db..7ae7d5fbdc680f062e4c025709fa4218148eb7be 100644 (file)
@@ -2,7 +2,7 @@
 
 $TTL   604800
 @      IN      SOA     <%= node[:fdqn] %>. root.openstreetmap.org. (
-                     2019040301                ; Serial
+                     2021092001                ; Serial
                          604800                ; Refresh
                           86400                ; Retry
                         2419200                ; Expire
@@ -11,83 +11,26 @@ $TTL        604800
 @              IN      NS      <%= node[:fdqn] %>.
 
 3.0.0          IN      PTR     ridley.ucl.openstreetmap.org.
-5.0.0          IN      PTR     norbert.ucl.openstreetmap.org.
-6.0.0          IN      PTR     urmel.ucl.openstreetmap.org.
-7.0.0          IN      PTR     faffy.ucl.openstreetmap.org.
-8.0.0          IN      PTR     zark.ucl.openstreetmap.org.
-9.0.0          IN      PTR     eustace.ucl.openstreetmap.org.
+4.0.0          IN      PTR     snap-02.ucl.openstreetmap.org.
 10.0.0         IN      PTR     eddie.ucl.openstreetmap.org.
-11.0.0         IN      PTR     draco.ucl.openstreetmap.org.
 12.0.0         IN      PTR     sarel.ucl.openstreetmap.org.
 13.0.0         IN      PTR     noquiklos.ucl.openstreetmap.org.
-14.0.0         IN      PTR     errol.ucl.openstreetmap.org.
-15.0.0         IN      PTR     yevaud.ucl.openstreetmap.org.
+15.0.0         IN      PTR     ysera.ucl.openstreetmap.org.
 17.0.0         IN      PTR     clifford.ucl.openstreetmap.org.
-19.0.0         IN      PTR     grindtooth.ucl.openstreetmap.org.
 20.0.0         IN      PTR     pummelzacken.ucl.openstreetmap.org.
-40.0.0         IN      PTR     tiamat-00.ucl.openstreetmap.org.
-41.0.0         IN      PTR     tiamat-01.ucl.openstreetmap.org.
-42.0.0         IN      PTR     tiamat-02.ucl.openstreetmap.org.
-43.0.0         IN      PTR     tiamat-03.ucl.openstreetmap.org.
-44.0.0         IN      PTR     tiamat-10.ucl.openstreetmap.org.
-45.0.0         IN      PTR     tiamat-11.ucl.openstreetmap.org.
-46.0.0         IN      PTR     tiamat-12.ucl.openstreetmap.org.
-47.0.0         IN      PTR     tiamat-13.ucl.openstreetmap.org.
-48.0.0         IN      PTR     tiamat-20.ucl.openstreetmap.org.
-49.0.0         IN      PTR     tiamat-21.ucl.openstreetmap.org.
-50.0.0         IN      PTR     tiamat-22.ucl.openstreetmap.org.
-51.0.0         IN      PTR     tiamat-23.ucl.openstreetmap.org.
 
 3.1.0          IN      PTR     ridley.oob.openstreetmap.org.
-5.1.0          IN      PTR     norbert.oob.openstreetmap.org.
-6.1.0          IN      PTR     urmel.oob.openstreetmap.org.
-8.1.0          IN      PTR     zark.oob.openstreetmap.org.
-9.1.0          IN      PTR     eustace.oob.openstreetmap.org.
+4.1.0          IN      PTR     snap-02.oob.openstreetmap.org.
 10.1.0         IN      PTR     eddie.oob.openstreetmap.org.
-11.1.0         IN      PTR     draco.oob.openstreetmap.org.
 12.1.0         IN      PTR     sarel.oob.openstreetmap.org.
 13.1.0         IN      PTR     noquiklos.oob.openstreetmap.org.
-14.1.0         IN      PTR     errol.oob.openstreetmap.org.
-15.1.0         IN      PTR     yevaud.oob.openstreetmap.org.
+15.1.0         IN      PTR     ysera.oob.openstreetmap.org.
 17.1.0         IN      PTR     clifford.oob.openstreetmap.org.
-19.1.0         IN      PTR     grindtooth.oob.openstreetmap.org.
 20.1.0         IN      PTR     pummelzacken.oob.openstreetmap.org.
-40.1.0         IN      PTR     tiamat-00.oob.openstreetmap.org.
-41.1.0         IN      PTR     tiamat-01.oob.openstreetmap.org.
-42.1.0         IN      PTR     tiamat-02.oob.openstreetmap.org.
-43.1.0         IN      PTR     tiamat-03.oob.openstreetmap.org.
-44.1.0         IN      PTR     tiamat-10.oob.openstreetmap.org.
-45.1.0         IN      PTR     tiamat-11.oob.openstreetmap.org.
-46.1.0         IN      PTR     tiamat-12.oob.openstreetmap.org.
-47.1.0         IN      PTR     tiamat-13.oob.openstreetmap.org.
-48.1.0         IN      PTR     tiamat-20.oob.openstreetmap.org.
-49.1.0         IN      PTR     tiamat-21.oob.openstreetmap.org.
-50.1.0         IN      PTR     tiamat-22.oob.openstreetmap.org.
-51.1.0         IN      PTR     tiamat-23.oob.openstreetmap.org.
 
-2.16.0         IN      PTR     orm.bm.openstreetmap.org.
-3.16.0         IN      PTR     shenron.bm.openstreetmap.org.
-
-20.32.0                IN      PTR     grisu.bm.openstreetmap.org.
-21.32.0                IN      PTR     spike-04.bm.openstreetmap.org.
-22.32.0                IN      PTR     spike-05.bm.openstreetmap.org.
-40.32.0                IN      PTR     katla.bm.openstreetmap.org.
-41.32.0                IN      PTR     thorn-04.bm.openstreetmap.org.
-42.32.0                IN      PTR     thorn-05.bm.openstreetmap.org.
-
-20.33.0                IN      PTR     grisu.oob.openstreetmap.org.
-21.33.0                IN      PTR     spike-04.oob.openstreetmap.org.
-22.33.0                IN      PTR     spike-05.oob.openstreetmap.org.
-40.33.0                IN      PTR     katla.oob.openstreetmap.org.
-41.33.0                IN      PTR     thorn-04.oob.openstreetmap.org.
-42.33.0                IN      PTR     thorn-05.oob.openstreetmap.org.
-
-3.48.0         IN      PTR     orm.ams.openstreetmap.org.
-4.48.0         IN      PTR     ouroboros.ams.openstreetmap.org.
-5.48.0         IN      PTR     ramoth.ams.openstreetmap.org.
-6.48.0         IN      PTR     spike-01.ams.openstreetmap.org.
-7.48.0         IN      PTR     spike-02.ams.openstreetmap.org.
-8.48.0         IN      PTR     spike-03.ams.openstreetmap.org.
+3.48.0         IN      PTR     faffy.ams.openstreetmap.org.
+4.48.0         IN      PTR     dribble.ams.openstreetmap.org.
+5.48.0         IN      PTR     vhagar.ams.openstreetmap.org.
 9.48.0         IN      PTR     dulcy.ams.openstreetmap.org.
 10.48.0                IN      PTR     ironbelly.ams.openstreetmap.org.
 11.48.0                IN      PTR     spike-06.ams.openstreetmap.org.
@@ -95,19 +38,14 @@ $TTL        604800
 13.48.0                IN      PTR     spike-08.ams.openstreetmap.org.
 14.48.0                IN      PTR     tabaluga.ams.openstreetmap.org.
 15.48.0                IN      PTR     odin.ams.openstreetmap.org.
+17.48.0                IN      PTR     norbert.ams.openstreetmap.org.
+49.48.0                IN      PTR     snap-01.ams.openstreetmap.org.
 50.48.0                IN      PTR     karm.ams.openstreetmap.org.
-51.48.0                IN      PTR     thorn-01.ams.openstreetmap.org.
-52.48.0                IN      PTR     thorn-02.ams.openstreetmap.org.
-53.48.0                IN      PTR     thorn-03.ams.openstreetmap.org.
-100.48.0       IN      PTR     pdu1.openstreetmap.org.
-101.48.0       IN      PTR     pdu2.openstreetmap.org.
+100.48.0       IN      PTR     pdu1.ams.openstreetmap.org.
+101.48.0       IN      PTR     pdu2.ams.openstreetmap.org.
+102.48.0       IN      PTR     oob1.ams.openstreetmap.org.
 
-3.49.0         IN      PTR     orm.oob.openstreetmap.org.
-4.49.0         IN      PTR     ouroboros.oob.openstreetmap.org.
-5.49.0         IN      PTR     ramoth.oob.openstreetmap.org.
-6.49.0         IN      PTR     spike-01.oob.openstreetmap.org.
-7.49.0         IN      PTR     spike-02.oob.openstreetmap.org.
-8.49.0         IN      PTR     spike-03.oob.openstreetmap.org.
+3.49.0         IN      PTR     faffy.oob.openstreetmap.org.
 9.49.0         IN      PTR     dulcy.oob.openstreetmap.org.
 10.49.0                IN      PTR     ironbelly.oob.openstreetmap.org.
 11.49.0                IN      PTR     spike-06.oob.openstreetmap.org.
@@ -115,7 +53,43 @@ $TTL        604800
 13.49.0                IN      PTR     spike-08.oob.openstreetmap.org.
 14.49.0                IN      PTR     tabaluga.oob.openstreetmap.org.
 15.49.0                IN      PTR     odin.oob.openstreetmap.org.
+17.49.0                IN      PTR     norbert.oob.openstreetmap.org.
+49.49.0                IN      PTR     snap-01.oob.openstreetmap.org.
 50.49.0                IN      PTR     karm.oob.openstreetmap.org.
-51.49.0                IN      PTR     thorn-01.oob.openstreetmap.org.
 52.49.0                IN      PTR     thorn-02.oob.openstreetmap.org.
 53.49.0                IN      PTR     thorn-03.oob.openstreetmap.org.
+
+2.64.0         IN      PTR     fafnir.dub.openstreetmap.org.
+3.64.0         IN      PTR     spike-01.dub.openstreetmap.org.
+4.64.0         IN      PTR     spike-02.dub.openstreetmap.org.
+5.64.0         IN      PTR     spike-03.dub.openstreetmap.org.
+6.64.0         IN      PTR     idris.dub.openstreetmap.org.
+7.64.0         IN      PTR     konqi.dub.openstreetmap.org.
+8.64.0         IN      PTR     naga.dub.openstreetmap.org.
+9.64.0         IN      PTR     culebre.dub.openstreetmap.org.
+10.64.0                IN      PTR     horntail.dub.openstreetmap.org.
+12.64.0                IN      PTR     jakelong.dub.openstreetmap.org.
+13.64.0                IN      PTR     longma.dub.openstreetmap.org.
+14.64.0                IN      PTR     smaug.dub.openstreetmap.org.
+15.64.0                IN      PTR     muirdris.dub.openstreetmap.org.
+16.64.0                IN      PTR     fume.dub.openstreetmap.org.
+17.64.0                IN      PTR     grisu.dub.openstreetmap.org.
+50.64.0                IN      PTR     snap-03.dub.openstreetmap.org.
+100.64.0       IN      PTR     pdu1.dub.openstreetmap.org.
+101.64.0       IN      PTR     pdu2.dub.openstreetmap.org.
+102.64.0       IN      PTR     oob1.dub.openstreetmap.org.
+
+2.65.0         IN      PTR     fafnir.oob.openstreetmap.org.
+3.65.0         IN      PTR     spike-01.oob.openstreetmap.org.
+4.65.0         IN      PTR     spike-02.oob.openstreetmap.org.
+5.65.0         IN      PTR     spike-03.oob.openstreetmap.org.
+6.65.0         IN      PTR     idris.oob.openstreetmap.org.
+7.65.0         IN      PTR     konqi.oob.openstreetmap.org.
+8.65.0         IN      PTR     naga.oob.openstreetmap.org.
+9.65.0         IN      PTR     culebre.oob.openstreetmap.org.
+10.65.0                IN      PTR     horntail.oob.openstreetmap.org.
+12.65.0                IN      PTR     jakelong.oob.openstreetmap.org.
+13.65.0                IN      PTR     longma.oob.openstreetmap.org.
+14.65.0                IN      PTR     smaug.oob.openstreetmap.org.
+15.65.0                IN      PTR     muirdris.oob.openstreetmap.org.
+50.65.0                IN      PTR     snap-03.oob.openstreetmap.org.
index 2ec4094dc8bb65d12e3b0924fff3af9c65872a24..ac4f32303267938744df6076b0ca39179fc13e8e 100644 (file)
@@ -1,38 +1,11 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-acl "osm" {
-       127.0.0.1/32;
-<% node.interfaces(:family => :inet).each do |interface| -%>
-        <%= interface[:network] %>/<%= interface[:prefix] %>;
-<% end -%>
-<% @ipv4_clients.sort.each do |address| -%>
-       <%= address %>/32;
-<% end -%>
-
-       ::1/128;
-<% node.interfaces(:family => :inet6).each do |interface| -%>
-        <%= interface[:network] %>/<%= interface[:prefix] %>;
-<% end -%>
-<% @ipv6_clients.sort.each do |address| -%>
-       <%= address %>/128;
-<% end -%>
-};
-
 options {
         # Directory to use for any working files
        directory "/var/cache/bind";
 
-<% if node[:bind][:forwarders] -%>
-       # Forward any queries we can't answer
-       forwarders {
-<% node[:bind][:forwarders].each do |forwarder| -%>
-               <%= forwarder %>;
-<% end -%>
-       };
-<% end -%>
-
        # Only allow queries from our machines
-       allow-query { osm; };
+       allow-query { localnets; };
 
        # Don't allow transfers
        allow-transfer { none; };
diff --git a/cookbooks/blog/recipes/birthday.rb b/cookbooks/blog/recipes/birthday.rb
new file mode 100644 (file)
index 0000000..eac984a
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# Cookbook:: blog
+# Recipe:: birthday
+#
+# Copyright:: 2024, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "wordpress"
+
+passwords = data_bag_item("birthday20", "passwords")
+wp2fa_encrypt_keys = data_bag_item("birthday20", "wp2fa_encrypt_keys")
+
+directory "/srv/birthday20.openstreetmap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+wordpress_site "birthday20.openstreetmap.org" do
+  aliases ["birthday20.osm.org", "birthday20.openstreetmap.com",
+           "birthday20.openstreetmap.net", "birthday20.openstreetmaps.org"]
+  directory "/srv/birthday20.openstreetmap.org/wp"
+  database_name "osm-birthday20"
+  database_user "osm-birthday20-user"
+  database_password passwords["osm-birthday20-user"]
+  wp2fa_encrypt_key wp2fa_encrypt_keys["key"]
+  fpm_prometheus_port 11403
+end
+
+wordpress_plugin "birthday20.openstreetmap.org-shareadraft" do
+  action :delete
+  plugin "shareadraft"
+  site "birthday20.openstreetmap.org"
+end
+
+wordpress_plugin "birthday20.openstreetmap.org-public-post-preview" do
+  plugin "public-post-preview"
+  site "birthday20.openstreetmap.org"
+end
+
+template "/etc/cron.daily/birthday20-backup" do
+  source "backup-birthday20.cron.erb"
+  owner "root"
+  group "root"
+  mode "750"
+  variables :passwords => passwords
+end
index 78965844826e7838bc510d5368c0259a48cf5bed..5a876d8a6b16878924abf1d2426221071bb50c97 100644 (file)
 include_recipe "wordpress"
 
 passwords = data_bag_item("blog", "passwords")
+wp2fa_encrypt_keys = data_bag_item("blog", "wp2fa_encrypt_keys")
 
 directory "/srv/blog.openstreetmap.org" do
   owner "wordpress"
   group "wordpress"
-  mode 0o755
+  mode "755"
 end
 
 wordpress_site "blog.openstreetmap.org" do
   aliases ["blog.osm.org", "blog.openstreetmap.com",
            "blog.openstreetmap.net", "blog.openstreetmaps.org",
-           "blog.osmfoundation.org"]
+           "blog.osmfoundation.org",
+           "opengeodata.org", "www.opengeodata.org",
+           "old.opengeodata.org" # https://blog.openstreetmap.org/2010/02/25/old-opengeodata-posts-now-up-at-old-opengeodata-org/
+          ]
   directory "/srv/blog.openstreetmap.org/wp"
   database_name "osm-blog"
   database_user "osm-blog-user"
   database_password passwords["osm-blog-user"]
+  wp2fa_encrypt_key wp2fa_encrypt_keys["key"]
   urls "/casts" => "/srv/blog.openstreetmap.org/casts",
        "/images" => "/srv/blog.openstreetmap.org/images",
        "/static" => "/srv/blog.openstreetmap.org/static"
+  fpm_prometheus_port 11401
 end
 
 wordpress_theme "blog.openstreetmap.org-osmblog-wp-theme" do
   theme "osmblog-wp-theme"
   site "blog.openstreetmap.org"
-  repository "git://github.com/harry-wood/osmblog-wp-theme.git"
+  repository "https://github.com/osmfoundation/osmblog-wp-theme.git"
 end
 
 wordpress_plugin "blog.openstreetmap.org-google-analytics-for-wordpress" do
+  action :delete
   plugin "google-analytics-for-wordpress"
   site "blog.openstreetmap.org"
 end
 
 wordpress_plugin "blog.openstreetmap.org-google-sitemap-generator" do
+  action :delete
   plugin "google-sitemap-generator"
   site "blog.openstreetmap.org"
 end
 
+# wordpress_plugin "blog.openstreetmap.org-www-xml-sitemap-generator-org" do
+#   plugin "www-xml-sitemap-generator-org"
+#   site "blog.openstreetmap.org"
+# end
+
 wordpress_plugin "blog.openstreetmap.org-shareadraft" do
+  action :delete
   plugin "shareadraft"
   site "blog.openstreetmap.org"
 end
 
+wordpress_plugin "blog.openstreetmap.org-public-post-preview" do
+  plugin "public-post-preview"
+  site "blog.openstreetmap.org"
+end
+
 wordpress_plugin "blog.openstreetmap.org-sitepress-multilingual-cms" do
   plugin "sitepress-multilingual-cms"
   site "blog.openstreetmap.org"
   repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
+  revision "master"
+  not_if { kitchen? }
 end
 
 wordpress_plugin "blog.openstreetmap.org-wordpress-importer" do
+  action :delete
   plugin "wordpress-importer"
   site "blog.openstreetmap.org"
 end
 
+wordpress_plugin "blog.openstreetmap.org-wp-piwik" do
+  plugin "wp-piwik"
+  site "blog.openstreetmap.org"
+end
+
 git "/srv/blog.openstreetmap.org/casts" do
   action :sync
-  repository "git://github.com/openstreetmap/opengeodata-podcasts.git"
+  repository "https://github.com/openstreetmap/opengeodata-podcasts.git"
+  revision "master"
   depth 1
   user "wordpress"
   group "wordpress"
@@ -82,7 +110,8 @@ end
 
 git "/srv/blog.openstreetmap.org/images" do
   action :sync
-  repository "git://github.com/openstreetmap/opengeodata-images.git"
+  repository "https://github.com/openstreetmap/opengeodata-images.git"
+  revision "master"
   depth 1
   user "wordpress"
   group "wordpress"
@@ -90,26 +119,17 @@ end
 
 git "/srv/blog.openstreetmap.org/static" do
   action :sync
-  repository "git://github.com/openstreetmap/opengeodata-static.git"
+  repository "https://github.com/openstreetmap/opengeodata-static.git"
+  revision "master"
   depth 1
   user "wordpress"
   group "wordpress"
 end
 
-ssl_certificate "opengeodata.org" do
-  domains ["opengeodata.org", "www.opengeodata.org", "old.opengeodata.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "opengeodata.org" do
-  template "opengeodata.erb"
-  directory "/srv/opengeodata.org"
-end
-
 template "/etc/cron.daily/blog-backup" do
   source "backup.cron.erb"
   owner "root"
   group "root"
-  mode 0o750
+  mode "750"
   variables :passwords => passwords
 end
diff --git a/cookbooks/blog/recipes/staging.rb b/cookbooks/blog/recipes/staging.rb
new file mode 100644 (file)
index 0000000..01d413b
--- /dev/null
@@ -0,0 +1,133 @@
+#
+# Cookbook:: blog
+# Recipe:: staging
+#
+# Copyright:: 2024, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "wordpress"
+
+passwords = data_bag_item("blog-staging", "passwords")
+wp2fa_encrypt_keys = data_bag_item("blog-staging", "wp2fa_encrypt_keys")
+
+directory "/srv/staging.blog.openstreetmap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+wordpress_site "staging.blog.openstreetmap.org" do
+  aliases ["staging.blog.osm.org", "staging.blog.openstreetmap.com",
+           "staging.blog.openstreetmap.net", "staging.blog.openstreetmaps.org",
+           "staging.blog.osmfoundation.org"
+          ]
+  directory "/srv/staging.blog.openstreetmap.org/wp"
+  database_name "osm-blog-staging"
+  database_user "osm-blog-staging-user"
+  database_password passwords["osm-blog-staging-user"]
+  wp2fa_encrypt_key wp2fa_encrypt_keys["key"]
+  urls "/casts" => "/srv/staging.blog.openstreetmap.org/casts",
+       "/images" => "/srv/staging.blog.openstreetmap.org/images",
+       "/static" => "/srv/staging.blog.openstreetmap.org/static"
+  fpm_prometheus_port 11401
+end
+
+wordpress_theme "staging.blog.openstreetmap.org-osmblog-wp-theme" do
+  theme "osmblog-wp-theme"
+  site "staging.blog.openstreetmap.org"
+  repository "https://github.com/osmfoundation/osmblog-wp-theme.git"
+end
+
+wordpress_plugin "staging.blog.openstreetmap.org-google-analytics-for-wordpress" do
+  action :delete
+  plugin "google-analytics-for-wordpress"
+  site "staging.blog.openstreetmap.org"
+end
+
+wordpress_plugin "staging.blog.openstreetmap.org-google-sitemap-generator" do
+  action :delete
+  plugin "google-sitemap-generator"
+  site "staging.blog.openstreetmap.org"
+end
+
+# wordpress_plugin "blog.openstreetmap.org-www-xml-sitemap-generator-org" do
+#   plugin "www-xml-sitemap-generator-org"
+#   site "staging.blog.openstreetmap.org"
+# end
+
+wordpress_plugin "staging.blog.openstreetmap.org-shareadraft" do
+  action :delete
+  plugin "shareadraft"
+  site "staging.blog.openstreetmap.org"
+end
+
+wordpress_plugin "staging.blog.openstreetmap.org-public-post-preview" do
+  plugin "public-post-preview"
+  site "staging.blog.openstreetmap.org"
+end
+
+wordpress_plugin "staging.blog.openstreetmap.org-sitepress-multilingual-cms" do
+  plugin "sitepress-multilingual-cms"
+  site "staging.blog.openstreetmap.org"
+  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
+  revision "master"
+  not_if { kitchen? }
+end
+
+wordpress_plugin "staging.blog.openstreetmap.org-wordpress-importer" do
+  action :delete
+  plugin "wordpress-importer"
+  site "staging.blog.openstreetmap.org"
+end
+
+wordpress_plugin "staging.blog.openstreetmap.org-wp-piwik" do
+  plugin "wp-piwik"
+  site "staging.blog.openstreetmap.org"
+end
+
+git "/srv/staging.blog.openstreetmap.org/casts" do
+  action :sync
+  repository "https://github.com/openstreetmap/opengeodata-podcasts.git"
+  revision "master"
+  depth 1
+  user "wordpress"
+  group "wordpress"
+end
+
+git "/srv/staging.blog.openstreetmap.org/images" do
+  action :sync
+  repository "https://github.com/openstreetmap/opengeodata-images.git"
+  revision "master"
+  depth 1
+  user "wordpress"
+  group "wordpress"
+end
+
+git "/srv/staging.blog.openstreetmap.org/static" do
+  action :sync
+  repository "https://github.com/openstreetmap/opengeodata-static.git"
+  revision "master"
+  depth 1
+  user "wordpress"
+  group "wordpress"
+end
+
+template "/etc/cron.daily/blog-staging-backup" do
+  source "backup-staging.cron.erb"
+  owner "root"
+  group "root"
+  mode "750"
+  variables :passwords => passwords
+end
diff --git a/cookbooks/blog/templates/default/backup-birthday20.cron.erb b/cookbooks/blog/templates/default/backup-birthday20.cron.erb
new file mode 100644 (file)
index 0000000..cef3d14
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+T=$(mktemp -d -t -p /var/tmp osm-birthday20.XXXXXXXXXX)
+D=$(date +%Y-%m-%d)
+B=osm-birthday20-$D.tar.gz
+
+mkdir $T/osm-birthday20-$D
+echo '[mysqldump]' > $T/mysqldump.opts
+echo 'user=osm-birthday20-user' >> $T/mysqldump.opts
+echo 'password=<%= @passwords["osm-birthday20-user"] %>' >> $T/mysqldump.opts
+mysqldump --defaults-file=$T/mysqldump.opts --opt --no-tablespaces osm-birthday20 > $T/osm-birthday20-$D/osm-birthday20.sql
+ln -s /srv/birthday20.openstreetmap.org $T/osm-birthday20-$D/www
+
+export RSYNC_RSH="ssh -ax"
+
+nice tar --create --dereference --directory=$T --warning=no-file-changed osm-birthday20-$D | nice gzip --rsyncable -9 > $T/$B
+nice rsync --preallocate --fuzzy $T/$B backup::backup
+
+rm -rf $T
diff --git a/cookbooks/blog/templates/default/backup-staging.cron.erb b/cookbooks/blog/templates/default/backup-staging.cron.erb
new file mode 100644 (file)
index 0000000..91169ed
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+T=$(mktemp -d -t -p /var/tmp osm-blog-staging.XXXXXXXXXX)
+D=$(date +%Y-%m-%d)
+B=osm-blog-staging-$D.tar.gz
+
+mkdir $T/osm-blog-staging-$D
+echo '[mysqldump]' > $T/mysqldump.opts
+echo 'user=osm-blog-staging-user' >> $T/mysqldump.opts
+echo 'password=<%= @passwords["osm-blog-staging-user"] %>' >> $T/mysqldump.opts
+mysqldump --defaults-file=$T/mysqldump.opts --opt --no-tablespaces osm-blog-staging > $T/osm-blog-staging-$D/osm-blog-staging.sql
+ln -s /srv/staging.blog.openstreetmap.org $T/osm-blog-staging-$D/www
+
+export RSYNC_RSH="ssh -ax"
+
+nice tar --create --dereference --directory=$T --warning=no-file-changed osm-blog-staging-$D | nice gzip --rsyncable -9 > $T/$B
+nice rsync --preallocate --fuzzy $T/$B backup::backup
+
+rm -rf $T
index 557440ff412c910e5dd9cbe26a10fb354337c31a..bc6159666e79bac886e06f3c70bc21ca4faf4843 100644 (file)
@@ -10,13 +10,12 @@ mkdir $T/osm-blog-$D
 echo '[mysqldump]' > $T/mysqldump.opts
 echo 'user=osm-blog-user' >> $T/mysqldump.opts
 echo 'password=<%= @passwords["osm-blog-user"] %>' >> $T/mysqldump.opts
-mysqldump --defaults-file=$T/mysqldump.opts --opt osm-blog > $T/osm-blog-$D/osm-blog.sql
+mysqldump --defaults-file=$T/mysqldump.opts --opt --no-tablespaces osm-blog > $T/osm-blog-$D/osm-blog.sql
 ln -s /srv/blog.openstreetmap.org $T/osm-blog-$D/www
 
-export GZIP="--rsyncable -9"
 export RSYNC_RSH="ssh -ax"
 
-nice tar --create --gzip --dereference --directory=$T --warning=no-file-changed --file=$T/$B osm-blog-$D
+nice tar --create --dereference --directory=$T --warning=no-file-changed osm-blog-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
diff --git a/cookbooks/blog/templates/default/opengeodata.erb b/cookbooks/blog/templates/default/opengeodata.erb
deleted file mode 100644 (file)
index 1150145..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:80>
-  ServerName opengeodata.org
-  ServerAlias www.opengeodata.org
-  ServerAlias old.opengeodata.org # https://blog.openstreetmap.org/2010/02/25/old-opengeodata-posts-now-up-at-old-opengeodata-org/
-
-  ServerAdmin webmaster@openstreetmap.org
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  RewriteEngine on
-  RewriteRule ^(.*/)index\.html$ https://blog.openstreetmap.org/$1 [R=permanent,L]
-
-  RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-  RedirectPermanent / https://blog.openstreetmap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-  ServerName opengeodata.org
-  ServerAlias www.opengeodata.org
-  ServerAlias old.opengeodata.org # https://blog.openstreetmap.org/2010/02/25/old-opengeodata-posts-now-up-at-old-opengeodata-org/
-
-  ServerAdmin webmaster@openstreetmap.org
-
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/opengeodata.org.pem
-  SSLCertificateKeyFile /etc/ssl/private/opengeodata.org.key
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  RewriteEngine on
-  RewriteRule ^(.*/)index\.html$ https://blog.openstreetmap.org/$1 [R=permanent,L]
-
-  RedirectPermanent / https://blog.openstreetmap.org/
-</VirtualHost>
index 6f2b7dfc6dc5aa667340907cc79daa1b24d9674d..0e797074db621b2d12016ac6c2490663976b8c00 100644 (file)
@@ -6,5 +6,8 @@ description       "Configures server-info web site"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
 depends           "git"
+depends           "ruby"
+depends           "systemd"
index d08fc482cb410b4c4ab27f4f2ba736c538aa8dd8..0fb2cc7aad06dc4739e903125d59de39ec871bdb 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "apache"
 include_recipe "git"
+include_recipe "ruby"
 
-package %w[
-  ruby
-  ruby-dev
+package %W[
   make
   gcc
+  g++
   libsqlite3-dev
+  sqlite3
 ]
 
-gem_package "bundler"
-
 directory "/srv/blogs.openstreetmap.org" do
   owner "blogs"
   group "blogs"
-  mode 0o755
+  mode "755"
 end
 
 git "/srv/blogs.openstreetmap.org" do
   action :sync
-  repository "git://github.com/gravitystorm/blogs.osm.org.git"
+  repository "https://github.com/gravitystorm/blogs.osm.org.git"
+  depth 1
   user "blogs"
   group "blogs"
-  notifies :run, "execute[/srv/blogs.openstreetmap.org/Gemfile]", :immediate
 end
 
-execute "/srv/blogs.openstreetmap.org/Gemfile" do
+bundle_install "/srv/blogs.openstreetmap.org" do
   action :nothing
-  command "bundle install"
-  cwd "/srv/blogs.openstreetmap.org"
-  user "root"
-  group "root"
-  notifies :run, "execute[/srv/blogs.openstreetmap.org]", :immediate
+  options "--deployment --without development test"
+  environment "BUNDLE_PATH" => "vendor/bundle"
+  user "blogs"
+  group "blogs"
+  subscribes :run, "git[/srv/blogs.openstreetmap.org]", :immediately
 end
 
-execute "/srv/blogs.openstreetmap.org" do
+bundle_exec "/srv/blogs.openstreetmap.org" do
   action :nothing
-  command "bundle exec /usr/local/bin/pluto build -t osm -o build"
-  cwd "/srv/blogs.openstreetmap.org"
+  command "pluto build -t osm -o build"
+  environment "BUNDLE_PATH" => "vendor/bundle"
   user "blogs"
   group "blogs"
+  subscribes :run, "git[/srv/blogs.openstreetmap.org]", :immediately
 end
 
 ssl_certificate "blogs.openstreetmap.org" do
@@ -72,9 +73,34 @@ apache_site "blogs.openstreetmap.org" do
   variables :aliases => ["blogs.osm.org"]
 end
 
-template "/etc/cron.d/blogs" do
-  source "cron.erb"
+template "/usr/local/bin/blogs-update" do
+  source "blogs-update.erb"
+  owner "root"
+  group "root"
+  mode "0755"
+end
+
+systemd_service "blogs-update" do
+  description "Update blog aggregator"
+  exec_start "/usr/local/bin/blogs-update"
+  user "blogs"
+  sandbox :enable_network => true
+  read_write_paths "/srv/blogs.openstreetmap.org"
+end
+
+systemd_timer "blogs-update" do
+  description "Update blog aggregator"
+  on_boot_sec "15m"
+  on_unit_inactive_sec "30m"
+end
+
+service "blogs-update.timer" do
+  action [:enable, :start]
+end
+
+template "/etc/cron.daily/blogs-backup" do
+  source "backup.cron.erb"
   owner "root"
   group "root"
-  mode "0644"
+  mode "0755"
 end
index 507d48b1968184c207b9a75a3c2cac91490f2e16..e2ae4cf3efb254545ec3eeab11f48c2cfd12d970 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -26,7 +26,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent / https://<%= @name %>/
@@ -41,7 +41,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   DocumentRoot <%= @directory %>
diff --git a/cookbooks/blogs/templates/default/backup.cron.erb b/cookbooks/blogs/templates/default/backup.cron.erb
new file mode 100644 (file)
index 0000000..382989a
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+T=$(mktemp -d -t -p /var/tmp blogs.XXXXXXXXXX)
+D=$(date +%Y-%m-%d)
+B=blogs-$D.tar.gz
+
+mkdir $T/blogs-$D
+sqlite3 /srv/blogs.openstreetmap.org/planet.db ".backup $T/blogs-$D/planet.db"
+
+export RSYNC_RSH="ssh -ax"
+
+nice tar --create --dereference --directory=$T blogs-$D | nice gzip --rsyncable -9 > $T/$B
+nice rsync --preallocate --fuzzy $T/$B backup::backup
+
+rm -rf $T
diff --git a/cookbooks/blogs/templates/default/blogs-update.erb b/cookbooks/blogs/templates/default/blogs-update.erb
new file mode 100644 (file)
index 0000000..a7d0214
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+cd /srv/blogs.openstreetmap.org
+
+export BUNDLE_PATH="vendor/bundle"
+
+<%= node[:ruby][:bundle] %> exec pluto \
+       --quieter \
+       --config=/srv/blogs.openstreetmap.org build \
+       --dbpath=/srv/blogs.openstreetmap.org \
+       --template=osm \
+       --output=/srv/blogs.openstreetmap.org/build \
+       /srv/blogs.openstreetmap.org/planet.ini > log.$$ 2>&1
+
+if [ $? -ne 0 ]
+then
+    cat log.$$
+fi
+
+rm -f log.$$
diff --git a/cookbooks/blogs/templates/default/cron.erb b/cookbooks/blogs/templates/default/cron.erb
deleted file mode 100644 (file)
index c2d6dfb..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-MAILTO=admins@openstreetmap.org
-
-*/30 * * * * blogs cd /srv/blogs.openstreetmap.org; bundle exec /usr/local/bin/pluto --quieter --config=/srv/blogs.openstreetmap.org build --dbpath=/srv/blogs.openstreetmap.org --template=osm --output=/srv/blogs.openstreetmap.org/build /srv/blogs.openstreetmap.org/planet.ini > /dev/null
diff --git a/cookbooks/cgiirc/README.md b/cookbooks/cgiirc/README.md
deleted file mode 100644 (file)
index 49eeb3d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# Cgiirc Cookbook
-
-This cookbook installs and configures the `cgiirc` program that powers the
-web interface to the OSM IRC channels, found at irc.openstreetmap.org
diff --git a/cookbooks/cgiirc/templates/default/apache.erb b/cookbooks/cgiirc/templates/default/apache.erb
deleted file mode 100644 (file)
index 1afb107..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-  ServerName <%= @name %>
-  ServerAdmin webmaster@openstreetmap.org
-
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  DocumentRoot /usr/lib/cgi-bin/cgiirc
-  DirectoryIndex irc.cgi
-  Alias /images /usr/share/images/cgiirc
-
-  <Directory "/usr/lib/cgi-bin/cgiirc">
-    AddHandler cgi-script .cgi
-    Require all granted
-  </Directory>
-
-  <Directory "/usr/share/images/cgiirc">
-    Require all granted
-  </Directory>
-
-  <IfModule mod_deflate.c>
-    RemoveOutputFilter DEFLATE
-    SetEnv no-gzip
-  </IfModule>
-</VirtualHost>
-<% unless @aliases.empty? -%>
-
-<VirtualHost *:443>
-  ServerName <%= @aliases.first %>
-<% @aliases.drop(1).each do |alias_name| -%>
-  ServerAlias <%= alias_name %>
-<% end -%>
-  ServerAdmin webmaster@openstreetmap.org
-
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
-<% end -%>
-
-<VirtualHost *:80>
-  ServerName <%= @name %>
-<% @aliases.each do |alias_name| -%>
-  ServerAlias <%= alias_name %>
-<% end -%>
-       ServerAdmin webmaster@openstreetmap.org
-
-       CustomLog /var/log/apache2/<%= @name %>-access.log combined
-       ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-       RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-       RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
diff --git a/cookbooks/cgiirc/templates/default/cgiirc.config.erb b/cookbooks/cgiirc/templates/default/cgiirc.config.erb
deleted file mode 100644 (file)
index 794b4cb..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# CGI:IRC configuration file.
-#
-# Check /usr/share/doc/cgiirc/examples/cgiirc.config.full.gz
-# for more details.
-
-# Configure defaults
-default_server = irc.oftc.net
-default_port = 6667
-default_channel = #osm,#osm-dev,#osm-ewg,#osm-cwg,#osm-ar,#osm-asia,#osm-au,#osm-br,#osm-bw,#osm-by,#osm-ca,#osm-ch,#osm-cz,#osm-de,#osm-dk,#osm-es,#osm-fi,#osm-fr,#osm-gb,#osm-gr,#osm-gsoc,#osm-ht,#osm-ie,#osm-it,#osm-ke,#osm-latam,#osm-local,#osm-lv,#osm-nl,#osm-no,#osm-nominatim,#osm-pl,#osm-pt,#osm-ru,#osm.se,#osm-strategic,#osm-ua,#osm-us,#osm-za,#osm-zh,#osmf-gm,#osrm,#openrailwaymap,#hot
-default_name = CGI:IRC User
-default_nick = CGI???
-
-# Path to images
-image_path = /images
-
-# Paths to CGI scripts
-script_nph = nph-irc.cgi
-script_form = client-perl.cgi
-script_login = irc.cgi
-
-# Access control file
-ip_access_file = ipaccess
diff --git a/cookbooks/cgiirc/templates/default/ipaccess.erb b/cookbooks/cgiirc/templates/default/ipaccess.erb
deleted file mode 100644 (file)
index ba2851c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# CGI:IRC ipaccess file. (For CGI:IRC versions from 0.5.3).
-#
-# Check /usr/share/doc/cgiirc/examples/ipaccess.example
-# for more details.
-
-<% @blocks.each do |name,addresses| -%>
-# Block <%= name %>
-<% addresses.each do |address| -%>
-<%= address %> 0
-<% end -%>
-
-<% end -%>
-# Allow everybody.
-0.0.0.0/0
index 2cac140f19e7489c274d0c24ca2b21de79b6ecd9..d6284df52d68f502322f83a064189382c761868b 100644 (file)
@@ -1,8 +1,5 @@
-# Add the opscode APT source for chef
-default[:apt][:sources] = node[:apt][:sources] | ["opscode"]
-
 # Set the default server version
-default[:chef][:server][:version] = "12.17.33"
+default[:chef][:server][:version] = "15.1.7"
 
 # Set the default client version
-default[:chef][:client][:version] = "14.12.9"
+default[:chef][:client][:version] = "18.4.12"
diff --git a/cookbooks/chef/libraries/cpu.rb b/cookbooks/chef/libraries/cpu.rb
new file mode 100644 (file)
index 0000000..1e2d844
--- /dev/null
@@ -0,0 +1,11 @@
+module OpenStreetMap
+  module Mixin
+    module CPU
+      def cpu_cores
+        [dig("cpu", "total").to_i, dig("cpu", "cores").to_i, 4].max
+      end
+    end
+  end
+end
+
+Chef::Node.include(OpenStreetMap::Mixin::CPU)
index bfbec455cebc82d00acc90725b70b627c9e3f36a..7de56267f3628b62f639ce6afdc1d6b267accb0a 100644 (file)
@@ -1,4 +1,4 @@
-class Chef
+module OpenStreetMap
   module Mixin
     module EditFile
       def edit_file(file, &_block)
@@ -10,8 +10,6 @@ class Chef
       end
     end
   end
-
-  class Recipe
-    include Chef::Mixin::EditFile
-  end
 end
+
+Chef::DSL::Recipe.include(OpenStreetMap::Mixin::EditFile)
diff --git a/cookbooks/chef/libraries/git.rb b/cookbooks/chef/libraries/git.rb
new file mode 100644 (file)
index 0000000..176613d
--- /dev/null
@@ -0,0 +1,13 @@
+module OpenStreetMap
+  module Provider
+    module Git
+      def git(*args, **run_opts)
+        args.push("--force") if args.first == "fetch" && args.last == "--tags"
+
+        super(args, **run_opts)
+      end
+    end
+  end
+end
+
+Chef::Provider::Git.prepend(OpenStreetMap::Provider::Git)
diff --git a/cookbooks/chef/libraries/persistent_token.rb b/cookbooks/chef/libraries/persistent_token.rb
new file mode 100644 (file)
index 0000000..944f193
--- /dev/null
@@ -0,0 +1,18 @@
+require "digest"
+
+module OpenStreetMap
+  module Mixin
+    module PersistentToken
+      def persistent_token(*args)
+        sha256 = Digest::SHA256.new
+        sha256.update(node[:machine_id])
+        args.each do |arg|
+          sha256.update(arg)
+        end
+        sha256.hexdigest
+      end
+    end
+  end
+end
+
+Chef::DSL::Recipe.include(OpenStreetMap::Mixin::PersistentToken)
diff --git a/cookbooks/chef/libraries/random_password.rb b/cookbooks/chef/libraries/random_password.rb
deleted file mode 100644 (file)
index 71d8bcf..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-class Chef
-  class Recipe
-    def random_password(length)
-      Array.new(length) do
-        "!\#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"[rand(91)].chr
-      end.join
-    end
-  end
-end
index cbcce026a8c772268d8eb9c32ae5d87f7b0848dd..e8717d06e4ae86d419dd99fa7752f7b2e602e5bc 100644 (file)
@@ -5,12 +5,18 @@ class Chef
     class Subversion
       extend Chef::Mixin::ShellOut
 
+      def shell_out!(*args, **options)
+        options = args.pop if options.empty? && args.last.is_a?(Hash)
+
+        super(*args, **options)
+      end
+
       def sync_command
         if current_repository_matches_target_repository?
           c = scm :update, new_resource.svn_arguments, verbose, authentication, proxy, "-r#{revision_int}", new_resource.destination
           Chef::Log.debug "#{new_resource} updated working copy #{new_resource.destination} to revision #{new_resource.revision}"
         else
-          c = scm :switch, new_resource.svn_arguments, verbose, authentication, proxy, "-r#{revision_int}", new_resource.repository, new_resource.destination
+          c = scm :switch, new_resource.svn_arguments, verbose, authentication, proxy, "-r#{revision_int}", "--ignore-ancestry", new_resource.repository, new_resource.destination
           Chef::Log.debug "#{new_resource} updated working copy #{new_resource.destination} to #{new_resource.repository} revision #{new_resource.revision}"
         end
         c
@@ -42,7 +48,18 @@ class Chef
 
       def svn_info
         command = scm(:info)
-        shell_out!(command, run_options(:cwd => cwd, :returns => [0, 1])).stdout
+        shell_out!(command, **run_options(:cwd => cwd, :returns => [0, 1])).stdout
+      end
+
+      def revision_int
+        @revision_int ||= if new_resource.revision =~ /^\d+$/
+                            new_resource.revision
+                          else
+                            command = scm(:info, new_resource.repository, new_resource.svn_info_args, authentication, "-r#{new_resource.revision}")
+                            svn_info = shell_out!(command, **run_options(:returns => [0, 1])).stdout
+
+                            extract_revision_info(svn_info)
+                          end
       end
     end
   end
index 69f344996ce045fd129812ab518e2f3f4965652d..b2572c50d54453a88dcaf5b495f61eb3a8c23027 100644 (file)
@@ -10,6 +10,5 @@ depends           "apache"
 depends           "apt"
 depends           "git"
 depends           "ohai"
-depends           "munin"
 depends           "systemd"
-gem               "mail"
+gem               "mail", "= 2.7.1"
index f2f0101c08b22d7c8a30b63e582545a57425b628..a27b99cbdcc4fcb5c25491f4aaf5f5b1b9208a4f 100644 (file)
 # limitations under the License.
 #
 
+cache_dir = Chef::Config[:file_cache_path]
+
 chef_version = node[:chef][:client][:version]
-chef_package = "chef_#{chef_version}-1_amd64.deb"
+
+chef_platform = if platform?("debian")
+                  "debian"
+                else
+                  "ubuntu"
+                end
+
+chef_arch = if arm?
+              "arm64"
+            else
+              "amd64"
+            end
+
+os_release = if platform?("debian") && node[:lsb][:release].to_f > 11
+               11
+             else
+               node[:lsb][:release]
+             end
+
+# Chef is currently not available for Debian 11 on arm64.
+if chef_platform == "debian" && os_release == 11 && chef_arch == "arm64"
+  chef_platform = "ubuntu"
+  os_release = "22.04"
+end
+
+chef_package = "chef_#{chef_version}-1_#{chef_arch}.deb"
 
 directory "/var/cache/chef" do
-  owner "root"
-  group "root"
-  mode 0o755
+  action :delete
+  recursive true
 end
 
-Dir.glob("/var/cache/chef/chef_*.deb").each do |deb|
-  next if deb == "/var/cache/chef/#{chef_package}"
+Dir.glob("#{cache_dir}/chef_*.deb").each do |deb|
+  next if deb == "#{cache_dir}/#{chef_package}"
 
   file deb do
     action :delete
@@ -35,91 +61,79 @@ Dir.glob("/var/cache/chef/chef_*.deb").each do |deb|
   end
 end
 
-remote_file "/var/cache/chef/#{chef_package}" do
-  source "https://packages.chef.io/files/stable/chef/#{chef_version}/ubuntu/#{node[:lsb][:release]}/#{chef_package}"
+remote_file "#{cache_dir}/#{chef_package}" do
+  source "https://packages.chef.io/files/stable/chef/#{chef_version}/#{chef_platform}/#{os_release}/#{chef_package}"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   backup false
   ignore_failure true
 end
 
 dpkg_package "chef" do
-  source "/var/cache/chef/#{chef_package}"
+  source "#{cache_dir}/#{chef_package}"
   version "#{chef_version}-1"
 end
 
 directory "/etc/chef" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 template "/etc/chef/client.rb" do
   source "client.rb.erb"
   owner "root"
   group "root"
-  mode 0o640
+  mode "640"
 end
 
 file "/etc/chef/client.pem" do
   owner "root"
   group "root"
-  mode 0o400
+  mode "400"
 end
 
 template "/etc/chef/report.rb" do
   source "report.rb.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 template "/etc/logrotate.d/chef" do
   source "logrotate.erb"
   owner "root"
   group "root"
-  mode 0o644
-end
-
-directory "/etc/chef/trusted_certs" do
-  owner "root"
-  group "root"
-  mode 0o755
-end
-
-template "/etc/chef/trusted_certs/verisign.pem" do
-  source "verisign.pem.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+  mode "644"
 end
 
 directory node[:ohai][:plugin_dir] do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/log/chef" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 systemd_service "chef-client" do
+  description "Chef client"
+  exec_start "/usr/bin/chef-client"
+  nice 10
+end
+
+systemd_timer "chef-client" do
   description "Chef client"
   after "network.target"
-  exec_start "/usr/bin/chef-client -i 1800 -s 20"
-  restart "on-failure"
+  on_active_sec 60
+  on_unit_inactive_sec 25 * 60
+  randomized_delay_sec 10 * 60
 end
 
-service "chef-client" do
+service "chef-client.timer" do
   action [:enable, :start]
-  restart_command "systemctl kill --signal=TERM chef-client.service"
-  supports :status => true, :restart => true, :reload => true
-  subscribes :restart, "dpkg_package[chef]"
-  subscribes :restart, "template[/etc/init/chef-client.conf]"
-  subscribes :restart, "template[/etc/chef/client.rb]"
-  subscribes :restart, "template[/etc/chef/report.rb]"
 end
diff --git a/cookbooks/chef/recipes/knife.rb b/cookbooks/chef/recipes/knife.rb
new file mode 100644 (file)
index 0000000..4f95d9f
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Cookbook:: chef
+# Recipe:: knife
+#
+# Copyright:: 2021, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+package %w[
+  gcc
+  g++
+  libc6-dev
+  make
+]
+
+chef_gem "knife"
index 28d0b2f39367ca85bab94406a9407a6dbfb93c20..752938bf3fe515935b58ea3afe642296bca3c057 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "chef::knife"
 include_recipe "git"
 
 keys = data_bag_item("chef", "keys")
 
+chef_gem "bundler" do
+  version ">= 2.1.4"
+end
+
 directory "/var/lib/chef" do
   owner "chefrepo"
   group "chefrepo"
-  mode 0o2775
+  mode "2775"
 end
 
 %w[public private].each do |repository|
@@ -41,28 +46,28 @@ end
   directory "/var/lib/chef/#{repository}/.chef" do
     owner "chefrepo"
     group "chefrepo"
-    mode 0o2775
+    mode "2775"
   end
 
   file "/var/lib/chef/#{repository}/.chef/client.pem" do
     content keys["git"].join("\n")
     owner "chefrepo"
     group "chefrepo"
-    mode 0o660
+    mode "660"
   end
 
   cookbook_file "/var/lib/chef/#{repository}/.chef/knife.rb" do
     source "knife.rb"
     owner "chefrepo"
     group "chefrepo"
-    mode 0o660
+    mode "660"
   end
 
   template "#{repository_directory}/hooks/post-receive" do
     source "post-receive.erb"
     owner "chefrepo"
     group "chefrepo"
-    mode 0o750
+    mode "750"
     variables :repository => repository
   end
 end
index eb2a33ae4a31ecb18178e791687aa57bff04f6b1..93e9363dc8e60859d570027b2744802881450160 100644 (file)
 #
 
 include_recipe "apache"
+include_recipe "chef::knife"
 
+# cache_dir = Chef::Config[:file_cache_path]
+#
 # chef_version = node[:chef][:server][:version]
 # chef_package = "chef-server-core_#{chef_version}-1_amd64.deb"
 #
-# directory "/var/cache/chef" do
-#   owner "root"
-#   group "root"
-#   mode 0755
-# end
+# Dir.glob("#{cache_dir}/chef-server-core_*.deb").each do |deb|
+#   next if deb == "#{cache_dir}/#{chef_package}"
 #
-# Dir.glob("/var/cache/chef/chef-server-core_*.deb").each do |deb|
-#   next if deb == "/var/cache/chef/#{chef_package}"
-
 #   file deb do
 #     action :delete
 #     backup false
 #   end
 # end
 #
-# remote_file "/var/cache/chef/#{chef_package}" do
-#   source "https://packages.chef.io/files/stable/chef-server/#{chef_version}/ubuntu/16.04/#{chef_package}"
+# remote_file "#{cache_dir}/#{chef_package}" do
+#   source "https://packages.chef.io/files/stable/chef-server/#{chef_version}/ubuntu/20.04/chef-server-core_#{chef_version}-1_amd64.deb"
 #   owner "root"
 #   group "root"
 #   mode 0644
@@ -46,7 +43,7 @@ include_recipe "apache"
 # end
 #
 # dpkg_package "chef-server-core" do
-#   source "/var/cache/chef/#{chef_package}"
+#   source "#{cache_dir}/#{chef_package}"
 #   version "#{chef_version}-1"
 #   notifies :run, "execute[chef-server-reconfigure]"
 # end
@@ -55,7 +52,7 @@ template "/etc/opscode/chef-server.rb" do
   source "server.rb.erb"
   owner "root"
   group "root"
-  mode 0o640
+  mode "640"
   notifies :run, "execute[chef-server-reconfigure]"
 end
 
@@ -101,7 +98,5 @@ template "/etc/cron.daily/chef-server-backup" do
   source "server-backup.cron.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
-
-munin_plugin "chef_status"
index 9d86d910e7c858b4ccdfdd3b9e71391e8c8a7705..917759a7cb4b1d2823b27460e643ebb7874e7a04 100644 (file)
@@ -5,7 +5,7 @@
        ServerAlias chef.osm.org
        ServerAdmin webmaster@openstreetmap.org
 
-       CustomLog /var/log/apache2/chef.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/chef.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/chef.openstreetmap.org-error.log
 
        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -16,7 +16,7 @@
        ServerName chef.openstreetmap.org
        ServerAdmin webmaster@openstreetmap.org
 
-       CustomLog /var/log/apache2/chef.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/chef.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/chef.openstreetmap.org-error.log
 
        SSLEngine on
diff --git a/cookbooks/chef/templates/default/chef-client.conf.erb b/cookbooks/chef/templates/default/chef-client.conf.erb
deleted file mode 100644 (file)
index 9414e05..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# chef-client
-#
-# Startup script for chef-client
-
-description "starts up chef-client in daemon mode"
-
-start on (net-device-up
-          and local-filesystems
-          and runlevel [2345])
-stop on runlevel [!2345]
-
-script
-        exec /usr/bin/chef-client -i 1800 -s 20
-end script
-
-respawn
index 5d1f463930de23870f0273116e749d3218690e62..6faa7384b5164c819b0cfde8c597ef2fa0e8c355 100644 (file)
@@ -9,6 +9,10 @@
 
 Encoding.default_external = Encoding::UTF_8
 
+# Accept the license
+
+chef_license "accept"
+
 # Log at level info
 
 log_level :info
@@ -29,9 +33,9 @@ ssl_verify_mode :verify_peer
 
 chef_server_url "https://chef.openstreetmap.org/organizations/openstreetmap"
 
-# Make our plugins visible to ohai
+# Enable some optional ohai plugins
 
-ohai.plugin_path << "<%= node[:ohai][:plugin_dir] %>"
+ohai.optional_plugins = %w[Passwd]
 
 # Load supporting code for report handlers
 
index b402265c17fffff8be8219c27293490bc965a3dc..28ef5b4345874929661a8c46ff85dbc9e64de4d8 100644 (file)
@@ -5,6 +5,8 @@
 umask 0002
 unset GIT_DIR
 
+knife="/opt/chef/embedded/bin/knife"
+
 while read oldrev newrev refname
 do
   if [[ "$refname" = "refs/heads/master" ]]
@@ -25,17 +27,17 @@ do
       if [[ $file == roles/*.rb ]]
       then
         case "$action" in
-          A|M) knife role from file "${file}";;
-          D) knife role delete -y "${file:t:r}";;
+          A|M) $knife role from file "${file}";;
+          D) $knife role delete -y "${file:t:r}";;
         esac
       elif [[ $file == data_bags/*/*.json ]]
       then
         case "$action" in
           A|M) 
-            knife data bag create "${file:h:t}"
-            knife data bag from file "${file:h:t}" "${file:t}";;
+            $knife data bag create "${file:h:t}"
+            $knife data bag from file "${file:h:t}" "${file:t}";;
           D)
-            knife data bag delete -y "${file:h:t}" "${file:t:r}";;
+            $knife data bag delete -y "${file:h:t}" "${file:t:r}";;
         esac
       elif [[ $file == cookbooks/* ]]
       then
@@ -52,14 +54,14 @@ do
 
     if [[ -n "$updated_cookbooks" ]]
     then
-      knife cookbook upload "${(ou)updated_cookbooks[@]}"
+      $knife cookbook upload "${(ou)updated_cookbooks[@]}"
     fi
 
     if [[ -n "$deleted_cookbooks" ]]
     then
       for cookbook in "${(ou)deleted_cookbooks[@]}"
       do
-        knife cookbook delete -y "$cookbook"
+        $knife cookbook delete -y "$cookbook"
       done
     fi
   fi
index 20e32ef4fccea228512250a50e68e2aaaf29e1a8..4265d0660cb18412a5070ee8ee44152cb024210f 100644 (file)
@@ -31,6 +31,10 @@ class Chef
 
         require "mail"
 
+        Mail.defaults do
+          delivery_method :exim, :location => "/usr/sbin/exim"
+        end
+
         Mail.deliver do
           to to_address
           from from_address
index 048bc99e9679e2b41ad5598f1d730f18056e8ec4..04e6c0e0c2363c1e0d61ad43f8b1dcd2d3da0fb9 100644 (file)
@@ -10,9 +10,7 @@ chmod g+rwx $T $T/chef-server-$D
 sudo -u opscode-pgsql /opt/opscode/embedded/bin/pg_dumpall --file=$T/chef-server-$D/chef.dmp --clean
 ln -s /var/opt/opscode/bookshelf/data $T/chef-server-$D/bookshelf
 
-export GZIP="--rsyncable -9"
-
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B chef-server-$D
+nice tar --create --dereference --directory=$T chef-server-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
diff --git a/cookbooks/chef/templates/default/verisign.pem.erb b/cookbooks/chef/templates/default/verisign.pem.erb
deleted file mode 100644 (file)
index d209ab6..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i
-2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ
-2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ
------END CERTIFICATE-----
index 244648c49c5d32627f453f5694ef48e46df86b18..43113c5697017bf3045a57b8954054edefdd772c 100644 (file)
@@ -1,4 +1,4 @@
 # CiviCRM Cookbook
 
 This cookbook installs  CiviCRM for Wordpress, and configures it for use with
-join.osmfoundation.org for OSMF memberships.
+supporting.openstreetmap.org (formerly join.osmfoundation.org) for OSMF memberships.
index d273ae4bd5db8d02ee19590d8acb7fac8a04e011..6f1d71185af7f8872e84eb2e75b99c9bfe8f5844 100644 (file)
@@ -1,37 +1,85 @@
-default[:civicrm][:version] = "5.14.0"
+default[:civicrm][:version] = "5.69.4"
 
-default[:civicrm][:extensions][:cividiscount][:name] = "org.civicrm.module.cividiscount"
-default[:civicrm][:extensions][:cividiscount][:repository] = "git://github.com/dlobo/org.civicrm.module.cividiscount.git"
-default[:civicrm][:extensions][:cividiscount][:revision] = "3.7"
-
-default[:civicrm][:extensions][:osm][:name] = "de.systopia.osm"
-default[:civicrm][:extensions][:osm][:repository] = "git://github.com/systopia/de.systopia.osm.git"
-default[:civicrm][:extensions][:osm][:revision] = "1.2.1"
+# was used for SotM
+# default[:civicrm][:extensions][:cividiscount][:name] = "org.civicrm.module.cividiscount"
+# default[:civicrm][:extensions][:cividiscount][:repository] = "https://lab.civicrm.org/extensions/cividiscount.git"
+# default[:civicrm][:extensions][:cividiscount][:revision] = "3.8.8"
 
+# used to email people from civicrm
 default[:civicrm][:extensions][:emailapi][:name] = "org.civicoop.emailapi"
-default[:civicrm][:extensions][:emailapi][:repository] = "git://github.com/CiviCooP/org.civicoop.emailapi.git"
-default[:civicrm][:extensions][:emailapi][:revision] = "1.19"
+default[:civicrm][:extensions][:emailapi][:repository] = "https://lab.civicrm.org/extensions/emailapi.git"
+default[:civicrm][:extensions][:emailapi][:revision] = "2.12"
+
+# fancy email templates - INSTALL MANUALLY, NOT FROM GIT
+default[:civicrm][:extensions][:mosaico][:name] = "uk.co.vedaconsulting.mosaico"
+default[:civicrm][:extensions][:mosaico][:zip] = "https://download.civicrm.org/extension/uk.co.vedaconsulting.mosaico/3.3.1697392242/uk.co.vedaconsulting.mosaico-3.3.1697392242.zip"
+
+# validate that osm username exists, simple check
+default[:civicrm][:extensions][:username][:name] = "org.openstreetmap.username"
+default[:civicrm][:extensions][:username][:repository] = "https://github.com/grischard/org.openstreetmap.username.git"
+default[:civicrm][:extensions][:username][:revision] = "9d67583bd3e0342a9770cde48f23586f707012ee"
+
+# do not send report emails if daily report is empty (mwg)
+default[:civicrm][:extensions][:donotsendreportemail][:name] = "org.civicrm.donotsendreportemail"
+default[:civicrm][:extensions][:donotsendreportemail][:repository] = "https://github.com/pradpnayak/org.civicrm.donotsendreportemail.git"
+default[:civicrm][:extensions][:donotsendreportemail][:revision] = "1.0"
+
+# make civicrm look nicer
+default[:civicrm][:extensions][:theisland][:name] = "theisland"
+default[:civicrm][:extensions][:theisland][:repository] = "https://lab.civicrm.org/extensions/theisland.git"
+default[:civicrm][:extensions][:theisland][:revision] = "2.3.1"
 
-default[:civicrm][:extensions][:civiruleshttppost][:name] = "org.civicoop.civiruleshttppost"
-default[:civicrm][:extensions][:civiruleshttppost][:repository] = "git://github.com/CiviCooP/org.civicoop.civiruleshttppost.git"
-default[:civicrm][:extensions][:civiruleshttppost][:revision] = "e2c7de5f0fee319b9fca8adb1d1e122202bd2bec"
+# civiprospect
+default[:civicrm][:extensions][:civiprospect][:name] = "uk.co.compucorp.civicrm.prospect"
+default[:civicrm][:extensions][:civiprospect][:repository] = "https://github.com/compucorp/uk.co.compucorp.civicrm.prospect.git"
+default[:civicrm][:extensions][:civiprospect][:revision] = "3.1.2"
 
-default[:civicrm][:extensions][:civirules][:name] = "org.civicoop.civirules"
-default[:civicrm][:extensions][:civirules][:repository] = "https://lab.civicrm.org/extensions/civirules.git"
-default[:civicrm][:extensions][:civirules][:revision] = "2.7"
+# advanced fundraising reports
+default[:civicrm][:extensions][:advancedfundraisingreports][:name] = "net.ourpowerbase.report.advancedfundraising"
+default[:civicrm][:extensions][:advancedfundraisingreports][:repository] = "https://github.com/jmcclelland/net.ourpowerbase.report.advancedfundraising.git"
+default[:civicrm][:extensions][:advancedfundraisingreports][:revision] = "3d5bd6cab70ba338bc85d42b4853dd4a6f8c9f9b"
 
+# membership churn report
+default[:civicrm][:extensions][:membershipchurn][:name] = "uk.co.vedaconsulting.membershipchurnchart"
+default[:civicrm][:extensions][:membershipchurn][:repository] = "https://github.com/veda-consulting/uk.co.vedaconsulting.membershipchurnchart.git"
+default[:civicrm][:extensions][:membershipchurn][:revision] = "v1.1"
+
+# pivot reports for civiprospect
+default[:civicrm][:extensions][:pivotreport][:name] = "uk.co.compucorp.civicrm.pivotreport"
+default[:civicrm][:extensions][:pivotreport][:repository] = "https://github.com/compucorp/uk.co.compucorp.civicrm.pivotreport.git"
+default[:civicrm][:extensions][:pivotreport][:revision] = "2.0.7"
+
+# extra rules for membership renewal
+default[:civicrm][:extensions][:membershipextra][:name] = "com.skvare.membershipextra"
+default[:civicrm][:extensions][:membershipextra][:repository] = "https://github.com/Skvare/com.skvare.membershipextra.git"
+default[:civicrm][:extensions][:membershipextra][:revision] = "41edc3c04d49987006500b7426b38c12470446b3"
+
+# Verify active contributor status
+default[:civicrm][:extensions][:osmfverifycontributor][:name] = "osmf-verify-contributor"
+default[:civicrm][:extensions][:osmfverifycontributor][:repository] = "https://github.com/openstreetmap/osmf-verify-contributor.git"
+default[:civicrm][:extensions][:osmfverifycontributor][:revision] = "bb0cd61783033fb2e108c30e47224e5a818987f8"
+
+# Pay with Mollie
+default[:civicrm][:extensions][:omnipay][:name] = "nz.co.fuzion.omnipaymultiprocessor"
+default[:civicrm][:extensions][:omnipay][:repository] = "https://github.com/eileenmcnaughton/nz.co.fuzion.omnipaymultiprocessor.git"
+default[:civicrm][:extensions][:omnipay][:revision] = "3.23"
+
+# Pay with Stripe
 default[:civicrm][:extensions][:stripe][:name] = "com.drastikbydesign.stripe"
-default[:civicrm][:extensions][:stripe][:repository] = "git://github.com/drastik/com.drastikbydesign.stripe.git"
-default[:civicrm][:extensions][:stripe][:revision] = "4.7.3"
+default[:civicrm][:extensions][:stripe][:repository] = "https://lab.civicrm.org/extensions/stripe.git"
+default[:civicrm][:extensions][:stripe][:revision] = "6.9.4"
 
-default[:civicrm][:extensions][:mailchimp][:name] = "uk.co.vedaconsulting.mailchimp"
-default[:civicrm][:extensions][:mailchimp][:repository] = "git://github.com/veda-consulting/uk.co.vedaconsulting.mailchimp.git"
-default[:civicrm][:extensions][:mailchimp][:revision] = "v2.0.1"
+# Stripe requires mjwshared ("payment shared")
+default[:civicrm][:extensions][:mjwshared][:name] = "com.mjwconsult.mjwshared"
+default[:civicrm][:extensions][:mjwshared][:repository] = "https://lab.civicrm.org/extensions/mjwshared.git"
+default[:civicrm][:extensions][:mjwshared][:revision] = "1.2.20"
 
-default[:civicrm][:extensions][:username][:name] = "org.openstreetmap.username"
-default[:civicrm][:extensions][:username][:repository] = "git://github.com/grischard/org.openstreetmap.username.git"
-default[:civicrm][:extensions][:username][:revision] = "master"
+# Stripe requires sweetalert
+default[:civicrm][:extensions][:sweetalert][:name] = "org.civicrm.sweetalert"
+default[:civicrm][:extensions][:sweetalert][:repository] = "https://lab.civicrm.org/extensions/sweetalert.git"
+default[:civicrm][:extensions][:sweetalert][:revision] = "1.5"
 
-default[:civicrm][:extensions][:donotsendreportemail][:name] = "org.civicrm.donotsendreportemail"
-default[:civicrm][:extensions][:donotsendreportemail][:repository] = "git://github.com/pradpnayak/org.civicrm.donotsendreportemail.git"
-default[:civicrm][:extensions][:donotsendreportemail][:revision] = "3b31c2e0c62183872c7ecd244395fb8dcfbd5dbb"
+# Stripe requires firewall
+default[:civicrm][:extensions][:firewall][:name] = "org.civicrm.firewall"
+default[:civicrm][:extensions][:firewall][:repository] = "https://lab.civicrm.org/extensions/firewall.git"
+default[:civicrm][:extensions][:firewall][:revision] = "1.5.9"
index 46c17d5040d2ab1af156c814a9f2710fde3b432d..dd6bd834239cf84de6ba0d791d19379972187cfe 100644 (file)
 include_recipe "wordpress"
 include_recipe "mysql"
 
-package "wkhtmltopdf"
+package %w[
+  php-xml
+  php-curl
+  rsync
+  wkhtmltopdf
+  php-bcmath
+  php-intl
+]
+
+apache_module "rewrite"
+
+cache_dir = Chef::Config[:file_cache_path]
 
 passwords = data_bag_item("civicrm", "passwords")
+wp2fa_encrypt_keys = data_bag_item("civicrm", "wp2fa_encrypt_keys")
 
 database_password = passwords["database"]
-site_key = passwords["key"]
+site_key = passwords["site_key"]
+cred_keys = passwords["cred_keys"]
+sign_keys = passwords["sign_keys"]
 
 mysql_user "civicrm@localhost" do
   password database_password
@@ -35,106 +49,143 @@ mysql_database "civicrm" do
   permissions "civicrm@localhost" => :all
 end
 
-wordpress_site "join.osmfoundation.org" do
-  aliases "crm.osmfoundation.org"
+wordpress_site "supporting.openstreetmap.org" do
+  aliases %w[
+    crm.osmfoundation.org
+    donate.openstreetmap.org
+    donate.openstreetmap.com
+    donate.openstreetmap.net
+    donate.osm.org
+    join.osmfoundation.org
+    supporting.osmfoundation.org
+    support.osmfoundation.org
+    support.openstreetmap.org
+    supporting.osm.org
+    support.osm.org
+  ]
   database_name "civicrm"
   database_user "civicrm"
   database_password database_password
+  wp2fa_encrypt_key wp2fa_encrypt_keys["key"]
+  fpm_prometheus_port 11301
 end
 
-wordpress_theme "osmblog-wp-theme" do
-  site "join.osmfoundation.org"
-  repository "git://github.com/harry-wood/osmblog-wp-theme.git"
+wordpress_plugin "civicrm-wp-piwik" do
+  plugin "wp-piwik"
+  site "supporting.openstreetmap.org"
 end
 
 wordpress_plugin "registration-honeypot" do
-  site "join.osmfoundation.org"
+  site "supporting.openstreetmap.org"
 end
 
-wordpress_plugin "sitepress-multilingual-cms" do
-  site "join.osmfoundation.org"
-  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
+wordpress_plugin "contact-form-7" do
+  site "supporting.openstreetmap.org"
 end
 
-wordpress_plugin "contact-form-7" do
-  site "join.osmfoundation.org"
+wordpress_plugin "civicrm-admin-utilities" do
+  site "supporting.openstreetmap.org"
+end
+
+wordpress_plugin "host-webfonts-local" do
+  site "supporting.openstreetmap.org"
 end
 
 civicrm_version = node[:civicrm][:version]
-civicrm_directory = "/srv/join.osmfoundation.org/wp-content/plugins/civicrm"
+civicrm_directory = "/srv/supporting.openstreetmap.org/wp-content/plugins/civicrm"
 
 directory "/opt/civicrm-#{civicrm_version}" do
   owner "wordpress"
   group "wordpress"
-  mode 0o755
+  mode "755"
 end
 
-remote_file "/var/cache/chef/civicrm-#{civicrm_version}-wordpress.zip" do
+remote_file "#{cache_dir}/civicrm-#{civicrm_version}-wordpress.zip" do
   action :create_if_missing
   source "https://download.civicrm.org/civicrm-#{civicrm_version}-wordpress.zip"
   owner "wordpress"
   group "wordpress"
-  mode 0o644
+  mode "644"
   backup false
 end
 
-remote_file "/var/cache/chef/civicrm-#{civicrm_version}-l10n.tar.gz" do
+remote_file "#{cache_dir}/civicrm-#{civicrm_version}-l10n.tar.gz" do
   action :create_if_missing
   source "https://download.civicrm.org/civicrm-#{civicrm_version}-l10n.tar.gz"
   owner "wordpress"
   group "wordpress"
-  mode 0o644
+  mode "644"
   backup false
 end
 
-execute "/var/cache/chef/civicrm-#{civicrm_version}-wordpress.zip" do
+archive_file "#{cache_dir}/civicrm-#{civicrm_version}-wordpress.zip" do
   action :nothing
-  command "unzip -qq /var/cache/chef/civicrm-#{civicrm_version}-wordpress.zip"
-  cwd "/opt/civicrm-#{civicrm_version}"
-  user "wordpress"
+  destination "/opt/civicrm-#{civicrm_version}"
+  overwrite true
+  owner "wordpress"
   group "wordpress"
-  subscribes :run, "remote_file[/var/cache/chef/civicrm-#{civicrm_version}-wordpress.zip]", :immediately
+  subscribes :extract, "remote_file[#{cache_dir}/civicrm-#{civicrm_version}-wordpress.zip]", :immediately
 end
 
-execute "/var/cache/chef/civicrm-#{civicrm_version}-l10n.tar.gz" do
+archive_file "#{cache_dir}/civicrm-#{civicrm_version}-l10n.tar.gz" do
   action :nothing
-  command "tar -zxf /var/cache/chef/civicrm-#{civicrm_version}-l10n.tar.gz"
-  cwd "/opt/civicrm-#{civicrm_version}/civicrm"
-  user "wordpress"
+  destination "/opt/civicrm-#{civicrm_version}/civicrm"
+  overwrite true
+  owner "wordpress"
   group "wordpress"
-  subscribes :run, "remote_file[/var/cache/chef/civicrm-#{civicrm_version}-l10n.tar.gz]", :immediately
+  subscribes :extract, "remote_file[#{cache_dir}/civicrm-#{civicrm_version}-l10n.tar.gz]", :immediately
 end
 
 execute "/opt/civicrm-#{civicrm_version}/civicrm" do
   action :nothing
-  command "rsync --archive --delete /opt/civicrm-#{civicrm_version}/civicrm/ #{civicrm_directory}"
+  command "rsync --archive --delete --delete-delay --delay-updates /opt/civicrm-#{civicrm_version}/civicrm/ #{civicrm_directory}"
   user "wordpress"
   group "wordpress"
-  subscribes :run, "execute[/var/cache/chef/civicrm-#{civicrm_version}-wordpress.zip]", :immediately
-  subscribes :run, "execute[/var/cache/chef/civicrm-#{civicrm_version}-l10n.tar.gz]", :immediately
+  subscribes :run, "archive_file[#{cache_dir}/civicrm-#{civicrm_version}-wordpress.zip]", :immediately
+  subscribes :run, "archive_file[#{cache_dir}/civicrm-#{civicrm_version}-l10n.tar.gz]", :immediately
 end
 
-directory "/srv/join.osmfoundation.org/wp-content/plugins/files" do
+directory "/srv/supporting.openstreetmap.org/wp-content/uploads" do
   owner "www-data"
   group "www-data"
-  mode 0o755
+  mode "755"
 end
 
-extensions_directory = "/srv/join.osmfoundation.org/wp-content/plugins/civicrm-extensions"
+extensions_directory = "/srv/supporting.openstreetmap.org/wp-content/plugins/civicrm-extensions"
 
 directory extensions_directory do
   owner "wordpress"
   group "wordpress"
-  mode 0o755
+  mode "755"
 end
 
 node[:civicrm][:extensions].each_value do |details|
-  git "#{extensions_directory}/#{details[:name]}" do
-    action :sync
-    repository details[:repository]
-    revision details[:revision]
-    user "wordpress"
-    group "wordpress"
+  if details[:repository]
+    git "#{extensions_directory}/#{details[:name]}" do
+      action :sync
+      repository details[:repository]
+      revision details[:revision]
+      user "wordpress"
+      group "wordpress"
+    end
+  elsif details[:zip]
+    remote_file "#{cache_dir}/#{details[:name]}.zip" do
+      source details[:zip]
+      owner "root"
+      group "root"
+      mode "644"
+      backup false
+    end
+
+    archive_file "#{cache_dir}/#{details[:name]}.zip" do
+      action :nothing
+      destination "#{extensions_directory}/#{details[:name]}"
+      strip_components 1
+      owner "wordpress"
+      group "wordpress"
+      overwrite true
+      subscribes :extract, "remote_file[#{cache_dir}/#{details[:name]}.zip]", :immediately
+    end
   end
 end
 
@@ -149,11 +200,12 @@ settings = edit_file "#{civicrm_directory}/civicrm/templates/CRM/common/civicrm.
   line.gsub!(/%%dbHost%%/, "localhost")
   line.gsub!(/%%dbName%%/, "civicrm")
   line.gsub!(/%%crmRoot%%/, "#{civicrm_directory}/civicrm/")
-  line.gsub!(/%%templateCompileDir%%/, "/srv/join.osmfoundation.org/wp-content/plugins/files/civicrm/templates_c/")
-  line.gsub!(/%%baseURL%%/, "http://join.osmfoundation.org/")
+  line.gsub!(/%%templateCompileDir%%/, "/srv/supporting.openstreetmap.org/wp-content/uploads/civicrm/templates_c/")
+  line.gsub!(/%%baseURL%%/, "http://supporting.openstreetmap.org/")
   line.gsub!(/%%siteKey%%/, site_key)
-  line.gsub!(%r{// *(.*'ext_repo_url'.*)$}, "\\1")
-  line.gsub!(%r{// *define\('CIVICRM_CMSDIR', '/path/to/install/root/'\);}, "define('CIVICRM_CMSDIR', '/srv/join.osmfoundation.org');")
+  line.gsub!(/%%credKeys%%/, cred_keys)
+  line.gsub!(/%%signKeys%%/, sign_keys)
+  line.gsub!(%r{// *define\('CIVICRM_CMSDIR', '/path/to/install/root/'\);}, "define('CIVICRM_CMSDIR', '/srv/supporting.openstreetmap.org');")
 
   line
 end
@@ -161,22 +213,34 @@ end
 file "#{civicrm_directory}/civicrm.settings.php" do
   owner "wordpress"
   group "wordpress"
-  mode 0o644
+  mode "644"
   content settings
 end
 
-template "/etc/cron.d/osmf-crm" do
-  source "cron.erb"
-  owner "root"
-  group "root"
-  mode 0o600
-  variables :directory => civicrm_directory, :passwords => passwords
+systemd_service "osmf-crm-jobs" do
+  description "Run CRM jobs"
+  exec_start "/usr/bin/php #{civicrm_directory}/civicrm/bin/cli.php -s supporting.openstreetmap.org -u batch -p \"#{passwords['batch']}\" -e Job -a execute"
+  user "www-data"
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/srv/supporting.openstreetmap.org/wp-content/uploads/civicrm"
+end
+
+systemd_timer "osmf-crm-jobs" do
+  description "Run CRM jobs"
+  on_boot_sec "15m"
+  on_unit_inactive_sec "15m"
+end
+
+service "osmf-crm-jobs.timer" do
+  action [:enable, :start]
 end
 
 template "/etc/cron.daily/osmf-crm-backup" do
   source "backup.cron.erb"
   owner "root"
   group "root"
-  mode 0o750
+  mode "750"
   variables :passwords => passwords
 end
diff --git a/cookbooks/civicrm/templates/default/apache.erb b/cookbooks/civicrm/templates/default/apache.erb
new file mode 100644 (file)
index 0000000..7f45c97
--- /dev/null
@@ -0,0 +1,34 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<% [80, 443].each do |port| -%>
+<VirtualHost *:<%= port %>>
+
+  ServerName join.osmfoundation.org
+  ServerAlias crm.osmfoundation.org
+  ServerAlias supporting.osmfoundation.org
+  ServerAlias support.osmfoundation.org
+  ServerAlias support.openstreetmap.org
+  ServerAlias supporting.osm.org
+  ServerAlias support.osm.org
+
+  ServerAdmin webmaster@openstreetmap.org
+
+  RewriteEngine on
+
+<% if port == 80 -%>
+  RewriteRule ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 [R=permanent,L]
+<% end -%>
+<% if port == 443 -%>
+  SSLEngine on
+  SSLCertificateFile /etc/ssl/certs/join.osmfoundation.org.pem
+  SSLCertificateKeyFile /etc/ssl/private/join.osmfoundation.org.key
+<% end -%>
+
+  RewriteRule ^/(.*)$ https://supporting.openstreetmap.org/$1 [R=307,L]
+
+  CustomLog /var/log/apache2/join.osmfoundation.org-access.log combined_extended
+  ErrorLog /var/log/apache2/join.osmfoundation.org-error.log
+
+</VirtualHost>
+
+<% end -%>
index 61bb4cd453898600d7414bddc15268004a6ed591..7f912d7f7f9d1dc3e40cf095c3ddd88f6aa76fa1 100644 (file)
@@ -10,13 +10,12 @@ mkdir $T/osmf-crm-$D
 echo '[mysqldump]' > $T/mysqldump.opts
 echo 'user=civicrm' >> $T/mysqldump.opts
 echo 'password=<%= @passwords["database"] %>' >> $T/mysqldump.opts
-mysqldump --defaults-file=$T/mysqldump.opts --opt --skip-lock-tables civicrm > $T/osmf-crm-$D/civicrm.sql
-ln -s /srv/join.osmfoundation.org $T/osmf-crm-$D/www
+mysqldump --defaults-file=$T/mysqldump.opts --opt --skip-lock-tables --no-tablespaces civicrm > $T/osmf-crm-$D/civicrm.sql
+ln -s /srv/supporting.openstreetmap.org $T/osmf-crm-$D/www
 
-export GZIP="--rsyncable -9"
 export RSYNC_RSH="ssh -ax"
 
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B osmf-crm-$D
+nice tar --create --dereference --directory=$T osmf-crm-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
diff --git a/cookbooks/civicrm/templates/default/cron.erb b/cookbooks/civicrm/templates/default/cron.erb
deleted file mode 100644 (file)
index 22c3631..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-MAILTO=admins@openstreetmap.org
-
-*/15 * * * * www-data php <%= @directory %>/civicrm/bin/cli.php -s join.osmfoundation.org -u batch -p "<%= @passwords["batch"] %>" -e Job -a execute 2>&1 | egrep -v '^PHP (Deprecated|Warning):'
index 32a05964e9fc346d59bdc77bb1777abd34122fbf..8ef95c90672f5621a9723b6337851dc0b87714d5 100644 (file)
@@ -6,3 +6,4 @@ description       "Installs and configures clamav"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
index 8e07f4fb76f23a8c597c4dd7f42f9134c0e388bf..938b2f5aba0c1caa72e448623ba894b8b494162d 100644 (file)
@@ -17,6 +17,8 @@
 # limitations under the License.
 #
 
+include_recipe "accounts"
+
 package %w[
   clamav-daemon
   clamav-freshclam
@@ -27,7 +29,17 @@ template "/etc/clamav-unofficial-sigs.conf.d/50-chef.conf" do
   source "clamav-unofficial-sigs.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
+end
+
+execute "freshclam" do
+  command "/usr/bin/freshclam"
+  user "clamav"
+  group "clamav"
+  not_if do
+    ::File.exist?("/var/lib/clamav/daily.cld") ||
+      ::File.exist?("/var/lib/clamav/daily.cvd")
+  end
 end
 
 service "clamav-daemon" do
diff --git a/cookbooks/community/README.md b/cookbooks/community/README.md
new file mode 100644 (file)
index 0000000..97ee9be
--- /dev/null
@@ -0,0 +1,3 @@
+# Community Cookbook
+
+This installs and configures the community.openstreetmap.org website.
diff --git a/cookbooks/community/attributes/default.rb b/cookbooks/community/attributes/default.rb
new file mode 100644 (file)
index 0000000..68a98c7
--- /dev/null
@@ -0,0 +1 @@
+default[:accounts][:users][:community][:status] = :role
diff --git a/cookbooks/community/metadata.rb b/cookbooks/community/metadata.rb
new file mode 100644 (file)
index 0000000..f2eaaaa
--- /dev/null
@@ -0,0 +1,14 @@
+name              "community"
+maintainer        "OpenStreetMap Administrators"
+maintainer_email  "admins@openstreetmap.org"
+license           "Apache-2.0"
+description       "Installs and configures community site"
+
+version           "1.0.0"
+supports          "ubuntu"
+depends           "accounts"
+depends           "docker"
+depends           "exim"
+depends           "geoipupdate"
+depends           "git"
+depends           "ssl"
diff --git a/cookbooks/community/recipes/default.rb b/cookbooks/community/recipes/default.rb
new file mode 100644 (file)
index 0000000..224cb97
--- /dev/null
@@ -0,0 +1,203 @@
+#
+# Cookbook:: community
+# Recipe:: default
+#
+# Copyright:: 2021, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "accounts"
+include_recipe "docker"
+include_recipe "git"
+include_recipe "ssl"
+
+passwords = data_bag_item("community", "passwords")
+license_keys = data_bag_item("geoipupdate", "license-keys") unless kitchen?
+
+prometheus_servers = search(:node, "recipes:prometheus\\:\\:server").map do |server|
+  server.ipaddresses(:role => :external)
+end.flatten
+
+# Disable any default installed apache2 service. Web server is embedded within the discourse docker container
+service "apache2" do
+  action [:disable, :stop]
+end
+
+directory "/srv/community.openstreetmap.org" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+directory "/srv/community.openstreetmap.org/shared" do
+  owner "community"
+  group "community"
+  mode "755"
+end
+
+directory "/srv/community.openstreetmap.org/files" do
+  owner "community"
+  group "community"
+  mode "755"
+end
+
+template "/srv/community.openstreetmap.org/files/update-feeds.atom" do
+  source "update-feeds.atom.erb"
+  owner "community"
+  group "community"
+  mode "644"
+end
+
+git "/srv/community.openstreetmap.org/docker" do
+  action :sync
+  repository "https://github.com/discourse/discourse_docker.git"
+  # Revision pin not possible as launch wrapper automatically updates git repo.
+  revision "main"
+  depth 1
+  user "root"
+  group "root"
+  notifies :run, "notify_group[discourse_container_new_data]"
+  notifies :run, "notify_group[discourse_container_new_web_only]"
+  notifies :run, "notify_group[discourse_container_new_mail_receiver]"
+end
+
+template "/srv/community.openstreetmap.org/docker/containers/data.yml" do
+  source "data.yml.erb"
+  owner "root"
+  group "root"
+  mode "640"
+  variables :passwords => passwords
+  notifies :run, "notify_group[discourse_container_new_data]"
+end
+
+template "/srv/community.openstreetmap.org/docker/containers/web_only.yml" do
+  source "web_only.yml.erb"
+  owner "root"
+  group "root"
+  mode "640"
+  variables :license_keys => license_keys, :passwords => passwords,
+            :prometheus_servers => prometheus_servers
+  notifies :run, "notify_group[discourse_container_new_web_only]"
+end
+
+template "/srv/community.openstreetmap.org/docker/containers/mail-receiver.yml" do
+  source "mail-receiver.yml.erb"
+  owner "root"
+  group "root"
+  mode "640"
+  variables :passwords => passwords
+  notifies :run, "notify_group[discourse_container_new_mail_receiver]"
+end
+
+ssl_certificate "community.openstreetmap.org" do
+  domains ["community.openstreetmap.org", "community.osm.org", "communities.openstreetmap.org", "communities.osm.org", "c.openstreetmap.org", "c.osm.org", "forum.openstreetmap.org", "forum.osm.org"]
+  notifies :run, "notify_group[discourse_container_new_web_only]"
+  notifies :run, "notify_group[discourse_container_new_mail_receiver]"
+end
+
+notify_group "discourse_container_new_web_only" do
+  notifies :run, "execute[discourse_container_data_start]", :immediately # noop if site up
+  notifies :run, "execute[discourse_container_web_only_bootstrap]", :immediately # site up but runs in parallel. Slow
+  notifies :run, "execute[discourse_container_web_only_destroy]", :immediately # site down
+  notifies :run, "execute[discourse_container_data_rebuild]", :immediately # site down
+  notifies :run, "execute[discourse_container_web_only_start]", :immediately # site restore
+end
+
+notify_group "discourse_container_new_data" do
+  notifies :run, "execute[discourse_container_web_only_destroy]", :immediately # site down
+  notifies :run, "execute[discourse_container_data_rebuild]", :immediately # site down
+  notifies :run, "execute[discourse_container_web_only_start]", :immediately # site restore
+end
+
+notify_group "discourse_container_new_mail_receiver" do
+  notifies :run, "execute[discourse_container_mail_receiver_rebuild]", :immediately
+end
+
+# Attempt at a failsafe to ensure all containers are running
+notify_group "discourse_container_ensure_all_running" do
+  action :run
+  notifies :run, "execute[discourse_container_data_start]", :delayed
+  notifies :run, "execute[discourse_container_web_only_start]", :delayed
+  notifies :run, "execute[discourse_container_mail_receiver_start]", :delayed
+end
+
+execute "discourse_container_data_start" do
+  action :nothing
+  command "./launcher start data"
+  cwd "/srv/community.openstreetmap.org/docker/"
+  user "root"
+  group "root"
+end
+
+execute "discourse_container_data_rebuild" do
+  action :nothing
+  command "./launcher rebuild data"
+  cwd "/srv/community.openstreetmap.org/docker/"
+  user "root"
+  group "root"
+end
+
+execute "discourse_container_web_only_bootstrap" do
+  action :nothing
+  command "./launcher bootstrap web_only"
+  cwd "/srv/community.openstreetmap.org/docker/"
+  user "root"
+  group "root"
+end
+
+execute "discourse_container_web_only_destroy" do
+  action :nothing
+  command "./launcher destroy web_only"
+  cwd "/srv/community.openstreetmap.org/docker/"
+  user "root"
+  group "root"
+end
+
+execute "discourse_container_web_only_start" do
+  action :nothing
+  command "./launcher start web_only"
+  cwd "/srv/community.openstreetmap.org/docker/"
+  user "root"
+  group "root"
+end
+
+# Rebuild: Stop Destroy Bootstap Start
+execute "discourse_container_mail_receiver_rebuild" do
+  action :nothing
+  command "./launcher rebuild mail-receiver"
+  cwd "/srv/community.openstreetmap.org/docker/"
+  user "root"
+  group "root"
+end
+
+execute "discourse_container_mail_receiver_start" do
+  action :nothing
+  command "./launcher start mail-receiver"
+  cwd "/srv/community.openstreetmap.org/docker/"
+  user "root"
+  group "root"
+end
+
+template "/etc/cron.daily/community-backup" do
+  source "backup.cron.erb"
+  owner "root"
+  group "root"
+  mode "750"
+end
+
+node.default[:prometheus][:exporters][443] = {
+  :name => "community",
+  :address => "#{node[:prometheus][:address]}:443",
+  :sni => "community.openstreetmap.org"
+}
diff --git a/cookbooks/community/templates/default/backup.cron.erb b/cookbooks/community/templates/default/backup.cron.erb
new file mode 100644 (file)
index 0000000..4cb919a
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+T=$(mktemp -d -t -p /var/tmp community.XXXXXXXXXX)
+D=$(date +%Y-%m-%d)
+B=community-$D.tar.gz
+
+mkdir $T/community-$D
+ln -s /srv/community.openstreetmap.org/docker/containers $T/community-$D/containers
+ln -s /srv/community.openstreetmap.org/shared/web-only $T/community-$D/shared-web-only
+ln -s /srv/community.openstreetmap.org/shared/data/redis_data $T/community-$D/shared-data-redis_data
+ln -s /srv/community.openstreetmap.org/shared/data/postgres_backup $T/community-$D/shared-data-postgres_backup
+
+export RSYNC_RSH="ssh -ax"
+
+nice tar --create --numeric-owner --dereference --directory=$T --warning=no-file-changed community-$D | nice gzip --rsyncable -9 > $T/$B
+nice rsync --preallocate --fuzzy $T/$B backup::backup
+
+rm -rf $T
diff --git a/cookbooks/community/templates/default/data.yml.erb b/cookbooks/community/templates/default/data.yml.erb
new file mode 100644 (file)
index 0000000..10cc507
--- /dev/null
@@ -0,0 +1,50 @@
+# A container for all things Data, be sure to set a secret password for
+# discourse account, SOME_SECRET is just an example
+#
+
+templates:
+  - "templates/postgres.13.template.yml"
+  - "templates/redis.template.yml"
+
+# any extra arguments for Docker?
+# docker_args:
+
+params:
+  db_default_text_search_config: "pg_catalog.english"
+
+  ## Set db_shared_buffers to a max of 25% of the total memory.
+  ## will be set automatically by bootstrap based on detected RAM, or you can override
+  db_shared_buffers: "4096MB"
+
+  ## can improve sorting performance, but adds memory usage per-connection
+  #db_work_mem: "40MB"
+
+env:
+  # ensure locale exists in container, you may need to install it
+  LC_ALL: en_US.UTF-8
+  LANG: en_US.UTF-8
+  LANGUAGE: en_US.UTF-8
+
+volumes:
+  - volume:
+        host: /srv/community.openstreetmap.org/shared/data
+        guest: /shared
+  - volume:
+        host: /srv/community.openstreetmap.org/shared/data/log/var-log
+        guest: /var/log
+
+# TODO: SOME_SECRET to a password for the discourse user
+hooks:
+  after_postgres:
+    - exec:
+        stdin: |
+          alter user discourse with password '<%= @passwords["database"] %>';
+        cmd: su - postgres -c 'psql discourse'
+
+        raise_on_fail: false
+    - file:
+        path: /var/spool/cron/crontabs/postgres
+        contents: |
+          # m h  dom mon dow   command
+          # MAILTO=?
+          0 4 * * * /var/lib/postgresql/take-database-backup
diff --git a/cookbooks/community/templates/default/mail-receiver.yml.erb b/cookbooks/community/templates/default/mail-receiver.yml.erb
new file mode 100644 (file)
index 0000000..2d214e9
--- /dev/null
@@ -0,0 +1,51 @@
+## this is the incoming mail receiver container template
+##
+## After making changes to this file, you MUST rebuild
+## /var/discourse/launcher rebuild mail-receiver
+##
+## BE *VERY* CAREFUL WHEN EDITING!
+## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
+## visit http://www.yamllint.com/ to validate this file as needed
+
+base_image: discourse/mail-receiver:release
+update_pups: false
+
+expose:
+  - "2500:25"   # SMTP
+
+env:
+  LC_ALL: en_US.UTF-8
+  LANG: en_US.UTF-8
+  LANGUAGE: en_US.UTF-8
+
+  ## Where e-mail to your forum should be sent.  In general, it's perfectly fine
+  ## to use the same domain as the forum itself here.
+  MAIL_DOMAIN: community.openstreetmap.org
+  POSTCONF_smtpd_tls_key_file: /shared/ssl/ssl.key
+  POSTCONF_smtpd_tls_cert_file: /shared/ssl/ssl.crt
+  POSTCONF_smtpd_tls_security_level: may
+
+  ## The URL of the mail processing endpoint of your Discourse forum.
+  ## This is simply your forum's base URL, with `/admin/email/handle_mail`
+  ## appended.  Be careful if you're running a subfolder setup -- in that case,
+  ## the URL needs to have the subfolder included!
+  DISCOURSE_MAIL_ENDPOINT: 'https://community.openstreetmap.org/admin/email/handle_mail'
+
+  ## The master API key of your Discourse forum.  You can get this from
+  ## the "API" tab of your admin panel.
+  DISCOURSE_API_KEY: '<%= @passwords["mail_receiver_api_key"] %>'
+
+  ## The username to use for processing incoming e-mail.  Unless you have
+  ## renamed the `system` user, you should leave this as-is.
+  DISCOURSE_API_USERNAME: system
+
+volumes:
+  - volume:
+      host: /srv/community.openstreetmap.org/shared/mail-receiver/postfix-spool
+      guest: /var/spool/postfix
+  - volume:
+      host: /etc/ssl/certs/community.openstreetmap.org.pem
+      guest: /shared/ssl/ssl.crt
+  - volume:
+      host: /etc/ssl/private/community.openstreetmap.org.key
+      guest: /shared/ssl/ssl.key
diff --git a/cookbooks/community/templates/default/update-feeds.atom.erb b/cookbooks/community/templates/default/update-feeds.atom.erb
new file mode 100644 (file)
index 0000000..f94dd9f
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+<title type="text" xml:lang="en">OpenStreetMap Forum Update Feed URL</title>
+<link type="application/atom+xml" href="https://community.openstreetmap.org/update-feeds.atom" rel="self"/>
+<link type="text/html" href="https://community.openstreetmap.org/" rel="alternate"/>
+<updated>2023-03-06T22:00:00Z</updated>
+<id>urn:uuid:1a19dde4-c98d-42ed-8f63-36674f06036a</id>
+<author>
+<name>OpenStreetMap Forum</name>
+</author>
+<rights>Public Domain</rights>
+<entry>
+<title>Update your Forum Feed URLs</title>
+<link href="https://community.openstreetmap.org/"/>
+<updated>2023-03-06T22:00:00Z</updated>
+<id>urn:uuid:1a19dde4-c98d-42ed-8f63-36674f06036f</id>
+<content type="html">forum.openstreetmap.org has been migrated to community.openstreetmap.org. The URLs of the feeds have been updated. Please update your RSS or Atom feed links.</content>
+</entry>
+</feed>
diff --git a/cookbooks/community/templates/default/web_only.yml.erb b/cookbooks/community/templates/default/web_only.yml.erb
new file mode 100644 (file)
index 0000000..9688dde
--- /dev/null
@@ -0,0 +1,133 @@
+templates:
+  - "templates/web.template.yml"
+  - "templates/web.ipv6.template.yml"
+  - "templates/web.ssl.template.yml"
+
+## which TCP/IP ports should this container expose?
+## If you want Discourse to share a port with another webserver like Apache or nginx,
+## see https://meta.discourse.org/t/17247 for details
+expose:
+  - "80:80"   # http
+  - "443:443" # https
+
+# Use 'links' key to link containers together, aka use Docker --link flag.
+links:
+  - link:
+      name: data
+      alias: data
+
+# any extra arguments for Docker?
+# docker_args:
+
+# Latest Version v3.2.1
+params:
+  version: stable
+
+env:
+  LC_ALL: en_US.UTF-8
+  LANG: en_US.UTF-8
+  LANGUAGE: en_US.UTF-8
+  DISCOURSE_FORCE_HTTPS: true
+
+  ## How many concurrent web requests are supported? Depends on memory and CPU cores.
+  ## will be set automatically by bootstrap based on detected CPUs, or you can override
+  UNICORN_WORKERS: <%= node.cpu_cores %>
+
+  ## TODO: The domain name this Discourse instance will respond to
+  DISCOURSE_HOSTNAME: community.openstreetmap.org
+  DISCOURSE_CDN_URL: https://community-cdn.openstreetmap.org
+
+  ## Uncomment if you want the container to be started with the same
+  ## hostname (-h option) as specified above (default "$hostname-$config")
+  #DOCKER_USE_HOSTNAME: true
+
+  ## TODO: List of comma delimited emails that will be made admin and developer
+  ## on initial signup example 'user1@example.com,user2@example.com'
+  DISCOURSE_DEVELOPER_EMAILS: 'operations@openstreetmap.org'
+
+  DISCOURSE_SMTP_ADDRESS: <%= node[:exim][:smarthost_via].split(":", 2)[0] %>
+  DISCOURSE_SMTP_PORT: <%= node[:exim][:smarthost_via].split(":", 2)[1] || "25" %>
+  DISCOURSE_SMTP_OPENSSL_VERIFY_MODE: none
+  DISCOURSE_SMTP_USER_NAME:
+  DISCOURSE_SMTP_PASSWORD:
+  DISCOURSE_SMTP_DOMAIN: community.openstreetmap.org
+  DISCOURSE_SMTP_OPEN_TIMEOUT: 30
+  DISCOURSE_SMTP_READ_TIMEOUT: 30
+  DISCOURSE_NOTIFICATION_EMAIL: community@noreply.openstreetmap.org
+
+  ## TODO: configure connectivity to the databases
+  DISCOURSE_DB_SOCKET: ''
+  #DISCOURSE_DB_USERNAME: discourse
+  DISCOURSE_DB_PASSWORD: '<%= @passwords["database"] %>'
+  DISCOURSE_DB_HOST: data
+  DISCOURSE_REDIS_HOST: data
+
+  ## The maxmind geolocation IP address key for IP address lookup
+  ## see https://meta.discourse.org/t/-/137387/23 for details
+<% if @license_keys -%>
+  DISCOURSE_MAXMIND_LICENSE_KEY: '<%= @license_keys[node[:geoipupdate][:account]] %>'
+<% end -%>
+
+  # Allow list for prometheus metric collection
+  DISCOURSE_PROMETHEUS_TRUSTED_IP_ALLOWLIST_REGEX: '^<%= @prometheus_servers.map { |a| Regexp.escape(a) }.join("|") %>$'
+
+  # Increase base SIDEKIQ memory limit to 1GB
+  UNICORN_SIDEKIQ_MAX_RSS: 1000
+
+volumes:
+  - volume:
+      host: /srv/community.openstreetmap.org/shared/web-only
+      guest: /shared
+  - volume:
+      host: /srv/community.openstreetmap.org/shared/web-only/log/var-log
+      guest: /var/log
+  - volume:
+      host: /etc/ssl/certs/community.openstreetmap.org.pem
+      guest: /shared/ssl/ssl.crt
+  - volume:
+      host: /etc/ssl/private/community.openstreetmap.org.key
+      guest: /shared/ssl/ssl.key
+  - volume:
+      host: /etc/ssl/certs/dhparam.pem
+      guest: /shared/ssl/dhparam.pem
+  - volume:
+      host: /srv/community.openstreetmap.org/files/update-feeds.atom
+      guest: /shared/feeds/update-feeds.atom
+
+## Plugins go here
+## see https://meta.discourse.org/t/19157 for details
+hooks:
+  after_code:
+    - exec:
+        cd: $home/plugins
+        cmd:
+          - sudo -H -E -u discourse git clone --depth 1 --branch main https://github.com/discourse/discourse-oauth2-basic.git
+          - sudo -H -E -u discourse git clone --depth 1 --branch main https://github.com/discourse/discourse-solved.git
+          - sudo -H -E -u discourse git clone --depth 1 --branch main https://github.com/discourse/discourse-reactions.git
+          - sudo -H -E -u discourse git clone --depth 1 --branch main https://github.com/discourse/discourse-prometheus.git
+          - sudo -H -E -u discourse git clone --depth 1 --branch main https://github.com/discourse/discourse-translator.git
+          - sudo -H -E -u discourse git clone --depth 1 --branch main https://github.com/discourse/discourse-saved-searches.git
+          - sudo -H -E -u discourse git clone --depth 1 --branch main https://github.com/discourse/discourse-post-voting.git
+    - exec:
+        # Needs to be copied in else builtin git cleanup fails
+        cd: $home
+        cmd:
+          - sudo -H -E -u discourse cp /shared/feeds/update-feeds.atom public/update-feeds.atom
+  after_ssl:
+    - replace:
+        filename: "/etc/nginx/conf.d/discourse.conf"
+        from: /listen 80;/
+        to: |
+          listen 80;
+          listen [::]:80;
+          rewrite ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 permanent;
+
+    - replace:
+        filename: "/etc/nginx/conf.d/discourse.conf"
+        from: /add_header.+/
+        to: |
+          add_header Strict-Transport-Security 'max-age=63072000' always;
+          ssl_stapling on;
+          resolver <%= node[:networking][:nameservers].join(" ") %>;
+          resolver_timeout 5s;
+          ssl_dhparam /shared/ssl/dhparam.pem;
diff --git a/cookbooks/db/attributes/default.rb b/cookbooks/db/attributes/default.rb
new file mode 100644 (file)
index 0000000..cbc5635
--- /dev/null
@@ -0,0 +1,4 @@
+default[:db][:cluster] = "15/main"
+
+default[:postgresql][:versions] |= ["15"]
+default[:postgresql][:monitor_database] = "openstreetmap"
diff --git a/cookbooks/db/files/default/monthly-reindex.sql b/cookbooks/db/files/default/monthly-reindex.sql
new file mode 100644 (file)
index 0000000..65412d4
--- /dev/null
@@ -0,0 +1,37 @@
+REINDEX (VERBOSE) TABLE CONCURRENTLY acls;
+REINDEX (VERBOSE) TABLE CONCURRENTLY active_storage_attachments;
+REINDEX (VERBOSE) TABLE CONCURRENTLY active_storage_blobs;
+REINDEX (VERBOSE) TABLE CONCURRENTLY active_storage_variant_records;
+REINDEX (VERBOSE) TABLE CONCURRENTLY ar_internal_metadata;
+REINDEX (VERBOSE) TABLE CONCURRENTLY changeset_comments;
+REINDEX (VERBOSE) TABLE CONCURRENTLY changeset_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY changesets;
+REINDEX (VERBOSE) TABLE CONCURRENTLY changesets_subscribers;
+REINDEX (VERBOSE) TABLE CONCURRENTLY client_applications;
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_relation_members;
+REINDEX (VERBOSE) TABLE CONCURRENTLY delayed_jobs;
+REINDEX (VERBOSE) TABLE CONCURRENTLY diary_comments;
+REINDEX (VERBOSE) TABLE CONCURRENTLY diary_entries;
+REINDEX (VERBOSE) TABLE CONCURRENTLY diary_entry_subscriptions;
+REINDEX (VERBOSE) TABLE CONCURRENTLY friends;
+REINDEX (VERBOSE) TABLE CONCURRENTLY gpx_files;
+REINDEX (VERBOSE) TABLE CONCURRENTLY gpx_file_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY issue_comments;
+REINDEX (VERBOSE) TABLE CONCURRENTLY issues;
+REINDEX (VERBOSE) TABLE CONCURRENTLY languages;
+REINDEX (VERBOSE) TABLE CONCURRENTLY messages;
+REINDEX (VERBOSE) TABLE CONCURRENTLY note_comments;
+REINDEX (VERBOSE) TABLE CONCURRENTLY notes;
+REINDEX (VERBOSE) TABLE CONCURRENTLY oauth_access_grants;
+REINDEX (VERBOSE) TABLE CONCURRENTLY oauth_access_tokens;
+REINDEX (VERBOSE) TABLE CONCURRENTLY oauth_applications;
+REINDEX (VERBOSE) TABLE CONCURRENTLY oauth_nonces;
+REINDEX (VERBOSE) TABLE CONCURRENTLY oauth_tokens;
+REINDEX (VERBOSE) TABLE CONCURRENTLY redactions;
+REINDEX (VERBOSE) TABLE CONCURRENTLY reports;
+REINDEX (VERBOSE) TABLE CONCURRENTLY schema_migrations;
+REINDEX (VERBOSE) TABLE CONCURRENTLY user_blocks;
+REINDEX (VERBOSE) TABLE CONCURRENTLY user_mutes;
+REINDEX (VERBOSE) TABLE CONCURRENTLY user_preferences;
+REINDEX (VERBOSE) TABLE CONCURRENTLY user_roles;
+REINDEX (VERBOSE) TABLE CONCURRENTLY users;
diff --git a/cookbooks/db/files/default/yearly-reindex.sql b/cookbooks/db/files/default/yearly-reindex.sql
new file mode 100644 (file)
index 0000000..5f41cb2
--- /dev/null
@@ -0,0 +1,16 @@
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_node_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_nodes;
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_relation_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_relations;
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_way_nodes;
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_way_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY current_ways;
+REINDEX (VERBOSE) TABLE CONCURRENTLY gps_points;
+REINDEX (VERBOSE) TABLE CONCURRENTLY node_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY nodes;
+REINDEX (VERBOSE) TABLE CONCURRENTLY relation_members;
+REINDEX (VERBOSE) TABLE CONCURRENTLY relation_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY relations;
+REINDEX (VERBOSE) TABLE CONCURRENTLY way_nodes;
+REINDEX (VERBOSE) TABLE CONCURRENTLY way_tags;
+REINDEX (VERBOSE) TABLE CONCURRENTLY ways;
index 092949cb0ca4642268e88b68c4f0e94636c4f80d..c81fffe5b35650c04ee818711ab58d14c1efeae5 100644 (file)
@@ -6,7 +6,10 @@ description       "Installs and configures database servers"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "postgresql"
-depends           "web"
+depends           "accounts"
 depends           "git"
+depends           "postgresql"
 depends           "python"
+depends           "ruby"
+depends           "systemd"
+depends           "web"
index 5a814392a3243d482e2cd90a5ef8bfb11bfa0943..39d6d573d4885a4844ee9bebe4bb4f6f39da8a50 100644 (file)
@@ -21,12 +21,23 @@ template "/usr/local/bin/backup-db" do
   source "backup-db.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
-template "/etc/cron.d/backup-db" do
-  source "backup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+systemd_service "backup-db" do
+  description "Database backup"
+  exec_start "/usr/local/bin/backup-db"
+  user "osmbackup"
+  sandbox :enable_network => true
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/store/backup"
+end
+
+systemd_timer "backup-db" do
+  description "Database backup"
+  on_calendar "Mon 02:00 #{node[:timezone]}"
+end
+
+service "backup-db.timer" do
+  action [:enable, :start]
 end
index ee9d0089f65f13ce799b411def26b481414a9c0a..d989d0bc91dd5f3bd16eb19b4a768a2c0aad16fd 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "postgresql"
+include_recipe "accounts"
 include_recipe "git"
+include_recipe "postgresql"
 include_recipe "python"
+include_recipe "ruby"
 
 passwords = data_bag_item("db", "passwords")
 wal_secrets = data_bag_item("db", "wal-secrets")
 
-postgresql_munin "openstreetmap" do
-  cluster node[:db][:cluster]
-  database "openstreetmap"
-end
-
 directory "/srv/www.openstreetmap.org" do
   group "rails"
-  mode 0o2775
+  mode "2775"
 end
 
 rails_port "www.openstreetmap.org" do
-  ruby "2.5"
   directory "/srv/www.openstreetmap.org/rails"
   user "rails"
   group "rails"
   repository "https://git.openstreetmap.org/public/rails.git"
   revision "live"
+  build_assets false
   database_host "localhost"
   database_name "openstreetmap"
   database_username "openstreetmap"
   database_password passwords["openstreetmap"]
-  gpx_dir "/store/rails/gpx"
 end
 
-db_version = node[:db][:cluster].split("/").first
-pg_config = "/usr/lib/postgresql/#{db_version}/bin/pg_config"
-function_directory = "/srv/www.openstreetmap.org/rails/db/functions/#{db_version}"
+package %w[
+  cmake
+  libosmium2-dev
+  libprotozero-dev
+  libboost-filesystem-dev
+  libboost-program-options-dev
+  libbz2-dev
+  zlib1g-dev
+  libexpat1-dev
+  libyaml-cpp-dev
+  libpqxx-dev
+]
 
-directory function_directory do
-  owner "rails"
-  group "rails"
-  mode 0o755
+git "/opt/osmdbt" do
+  action :sync
+  repository "https://github.com/openstreetmap/osmdbt.git"
+  revision "v0.5"
+  depth 1
+  user "root"
+  group "root"
 end
 
-execute function_directory do
-  action :nothing
-  command "make PG_CONFIG=#{pg_config} DESTDIR=#{function_directory}"
-  cwd "/srv/www.openstreetmap.org/rails/db/functions"
-  user "rails"
-  group "rails"
-  subscribes :run, "directory[#{function_directory}]"
-  subscribes :run, "git[/srv/www.openstreetmap.org/rails]"
-end
+node[:postgresql][:versions].each do |db_version|
+  directory "/opt/osmdbt/build-#{db_version}" do
+    owner "root"
+    group "root"
+    mode "755"
+  end
 
-link "/usr/lib/postgresql/#{db_version}/lib/libpgosm.so" do
-  to "#{function_directory}/libpgosm.so"
-  owner "root"
-  group "root"
-end
+  execute "/opt/osmdbt/build-#{db_version}" do
+    action :nothing
+    command "cmake -DPG_CONFIG=/usr/lib/postgresql/#{db_version}/bin/pg_config .."
+    cwd "/opt/osmdbt/build-#{db_version}"
+    user "root"
+    group "root"
+    subscribes :run, "directory[/opt/osmdbt/build-#{db_version}]"
+    subscribes :run, "git[/opt/osmdbt]"
+  end
 
-package "lzop"
+  execute "/opt/osmdbt/build-#{db_version}/postgresql-plugin/Makefile" do
+    action :nothing
+    command "make"
+    cwd "/opt/osmdbt/build-#{db_version}/postgresql-plugin"
+    user "root"
+    group "root"
+    subscribes :run, "execute[/opt/osmdbt/build-#{db_version}]"
+  end
 
-python_package "wal-e" do
-  python_version "3"
+  link "/usr/lib/postgresql/#{db_version}/lib/osm-logical.so" do
+    to "/opt/osmdbt/build-#{db_version}/postgresql-plugin/osm-logical.so"
+    owner "root"
+    group "root"
+  end
 end
 
-python_package "boto" do
-  python_version "3"
+package "lzop"
+
+remote_file "/usr/local/bin/wal-g" do
+  action :create
+  source "https://github.com/wal-g/wal-g/releases/download/v2.0.1/wal-g-pg-ubuntu-20.04-amd64"
+  owner "root"
+  group "root"
+  mode "755"
 end
 
-template "/usr/local/bin/openstreetmap-wal-e" do
-  source "wal-e.erb"
+template "/usr/local/bin/openstreetmap-wal-g" do
+  source "wal-g.erb"
   owner "root"
   group "postgres"
-  mode 0o750
+  mode "750"
   variables :s3_key => wal_secrets["s3_key"]
 end
index 5e51ca030478d2c2552ad796ef605a5a394f2969..c2d1da0247dbe65bf12fe79276530a9cd756cc04 100644 (file)
@@ -41,6 +41,11 @@ postgresql_user "rails" do
   password passwords["rails"]
 end
 
+postgresql_user "cgimap" do
+  cluster node[:db][:cluster]
+  password passwords["cgimap"]
+end
+
 postgresql_user "planetdump" do
   cluster node[:db][:cluster]
   password passwords["planetdump"]
@@ -49,6 +54,7 @@ end
 postgresql_user "planetdiff" do
   cluster node[:db][:cluster]
   password passwords["planetdiff"]
+  replication true
 end
 
 postgresql_user "backup" do
@@ -56,16 +62,6 @@ postgresql_user "backup" do
   password passwords["backup"]
 end
 
-postgresql_user "gpximport" do
-  cluster node[:db][:cluster]
-  password passwords["gpximport"]
-end
-
-postgresql_user "munin" do
-  cluster node[:db][:cluster]
-  password passwords["munin"]
-end
-
 postgresql_user "replication" do
   cluster node[:db][:cluster]
   password passwords["replication"]
@@ -83,6 +79,235 @@ postgresql_extension "btree_gist" do
   only_if { node[:postgresql][:clusters][node[:db][:cluster]] && node[:postgresql][:clusters][node[:db][:cluster]][:version] >= 9.0 }
 end
 
-file "/etc/cron.daily/rails-db" do
-  action :delete
+CGIMAP_PERMISSIONS = {
+  "changeset_comments" => [:select],
+  "changeset_tags" => [:select],
+  "changesets" => [:select, :update],
+  "client_applications" => [:select],
+  "current_node_tags" => [:select, :insert, :delete],
+  "current_nodes" => [:select, :insert, :update],
+  "current_nodes_id_seq" => [:update],
+  "current_relation_members" => [:select, :insert, :delete],
+  "current_relation_tags" => [:select, :insert, :delete],
+  "current_relations" => [:select, :insert, :update],
+  "current_relations_id_seq" => [:update],
+  "current_way_nodes" => [:select, :insert, :delete],
+  "current_way_tags" => [:select, :insert, :delete],
+  "current_ways" => [:select, :insert, :update],
+  "current_ways_id_seq" => [:update],
+  "issues" => [:select],
+  "node_tags" => [:select, :insert],
+  "nodes" => [:select, :insert],
+  "oauth_access_grants" => [:select],
+  "oauth_access_tokens" => [:select],
+  "oauth_applications" => [:select],
+  "oauth_nonces" => [:select, :insert],
+  "oauth_nonces_id_seq" => [:update],
+  "oauth_tokens" => [:select],
+  "relation_members" => [:select, :insert],
+  "relation_tags" => [:select, :insert],
+  "relations" => [:select, :insert],
+  "reports" => [:select],
+  "user_blocks" => [:select],
+  "user_roles" => [:select],
+  "users" => [:select],
+  "way_nodes" => [:select, :insert],
+  "way_tags" => [:select, :insert],
+  "ways" => [:select, :insert]
+}.freeze
+
+PLANETDUMP_PERMISSIONS = {
+  "note_comments" => :select,
+  "notes" => :select,
+  "users" => :select
+}.freeze
+
+PLANETDIFF_PERMISSIONS = {
+  "changeset_comments" => :select,
+  "changeset_tags" => :select,
+  "changesets" => :select,
+  "node_tags" => :select,
+  "nodes" => :select,
+  "relation_members" => :select,
+  "relation_tags" => :select,
+  "relations" => :select,
+  "users" => :select,
+  "way_nodes" => :select,
+  "way_tags" => :select,
+  "ways" => :select
+}.freeze
+
+PROMETHEUS_PERMISSIONS = {
+  "delayed_jobs" => :select
+}.freeze
+
+%w[
+  acls
+  active_storage_attachments
+  active_storage_blobs
+  active_storage_variant_records
+  ar_internal_metadata
+  changeset_comments
+  changeset_tags
+  changesets
+  changesets_subscribers
+  client_applications
+  current_node_tags
+  current_nodes
+  current_relation_members
+  current_relation_tags
+  current_relations
+  current_way_nodes
+  current_way_tags
+  current_ways
+  delayed_jobs
+  diary_comments
+  diary_entries
+  diary_entry_subscriptions
+  friends
+  gps_points
+  gpx_file_tags
+  gpx_files
+  issue_comments
+  issues
+  languages
+  messages
+  node_tags
+  nodes
+  note_comments
+  notes
+  oauth_access_grants
+  oauth_access_tokens
+  oauth_applications
+  oauth_nonces
+  oauth_openid_requests
+  oauth_tokens
+  redactions
+  relation_members
+  relation_tags
+  relations
+  reports
+  schema_migrations
+  user_blocks
+  user_mutes
+  user_preferences
+  user_roles
+  users
+  way_nodes
+  way_tags
+  ways
+].each do |table|
+  postgresql_table table do
+    cluster node[:db][:cluster]
+    database "openstreetmap"
+    owner "openstreetmap"
+    permissions "openstreetmap" => [:all],
+                "rails" => [:select, :insert, :update, :delete],
+                "cgimap" => CGIMAP_PERMISSIONS[table],
+                "planetdump" => PLANETDUMP_PERMISSIONS[table],
+                "planetdiff" => PLANETDIFF_PERMISSIONS[table],
+                "prometheus" => PROMETHEUS_PERMISSIONS[table],
+                "backup" => [:select]
+  end
+end
+
+%w[
+  acls_id_seq
+  active_storage_attachments_id_seq
+  active_storage_blobs_id_seq
+  active_storage_variant_records_id_seq
+  changeset_comments_id_seq
+  changesets_id_seq
+  client_applications_id_seq
+  current_nodes_id_seq
+  current_relations_id_seq
+  current_ways_id_seq
+  delayed_jobs_id_seq
+  diary_comments_id_seq
+  diary_entries_id_seq
+  friends_id_seq
+  gpx_file_tags_id_seq
+  gpx_files_id_seq
+  issue_comments_id_seq
+  issues_id_seq
+  messages_id_seq
+  note_comments_id_seq
+  notes_id_seq
+  oauth_access_grants_id_seq
+  oauth_access_tokens_id_seq
+  oauth_applications_id_seq
+  oauth_nonces_id_seq
+  oauth_openid_requests_id_seq
+  oauth_tokens_id_seq
+  redactions_id_seq
+  reports_id_seq
+  user_blocks_id_seq
+  user_mutes_id_seq
+  user_roles_id_seq
+  users_id_seq
+].each do |sequence|
+  postgresql_sequence sequence do
+    cluster node[:db][:cluster]
+    database "openstreetmap"
+    owner "openstreetmap"
+    permissions "openstreetmap" => [:all],
+                "rails" => [:usage],
+                "cgimap" => CGIMAP_PERMISSIONS[sequence],
+                "backup" => [:select]
+  end
+end
+
+cookbook_file "/usr/local/share/monthly-reindex.sql" do
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+systemd_service "monthly-reindex" do
+  description "Monthly database reindex"
+  exec_start "/usr/bin/psql -f /usr/local/share/monthly-reindex.sql openstreetmap"
+  user "postgres"
+  sandbox true
+  restrict_address_families "AF_UNIX"
+  remove_ipc false
+end
+
+systemd_timer "monthly-reindex" do
+  description "Monthly database reindex"
+  on_calendar "Sun *-*-1..7 02:00"
+end
+
+service "monthly-reindex.timer" do
+  action [:enable, :start]
+end
+
+cookbook_file "/usr/local/share/yearly-reindex.sql" do
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+systemd_service "yearly-reindex" do
+  description "Yearly database reindex"
+  exec_start "/usr/bin/psql -f /usr/local/share/yearly-reindex.sql openstreetmap"
+  user "postgres"
+  sandbox true
+  restrict_address_families "AF_UNIX"
+  remove_ipc false
+end
+
+systemd_timer "yearly-reindex" do
+  description "Yearly database reindex"
+  on_calendar "Thu *-1-8..14 02:00"
+end
+
+service "yearly-reindex.timer" do
+  action [:enable, :start]
+end
+
+template "/etc/prometheus/exporters/sql_rails.collector.yml" do
+  source "sql_rails.yml.erb"
+  owner "root"
+  group "root"
+  mode "0644"
 end
index 70dc970e75322c15dae275eb7d687d60fb4555d5..f882db614d588adc7917d2fcc16337493acbb0b5 100644 (file)
@@ -18,3 +18,7 @@
 #
 
 include_recipe "db::base"
+
+service "monthly-reindex.timer" do
+  action [:disable, :stop]
+end
index 7cf32f39ce7b631dca7474a453c98be9a9a8a094..573f31a5edd7a60d7f993c04ae2be7dcc9eca525 100644 (file)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/sh -e
 
 # DO NOT EDIT - This file is being maintained by Chef
 
diff --git a/cookbooks/db/templates/default/backup.cron.erb b/cookbooks/db/templates/default/backup.cron.erb
deleted file mode 100644 (file)
index b7249c7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-MAILTO=admins@openstreetmap.org
-
-00 02 * * 1 osmbackup /usr/local/bin/backup-db
diff --git a/cookbooks/db/templates/default/sql_rails.yml.erb b/cookbooks/db/templates/default/sql_rails.yml.erb
new file mode 100644 (file)
index 0000000..8d4990d
--- /dev/null
@@ -0,0 +1,25 @@
+collector_name: sql_rails
+
+metrics:
+  - metric_name: rails_queue_length
+    type: gauge
+    help: Rails job queue length
+    key_labels:
+      - queue
+      - status
+    values: [length]
+    query: |
+      SELECT
+        queue,
+        CASE
+        WHEN failed_at IS NOT NULL THEN 'failed'
+        WHEN locked_at IS NOT NULL THEN 'running'
+        WHEN attempts > 0 THEN 'retry'
+        ELSE 'pending'
+        END AS status,
+        COUNT(*) AS length
+      FROM
+        delayed_jobs
+      GROUP BY
+        queue,
+        status
index 93f3144983c575a5e405a2a4b89f75215d6a9cc2..b4c13bd1d9f83c941e4bb31b1dc7c5215aaa91df 100644 (file)
@@ -7,4 +7,4 @@ export AWS_ACCESS_KEY_ID="AKIAIQX2LTDOBIW4CZUQ"
 export AWS_SECRET_ACCESS_KEY="<%= @s3_key %>"
 export AWS_REGION="eu-west-2"
 
-exec /usr/local/bin/wal-e "$@"
+exec /usr/local/bin/wal-e "$@" < /dev/null
diff --git a/cookbooks/db/templates/default/wal-g.erb b/cookbooks/db/templates/default/wal-g.erb
new file mode 100644 (file)
index 0000000..2297fd4
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+export WALG_S3_PREFIX="s3://openstreetmap-wal/"
+export WALG_COMPRESSION_METHOD="lz4"
+export AWS_ACCESS_KEY_ID="AKIAIQX2LTDOBIW4CZUQ"
+export AWS_SECRET_ACCESS_KEY="<%= @s3_key %>"
+export AWS_REGION="eu-west-2"
+
+exec /usr/local/bin/wal-g "$@" < /dev/null
index e7208b0ae63c447d064c4cd7edb44c30be7b7682..d6aa0621264b0968edfa852acf02098646fe83cf 100644 (file)
@@ -6,7 +6,7 @@
     <link rel="stylesheet" href="map.css" type="text/css" media="all" />
     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="anonymous" />
     <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js" integrity="sha512-C7BBF9irt5R7hqbUm2uxtODlUVs+IsNu2UULGuZN7gM+k/mmeG4xvIEac01BtQa4YIkUpp23zZC4wIwuXaPMQA==" crossorigin="anonymous"></script>
-    <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
     <script type="text/javascript" src="map.js"></script>
   </head>
   <body>
index bcd716e41af04afe524558ae093085c7f479ec40..f84941d94ca0b1fc12a69bff6a00b112c98d2d68 100644 (file)
@@ -8,11 +8,15 @@ version           "1.0.0"
 supports          "ubuntu"
 depends           "apache"
 depends           "passenger"
+depends           "chef"
+depends           "geoipupdate"
 depends           "git"
 depends           "memcached"
 depends           "mysql"
 depends           "nodejs"
+depends           "php"
 depends           "postgresql"
 depends           "python"
+depends           "ruby"
 depends           "tools"
 depends           "web"
index a5729160faceb52b972d06d8ffc27dddcadb6861..cba5239ae962b429080b60e1aacd56af822d81a2 100644 (file)
@@ -22,59 +22,138 @@ require "securerandom"
 
 include_recipe "apache"
 include_recipe "passenger"
+include_recipe "geoipupdate"
 include_recipe "git"
 include_recipe "memcached"
 include_recipe "mysql"
 include_recipe "nodejs"
+include_recipe "php::fpm"
 include_recipe "postgresql"
 include_recipe "python"
+include_recipe "ruby"
 
 package %w[
-  php
+  ant
+  apache2-dev
+  aria2
+  at
+  autoconf
+  automake
+  awscli
+  cmake
+  composer
+  default-jdk-headless
+  default-jre-headless
+  fonts-dejavu
+  fonts-dejavu-core
+  fonts-dejavu-extra
+  fonts-droid-fallback
+  fonts-liberation
+  fonts-noto-mono
+  g++
+  gcc
+  gdal-bin
+  gnuplot-nox
+  golang
+  graphviz
+  irssi
+  jq
+  libargon2-dev
+  libboost-date-time-dev
+  libboost-dev
+  libboost-filesystem-dev
+  libboost-locale-dev
+  libboost-program-options-dev
+  libboost-regex-dev
+  libboost-system-dev
+  libbrotli-dev
+  libbytes-random-secure-perl
+  libcairo2-dev
+  libcrypto++-dev
+  libcurl4-openssl-dev
+  libfcgi-dev
+  libfmt-dev
+  libglib2.0-dev
+  libiniparser-dev
+  libjson-xs-perl
+  libmapnik-dev
+  libmemcached-dev
+  libpqxx-dev
+  libtool
+  libxml-twig-perl
+  libxml2-dev
+  libyajl-dev
+  lua-any
+  luajit
+  lz4
+  lzip
+  lzop
+  mailutils
+  make
+  nano
+  netcat
+  osm2pgsql
+  osmosis
+  pandoc
+  pandoc
+  pbzip2
+  php-apcu
   php-cgi
   php-cli
   php-curl
   php-db
-  php-fpm
+  php-gd
+  php-igbinary
   php-imagick
+  php-intl
+  php-mbstring
+  php-memcache
   php-mysql
   php-pear
   php-pgsql
   php-sqlite3
+  php-xml
+  pigz
   pngcrush
   pngquant
-  python
-  python-argparse
-  python-beautifulsoup
-  python-cheetah
-  python-dateutil
-  python-magic
-  python-psycopg2
-  python-gdal
-  g++
-  gcc
-  make
-  autoconf
-  automake
-  libtool
-  libfcgi-dev
-  libxml2-dev
-  libmemcached-dev
-  libboost-regex-dev
-  libboost-system-dev
-  libboost-program-options-dev
-  libboost-date-time-dev
-  libboost-filesystem-dev
-  libboost-locale-dev
-  libpqxx-dev
-  libcrypto++-dev
-  libyajl-dev
+  proj-bin
+  python-is-python3
+  python3
+  python3-brotli
+  python3-bs4
+  python3-cheetah
+  python3-dateutil
+  python3-dev
+  python3-dotenv
+  python3-gdal
+  python3-lxml
+  python3-lz4
+  python3-magic
+  python3-pil
+  python3-psycopg2
+  python3-pyproj
+  python3-venv
+  r-base
+  redis
+  tmux
+  unrar
+  unzip
+  whois
+  zip
   zlib1g-dev
 ]
 
+# Add uk_os_OSTN15_NTv2_OSGBtoETRS.tif used for reprojecting OS data
+execute "uk_os_OSTN15_NTv2_OSGBtoETRS.tif" do
+  command "projsync --file uk_os_OSTN15_NTv2_OSGBtoETRS.tif --system-directory"
+  not_if { ::File.exist?("/usr/share/proj/uk_os_OSTN15_NTv2_OSGBtoETRS.tif") }
+end
+
 nodejs_package "svgo"
 
-python_package "geojson"
+python_package "geojson" do
+  python_version "3"
+end
 
 apache_module "env"
 apache_module "expires"
@@ -84,38 +163,35 @@ apache_module "proxy_fcgi"
 apache_module "rewrite"
 apache_module "suexec"
 apache_module "userdir"
-apache_module "wsgi"
-
-package "apache2-suexec-pristine"
 
-service "php7.2-fpm" do
-  action [:enable, :start]
+apache_module "wsgi" do
+  package "libapache2-mod-wsgi-py3"
 end
 
-template "/etc/php/7.2/fpm/pool.d/default.conf" do
-  source "fpm-default.conf.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  notifies :reload, "service[php7.2-fpm]"
+package "apache2-suexec-pristine"
+
+php_fpm "default" do
+  pm_max_children 10
+  pm_start_servers 4
+  pm_min_spare_servers 2
+  pm_max_spare_servers 6
 end
 
-file "/etc/php/7.2/fpm/pool.d/www.conf" do
+php_fpm "www" do
   action :delete
-  notifies :reload, "service[php7.2-fpm]"
 end
 
 directory "/srv/dev.openstreetmap.org" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 template "/srv/dev.openstreetmap.org/index.html" do
   source "dev.html.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 ssl_certificate "dev.openstreetmap.org" do
@@ -133,7 +209,7 @@ template "/etc/phppgadmin/config.inc.php" do
   source "phppgadmin.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 file "/etc/apache2/conf.d/phppgadmin" do
@@ -159,15 +235,27 @@ search(:accounts, "*:*").each do |account|
 
   next unless File.directory?("#{user_home}/public_html")
 
-  port = 7000 + account["uid"].to_i
-
-  template "/etc/php/7.2/fpm/pool.d/#{name}.conf" do
-    source "fpm.conf.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    variables :user => name, :port => port
-    notifies :reload, "service[php7.2-fpm]"
+  php_fpm name do
+    user name
+    group name
+    pm_max_children 10
+    pm_start_servers 4
+    pm_min_spare_servers 2
+    pm_max_spare_servers 6
+    pm_max_requests 10000
+    request_terminate_timeout 1800
+    environment "HOSTNAME" => "$HOSTNAME",
+                "PATH" => "/usr/local/bin:/usr/bin:/bin",
+                "TMP" => "/tmp",
+                "TMPDIR" => "/tmp",
+                "TEMP" => "/tmp"
+    php_values "max_execution_time" => "300",
+               "memory_limit" => "128M",
+               "post_max_size" => "32M",
+               "upload_max_filesize" => "32M"
+    php_admin_values "sendmail_path" => "/usr/sbin/sendmail -t -i -f #{name}@dev.openstreetmap.org",
+                     "open_basedir" => "/home/#{name}/:/tmp/:/usr/share/php/"
+    php_flags "display_errors" => "on"
   end
 
   ssl_certificate "#{name}.dev.openstreetmap.org" do
@@ -178,21 +266,25 @@ search(:accounts, "*:*").each do |account|
   apache_site "#{name}.dev.openstreetmap.org" do
     template "apache.user.erb"
     directory "#{user_home}/public_html"
-    variables :user => name, :port => port
+    variables :user => name
   end
 
   template "/etc/sudoers.d/#{name}" do
     source "sudoers.user.erb"
     owner "root"
     group "root"
-    mode 0o440
+    mode "440"
     variables :user => name
   end
 end
 
-if node[:postgresql][:clusters][:"9.5/main"]
+node[:postgresql][:versions].each do |version|
+  package "postgresql-#{version}-postgis-3"
+end
+
+if node[:postgresql][:clusters][:"15/main"]
   postgresql_user "apis" do
-    cluster "9.5/main"
+    cluster "15/main"
   end
 
   template "/usr/local/bin/cleanup-rails-assets" do
@@ -200,23 +292,25 @@ if node[:postgresql][:clusters][:"9.5/main"]
     source "cleanup-assets.erb"
     owner "root"
     group "root"
-    mode 0o755
+    mode "755"
   end
 
-  ruby_version = node[:passenger][:ruby_version]
-
   systemd_service "rails-jobs@" do
     description "Rails job queue runner"
     type "simple"
+    environment_file "/etc/default/rails-%i"
     user "apis"
     working_directory "/srv/%i.apis.dev.openstreetmap.org/rails"
-    exec_start "/usr/local/bin/bundle#{ruby_version} exec rake jobs:work"
+    exec_start "#{node[:ruby][:bundle]} exec rails jobs:work"
     restart "on-failure"
-    private_tmp true
-    private_devices true
-    protect_system "full"
-    protect_home true
-    no_new_privileges true
+    nice 10
+    sandbox :enable_network => true
+    restrict_address_families "AF_UNIX"
+    memory_deny_write_execute false
+    read_write_paths [
+      "/srv/%i.apis.dev.openstreetmap.org/logs",
+      "/srv/%i.apis.dev.openstreetmap.org/rails/storage"
+    ]
   end
 
   systemd_service "cgimap@" do
@@ -224,17 +318,20 @@ if node[:postgresql][:clusters][:"9.5/main"]
     type "forking"
     environment_file "/etc/default/cgimap-%i"
     user "apis"
-    exec_start "/srv/%i.apis.dev.openstreetmap.org/cgimap/openstreetmap-cgimap --daemon --port $CGIMAP_PORT --instances 5"
+    group "www-data"
+    umask "0002"
+    exec_start "/srv/%i.apis.dev.openstreetmap.org/cgimap/build/openstreetmap-cgimap --daemon --instances 5"
     exec_reload "/bin/kill -HUP $MAINPID"
-    private_tmp true
-    private_devices true
-    protect_system "full"
-    protect_home true
-    no_new_privileges true
+    runtime_directory "cgimap-%i"
+    sandbox :enable_network => true
+    restrict_address_families "AF_UNIX"
+    read_write_paths ["/srv/%i.apis.dev.openstreetmap.org/logs", "/srv/%i.apis.dev.openstreetmap.org/rails/tmp"]
     restart "on-failure"
   end
 
-  cgimap_port = 9000
+  Dir.glob("/srv/*.apis.dev.openstreetmap.org").each do |dir|
+    node.default_unless[:dev][:rails][File.basename(dir).split(".").first] = {}
+  end
 
   node[:dev][:rails].each do |name, details|
     database_name = details[:database] || "apis_#{name}"
@@ -247,17 +344,15 @@ if node[:postgresql][:clusters][:"9.5/main"]
 
     if details[:repository]
       site_aliases = details[:aliases] || []
-      secret_key_base = details[:secret_key_base] || SecureRandom.base64(96)
-
-      node.normal[:dev][:rails][name][:secret_key_base] = secret_key_base
+      secret_key_base = persistent_token("dev", "rails", name, "secret_key_base")
 
       postgresql_database database_name do
-        cluster "9.5/main"
+        cluster "15/main"
         owner "apis"
       end
 
       postgresql_extension "#{database_name}_btree_gist" do
-        cluster "9.5/main"
+        cluster "15/main"
         database database_name
         extension "btree_gist"
       end
@@ -265,65 +360,80 @@ if node[:postgresql][:clusters][:"9.5/main"]
       directory site_directory do
         owner "apis"
         group "apis"
-        mode 0o755
+        mode "755"
       end
 
       directory log_directory do
         owner "apis"
         group "apis"
-        mode 0o755
+        mode "755"
       end
 
       directory gpx_directory do
         owner "apis"
         group "apis"
-        mode 0o755
+        mode "755"
       end
 
       directory "#{gpx_directory}/traces" do
         owner "apis"
         group "apis"
-        mode 0o755
+        mode "755"
       end
 
       directory "#{gpx_directory}/images" do
         owner "apis"
         group "apis"
-        mode 0o755
+        mode "755"
+      end
+
+      openssl_rsa_private_key "#{site_directory}/doorkeeper.key" do
+        owner "root"
+        group "root"
+        mode "0400"
       end
 
       rails_port site_name do
-        ruby ruby_version
         directory rails_directory
         user "apis"
         group "apis"
         repository details[:repository]
         revision details[:revision]
-        database_port node[:postgresql][:clusters][:"9.5/main"][:port]
+        database_port node[:postgresql][:clusters][:"15/main"][:port]
         database_name database_name
         database_username "apis"
+        email_from "OpenStreetMap <web@noreply.openstreetmap.org>"
         gpx_dir gpx_directory
         log_path "#{log_directory}/rails.log"
         memcache_servers ["127.0.0.1"]
         csp_enforce true
         run_migrations true
         trace_use_job_queue true
+        doorkeeper_signing_key lazy { File.read("#{site_directory}/doorkeeper.key") }
       end
 
       template "#{rails_directory}/config/initializers/setup.rb" do
         source "rails.setup.rb.erb"
         owner "apis"
         group "apis"
-        mode 0o644
+        mode "644"
         variables :site => site_name
         notifies :restart, "rails_port[#{site_name}]"
       end
 
+      template "/etc/default/rails-#{name}" do
+        source "rails.environment.erb"
+        owner "root"
+        group "root"
+        mode "0600"
+        variables :secret_key_base => secret_key_base
+      end
+
       service "rails-jobs@#{name}" do
         action [:enable, :start]
         supports :restart => true
         subscribes :restart, "rails_port[#{site_name}]"
-        subscribes :restart, "systemd_service[#{name}]"
+        subscribes :restart, "systemd_service[rails-jobs@]"
         only_if "fgrep -q delayed_job #{rails_directory}/Gemfile.lock"
       end
 
@@ -336,48 +446,47 @@ if node[:postgresql][:clusters][:"9.5/main"]
           group "apis"
         end
 
-        execute "#{cgimap_directory}/autogen.sh" do
-          action :nothing
-          command "./autogen.sh"
-          cwd cgimap_directory
+        directory "#{cgimap_directory}/build" do
           user "apis"
           group "apis"
-          subscribes :run, "git[#{cgimap_directory}]", :immediate
+          mode "0755"
         end
 
-        execute "#{cgimap_directory}/configure" do
+        execute "#{cgimap_directory}/CMakeLists.txt" do
           action :nothing
-          command "./configure --with-fcgi=/usr --with-boost-libdir=/usr/lib/x86_64-linux-gnu --enable-yajl"
-          cwd cgimap_directory
+          command "cmake .."
+          cwd "#{cgimap_directory}/build"
           user "apis"
           group "apis"
-          subscribes :run, "execute[#{cgimap_directory}/autogen.sh]", :immediate
+          subscribes :run, "git[#{cgimap_directory}]", :immediately
         end
 
-        execute "#{cgimap_directory}/Makefile" do
+        execute "#{cgimap_directory}/build/Makefile" do
           action :nothing
           command "make -j"
-          cwd cgimap_directory
+          cwd "#{cgimap_directory}/build"
           user "apis"
           group "apis"
-          subscribes :run, "execute[#{cgimap_directory}/configure]", :immediate
-          notifies :restart, "service[cgimap@#{name}]"
+          subscribes :run, "execute[#{cgimap_directory}/CMakeLists.txt]", :immediately
         end
 
         template "/etc/default/cgimap-#{name}" do
           source "cgimap.environment.erb"
           owner "root"
           group "root"
-          mode 0o640
-          variables :cgimap_port => cgimap_port,
-                    :database_port => node[:postgresql][:clusters][:"9.5/main"][:port],
+          mode "640"
+          variables :cgimap_socket => "/run/cgimap-#{name}/socket",
+                    :database_port => node[:postgresql][:clusters][:"15/main"][:port],
                     :database_name => database_name,
-                    :log_directory => log_directory
-          notifies :restart, "service[cgimap@#{name}]"
+                    :log_directory => log_directory,
+                    :options => details[:cgimap_options]
         end
 
         service "cgimap@#{name}" do
           action [:start, :enable]
+          subscribes :restart, "execute[#{cgimap_directory}/build/Makefile]"
+          subscribes :restart, "template[/etc/default/cgimap-#{name}]"
+          subscribes :restart, "systemd_service[cgimap@]"
         end
       end
 
@@ -392,20 +501,18 @@ if node[:postgresql][:clusters][:"9.5/main"]
                   :aliases => site_aliases,
                   :secret_key_base => secret_key_base,
                   :cgimap_enabled => details.key?(:cgimap_repository),
-                  :cgimap_port => cgimap_port
+                  :cgimap_socket => "/run/cgimap-#{name}/socket"
       end
 
       template "/etc/logrotate.d/apis-#{name}" do
         source "logrotate.apis.erb"
         owner "root"
         group "root"
-        mode 0o644
+        mode "644"
         variables :name => name,
                   :log_directory => log_directory,
                   :rails_directory => rails_directory
       end
-
-      cgimap_port += 1
     else
       file "/etc/logrotate.d/apis-#{name}" do
         action :delete
@@ -423,6 +530,10 @@ if node[:postgresql][:clusters][:"9.5/main"]
         action :delete
       end
 
+      service "rails-jobs@#{name}" do
+        action [:stop, :disable]
+      end
+
       directory site_directory do
         action :delete
         recursive true
@@ -434,24 +545,22 @@ if node[:postgresql][:clusters][:"9.5/main"]
 
       postgresql_database database_name do
         action :drop
-        cluster "9.5/main"
+        cluster "15/main"
       end
-
-      node.normal[:dev][:rails].delete(name)
     end
   end
 
   directory "/srv/apis.dev.openstreetmap.org" do
     owner "apis"
     group "apis"
-    mode 0o755
+    mode "755"
   end
 
   template "/srv/apis.dev.openstreetmap.org/index.html" do
     source "apis.html.erb"
     owner "apis"
     group "apis"
-    mode 0o644
+    mode "644"
   end
 
   ssl_certificate "apis.dev.openstreetmap.org" do
@@ -462,29 +571,22 @@ if node[:postgresql][:clusters][:"9.5/main"]
   apache_site "apis.dev.openstreetmap.org" do
     template "apache.apis.erb"
   end
-
-  node[:postgresql][:clusters].each_key do |name|
-    postgresql_munin name do
-      cluster name
-      database "ALL"
-    end
-  end
 end
 
 directory "/srv/ooc.openstreetmap.org" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 remote_directory "/srv/ooc.openstreetmap.org/html" do
   source "ooc"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o644
+  files_mode "644"
 end
 
 ssl_certificate "ooc.openstreetmap.org" do
@@ -498,3 +600,16 @@ end
 apache_site "ooc.openstreetmap.org" do
   template "apache.ooc.erb"
 end
+
+directory "/etc/systemd/system/user-.slice.d" do
+  owner "root"
+  group "root"
+  mode "0755"
+end
+
+template "/etc/systemd/system/user-.slice.d/99-chef.conf" do
+  source "user-slice.conf.erb"
+  owner "root"
+  group "root"
+  mode "0644"
+end
index c1eddbdb2b1e83924d95c986a9069a82e786163b..4d78fdd6aa864e0504ae9172bfc60ff40fff4843 100644 (file)
@@ -8,7 +8,7 @@
        SSLCertificateFile /etc/ssl/certs/apis.dev.openstreetmap.org.pem
        SSLCertificateKeyFile /etc/ssl/private/apis.dev.openstreetmap.org.key
 
-       CustomLog /var/log/apache2/apis.dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/apis.dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/apis.dev.openstreetmap.org-error.log
 
        DocumentRoot /srv/apis.dev.openstreetmap.org
@@ -18,7 +18,7 @@
        ServerName apis.dev.openstreetmap.org
        ServerAdmin webmaster@openstreetmap.org
 
-       CustomLog /var/log/apache2/apis.dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/apis.dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/apis.dev.openstreetmap.org-error.log
 
        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
index 71b73b976bc45f2154eb993664d8dd9f1551186d..2d3d9473d27e99858d4d0cb9bf68784db286c68e 100644 (file)
@@ -8,7 +8,7 @@
        SSLCertificateFile /etc/ssl/certs/dev.openstreetmap.org.pem
        SSLCertificateKeyFile /etc/ssl/private/dev.openstreetmap.org.key
 
-       CustomLog /var/log/apache2/dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/dev.openstreetmap.org-error.log
 
        DocumentRoot /srv/dev.openstreetmap.org
@@ -23,7 +23,7 @@
        ServerName dev.openstreetmap.org
        ServerAdmin webmaster@openstreetmap.org
 
-       CustomLog /var/log/apache2/dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/dev.openstreetmap.org-error.log
 
        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
index 6b921e830b241a86d2c326b8f1c62fd7eb8fde08..0a9b0b9799484e8cd74dde9d926fecff40c21fc9 100644 (file)
@@ -11,7 +11,7 @@
        SSLCertificateFile /etc/ssl/certs/ooc.openstreetmap.org.pem
        SSLCertificateKeyFile /etc/ssl/private/ooc.openstreetmap.org.key
 
-       CustomLog /var/log/apache2/ooc.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/ooc.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/ooc.openstreetmap.org-error.log
 
        DocumentRoot /srv/ooc.openstreetmap.org/html
@@ -28,7 +28,7 @@
        ServerAlias c.ooc.openstreetmap.org
        ServerAdmin webmaster@openstreetmap.org
 
-       CustomLog /var/log/apache2/ooc.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/ooc.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/ooc.openstreetmap.org-error.log
 
        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -39,7 +39,7 @@
        ServerName npe.openstreetmap.org
        ServerAdmin webmaster@openstreetmap.org
 
-       CustomLog /var/log/apache2/npe.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/npe.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/npe.openstreetmap.org-error.log
 
        RewriteEngine on
index ec74a54da0638f99f47468e88f2822b858e2c4c8..546a05cbee3c45605f9f42cc9620943252c4ec5d 100644 (file)
@@ -8,7 +8,7 @@
        SSLCertificateFile /etc/ssl/certs/phppgadmin.dev.openstreetmap.org.pem
        SSLCertificateKeyFile /etc/ssl/private/phppgadmin.dev.openstreetmap.org.key
 
-       CustomLog /var/log/apache2/phppgadmin.dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/phppgadmin.dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/phppgadmin.dev.openstreetmap.org-error.log
 
        DocumentRoot /usr/share/phppgadmin
        # Remove Proxy request header to mitigate https://httpoxy.org/
        RequestHeader unset Proxy early
 
-       ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:7000/usr/share/phppgadmin
-       ProxyPassMatch ^/(.*\.phpx(/.*)?)$ fcgi://127.0.0.1:7000/usr/share/phppgadmin
-       ProxyPassMatch ^/(.*\.phpj(/.*)?)$ fcgi://127.0.0.1:7000/usr/share/phppgadmin
+       ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php-default-fpm.sock|fcgi://127.0.0.1
+       ProxyPassMatch ^/(.*\.phpx(/.*)?)$ unix:/run/php/php-default-fpm.sock|fcgi://127.0.0.1
+       ProxyPassMatch ^/(.*\.phpj(/.*)?)$ unix:/run/php/php-default-fpm.sock|fcgi://127.0.0.1
 </VirtualHost>
 
 <VirtualHost *:80>
        ServerName phppgadmin.dev.openstreetmap.org
        ServerAdmin webmaster@openstreetmap.org
 
-       CustomLog /var/log/apache2/phppgadmin.dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/phppgadmin.dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/phppgadmin.dev.openstreetmap.org-error.log
 
        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
index 3c7eca7e44e864fd771e44941cddc3a90b20ae74..957866c5c482473e12a185a378d3567a38fe6137 100644 (file)
@@ -11,7 +11,7 @@
         SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
         SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         DocumentRoot /srv/<%= @name %>/rails/public
 
         # Pass supported calls to cgimap
         RewriteEngine on
-        RewriteRule ^/api/0\.6/map(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
+        RewriteRule ^/api/0\.6/map(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
         RewriteCond %{REQUEST_METHOD} ^(HEAD|GET)$
-        RewriteRule ^/api/0\.6/(node|way|relation|changeset)/[0-9]+(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
-        RewriteRule ^/api/0\.6/(node|way|relation)/[0-9]+/history(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
-        RewriteRule ^/api/0\.6/(node|way|relation)/[0-9]+/relations(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
-        RewriteRule ^/api/0\.6/node/[0-9]+/ways(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
-        RewriteRule ^/api/0\.6/(way|relation)/[0-9]+/full(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
-        RewriteRule ^/api/0\.6/(nodes|ways|relations)(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
-        RewriteRule ^/api/0\.6/changeset/[0-9]+/(upload|download)(\.json)?$ fcgi://127.0.0.1:<%= @cgimap_port %>$0 [P]
+        RewriteRule ^/api/0\.6/(node|way|relation|changeset)/[0-9]+(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
+        RewriteRule ^/api/0\.6/(node|way|relation)/[0-9]+/history(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
+        RewriteRule ^/api/0\.6/(node|way|relation)/[0-9]+/relations(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
+        RewriteRule ^/api/0\.6/node/[0-9]+/ways(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
+        RewriteRule ^/api/0\.6/(way|relation)/[0-9]+/full(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
+        RewriteRule ^/api/0\.6/(nodes|ways|relations)(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
+        RewriteRule ^/api/0\.6/changeset/[0-9]+/(upload|download)(\.json|\.xml)?$ unix:<%= @cgimap_socket %>|fcgi://127.0.0.1$0 [P]
 <% end -%>
 </VirtualHost>
 
@@ -60,7 +60,7 @@
 <% end -%>
         ServerAdmin webmaster@openstreetmap.org
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
index a6d4d8866402de0405897b2048174113ab6a783a..373d12258faef19fd427c44d5d66f331092e54ad 100644 (file)
@@ -1,6 +1,6 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-WSGIDaemonProcess <%= @user %>.dev.openstreetmap.org user=<%= @user %> inactivity-timeout=600
+WSGIDaemonProcess <%= @user %>.dev.openstreetmap.org user=<%= @user %> processes=2 threads=8 restart-interval=3600 inactivity-timeout=600 graceful-timeout=60 maximum-requests=2000
 
 <VirtualHost *:443>
        ServerName <%= @user %>.dev.openstreetmap.org
@@ -23,14 +23,15 @@ WSGIDaemonProcess <%= @user %>.dev.openstreetmap.org user=<%= @user %> inactivit
        RewriteEngine on
        #LogLevel rewrite:trace2
 
-       CustomLog /var/log/apache2/<%= @user %>.dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/<%= @user %>.dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/<%= @user %>.dev.openstreetmap.org-error.log
 
        RewriteCond <%= @directory %>%{REQUEST_FILENAME} -f
        RewriteRule ^/cgi-bin/(.*)$ /~<%= @user %>/cgi-bin/$1 [PT,L]
 
-       RewriteCond <%= @directory %>%{REQUEST_FILENAME} -f
-       RewriteRule ^/(.*\.ph(p|ps|p3|tml)(/.*)?)$ fcgi://127.0.0.1:<%= @port %><%= @directory %>/$1 [P]
+       <FilesMatch ".+\.ph(p|ps|p3|tml)$">
+               SetHandler "proxy:unix:/run/php/php-<%= @user %>-fpm.sock|fcgi://127.0.0.1"
+       </FilesMatch>
 </VirtualHost>
 
 <VirtualHost *:80>
@@ -38,7 +39,7 @@ WSGIDaemonProcess <%= @user %>.dev.openstreetmap.org user=<%= @user %> inactivit
        ServerAdmin webmaster@openstreetmap.org
        ServerAlias <%= @user %>.dev.osm.org
 
-       CustomLog /var/log/apache2/<%= @user %>.dev.openstreetmap.org-access.log combined
+       CustomLog /var/log/apache2/<%= @user %>.dev.openstreetmap.org-access.log combined_extended
        ErrorLog /var/log/apache2/<%= @user %>.dev.openstreetmap.org-error.log
 
        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
index b9f71ee7ae1484f7b7648832f6589be12e137a75..485d58e87b6f4843324a2c2b5bbf6b2b68db1876 100644 (file)
@@ -1,6 +1,6 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-CGIMAP_PORT="<%= @cgimap_port %>"
+CGIMAP_SOCKET="<%= @cgimap_socket %>"
 CGIMAP_DBPORT="<%= @database_port %>"
 CGIMAP_DBNAME="<%= @database_name %>"
 CGIMAP_USERNAME="apis"
@@ -8,3 +8,11 @@ CGIMAP_LOGFILE="<%= @log_directory %>/cgimap.log"
 CGIMAP_MEMCACHE="127.0.0.1"
 CGIMAP_RATELIMIT="204800"
 CGIMAP_MAXDEBT="250"
+CGIMAP_MAP_AREA="<%= node[:web][:max_request_area] %>"
+CGIMAP_MAP_NODES"<%= node[:web][:max_number_of_nodes] %>"
+CGIMAP_MAX_WAY_NODES="<%= node[:web][:max_number_of_way_nodes] %>"
+CGIMAP_MAX_RELATION_MEMBERS="<%= node[:web][:max_number_of_relation_members] %>"
+CGIMAP_RATELIMIT_UPLOAD="true"
+<% Hash(@options).each do |name, value| -%>
+CGIMAP_<%= name.to_s.upcase %>="<%= value %>"
+<% end -%>
index 3b4ab2fba87e97d6e992cfe023601b0d7c022375..c259f0013d9e8d13d6b509d0d22ac4e7fc8cba93 100644 (file)
@@ -1,10 +1,28 @@
 <html>
-<body>
-You've reached errol, the OpenStreetMap dev server. <br />
-<dl>
-<dt>If you are a user...</dt>
-<dd>You probably want <a href="https://www.openstreetmap.org/">OpenStreetMap</a> itself.</dd>
-<dt>If you are a developer...</dt>
-<dd>You might be interested in <a href="https://apis.dev.openstreetmap.org/">live instances</a> of various <a href="https://wiki.openstreetmap.org/index.php/The_Rails_Port#Installation_on_Debian">Rails Port</a> code branches in <a href="https://svn.openstreetmap.org/sites/rails_port_branches/">SVN</a> for testing clients against.</dd>
-</body>
+  <body>
+    <h4>
+      You've reached <a href="https://hardware.openstreetmap.org/servers/faffy.openstreetmap.org/">faffy</a>, the OpenStreetMap dev server.
+    </h4>
+    <dl>
+      <dt>If you are a user...</dt>
+      <dd>
+        You probably want
+        <a href="https://www.openstreetmap.org/">OpenStreetMap</a> itself.
+      </dd>
+      <dt>If you are a developer...</dt>
+      <dd>
+        You might be interested in
+        <a href="https://apis.dev.openstreetmap.org/">live instances</a> of
+        various
+        <a href="https://github.com/openstreetmap/openstreetmap-website#readme">Rails Port</a>
+        code branches for testing clients against.
+      </dd>
+      <dt>Request an account</dt>
+      <dd>
+        Anyone who wants to work on OpenStreetMap-related projects can
+        <a href="https://github.com/openstreetmap/operations/issues/new?assignees=Firefishy&labels=faffy%2Cuser+request&template=ACCOUNT-REQUEST.yml&title=%5BAccount+request%5D%3A+">request an account</a>
+        on the dev server.
+      </dd>
+    </dl>
+  </body>
 </html>
diff --git a/cookbooks/dev/templates/default/fpm-default.conf.erb b/cookbooks/dev/templates/default/fpm-default.conf.erb
deleted file mode 100644 (file)
index fe7ee4c..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-; Start a new pool named 'default'.
-; the variable $pool can we used in any directive and will be replaced by the
-; pool name ('default' here)
-[default]
-
-; Per pool prefix
-; It only applies on the following directives:
-; - 'slowlog'
-; - 'listen' (unixsocket)
-; - 'chroot'
-; - 'chdir'
-; - 'php_values'
-; - 'php_admin_values'
-; When not set, the global prefix (or /usr) applies instead.
-; Note: This directive can also be relative to the global prefix.
-; Default Value: none
-;prefix = /path/to/pools/$pool
-
-; Unix user/group of processes
-; Note: The user is mandatory. If the group is not set, the default user's group
-;       will be used.
-user = www-data
-group = www-data
-
-; The address on which to accept FastCGI requests.
-; Valid syntaxes are:
-;   'ip.add.re.ss:port'    - to listen on a TCP socket to a specific address on
-;                            a specific port;
-;   'port'                 - to listen on a TCP socket to all addresses on a
-;                            specific port;
-;   '/path/to/unix/socket' - to listen on a unix socket.
-; Note: This value is mandatory.
-listen = 127.0.0.1:7000
-
-; Set listen(2) backlog. A value of '-1' means unlimited.
-; Default Value: 128 (-1 on FreeBSD and OpenBSD)
-;listen.backlog = -1
-
-; Set permissions for unix socket, if one is used. In Linux, read/write
-; permissions must be set in order to allow connections from a web server. Many
-; BSD-derived systems allow connections regardless of permissions. 
-; Default Values: user and group are set as the running user
-;                 mode is set to 0666
-;listen.owner = www-data
-;listen.group = www-data
-;listen.mode = 0660
-; List of ipv4 addresses of FastCGI clients which are allowed to connect.
-; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original
-; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address
-; must be separated by a comma. If this value is left blank, connections will be
-; accepted from any ip address.
-; Default Value: any
-;listen.allowed_clients = 127.0.0.1
-
-; Choose how the process manager will control the number of child processes.
-; Possible Values:
-;   static  - a fixed number (pm.max_children) of child processes;
-;   dynamic - the number of child processes are set dynamically based on the
-;             following directives. With this process management, there will be
-;             always at least 1 children.
-;             pm.max_children      - the maximum number of children that can
-;                                    be alive at the same time.
-;             pm.start_servers     - the number of children created on startup.
-;             pm.min_spare_servers - the minimum number of children in 'idle'
-;                                    state (waiting to process). If the number
-;                                    of 'idle' processes is less than this
-;                                    number then some children will be created.
-;             pm.max_spare_servers - the maximum number of children in 'idle'
-;                                    state (waiting to process). If the number
-;                                    of 'idle' processes is greater than this
-;                                    number then some children will be killed.
-;  ondemand - no children are created at startup. Children will be forked when
-;             new requests will connect. The following parameter are used:
-;             pm.max_children           - the maximum number of children that
-;                                         can be alive at the same time.
-;             pm.process_idle_timeout   - The number of seconds after which
-;                                         an idle process will be killed.
-; Note: This value is mandatory.
-pm = dynamic
-
-; The number of child processes to be created when pm is set to 'static' and the
-; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
-; This value sets the limit on the number of simultaneous requests that will be
-; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
-; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
-; CGI. The below defaults are based on a server without much resources. Don't
-; forget to tweak pm.* to fit your needs.
-; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
-; Note: This value is mandatory.
-pm.max_children = 10
-
-; The number of child processes created on startup.
-; Note: Used only when pm is set to 'dynamic'
-; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
-pm.start_servers = 4
-
-; The desired minimum number of idle server processes.
-; Note: Used only when pm is set to 'dynamic'
-; Note: Mandatory when pm is set to 'dynamic'
-pm.min_spare_servers = 2
-
-; The desired maximum number of idle server processes.
-; Note: Used only when pm is set to 'dynamic'
-; Note: Mandatory when pm is set to 'dynamic'
-pm.max_spare_servers = 6
-
-; The number of seconds after which an idle process will be killed.
-; Note: Used only when pm is set to 'ondemand'
-; Default Value: 10s
-;pm.process_idle_timeout = 10s;
-; The number of requests each child process should execute before respawning.
-; This can be useful to work around memory leaks in 3rd party libraries. For
-; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS.
-; Default Value: 0
-;pm.max_requests = 500
-
-; The URI to view the FPM status page. If this value is not set, no URI will be
-; recognized as a status page. It shows the following informations:
-;   pool                 - the name of the pool;
-;   process manager      - static, dynamic or ondemand;
-;   start time           - the date and time FPM has started;
-;   start since          - number of seconds since FPM has started;
-;   accepted conn        - the number of request accepted by the pool;
-;   listen queue         - the number of request in the queue of pending
-;                          connections (see backlog in listen(2));
-;   max listen queue     - the maximum number of requests in the queue
-;                          of pending connections since FPM has started;
-;   listen queue len     - the size of the socket queue of pending connections;
-;   idle processes       - the number of idle processes;
-;   active processes     - the number of active processes;
-;   total processes      - the number of idle + active processes;
-;   max active processes - the maximum number of active processes since FPM
-;                          has started;
-;   max children reached - number of times, the process limit has been reached,
-;                          when pm tries to start more children (works only for
-;                          pm 'dynamic' and 'ondemand');
-; Value are updated in real time.
-; Example output:
-;   pool:                 www
-;   process manager:      static
-;   start time:           01/Jul/2011:17:53:49 +0200
-;   start since:          62636
-;   accepted conn:        190460
-;   listen queue:         0
-;   max listen queue:     1
-;   listen queue len:     42
-;   idle processes:       4
-;   active processes:     11
-;   total processes:      15
-;   max active processes: 12
-;   max children reached: 0
-;
-; By default the status page output is formatted as text/plain. Passing either
-; 'html', 'xml' or 'json' in the query string will return the corresponding
-; output syntax. Example:
-;   http://www.foo.bar/status
-;   http://www.foo.bar/status?json
-;   http://www.foo.bar/status?html
-;   http://www.foo.bar/status?xml
-;
-; By default the status page only outputs short status. Passing 'full' in the
-; query string will also return status for each pool process.
-; Example: 
-;   http://www.foo.bar/status?full
-;   http://www.foo.bar/status?json&full
-;   http://www.foo.bar/status?html&full
-;   http://www.foo.bar/status?xml&full
-; The Full status returns for each process:
-;   pid                  - the PID of the process;
-;   state                - the state of the process (Idle, Running, ...);
-;   start time           - the date and time the process has started;
-;   start since          - the number of seconds since the process has started;
-;   requests             - the number of requests the process has served;
-;   request duration     - the duration in µs of the requests;
-;   request method       - the request method (GET, POST, ...);
-;   request URI          - the request URI with the query string;
-;   content length       - the content length of the request (only with POST);
-;   user                 - the user (PHP_AUTH_USER) (or '-' if not set);
-;   script               - the main script called (or '-' if not set);
-;   last request cpu     - the %cpu the last request consumed
-;                          it's always 0 if the process is not in Idle state
-;                          because CPU calculation is done when the request
-;                          processing has terminated;
-;   last request memory  - the max amount of memory the last request consumed
-;                          it's always 0 if the process is not in Idle state
-;                          because memory calculation is done when the request
-;                          processing has terminated;
-; If the process is in Idle state, then informations are related to the
-; last request the process has served. Otherwise informations are related to
-; the current request being served.
-; Example output:
-;   ************************
-;   pid:                  31330
-;   state:                Running
-;   start time:           01/Jul/2011:17:53:49 +0200
-;   start since:          63087
-;   requests:             12808
-;   request duration:     1250261
-;   request method:       GET
-;   request URI:          /test_mem.php?N=10000
-;   content length:       0
-;   user:                 -
-;   script:               /home/fat/web/docs/php/test_mem.php
-;   last request cpu:     0.00
-;   last request memory:  0
-;
-; Note: There is a real-time FPM status monitoring sample web page available
-;       It's available in: ${prefix}/share/fpm/status.html
-;
-; Note: The value must start with a leading slash (/). The value can be
-;       anything, but it may not be a good idea to use the .php extension or it
-;       may conflict with a real PHP file.
-; Default Value: not set 
-;pm.status_path = /status
-; The ping URI to call the monitoring page of FPM. If this value is not set, no
-; URI will be recognized as a ping page. This could be used to test from outside
-; that FPM is alive and responding, or to
-; - create a graph of FPM availability (rrd or such);
-; - remove a server from a group if it is not responding (load balancing);
-; - trigger alerts for the operating team (24/7).
-; Note: The value must start with a leading slash (/). The value can be
-;       anything, but it may not be a good idea to use the .php extension or it
-;       may conflict with a real PHP file.
-; Default Value: not set
-;ping.path = /ping
-
-; This directive may be used to customize the response of a ping request. The
-; response is formatted as text/plain with a 200 response code.
-; Default Value: pong
-;ping.response = pong
-
-; The access log file
-; Default: not set
-;access.log = log/$pool.access.log
-
-; The access log format.
-; The following syntax is allowed
-;  %%: the '%' character
-;  %C: %CPU used by the request
-;      it can accept the following format:
-;      - %{user}C for user CPU only
-;      - %{system}C for system CPU only
-;      - %{total}C  for user + system CPU (default)
-;  %d: time taken to serve the request
-;      it can accept the following format:
-;      - %{seconds}d (default)
-;      - %{miliseconds}d
-;      - %{mili}d
-;      - %{microseconds}d
-;      - %{micro}d
-;  %e: an environment variable (same as $_ENV or $_SERVER)
-;      it must be associated with embraces to specify the name of the env
-;      variable. Some exemples:
-;      - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e
-;      - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e
-;  %f: script filename
-;  %l: content-length of the request (for POST request only)
-;  %m: request method
-;  %M: peak of memory allocated by PHP
-;      it can accept the following format:
-;      - %{bytes}M (default)
-;      - %{kilobytes}M
-;      - %{kilo}M
-;      - %{megabytes}M
-;      - %{mega}M
-;  %n: pool name
-;  %o: ouput header
-;      it must be associated with embraces to specify the name of the header:
-;      - %{Content-Type}o
-;      - %{X-Powered-By}o
-;      - %{Transfert-Encoding}o
-;      - ....
-;  %p: PID of the child that serviced the request
-;  %P: PID of the parent of the child that serviced the request
-;  %q: the query string 
-;  %Q: the '?' character if query string exists
-;  %r: the request URI (without the query string, see %q and %Q)
-;  %R: remote IP address
-;  %s: status (response code)
-;  %t: server time the request was received
-;      it can accept a strftime(3) format:
-;      %d/%b/%Y:%H:%M:%S %z (default)
-;  %T: time the log has been written (the request has finished)
-;      it can accept a strftime(3) format:
-;      %d/%b/%Y:%H:%M:%S %z (default)
-;  %u: remote user
-;
-; Default: "%R - %u %t \"%m %r\" %s"
-;access.format = %R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%%
-; The log file for slow requests
-; Default Value: not set
-; Note: slowlog is mandatory if request_slowlog_timeout is set
-;slowlog = log/$pool.log.slow
-; The timeout for serving a single request after which a PHP backtrace will be
-; dumped to the 'slowlog' file. A value of '0s' means 'off'.
-; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
-; Default Value: 0
-;request_slowlog_timeout = 0
-; The timeout for serving a single request after which the worker process will
-; be killed. This option should be used when the 'max_execution_time' ini option
-; does not stop script execution for some reason. A value of '0' means 'off'.
-; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
-; Default Value: 0
-;request_terminate_timeout = 0
-; Set open file descriptor rlimit.
-; Default Value: system defined value
-;rlimit_files = 1024
-; Set max core size rlimit.
-; Possible Values: 'unlimited' or an integer greater or equal to 0
-; Default Value: system defined value
-;rlimit_core = 0
-; Chroot to this directory at the start. This value must be defined as an
-; absolute path. When this value is not set, chroot is not used.
-; Note: you can prefix with '$prefix' to chroot to the pool prefix or one
-; of its subdirectories. If the pool prefix is not set, the global prefix
-; will be used instead.
-; Note: chrooting is a great security feature and should be used whenever 
-;       possible. However, all PHP paths will be relative to the chroot
-;       (error_log, sessions.save_path, ...).
-; Default Value: not set
-;chroot = 
-; Chdir to this directory at the start.
-; Note: relative path can be used.
-; Default Value: current directory or / when chroot
-chdir = /
-; Redirect worker stdout and stderr into main error log. If not set, stdout and
-; stderr will be redirected to /dev/null according to FastCGI specs.
-; Note: on highloaded environement, this can cause some delay in the page
-; process time (several ms).
-; Default Value: no
-;catch_workers_output = yes
-
-; Limits the extensions of the main script FPM will allow to parse. This can
-; prevent configuration mistakes on the web server side. You should only limit
-; FPM to .php extensions to prevent malicious users to use other extensions to
-; exectute php code.
-; Note: set an empty value to allow all extensions.
-; Default Value: .php
-;security.limit_extensions = .php .php3 .php4 .php5
-; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
-; the current environment.
-; Default Value: clean env
-;env[HOSTNAME] = $HOSTNAME
-;env[PATH] = /usr/local/bin:/usr/bin:/bin
-;env[TMP] = /tmp
-;env[TMPDIR] = /tmp
-;env[TEMP] = /tmp
-
-; Additional php.ini defines, specific to this pool of workers. These settings
-; overwrite the values previously defined in the php.ini. The directives are the
-; same as the PHP SAPI:
-;   php_value/php_flag             - you can set classic ini defines which can
-;                                    be overwritten from PHP call 'ini_set'. 
-;   php_admin_value/php_admin_flag - these directives won't be overwritten by
-;                                     PHP call 'ini_set'
-; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
-
-; Defining 'extension' will load the corresponding shared extension from
-; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
-; overwrite previously defined php.ini values, but will append the new value
-; instead.
-
-; Note: path INI options can be relative and will be expanded with the prefix
-; (pool, global or /usr)
-
-; Default Value: nothing is defined by default except the values in php.ini and
-;                specified at startup with the -d argument
-;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
-;php_flag[display_errors] = off
-;php_admin_value[error_log] = /var/log/fpm-php.www.log
-;php_admin_flag[log_errors] = on
-;php_admin_value[memory_limit] = 32M
diff --git a/cookbooks/dev/templates/default/fpm.conf.erb b/cookbooks/dev/templates/default/fpm.conf.erb
deleted file mode 100644 (file)
index 523d8ca..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-; DO NOT EDIT - This file is being maintained by Chef
-
-[<%= @user %>]
-listen = 127.0.0.1:<%= @port %>
-listen.backlog = 256
-
-user = <%= @user %>
-group = <%= @user %>
-
-pm = dynamic
-pm.max_children = 10
-pm.start_servers = 4
-pm.min_spare_servers = 2
-pm.max_spare_servers = 6
-pm.max_requests = 10000
-
-request_terminate_timeout = 1800
-
-;pm.status_path = /status
-;ping.path = /ping
-;ping.response = pong
-;request_terminate_timeout = 0
-;request_slowlog_timeout = 0
-;slowlog = /var/log/php5-fpm.log.slow
-;rlimit_files = 1024
-;rlimit_core = 0
-;chroot = 
-;chdir = /var/www
-;catch_workers_output = yes
-env[HOSTNAME] = $HOSTNAME
-env[PATH] = /usr/local/bin:/usr/bin:/bin
-env[TMP] = /tmp
-env[TMPDIR] = /tmp
-env[TEMP] = /tmp
-
-php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f <%= @user %>@errol.openstreetmap.org
-php_admin_value[open_basedir] = /home/<%= @user %>/:/tmp/:/usr/share/php/
-php_flag[display_errors] = on
-;php_admin_value[error_log] = /var/log/fpm-php.www.log
-;php_admin_flag[log_errors] = on
-php_value[max_execution_time] = 300
-php_value[memory_limit] = 128M
-php_value[post_max_size] = 32M
-php_value[upload_max_filesize] = 32M
-
diff --git a/cookbooks/dev/templates/default/rails.environment.erb b/cookbooks/dev/templates/default/rails.environment.erb
new file mode 100644 (file)
index 0000000..c8a6ee0
--- /dev/null
@@ -0,0 +1,5 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+RAILS_ENV="production"
+SLEEP_DELAY="60"
+SECRET_KEY_BASE="<%= @secret_key_base %>"
index ad42b68f723ed186eed5de0a80a436020c8f8d04..afdb0a44afea669372d395a50c2b6846a73b98b4 100644 (file)
@@ -1,14 +1,14 @@
 OpenStreetMap::Application.config.after_initialize do
-  if ActiveRecord::Base.connection.table_exists?(:client_applications)
-    unless webmaster = User.find_by_email("webmaster@openstreetmap.org")
-      webmaster = User.new
-      webmaster.display_name = "OpenStreetMap Webmaster"
-      webmaster.email = "webmaster@openstreetmap.org"
-      webmaster.pass_crypt = SecureRandom.hex
-      webmaster.status = "active"
-      webmaster.save!
-    end
+  unless webmaster = User.find_by_email("webmaster@openstreetmap.org")
+    webmaster = User.new
+    webmaster.display_name = "OpenStreetMap Webmaster"
+    webmaster.email = "webmaster@openstreetmap.org"
+    webmaster.pass_crypt = SecureRandom.hex
+    webmaster.activate
+    webmaster.save!
+  end
 
+  if ActiveRecord::Base.connection.table_exists?(:client_applications)
     unless id = webmaster.client_applications.find_by_name("iD")
       id = webmaster.client_applications.new
       id.name = "iD"
@@ -51,4 +51,36 @@ OpenStreetMap::Application.config.after_initialize do
       OAUTH_KEY = website.key
     end
   end
+
+  if ActiveRecord::Base.connection.table_exists?(:oauth_applications)
+    unless id = webmaster.oauth2_applications.find_by_name("iD")
+      id = webmaster.oauth2_applications.new
+      id.name = "iD"
+      id.redirect_uri = "https://<%= @site %>/id"
+      id.scopes = Oauth.scopes.map(&:name)
+      id.confidential = true
+      id.save!
+    end
+
+    if Kernel.const_defined?("Settings")
+      Settings.id_application = id.uid
+    else
+      ID_APPLICATION = id.uid
+    end
+
+    unless website = webmaster.oauth2_applications.find_by_name("Web Site")
+      website = webmaster.oauth2_applications.new
+      website.name = "Web Site"
+      website.redirect_uri = "https://<%= @site %>/"
+      website.scopes = Oauth.scopes.map(&:name)
+      website.confidential = true
+      website.save!
+    end
+
+    if Kernel.const_defined?("Settings")
+      Settings.oauth_application = website.uid
+    else
+      OAUTH_APPLICATION = website.uid
+    end
+  end
 end
diff --git a/cookbooks/dev/templates/default/user-slice.conf.erb b/cookbooks/dev/templates/default/user-slice.conf.erb
new file mode 100644 (file)
index 0000000..47d8a06
--- /dev/null
@@ -0,0 +1,3 @@
+[Slice]
+MemoryHigh=80%
+MemoryMax=90%
index 0b8ba5a514d02d7670ff903e0c66f779b1b4334d..9bcaf898f07a8d166d76b6705ec1383e32526a71 100644 (file)
 cookbook_file "/usr/local/bin/fixeep-82574_83.sh" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 execute "udevadm-trigger" do
   action :nothing
-  command "/sbin/udevadm trigger --action=add"
+  command "/bin/udevadm trigger --action=add"
 end
 
 template "/etc/udev/rules.d/99-chef.rules" do
   source "udev.rules.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :run, "execute[udevadm-trigger]"
 end
+
+template "/etc/modprobe.d/nvme.conf" do
+  source "nvme.conf.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  only_if { ::File.exist?("/sys/module/nvme/parameters/poll_queues") }
+end
+
+package "initramfs-tools"
+
+execute "update-initramfs" do
+  action :nothing
+  command "/usr/sbin/update-initramfs -u"
+  subscribes :run, "template[/etc/modprobe.d/nvme.conf]"
+end
similarity index 67%
rename from cookbooks/munin/templates/default/ipmi.erb
rename to cookbooks/devices/templates/default/nvme.conf.erb
index a52fa50a0b22effe7bd19aa9c6acd652d65ce60e..9c90d93c4d39df7d9708246144d597ae05f4cce2 100644 (file)
@@ -1,4 +1,3 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-[ipmi_*]
-timeout 10
+options nvme poll_queues=4
index a3c43a531450be7fa1f4e2108a1c455aed8be61d..be990389110e34fa05a7ce398c662a6fb63f5ccc 100644 (file)
@@ -1,14 +1,15 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
 # HP Smart Array configuration
-ACTION=="add", SUBSYSTEM=="block", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/scheduler}="noop"
-ACTION=="add", SUBSYSTEM=="block", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/nr_requests}="512"
-ACTION=="add", SUBSYSTEM=="block", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/read_ahead_kb}="4096"
-ACTION=="add", SUBSYSTEM=="block", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/rq_affinity}="2"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/scheduler}="noop"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/nr_requests}="512"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="LOGICAL_VOLUME", ATTR{queue/rq_affinity}="2"
 
-# VMware Virtual disk configuration
-ACTION=="add", SUBSYSTEM=="block", ENV{ID_VENDOR}=="VMware", ENV{ID_MODEL}=="Virtual_disk", ATTR{queue/read_ahead_kb}="4096"
-ACTION=="add", SUBSYSTEM=="block", ENV{ID_VENDOR}=="VMware", ENV{ID_MODEL}=="Virtual_disk", ATTR{queue/scheduler}="noop"
+# Dell PERC H710 tune
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="DELL", ENV{ID_MODEL}=="PERC_H710", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="DELL", ENV{ID_MODEL}=="PERC_H710", ATTR{queue/scheduler}="deadline"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="DELL", ENV{ID_MODEL}=="PERC_H710", ATTR{queue/nr_requests}="512"
 
 <% node[:devices].each do |name,device| -%>
 
@@ -31,14 +32,69 @@ ACTION=="add", SUBSYSTEM=="block", ENV{ID_BUS}=="<%= device[:bus] %>", ENV{ID_SE
 <% end -%>
 <% end -%>
 
+# Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x10ec", ATTRS{device}=="0x8168", RUN+="/sbin/ethtool -K $name tso off gso off"
+
+# Ethernet controller: Mellanox Technologies MT27710 Family [ConnectX-4 Lx]
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x15b3", ATTRS{device}=="0x1015", RUN+="/sbin/ethtool -G $name rx 8192 tx 8192"
+
+# Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme II BCM5709 Gigabit Ethernet
+# Hewlett-Packard Company NC382i Integrated Multi-port PCI Express Gigabit Server Adapter
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x14e4", ATTRS{device}=="0x1639", RUN+="/sbin/ethtool -G $name rx 2040"
+# Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme II BCM5708 Gigabit Ethernet
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x14e4", ATTRS{device}=="0x164c", RUN+="/sbin/ethtool -G $name rx 2040"
+# Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme BCM5719 Gigabit Ethernet PCIe
+# Hewlett-Packard Company Ethernet 1Gb 4-port 331i Adapter
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x14e4", ATTRS{device}=="0x1657", RUN+="/sbin/ethtool -G $name rx 2047"
+# Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme BCM5721 Gigabit Ethernet PCI Express
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x14e4", ATTRS{device}=="0x1659", RUN+="/sbin/ethtool -G $name rx 511"
+# Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme BCM5720 2-port Gigabit Ethernet PCIe
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x14e4", ATTRS{device}=="0x165f", RUN+="/sbin/ethtool -G $name rx 2047"
+
+# Ethernet controller: Intel Corporation 82571EB/82571GB Gigabit Ethernet Controller D0/D1 (copper applications)
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x105e", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation 80003ES2LAN Gigabit Ethernet Controller (Copper)
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1096", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation 82575EB Gigabit Network Connection
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x10a7", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
 # Disable scatter-gather offload for HP NC362i network controllers
 SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x10c9", ATTRS{subsystem_vendor}=="0x103c", ATTRS{subsystem_device}=="0x323f", RUN+="/sbin/ethtool -K $name gso off tso off sg off gro off"
-
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x10c9", ATTRS{subsystem_vendor}=="0x103c", ATTRS{subsystem_device}=="0x323f", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation 82574L Gigabit Network Connection
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x10d3", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
 # Fix Power Saving Bug on Intel 82574L and Intel 82583 network controllers
 SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x10d3", RUN+="/usr/local/bin/fixeep-82574_83.sh $name"
 SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x10f6", RUN+="/usr/local/bin/fixeep-82574_83.sh $name"
 SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x150c", RUN+="/usr/local/bin/fixeep-82574_83.sh $name"
 
+# Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x10fb", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation 82580 Gigabit Network Connection
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x150e", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation I350 Gigabit Network Connection
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1521", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation Ethernet Controller 10-Gigabit X540-AT2
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1528", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation I210 Gigabit Network Connection
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1533", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation I211 Gigabit Network Connection
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1539", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x157b", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation Ethernet Controller 10G X550T
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1563", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GBASE-T
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1586", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation Ethernet Controller X710 for 10GBASE-T
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x15ff", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation Ethernet Connection I354 (rev 03)
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x1f41", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+# Ethernet controller: Intel Corporation Ethernet Connection X722 for 10GBASE-T
+SUBSYSTEM=="net", ACTION=="add", ATTRS{vendor}=="0x8086", ATTRS{device}=="0x37d2", RUN+="/sbin/ethtool -G $name rx 4096 tx 4096"
+
+# Disable Firmware Based LLDP handler
+SUBSYSTEM=="net", ACTION=="add", ENV{INTERFACE}=="*", DRIVERS=="i40e", RUN+="/sbin/ethtool --set-priv-flags $name disable-fw-lldp on"
+
 # Workaround unreliable Western Digital WD RE3/RE4 disks (ATA only)
 # Set sufficent Linux subsystem timeout and fix severe NCQ performance issue
 ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="WDC_WD5002ABYS-02B1B0", ATTR{device/timeout}="90", ATTR{device/queue_depth}="1", ATTR{queue/nr_requests}="256"
@@ -58,9 +114,47 @@ ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV
 ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="HGST_HTS725050A7E630", RUN+="/usr/sbin/smartctl -q errorsonly -l scterc,100,100 $env{DEVNAME}"
 ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="HGST_HTE721010A9E630", RUN+="/usr/sbin/smartctl -q errorsonly -l scterc,100,100 $env{DEVNAME}"
 
+# Add SSD optimisation
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="OCZ-VERTEX3", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="OCZ-VERTEX3", ATTR{queue/scheduler}="noop"
+
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_840_PRO_*", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_840_PRO_*", ATTR{queue/scheduler}="noop"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_840_PRO_*", ATTR{queue/read_ahead_kb}="256"
+
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_850_PRO_*", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_850_PRO_*", ATTR{queue/scheduler}="noop"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_850_PRO_*", ATTR{queue/read_ahead_kb}="256"
+
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_860_PRO_*", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_860_PRO_*", ATTR{queue/scheduler}="noop"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="Samsung_SSD_860_PRO_*", ATTR{queue/read_ahead_kb}="256"
+
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="ST240FN0021", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="ST240FN0021", ATTR{queue/scheduler}="noop"
+
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="SuperMicro_SSD", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="SuperMicro_SSD", ATTR{queue/scheduler}="noop"
+
+# Delete failed disk in cmok
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_MODEL}=="ST_M13FQBL", ENV{ID_SERIAL}=="ST_M13FQBL_QNR_BFW", ATTR{device/delete}="1"
+
 # Enable request merging for NVME devices
 ACTION=="add", SUBSYSTEM=="block", DRIVERS=="nvme", ATTR{queue/nomerges}="1"
 
+# VMware Virtual disk configuration
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="VMware", ENV{ID_MODEL}=="Virtual_disk", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_VENDOR}=="VMware", ENV{ID_MODEL}=="Virtual_disk", ATTR{queue/scheduler}="noop"
+
 # Increase readahead on virtio block devices
 ACTION=="add", SUBSYSTEM=="block", DRIVERS=="virtio_blk", ATTR{queue/read_ahead_kb}="4096"
 # Note virtio sets scheduler to none automatically
+
+# QEMU Disk IO tune
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_MODEL}=="QEMU_HARDDISK", ATTR{queue/read_ahead_kb}="4096"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{ID_MODEL}=="QEMU_HARDDISK", ATTR{queue/scheduler}="noop"
+# Vendor is sometimes missing
+
+# Increase default MD raid5/raid6 strip cache + group_thread_cnt
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{MD_LEVEL}=="raid5", ATTR{md/stripe_cache_size}="8192", ATTR{md/group_thread_cnt}="4"
+ACTION=="add", SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", ENV{MD_LEVEL}=="raid6", ATTR{md/stripe_cache_size}="8192", ATTR{md/group_thread_cnt}="4"
index cc693c7df23b3e6e9498319a95bc9b0a5f5a8049..2e239b15745d5a275aa2ecb83885ee8069e1c055 100644 (file)
@@ -7,3 +7,4 @@ description       "Configures dhcpd"
 version           "1.0.0"
 supports          "ubuntu"
 depends           "networking"
+depends           "ntp"
index 18343a67d1afea65f01c4c13090611d41e76affc..0e6b9ec3fcf35f330241105acb7fde1b1c98c100 100644 (file)
 
 include_recipe "networking"
 
-package "isc-dhcp-server"
+package %w[
+  isc-dhcp-server
+  tftpd-hpa
+]
+
+service "tftpd-hpa" do
+  action [:enable, :start]
+  supports :status => true, :restart => true
+end
+
+remote_file "/srv/tftp/netboot.xyz.efi" do
+  action :create
+  source "https://boot.netboot.xyz/ipxe/netboot.xyz.efi"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+remote_file "/srv/tftp/netboot.xyz-snp.efi" do
+  action :create
+  source "https://boot.netboot.xyz/ipxe/netboot.xyz-snp.efi"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+remote_file "/srv/tftp/netboot.xyz.kpxe" do
+  action :create
+  source "https://boot.netboot.xyz/ipxe/netboot.xyz.kpxe"
+  owner "root"
+  group "root"
+  mode "644"
+end
 
 domain = "#{node[:networking][:roles][:external][:zone]}.openstreetmap.org"
 
@@ -27,12 +59,24 @@ template "/etc/dhcp/dhcpd.conf" do
   source "dhcpd.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   variables :domain => domain
 end
 
+template "/etc/default/isc-dhcp-server" do
+  source "default.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
 service "isc-dhcp-server" do
   action [:enable, :start]
   supports :status => true, :restart => true
   subscribes :restart, "template[/etc/dhcp/dhcpd.conf]"
+  subscribes :restart, "template[/etc/default/isc-dhcp-server]"
+end
+
+service "isc-dhcp-server6" do
+  action [:disable, :stop]
 end
diff --git a/cookbooks/dhcpd/templates/default/default.erb b/cookbooks/dhcpd/templates/default/default.erb
new file mode 100644 (file)
index 0000000..96dfbd8
--- /dev/null
@@ -0,0 +1,18 @@
+# Defaults for isc-dhcp-server (sourced by /etc/init.d/isc-dhcp-server)
+
+# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf).
+#DHCPDv4_CONF=/etc/dhcp/dhcpd.conf
+#DHCPDv6_CONF=/etc/dhcp/dhcpd6.conf
+
+# Path to dhcpd's PID file (default: /var/run/dhcpd.pid).
+#DHCPDv4_PID=/var/run/dhcpd.pid
+#DHCPDv6_PID=/var/run/dhcpd6.pid
+
+# Additional options to start dhcpd with.
+#      Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead
+#OPTIONS=""
+
+# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
+#      Separate multiple interfaces with spaces, e.g. "eth0 eth1".
+INTERFACESv4="<%= node.interfaces(:role => :internal).map { |i| i[:interface] }.join(" ") %>"
+INTERFACESv6=""
index 78397dff73c33430733a80a2152fcaa49345b823..2251b92d1754ae5eb6d5ad06e7abb6a566657923 100644 (file)
@@ -1,20 +1,48 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
+option arch code 93 = unsigned integer 16;
+# ilo5 expects TZ data per rfc4833
+option PCode code 100 = text;
+option TCode code 101 = text;
+
 default-lease-time 600;
 max-lease-time 7200;
-<% node.interfaces(:role => :internal).each do |interface| -%>
+<% node.ipaddresses(:role => :internal, :family => :inet).each do |address| -%>
 
-subnet <%= interface[:network] %> netmask <%= interface[:netmask] %> {
+subnet <%= address.network %> netmask <%= address.netmask %> {
   authoritative;
   range dynamic-bootp <%= node[:dhcpd][:first_address] %> <%= node[:dhcpd][:last_address] %>;
-  # option broadcast-address <%= interface[:broadcast] %>;
-  option routers <%= interface[:gateway] %>;
+  option routers <%= address.gateway %>;
   option domain-name "<%= @domain %>";
-  option domain-name-servers <%= interface[:gateway] %>;
-  option ntp-servers <%= node[:ntp][:servers].first %>;
+  option domain-name-servers <%= address.gateway %>;
+  option ntp-servers <%= node[:ntp][:servers].join(", ") %>;
+
+  option time-offset 0;
+  option PCode "UTC0";
+  option TCode "Etc/UTC";
+
+  next-server <%= address.gateway %>;
+
+  # See https://netboot.xyz/docs/docker/#dhcp-configurations
+  if exists user-class and ( option user-class = "iPXE" ) {
+    filename "http://boot.netboot.xyz/menu.ipxe";
+  } elsif option arch = encode-int ( 16, 16 ) {
+    filename "http://boot.netboot.xyz/ipxe/netboot.xyz.efi";
+    option vendor-class-identifier "HTTPClient";
+  } elsif option arch = 00:07 {
+    filename "netboot.xyz.efi";
+  } else {
+    filename "netboot.xyz.kpxe";
+  }
 }
 <% end -%>
 
+host oob1.ams.openstreetmap.org {
+  hardware ethernet ea:e4:8e:c2:5b:19;
+  server-name "oob1.ams.openstreetmap.org";
+  fixed-address oob1.ams.openstreetmap.org;
+}
+
 host pdu1.ams.openstreetmap.org {
   hardware ethernet 00:c0:b7:e3:e8:f2;
   server-name "pdu1.ams.openstreetmap.org";
@@ -27,16 +55,40 @@ host pdu2.ams.openstreetmap.org {
   fixed-address pdu2.ams.openstreetmap.org;
 }
 
+host oob1.dub.openstreetmap.org {
+  hardware ethernet 62:bd:62:a6:05:25;
+  server-name "oob1.dub.openstreetmap.org";
+  fixed-address oob1.dub.openstreetmap.org;
+}
+
+host pdu1.dub.openstreetmap.org {
+  hardware ethernet 28:29:86:48:f7:f5;
+  server-name "pdu1.dub.openstreetmap.org";
+  fixed-address pdu1.dub.openstreetmap.org;
+}
+
+host pdu2.dub.openstreetmap.org {
+  hardware ethernet 28:29:86:48:f8:64;
+  server-name "pdu2.dub.openstreetmap.org";
+  fixed-address pdu2.dub.openstreetmap.org;
+}
+
 host clifford.oob.openstreetmap.org {
   hardware ethernet 1c:c1:de:78:20:d6;
   server-name "clifford.oob.openstreetmap.org";
   fixed-address clifford.oob.openstreetmap.org;
 }
 
-host draco.oob.openstreetmap.org {
-  hardware ethernet 9c:8e:99:25:99:7d;
-  server-name "draco.oob.openstreetmap.org";
-  fixed-address draco.oob.openstreetmap.org;
+host culebre.oob.openstreetmap.org {
+  hardware ethernet 3c:ec:ef:2f:29:41;
+  server-name "culebre.oob.openstreetmap.org";
+  fixed-address culebre.oob.openstreetmap.org;
+}
+
+host dribble.oob.openstreetmap.org {
+  hardware ethernet 80:30:e0:3e:e0:a0;
+  server-name "dribble.oob.openstreetmap.org";
+  fixed-address dribble.oob.openstreetmap.org;
 }
 
 host dulcy.oob.openstreetmap.org {
@@ -51,22 +103,40 @@ host eddie.oob.openstreetmap.org {
   fixed-address eddie.oob.openstreetmap.org;
 }
 
-host errol.oob.openstreetmap.org {
-  hardware ethernet 00:e0:81:c0:8d:01;
-  server-name "errol.oob.openstreetmap.org";
-  fixed-address errol.oob.openstreetmap.org;
+host faffy.oob.openstreetmap.org {
+  hardware ethernet 98:f2:b3:21:f6:e2;
+  server-name "faffy.oob.openstreetmap.org";
+  fixed-address faffy.oob.openstreetmap.org;
 }
 
-host eustace.oob.openstreetmap.org {
-  hardware ethernet 1c:c1:de:71:4d:2e;
-  server-name "eustace.oob.openstreetmap.org";
-  fixed-address eustace.oob.openstreetmap.org;
+host fafnir.oob.openstreetmap.org {
+  hardware ethernet 38:63:bb:39:f0:96;
+  server-name "fafnir.oob.openstreetmap.org";
+  fixed-address fafnir.oob.openstreetmap.org;
 }
 
-host grindtooth.oob.openstreetmap.org {
-  hardware ethernet 98:4b:e1:6d:77:85;
-  server-name "grindtooth.oob.openstreetmap.org";
-  fixed-address grindtooth.oob.openstreetmap.org;
+host fume.oob.openstreetmap.org {
+  hardware ethernet 54:80:28:67:5e:31;
+  server-name "fume.oob.openstreetmap.org";
+  fixed-address fume.oob.openstreetmap.org;
+}
+
+host grisu.oob.openstreetmap.org {
+  hardware ethernet 54:80:28:67:61:03;
+  server-name "grisu.oob.openstreetmap.org";
+  fixed-address grisu.oob.openstreetmap.org;
+}
+
+host horntail.oob.openstreetmap.org {
+  hardware ethernet 3c:ec:ef:82:ac:d2;
+  server-name "horntail.oob.openstreetmap.org";
+  fixed-address horntail.oob.openstreetmap.org;
+}
+
+host idris.oob.openstreetmap.org {
+  hardware ethernet 94:57:a5:50:b5:a0;
+  server-name "idris.oob.openstreetmap.org";
+  fixed-address idris.oob.openstreetmap.org;
 }
 
 host ironbelly.oob.openstreetmap.org {
@@ -75,48 +145,66 @@ host ironbelly.oob.openstreetmap.org {
   fixed-address ironbelly.oob.openstreetmap.org;
 }
 
+host jakelong.oob.openstreetmap.org {
+  hardware ethernet d8:9d:67:66:02:9e;
+  server-name "jakelong.oob.openstreetmap.org";
+  fixed-address jakelong.oob.openstreetmap.org;
+}
+
 host karm.oob.openstreetmap.org {
   hardware ethernet 0c:c4:7a:67:cf:c4;
   server-name "karm.oob.openstreetmap.org";
   fixed-address karm.oob.openstreetmap.org;
 }
 
+host konqi.oob.openstreetmap.org {
+  hardware ethernet ec:b1:d7:7a:ea:64;
+  server-name "konqi.oob.openstreetmap.org";
+  fixed-address konqi.oob.openstreetmap.org;
+}
+
+host longma.oob.openstreetmap.org {
+  hardware ethernet 3c:ec:ef:2f:6d:4e;
+  server-name "longma.oob.openstreetmap.org";
+  fixed-address longma.oob.openstreetmap.org;
+}
+
+host muirdris.oob.openstreetmap.org {
+  hardware ethernet 80:30:e0:3e:f0:2a;
+  server-name "muirdris.oob.openstreetmap.org";
+  fixed-address muirdris.oob.openstreetmap.org;
+}
+
+host naga.oob.openstreetmap.org {
+  hardware ethernet 94:57:a5:5f:11:f2;
+  server-name "naga.oob.openstreetmap.org";
+  fixed-address naga.oob.openstreetmap.org;
+}
+
 host noquiklos.oob.openstreetmap.org {
   hardware ethernet 18:a9:05:70:b0:1e;
   server-name "noquiklos.oob.openstreetmap.org";
   fixed-address noquiklos.oob.openstreetmap.org;
 }
 
+host norbert.oob.openstreetmap.org {
+  hardware ethernet 3c:ec:ef:82:ac:cf;
+  server-name "norbert.oob.openstreetmap.org";
+  fixed-address norbert.oob.openstreetmap.org;
+}
+
 host odin.oob.openstreetmap.org {
   hardware ethernet ac:1f:6b:c0:59:a3;
   server-name "odin.oob.openstreetmap.org";
   fixed-address odin.oob.openstreetmap.org;
 }
 
-host orm.oob.openstreetmap.org {
-  hardware ethernet 00:e0:81:c5:26:80;
-  server-name "orm.oob.openstreetmap.org";
-  fixed-address orm.oob.openstreetmap.org;
-}
-
-host ouroboros.oob.openstreetmap.org {
-  hardware ethernet d4:85:64:4c:3d:00;
-  server-name "ouroboros.oob.openstreetmap.org";
-  fixed-address ouroboros.oob.openstreetmap.org;
-}
-
 host pummelzacken.oob.openstreetmap.org {
   hardware ethernet 00:25:90:cf:72:73;
   server-name "pummelzacken.oob.openstreetmap.org";
   fixed-address pummelzacken.oob.openstreetmap.org;
 }
 
-host ramoth.oob.openstreetmap.org {
-  hardware ethernet 0c:c4:7a:af:75:eb;
-  server-name "ramoth.oob.openstreetmap.org";
-  fixed-address ramoth.oob.openstreetmap.org;
-}
-
 host ridley.oob.openstreetmap.org {
   hardware ethernet d4:85:64:52:2d:d8;
   server-name "ridley.oob.openstreetmap.org";
@@ -129,26 +217,44 @@ host sarel.oob.openstreetmap.org {
   fixed-address sarel.oob.openstreetmap.org;
 }
 
+host snap-01.oob.openstreetmap.org {
+  hardware ethernet 3c:ec:ef:17:a6:72;
+  server-name "snap-01.oob.openstreetmap.org";
+  fixed-address snap-01.oob.openstreetmap.org;
+}
+
+host snap-02.oob.openstreetmap.org {
+  hardware ethernet 3c:ec:ef:17:a5:37;
+  server-name "snap-02.oob.openstreetmap.org";
+  fixed-address snap-02.oob.openstreetmap.org;
+}
+
+host snap-03.oob.openstreetmap.org {
+  hardware ethernet 3c:ec:ef:82:ab:f2;
+  server-name "snap-03.oob.openstreetmap.org";
+  fixed-address snap-03.oob.openstreetmap.org;
+}
+
 host smaug.oob.openstreetmap.org {
-  hardware ethernet 00:30:48:9d:57:ff;
+  hardware ethernet 80:30:e0:3e:d0:62;
   server-name "smaug.oob.openstreetmap.org";
   fixed-address smaug.oob.openstreetmap.org;
 }
 
 host spike-01.oob.openstreetmap.org {
-  hardware ethernet 1c:c1:de:e8:1a:1c;
+  hardware ethernet 3c:a8:2a:11:78:d6;
   server-name "spike-01.oob.openstreetmap.org";
   fixed-address spike-01.oob.openstreetmap.org;
 }
 
 host spike-02.oob.openstreetmap.org {
-  hardware ethernet 68:b5:99:af:d6:9c;
+  hardware ethernet 14:58:d0:5d:74:44;
   server-name "spike-02.oob.openstreetmap.org";
   fixed-address spike-02.oob.openstreetmap.org;
 }
 
 host spike-03.oob.openstreetmap.org {
-  hardware ethernet 1c:c1:de:79:61:98;
+  hardware ethernet 38:63:bb:3a:b0:ce;
   server-name "spike-03.oob.openstreetmap.org";
   fixed-address spike-03.oob.openstreetmap.org;
 }
@@ -237,12 +343,6 @@ host tiamat-23.oob.openstreetmap.org {
   fixed-address tiamat-23.oob.openstreetmap.org;
 }
 
-host thorn-01.oob.openstreetmap.org {
-  hardware ethernet 44:1e:a1:57:8f:fe;
-  server-name "thorn-01.oob.openstreetmap.org";
-  fixed-address thorn-01.oob.openstreetmap.org;
-}
-
 host thorn-02.oob.openstreetmap.org {
   hardware ethernet e4:11:5b:ce:e8:aa;
   server-name "thorn-02.oob.openstreetmap.org";
@@ -255,10 +355,10 @@ host thorn-03.oob.openstreetmap.org {
   fixed-address thorn-03.oob.openstreetmap.org;
 }
 
-host urmel.oob.openstreetmap.org {
-  hardware ethernet 1c:c1:de:e7:4d:b2;
-  server-name "urmel.oob.openstreetmap.org";
-  fixed-address urmel.oob.openstreetmap.org;
+host vhagar.oob.openstreetmap.org {
+  hardware ethernet 80:30:e0:3e:11:a0;
+  server-name "vhagar.oob.openstreetmap.org";
+  fixed-address vhagar.oob.openstreetmap.org;
 }
 
 host ysera.oob.openstreetmap.org {
diff --git a/cookbooks/dmca/files/default/html/HTML/Common.php b/cookbooks/dmca/files/default/html/HTML/Common.php
deleted file mode 100644 (file)
index 8823ea4..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Base class for all HTML classes
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- * 
- * @category    HTML
- * @package     HTML_Common
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @copyright   2001-2009 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id: Common.php,v 1.15 2009/04/03 15:26:22 avb Exp $
- * @link        http://pear.php.net/package/HTML_Common/
- */ 
-
-/**
- * Base class for all HTML classes
- *
- * @category    HTML
- * @package     HTML_Common
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @version     Release: 1.2.5
- * @abstract
- */
-class HTML_Common
-{
-    /**
-     * Associative array of attributes
-     * @var     array
-     * @access  private
-     */
-    var $_attributes = array();
-
-    /**
-     * Tab offset of the tag
-     * @var     int
-     * @access  private
-     */
-    var $_tabOffset = 0;
-
-    /**
-     * Tab string
-     * @var       string
-     * @since     1.7
-     * @access    private
-     */
-    var $_tab = "\11";
-
-    /**
-     * Contains the line end string
-     * @var       string
-     * @since     1.7
-     * @access    private
-     */
-    var $_lineEnd = "\12";
-
-    /**
-     * HTML comment on the object
-     * @var       string
-     * @since     1.5
-     * @access    private
-     */
-    var $_comment = '';
-
-    /**
-     * Class constructor
-     * @param    mixed   $attributes     Associative array of table tag attributes
-     *                                   or HTML attributes name="value" pairs
-     * @param    int     $tabOffset      Indent offset in tabs
-     * @access   public
-     */
-    function HTML_Common($attributes = null, $tabOffset = 0)
-    {
-        $this->setAttributes($attributes);
-        $this->setTabOffset($tabOffset);
-    } // end constructor
-
-    /**
-     * Returns the current API version
-     * @access   public
-     * @returns  double
-     */
-    function apiVersion()
-    {
-        return 1.7;
-    } // end func apiVersion
-
-    /**
-     * Returns the lineEnd
-     *
-     * @since     1.7
-     * @access    private
-     * @return    string
-     */
-    function _getLineEnd()
-    {
-        return $this->_lineEnd;
-    } // end func getLineEnd
-
-    /**
-     * Returns a string containing the unit for indenting HTML
-     *
-     * @since     1.7
-     * @access    private
-     * @return    string
-     */
-    function _getTab()
-    {
-        return $this->_tab;
-    } // end func _getTab
-
-    /**
-     * Returns a string containing the offset for the whole HTML code
-     *
-     * @return    string
-     * @access   private
-     */
-    function _getTabs()
-    {
-        return str_repeat($this->_getTab(), $this->_tabOffset);
-    } // end func _getTabs
-
-    /**
-     * Returns an HTML formatted attribute string
-     * @param    array   $attributes
-     * @return   string
-     * @access   private
-     */
-    function _getAttrString($attributes)
-    {
-        $strAttr = '';
-
-        if (is_array($attributes)) {
-            $charset = HTML_Common::charset();
-            foreach ($attributes as $key => $value) {
-                $strAttr .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT, $charset) . '"';
-            }
-        }
-        return $strAttr;
-    } // end func _getAttrString
-
-    /**
-     * Returns a valid atrributes array from either a string or array
-     * @param    mixed   $attributes     Either a typical HTML attribute string or an associative array
-     * @access   private
-     * @return   array
-     */
-    function _parseAttributes($attributes)
-    {
-        if (is_array($attributes)) {
-            $ret = array();
-            foreach ($attributes as $key => $value) {
-                if (is_int($key)) {
-                    $key = $value = strtolower($value);
-                } else {
-                    $key = strtolower($key);
-                }
-                $ret[$key] = $value;
-            }
-            return $ret;
-
-        } elseif (is_string($attributes)) {
-            $preg = "/(([A-Za-z_:]|[^\\x00-\\x7F])([A-Za-z0-9_:.-]|[^\\x00-\\x7F])*)" .
-                "([ \\n\\t\\r]+)?(=([ \\n\\t\\r]+)?(\"[^\"]*\"|'[^']*'|[^ \\n\\t\\r]*))?/";
-            if (preg_match_all($preg, $attributes, $regs)) {
-                for ($counter=0; $counter<count($regs[1]); $counter++) {
-                    $name  = $regs[1][$counter];
-                    $check = $regs[0][$counter];
-                    $value = $regs[7][$counter];
-                    if (trim($name) == trim($check)) {
-                        $arrAttr[strtolower(trim($name))] = strtolower(trim($name));
-                    } else {
-                        if (substr($value, 0, 1) == "\"" || substr($value, 0, 1) == "'") {
-                            $arrAttr[strtolower(trim($name))] = substr($value, 1, -1);
-                        } else {
-                            $arrAttr[strtolower(trim($name))] = trim($value);
-                        }
-                    }
-                }
-                return $arrAttr;
-            }
-        }
-    } // end func _parseAttributes
-
-    /**
-     * Returns the array key for the given non-name-value pair attribute
-     *
-     * @param     string    $attr         Attribute
-     * @param     array     $attributes   Array of attribute
-     * @since     1.0
-     * @access    private
-     * @return    bool
-     */
-    function _getAttrKey($attr, $attributes)
-    {
-        if (isset($attributes[strtolower($attr)])) {
-            return true;
-        } else {
-            return null;
-        }
-    } //end func _getAttrKey
-
-    /**
-     * Updates the attributes in $attr1 with the values in $attr2 without changing the other existing attributes
-     * @param    array   $attr1      Original attributes array
-     * @param    array   $attr2      New attributes array
-     * @access   private
-     */
-    function _updateAttrArray(&$attr1, $attr2)
-    {
-        if (!is_array($attr2)) {
-            return false;
-        }
-        foreach ($attr2 as $key => $value) {
-            $attr1[$key] = $value;
-        }
-    } // end func _updateAtrrArray
-
-    /**
-     * Removes the given attribute from the given array
-     *
-     * @param     string    $attr           Attribute name
-     * @param     array     $attributes     Attribute array
-     * @since     1.4
-     * @access    private
-     * @return    void
-     */
-    function _removeAttr($attr, &$attributes)
-    {
-        $attr = strtolower($attr);
-        if (isset($attributes[$attr])) {
-            unset($attributes[$attr]);
-        }
-    } //end func _removeAttr
-
-    /**
-     * Returns the value of the given attribute
-     *
-     * @param     string    $attr   Attribute name
-     * @since     1.5
-     * @access    public
-     * @return    string|null   returns null if an attribute does not exist
-     */
-    function getAttribute($attr)
-    {
-        $attr = strtolower($attr);
-        if (isset($this->_attributes[$attr])) {
-            return $this->_attributes[$attr];
-        }
-        return null;
-    } //end func getAttribute
-
-    /**
-     * Sets the value of the attribute
-     *
-     * @param   string  Attribute name
-     * @param   string  Attribute value (will be set to $name if omitted)
-     * @access  public
-     */
-    function setAttribute($name, $value = null)
-    {
-        $name = strtolower($name);
-        if (is_null($value)) {
-            $value = $name;
-        }
-        $this->_attributes[$name] = $value;
-    } // end func setAttribute
-
-    /**
-     * Sets the HTML attributes
-     * @param    mixed   $attributes     Either a typical HTML attribute string or an associative array
-     * @access   public
-     */
-    function setAttributes($attributes)
-    {
-        $this->_attributes = $this->_parseAttributes($attributes);
-    } // end func setAttributes
-
-    /**
-     * Returns the assoc array (default) or string of attributes
-     *
-     * @param     bool    Whether to return the attributes as string
-     * @since     1.6
-     * @access    public
-     * @return    mixed   attributes
-     */
-    function getAttributes($asString = false)
-    {
-        if ($asString) {
-            return $this->_getAttrString($this->_attributes);
-        } else {
-            return $this->_attributes;
-        }
-    } //end func getAttributes
-
-    /**
-     * Updates the passed attributes without changing the other existing attributes
-     * @param    mixed   $attributes     Either a typical HTML attribute string or an associative array
-     * @access   public
-     */
-    function updateAttributes($attributes)
-    {
-        $this->_updateAttrArray($this->_attributes, $this->_parseAttributes($attributes));
-    } // end func updateAttributes
-
-    /**
-     * Removes an attribute
-     *
-     * @param     string    $attr   Attribute name
-     * @since     1.4
-     * @access    public
-     * @return    void
-     */
-    function removeAttribute($attr)
-    {
-        $this->_removeAttr($attr, $this->_attributes);
-    } //end func removeAttribute
-
-    /**
-     * Sets the line end style to Windows, Mac, Unix or a custom string.
-     *
-     * @param   string  $style  "win", "mac", "unix" or custom string.
-     * @since   1.7
-     * @access  public
-     * @return  void
-     */
-    function setLineEnd($style)
-    {
-        switch ($style) {
-            case 'win':
-                $this->_lineEnd = "\15\12";
-                break;
-            case 'unix':
-                $this->_lineEnd = "\12";
-                break;
-            case 'mac':
-                $this->_lineEnd = "\15";
-                break;
-            default:
-                $this->_lineEnd = $style;
-        }
-    } // end func setLineEnd
-
-    /**
-     * Sets the tab offset
-     *
-     * @param    int     $offset
-     * @access   public
-     */
-    function setTabOffset($offset)
-    {
-        $this->_tabOffset = $offset;
-    } // end func setTabOffset
-
-    /**
-     * Returns the tabOffset
-     *
-     * @since     1.5
-     * @access    public
-     * @return    int
-     */
-    function getTabOffset()
-    {
-        return $this->_tabOffset;
-    } //end func getTabOffset
-
-    /**
-     * Sets the string used to indent HTML
-     *
-     * @since     1.7
-     * @param     string    $string     String used to indent ("\11", "\t", '  ', etc.).
-     * @access    public
-     * @return    void
-     */
-    function setTab($string)
-    {
-        $this->_tab = $string;
-    } // end func setTab
-
-    /**
-     * Sets the HTML comment to be displayed at the beginning of the HTML string
-     *
-     * @param     string
-     * @since     1.4
-     * @access    public
-     * @return    void
-     */
-    function setComment($comment)
-    {
-        $this->_comment = $comment;
-    } // end func setHtmlComment
-
-    /**
-     * Returns the HTML comment
-     *
-     * @since     1.5
-     * @access    public
-     * @return    string
-     */
-    function getComment()
-    {
-        return $this->_comment;
-    } //end func getComment
-
-    /**
-     * Abstract method.  Must be extended to return the objects HTML
-     *
-     * @access    public
-     * @return    string
-     * @abstract
-     */
-    function toHtml()
-    {
-        return '';
-    } // end func toHtml
-
-    /**
-     * Displays the HTML to the screen
-     *
-     * @access    public
-     */
-    function display()
-    {
-        print $this->toHtml();
-    } // end func display
-
-    /**
-     * Sets the charset to use by htmlspecialchars() function
-     *
-     * Since this parameter is expected to be global, the function is designed
-     * to be called statically:
-     * <code>
-     * HTML_Common::charset('utf-8');
-     * </code>
-     * or
-     * <code>
-     * $charset = HTML_Common::charset();
-     * </code>
-     *
-     * @param   string  New charset to use. Omit if just getting the 
-     *                  current value. Consult the htmlspecialchars() docs 
-     *                  for a list of supported character sets.
-     * @return  string  Current charset
-     * @access  public
-     * @static
-     */
-    function charset($newCharset = null)
-    {
-        static $charset = 'ISO-8859-1';
-
-        if (!is_null($newCharset)) {
-            $charset = $newCharset;
-        }
-        return $charset;
-    } // end func charset
-} // end class HTML_Common
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm.php b/cookbooks/dmca/files/default/html/HTML/QuickForm.php
deleted file mode 100644 (file)
index f769b1f..0000000
+++ /dev/null
@@ -1,2073 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Create, validate and process HTML forms
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * PEAR and PEAR_Error classes, for error handling
- */
-require_once 'PEAR.php';
-/**
- * Base class for all HTML classes
- */
-require_once 'HTML/Common.php';
-/**
- * Static utility methods
- */
-require_once 'HTML/QuickForm/utils.php';
-
-/**
- * Element types known to HTML_QuickForm
- * @see HTML_QuickForm::registerElementType(), HTML_QuickForm::getRegisteredTypes(),
- *      HTML_QuickForm::isTypeRegistered()
- * @global array $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']
- */
-$GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] =
-        array(
-            'group'         =>array('HTML/QuickForm/group.php','HTML_QuickForm_group'),
-            'hidden'        =>array('HTML/QuickForm/hidden.php','HTML_QuickForm_hidden'),
-            'reset'         =>array('HTML/QuickForm/reset.php','HTML_QuickForm_reset'),
-            'checkbox'      =>array('HTML/QuickForm/checkbox.php','HTML_QuickForm_checkbox'),
-            'file'          =>array('HTML/QuickForm/file.php','HTML_QuickForm_file'),
-            'image'         =>array('HTML/QuickForm/image.php','HTML_QuickForm_image'),
-            'password'      =>array('HTML/QuickForm/password.php','HTML_QuickForm_password'),
-            'radio'         =>array('HTML/QuickForm/radio.php','HTML_QuickForm_radio'),
-            'button'        =>array('HTML/QuickForm/button.php','HTML_QuickForm_button'),
-            'submit'        =>array('HTML/QuickForm/submit.php','HTML_QuickForm_submit'),
-            'select'        =>array('HTML/QuickForm/select.php','HTML_QuickForm_select'),
-            'hiddenselect'  =>array('HTML/QuickForm/hiddenselect.php','HTML_QuickForm_hiddenselect'),
-            'text'          =>array('HTML/QuickForm/text.php','HTML_QuickForm_text'),
-            'textarea'      =>array('HTML/QuickForm/textarea.php','HTML_QuickForm_textarea'),
-            'link'          =>array('HTML/QuickForm/link.php','HTML_QuickForm_link'),
-            'advcheckbox'   =>array('HTML/QuickForm/advcheckbox.php','HTML_QuickForm_advcheckbox'),
-            'date'          =>array('HTML/QuickForm/date.php','HTML_QuickForm_date'),
-            'static'        =>array('HTML/QuickForm/static.php','HTML_QuickForm_static'),
-            'header'        =>array('HTML/QuickForm/header.php', 'HTML_QuickForm_header'),
-            'html'          =>array('HTML/QuickForm/html.php', 'HTML_QuickForm_html'),
-            'hierselect'    =>array('HTML/QuickForm/hierselect.php', 'HTML_QuickForm_hierselect'),
-            'autocomplete'  =>array('HTML/QuickForm/autocomplete.php', 'HTML_QuickForm_autocomplete'),
-            'xbutton'       =>array('HTML/QuickForm/xbutton.php','HTML_QuickForm_xbutton')
-        );
-
-/**
- * Validation rules known to HTML_QuickForm
- * @see HTML_QuickForm::registerRule(), HTML_QuickForm::getRegisteredRules(),
- *      HTML_QuickForm::isRuleRegistered()
- * @global array $GLOBALS['_HTML_QuickForm_registered_rules']
- */
-$GLOBALS['_HTML_QuickForm_registered_rules'] = array(
-    'required'      => array('html_quickform_rule_required', 'HTML/QuickForm/Rule/Required.php'),
-    'maxlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
-    'minlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
-    'rangelength'   => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
-    'email'         => array('html_quickform_rule_email',    'HTML/QuickForm/Rule/Email.php'),
-    'regex'         => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
-    'lettersonly'   => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
-    'alphanumeric'  => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
-    'numeric'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
-    'nopunctuation' => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
-    'nonzero'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
-    'callback'      => array('html_quickform_rule_callback', 'HTML/QuickForm/Rule/Callback.php'),
-    'compare'       => array('html_quickform_rule_compare',  'HTML/QuickForm/Rule/Compare.php')
-);
-
-// {{{ error codes
-
-/**#@+
- * Error codes for HTML_QuickForm
- *
- * Codes are mapped to textual messages by errorMessage() method, if you add a
- * new code be sure to add a new message for it to errorMessage()
- *
- * @see HTML_QuickForm::errorMessage()
- */
-define('QUICKFORM_OK',                      1);
-define('QUICKFORM_ERROR',                  -1);
-define('QUICKFORM_INVALID_RULE',           -2);
-define('QUICKFORM_NONEXIST_ELEMENT',       -3);
-define('QUICKFORM_INVALID_FILTER',         -4);
-define('QUICKFORM_UNREGISTERED_ELEMENT',   -5);
-define('QUICKFORM_INVALID_ELEMENT_NAME',   -6);
-define('QUICKFORM_INVALID_PROCESS',        -7);
-define('QUICKFORM_DEPRECATED',             -8);
-define('QUICKFORM_INVALID_DATASOURCE',     -9);
-/**#@-*/
-
-// }}}
-
-/**
- * Create, validate and process HTML forms
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- */
-class HTML_QuickForm extends HTML_Common
-{
-    // {{{ properties
-
-    /**
-     * Array containing the form fields
-     * @since     1.0
-     * @var  array
-     * @access   private
-     */
-    var $_elements = array();
-
-    /**
-     * Array containing element name to index map
-     * @since     1.1
-     * @var  array
-     * @access   private
-     */
-    var $_elementIndex = array();
-
-    /**
-     * Array containing indexes of duplicate elements
-     * @since     2.10
-     * @var  array
-     * @access   private
-     */
-    var $_duplicateIndex = array();
-
-    /**
-     * Array containing required field IDs
-     * @since     1.0
-     * @var  array
-     * @access   private
-     */
-    var $_required = array();
-
-    /**
-     * Prefix message in javascript alert if error
-     * @since     1.0
-     * @var  string
-     * @access   public
-     */
-    var $_jsPrefix = 'Invalid information entered.';
-
-    /**
-     * Postfix message in javascript alert if error
-     * @since     1.0
-     * @var  string
-     * @access   public
-     */
-    var $_jsPostfix = 'Please correct these fields.';
-
-    /**
-     * Datasource object implementing the informal
-     * datasource protocol
-     * @since     3.3
-     * @var  object
-     * @access   private
-     */
-    var $_datasource;
-
-    /**
-     * Array of default form values
-     * @since     2.0
-     * @var  array
-     * @access   private
-     */
-    var $_defaultValues = array();
-
-    /**
-     * Array of constant form values
-     * @since     2.0
-     * @var  array
-     * @access   private
-     */
-    var $_constantValues = array();
-
-    /**
-     * Array of submitted form values
-     * @since     1.0
-     * @var  array
-     * @access   private
-     */
-    var $_submitValues = array();
-
-    /**
-     * Array of submitted form files
-     * @since     1.0
-     * @var  integer
-     * @access   public
-     */
-    var $_submitFiles = array();
-
-    /**
-     * Value for maxfilesize hidden element if form contains file input
-     * @since     1.0
-     * @var  integer
-     * @access   public
-     */
-    var $_maxFileSize = 1048576; // 1 Mb = 1048576
-
-    /**
-     * Flag to know if all fields are frozen
-     * @since     1.0
-     * @var  boolean
-     * @access   private
-     */
-    var $_freezeAll = false;
-
-    /**
-     * Array containing the form rules
-     * @since     1.0
-     * @var  array
-     * @access   private
-     */
-    var $_rules = array();
-
-    /**
-     * Form rules, global variety
-     * @var     array
-     * @access  private
-     */
-    var $_formRules = array();
-
-    /**
-     * Array containing the validation errors
-     * @since     1.0
-     * @var  array
-     * @access   private
-     */
-    var $_errors = array();
-
-    /**
-     * Note for required fields in the form
-     * @var       string
-     * @since     1.0
-     * @access    private
-     */
-    var $_requiredNote = '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>';
-
-    /**
-     * Whether the form was submitted
-     * @var       boolean
-     * @access    private
-     */
-    var $_flagSubmitted = false;
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * @param    string      $formName          Form's name.
-     * @param    string      $method            (optional)Form's method defaults to 'POST'
-     * @param    string      $action            (optional)Form's action
-     * @param    string      $target            (optional)Form's target defaults to '_self'
-     * @param    mixed       $attributes        (optional)Extra attributes for <form> tag
-     * @param    bool        $trackSubmit       (optional)Whether to track if the form was submitted by adding a special hidden field
-     * @access   public
-     */
-    function HTML_QuickForm($formName='', $method='post', $action='', $target='', $attributes=null, $trackSubmit = false)
-    {
-        HTML_Common::HTML_Common($attributes);
-        $method = (strtoupper($method) == 'GET') ? 'get' : 'post';
-        $action = ($action == '') ? $_SERVER['PHP_SELF'] : $action;
-        $target = empty($target) ? array() : array('target' => $target);
-        $attributes = array('action'=>$action, 'method'=>$method, 'name'=>$formName, 'id'=>$formName) + $target;
-        $this->updateAttributes($attributes);
-        if (!$trackSubmit || isset($_REQUEST['_qf__' . $formName])) {
-            if (1 == get_magic_quotes_gpc()) {
-                $this->_submitValues = $this->_recursiveFilter('stripslashes', 'get' == $method? $_GET: $_POST);
-                foreach ($_FILES as $keyFirst => $valFirst) {
-                    foreach ($valFirst as $keySecond => $valSecond) {
-                        if ('name' == $keySecond) {
-                            $this->_submitFiles[$keyFirst][$keySecond] = $this->_recursiveFilter('stripslashes', $valSecond);
-                        } else {
-                            $this->_submitFiles[$keyFirst][$keySecond] = $valSecond;
-                        }
-                    }
-                }
-            } else {
-                $this->_submitValues = 'get' == $method? $_GET: $_POST;
-                $this->_submitFiles  = $_FILES;
-            }
-            $this->_flagSubmitted = count($this->_submitValues) > 0 || count($this->_submitFiles) > 0;
-        }
-        if ($trackSubmit) {
-            unset($this->_submitValues['_qf__' . $formName]);
-            $this->addElement('hidden', '_qf__' . $formName, null);
-        }
-        if (preg_match('/^([0-9]+)([a-zA-Z]*)$/', ini_get('upload_max_filesize'), $matches)) {
-            // see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
-            switch (strtoupper($matches['2'])) {
-                case 'G':
-                    $this->_maxFileSize = $matches['1'] * 1073741824;
-                    break;
-                case 'M':
-                    $this->_maxFileSize = $matches['1'] * 1048576;
-                    break;
-                case 'K':
-                    $this->_maxFileSize = $matches['1'] * 1024;
-                    break;
-                default:
-                    $this->_maxFileSize = $matches['1'];
-            }
-        }
-    } // end constructor
-
-    // }}}
-    // {{{ apiVersion()
-
-    /**
-     * Returns the current API version
-     *
-     * @since     1.0
-     * @access    public
-     * @return    float
-     */
-    function apiVersion()
-    {
-        return 3.2;
-    } // end func apiVersion
-
-    // }}}
-    // {{{ registerElementType()
-
-    /**
-     * Registers a new element type
-     *
-     * @param     string    $typeName   Name of element type
-     * @param     string    $include    Include path for element type
-     * @param     string    $className  Element class name
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function registerElementType($typeName, $include, $className)
-    {
-        $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($typeName)] = array($include, $className);
-    } // end func registerElementType
-
-    // }}}
-    // {{{ registerRule()
-
-    /**
-     * Registers a new validation rule
-     *
-     * @param     string    $ruleName   Name of validation rule
-     * @param     string    $type       Either: 'regex', 'function' or 'rule' for an HTML_QuickForm_Rule object
-     * @param     string    $data1      Name of function, regular expression or HTML_QuickForm_Rule classname
-     * @param     string    $data2      Object parent of above function or HTML_QuickForm_Rule file path
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function registerRule($ruleName, $type, $data1, $data2 = null)
-    {
-        include_once('HTML/QuickForm/RuleRegistry.php');
-        $registry =& HTML_QuickForm_RuleRegistry::singleton();
-        $registry->registerRule($ruleName, $type, $data1, $data2);
-    } // end func registerRule
-
-    // }}}
-    // {{{ elementExists()
-
-    /**
-     * Returns true if element is in the form
-     *
-     * @param     string   $element         form name of element to check
-     * @since     1.0
-     * @access    public
-     * @return    boolean
-     */
-    function elementExists($element=null)
-    {
-        return isset($this->_elementIndex[$element]);
-    } // end func elementExists
-
-    // }}}
-    // {{{ setDatasource()
-
-    /**
-     * Sets a datasource object for this form object
-     *
-     * Datasource default and constant values will feed the QuickForm object if
-     * the datasource implements defaultValues() and constantValues() methods.
-     *
-     * @param     object   $datasource          datasource object implementing the informal datasource protocol
-     * @param     mixed    $defaultsFilter      string or array of filter(s) to apply to default values
-     * @param     mixed    $constantsFilter     string or array of filter(s) to apply to constants values
-     * @since     3.3
-     * @access    public
-     * @return    void
-     * @throws    HTML_QuickForm_Error
-     */
-    function setDatasource(&$datasource, $defaultsFilter = null, $constantsFilter = null)
-    {
-        if (is_object($datasource)) {
-            $this->_datasource =& $datasource;
-            if (is_callable(array($datasource, 'defaultValues'))) {
-                $this->setDefaults($datasource->defaultValues($this), $defaultsFilter);
-            }
-            if (is_callable(array($datasource, 'constantValues'))) {
-                $this->setConstants($datasource->constantValues($this), $constantsFilter);
-            }
-        } else {
-            return PEAR::raiseError(null, QUICKFORM_INVALID_DATASOURCE, null, E_USER_WARNING, "Datasource is not an object in QuickForm::setDatasource()", 'HTML_QuickForm_Error', true);
-        }
-    } // end func setDatasource
-
-    // }}}
-    // {{{ setDefaults()
-
-    /**
-     * Initializes default form values
-     *
-     * @param     array    $defaultValues       values used to fill the form
-     * @param     mixed    $filter              (optional) filter(s) to apply to all default values
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    HTML_QuickForm_Error
-     */
-    function setDefaults($defaultValues = null, $filter = null)
-    {
-        if (is_array($defaultValues)) {
-            if (isset($filter)) {
-                if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
-                    foreach ($filter as $val) {
-                        if (!is_callable($val)) {
-                            return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
-                        } else {
-                            $defaultValues = $this->_recursiveFilter($val, $defaultValues);
-                        }
-                    }
-                } elseif (!is_callable($filter)) {
-                    return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
-                } else {
-                    $defaultValues = $this->_recursiveFilter($filter, $defaultValues);
-                }
-            }
-            $this->_defaultValues = HTML_QuickForm::arrayMerge($this->_defaultValues, $defaultValues);
-            foreach (array_keys($this->_elements) as $key) {
-                $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
-            }
-        }
-    } // end func setDefaults
-
-    // }}}
-    // {{{ setConstants()
-
-    /**
-     * Initializes constant form values.
-     * These values won't get overridden by POST or GET vars
-     *
-     * @param     array   $constantValues        values used to fill the form
-     * @param     mixed    $filter              (optional) filter(s) to apply to all default values
-     *
-     * @since     2.0
-     * @access    public
-     * @return    void
-     * @throws    HTML_QuickForm_Error
-     */
-    function setConstants($constantValues = null, $filter = null)
-    {
-        if (is_array($constantValues)) {
-            if (isset($filter)) {
-                if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
-                    foreach ($filter as $val) {
-                        if (!is_callable($val)) {
-                            return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
-                        } else {
-                            $constantValues = $this->_recursiveFilter($val, $constantValues);
-                        }
-                    }
-                } elseif (!is_callable($filter)) {
-                    return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
-                } else {
-                    $constantValues = $this->_recursiveFilter($filter, $constantValues);
-                }
-            }
-            $this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, $constantValues);
-            foreach (array_keys($this->_elements) as $key) {
-                $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
-            }
-        }
-    } // end func setConstants
-
-    // }}}
-    // {{{ setMaxFileSize()
-
-    /**
-     * Sets the value of MAX_FILE_SIZE hidden element
-     *
-     * @param     int    $bytes    Size in bytes
-     * @since     3.0
-     * @access    public
-     * @return    void
-     */
-    function setMaxFileSize($bytes = 0)
-    {
-        if ($bytes > 0) {
-            $this->_maxFileSize = $bytes;
-        }
-        if (!$this->elementExists('MAX_FILE_SIZE')) {
-            $this->addElement('hidden', 'MAX_FILE_SIZE', $this->_maxFileSize);
-        } else {
-            $el =& $this->getElement('MAX_FILE_SIZE');
-            $el->updateAttributes(array('value' => $this->_maxFileSize));
-        }
-    } // end func setMaxFileSize
-
-    // }}}
-    // {{{ getMaxFileSize()
-
-    /**
-     * Returns the value of MAX_FILE_SIZE hidden element
-     *
-     * @since     3.0
-     * @access    public
-     * @return    int   max file size in bytes
-     */
-    function getMaxFileSize()
-    {
-        return $this->_maxFileSize;
-    } // end func getMaxFileSize
-
-    // }}}
-    // {{{ &createElement()
-
-    /**
-     * Creates a new form element of the given type.
-     *
-     * This method accepts variable number of parameters, their
-     * meaning and count depending on $elementType
-     *
-     * @param     string     $elementType    type of element to add (text, textarea, file...)
-     * @since     1.0
-     * @access    public
-     * @return    HTML_QuickForm_Element
-     * @throws    HTML_QuickForm_Error
-     */
-    function &createElement($elementType)
-    {
-        $args    =  func_get_args();
-        $element =& HTML_QuickForm::_loadElement('createElement', $elementType, array_slice($args, 1), null);
-        return $element;
-    } // end func createElement
-
-    // }}}
-    // {{{ _loadElement()
-
-    /**
-     * Returns a form element of the given type
-     *
-     * @param     string   $event   event to send to newly created element ('createElement' or 'addElement')
-     * @param     string   $type    element type
-     * @param     array    $args    arguments for event
-     * @since     2.0
-     * @access    private
-     * @return    HTML_QuickForm_Element
-     * @throws    HTML_QuickForm_Error
-     */
-    function &_loadElement($event, $type, $args, $form)
-    {
-        $type = strtolower($type);
-        if (!HTML_QuickForm::isTypeRegistered($type)) {
-            $error = PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, "Element '$type' does not exist in HTML_QuickForm::_loadElement()", 'HTML_QuickForm_Error', true);
-            return $error;
-        }
-        $className = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][1];
-        $includeFile = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][0];
-        include_once($includeFile);
-        $elementObject = new $className();
-        for ($i = 0; $i < 5; $i++) {
-            if (!isset($args[$i])) {
-                $args[$i] = null;
-            }
-        }
-        $err = $elementObject->onQuickFormEvent($event, $args, $form);
-        if ($err !== true) {
-            return $err;
-        }
-        return $elementObject;
-    } // end func _loadElement
-
-    // }}}
-    // {{{ addElement()
-
-    /**
-     * Adds an element into the form
-     *
-     * If $element is a string representing element type, then this
-     * method accepts variable number of parameters, their meaning
-     * and count depending on $element
-     *
-     * @param    mixed      $element        element object or type of element to add (text, textarea, file...)
-     * @since    1.0
-     * @return   HTML_QuickForm_Element     a reference to newly added element
-     * @access   public
-     * @throws   HTML_QuickForm_Error
-     */
-    function &addElement($element)
-    {
-        if (is_object($element) && is_subclass_of($element, 'html_quickform_element')) {
-           $elementObject = &$element;
-           $elementObject->onQuickFormEvent('updateValue', null, $this);
-        } else {
-            $args = func_get_args();
-            $elementObject =& $this->_loadElement('addElement', $element, array_slice($args, 1), $this);
-            if (PEAR::isError($elementObject)) {
-                return $elementObject;
-            }
-        }
-        $elementName = $elementObject->getName();
-
-        // Add the element if it is not an incompatible duplicate
-        if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
-            if ($this->_elements[$this->_elementIndex[$elementName]]->getType() ==
-                $elementObject->getType()) {
-                $this->_elements[] =& $elementObject;
-                $elKeys = array_keys($this->_elements);
-                $this->_duplicateIndex[$elementName][] = end($elKeys);
-            } else {
-                $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::addElement()", 'HTML_QuickForm_Error', true);
-                return $error;
-            }
-        } else {
-            $this->_elements[] =& $elementObject;
-            $elKeys = array_keys($this->_elements);
-            $this->_elementIndex[$elementName] = end($elKeys);
-        }
-        if ($this->_freezeAll) {
-            $elementObject->freeze();
-        }
-
-        return $elementObject;
-    } // end func addElement
-
-    // }}}
-    // {{{ insertElementBefore()
-
-   /**
-    * Inserts a new element right before the other element
-    *
-    * Warning: it is not possible to check whether the $element is already
-    * added to the form, therefore if you want to move the existing form
-    * element to a new position, you'll have to use removeElement():
-    * $form->insertElementBefore($form->removeElement('foo', false), 'bar');
-    *
-    * @access   public
-    * @since    3.2.4
-    * @param    HTML_QuickForm_element  Element to insert
-    * @param    string                  Name of the element before which the new
-    *                                   one is inserted
-    * @return   HTML_QuickForm_element  reference to inserted element
-    * @throws   HTML_QuickForm_Error
-    */
-    function &insertElementBefore(&$element, $nameAfter)
-    {
-        if (!empty($this->_duplicateIndex[$nameAfter])) {
-            $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, 'Several elements named "' . $nameAfter . '" exist in HTML_QuickForm::insertElementBefore().', 'HTML_QuickForm_Error', true);
-            return $error;
-        } elseif (!$this->elementExists($nameAfter)) {
-            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$nameAfter' does not exist in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
-            return $error;
-        }
-        $elementName = $element->getName();
-        $targetIdx   = $this->_elementIndex[$nameAfter];
-        $duplicate   = false;
-        // Like in addElement(), check that it's not an incompatible duplicate
-        if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
-            if ($this->_elements[$this->_elementIndex[$elementName]]->getType() != $element->getType()) {
-                $error = PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::insertElementBefore()", 'HTML_QuickForm_Error', true);
-                return $error;
-            }
-            $duplicate = true;
-        }
-        // Move all the elements after added back one place, reindex _elementIndex and/or _duplicateIndex
-        $elKeys = array_keys($this->_elements);
-        for ($i = end($elKeys); $i >= $targetIdx; $i--) {
-            if (isset($this->_elements[$i])) {
-                $currentName = $this->_elements[$i]->getName();
-                $this->_elements[$i + 1] =& $this->_elements[$i];
-                if ($this->_elementIndex[$currentName] == $i) {
-                    $this->_elementIndex[$currentName] = $i + 1;
-                } else {
-                    $dupIdx = array_search($i, $this->_duplicateIndex[$currentName]);
-                    $this->_duplicateIndex[$currentName][$dupIdx] = $i + 1;
-                }
-                unset($this->_elements[$i]);
-            }
-        }
-        // Put the element in place finally
-        $this->_elements[$targetIdx] =& $element;
-        if (!$duplicate) {
-            $this->_elementIndex[$elementName] = $targetIdx;
-        } else {
-            $this->_duplicateIndex[$elementName][] = $targetIdx;
-        }
-        $element->onQuickFormEvent('updateValue', null, $this);
-        if ($this->_freezeAll) {
-            $element->freeze();
-        }
-        // If not done, the elements will appear in reverse order
-        ksort($this->_elements);
-        return $element;
-    }
-
-    // }}}
-    // {{{ addGroup()
-
-    /**
-     * Adds an element group
-     * @param    array      $elements       array of elements composing the group
-     * @param    string     $name           (optional)group name
-     * @param    string     $groupLabel     (optional)group label
-     * @param    string     $separator      (optional)string to separate elements
-     * @param    string     $appendName     (optional)specify whether the group name should be
-     *                                      used in the form element name ex: group[element]
-     * @return   HTML_QuickForm_group       reference to a newly added group
-     * @since    2.8
-     * @access   public
-     * @throws   HTML_QuickForm_Error
-     */
-    function &addGroup($elements, $name=null, $groupLabel='', $separator=null, $appendName = true)
-    {
-        static $anonGroups = 1;
-
-        if (0 == strlen($name)) {
-            $name       = 'qf_group_' . $anonGroups++;
-            $appendName = false;
-        }
-        $group =& $this->addElement('group', $name, $groupLabel, $elements, $separator, $appendName);
-        return $group;
-    } // end func addGroup
-
-    // }}}
-    // {{{ &getElement()
-
-    /**
-     * Returns a reference to the element
-     *
-     * @param     string     $element    Element name
-     * @since     2.0
-     * @access    public
-     * @return    HTML_QuickForm_element    reference to element
-     * @throws    HTML_QuickForm_Error
-     */
-    function &getElement($element)
-    {
-        if (isset($this->_elementIndex[$element])) {
-            return $this->_elements[$this->_elementIndex[$element]];
-        } else {
-            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElement()", 'HTML_QuickForm_Error', true);
-            return $error;
-        }
-    } // end func getElement
-
-    // }}}
-    // {{{ &getElementValue()
-
-    /**
-     * Returns the element's raw value
-     *
-     * This returns the value as submitted by the form (not filtered)
-     * or set via setDefaults() or setConstants()
-     *
-     * @param     string     $element    Element name
-     * @since     2.0
-     * @access    public
-     * @return    mixed     element value
-     * @throws    HTML_QuickForm_Error
-     */
-    function &getElementValue($element)
-    {
-        if (!isset($this->_elementIndex[$element])) {
-            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
-            return $error;
-        }
-        $value = $this->_elements[$this->_elementIndex[$element]]->getValue();
-        if (isset($this->_duplicateIndex[$element])) {
-            foreach ($this->_duplicateIndex[$element] as $index) {
-                if (null !== ($v = $this->_elements[$index]->getValue())) {
-                    if (is_array($value)) {
-                        $value[] = $v;
-                    } else {
-                        $value = (null === $value)? $v: array($value, $v);
-                    }
-                }
-            }
-        }
-        return $value;
-    } // end func getElementValue
-
-    // }}}
-    // {{{ getSubmitValue()
-
-    /**
-     * Returns the elements value after submit and filter
-     *
-     * @param     string     Element name
-     * @since     2.0
-     * @access    public
-     * @return    mixed     submitted element value or null if not set
-     */
-    function getSubmitValue($elementName)
-    {
-        $value = null;
-        if (isset($this->_submitValues[$elementName]) || isset($this->_submitFiles[$elementName])) {
-            $value = isset($this->_submitValues[$elementName])? $this->_submitValues[$elementName]: array();
-            if (is_array($value) && isset($this->_submitFiles[$elementName])) {
-                foreach ($this->_submitFiles[$elementName] as $k => $v) {
-                    $value = HTML_QuickForm::arrayMerge($value, $this->_reindexFiles($this->_submitFiles[$elementName][$k], $k));
-                }
-            }
-
-        } elseif ('file' == $this->getElementType($elementName)) {
-            return $this->getElementValue($elementName);
-
-        } elseif (false !== ($pos = strpos($elementName, '['))) {
-            $base = str_replace(
-                        array('\\', '\''), array('\\\\', '\\\''),
-                        substr($elementName, 0, $pos)
-                    );
-
-            $keys = str_replace(
-                array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
-                substr($elementName, $pos + 1, -1)
-                );
-            $idx  = "['" . $keys . "']";
-            $keyArray = explode("']['", $keys);
-
-            if (isset($this->_submitValues[$base])) {
-                $value = HTML_QuickForm_utils::recursiveValue($this->_submitValues[$base], $keyArray, NULL);
-            }
-
-            if ((is_array($value) || null === $value) && isset($this->_submitFiles[$base])) {
-                $props = array('name', 'type', 'size', 'tmp_name', 'error');
-                $code  = "if (!isset(\$this->_submitFiles['{$base}']['name']{$idx})) {\n" .
-                         "    return null;\n" .
-                         "} else {\n" .
-                         "    \$v = array();\n";
-                foreach ($props as $prop) {
-                    $code .= "    \$v = HTML_QuickForm::arrayMerge(\$v, \$this->_reindexFiles(\$this->_submitFiles['{$base}']['{$prop}']{$idx}, '{$prop}'));\n";
-                }
-                $fileValue = eval($code . "    return \$v;\n}\n");
-                if (null !== $fileValue) {
-                    $value = null === $value? $fileValue: HTML_QuickForm::arrayMerge($value, $fileValue);
-                }
-            }
-        }
-
-        // This is only supposed to work for groups with appendName = false
-        if (null === $value && 'group' == $this->getElementType($elementName)) {
-            $group    =& $this->getElement($elementName);
-            $elements =& $group->getElements();
-            foreach (array_keys($elements) as $key) {
-                $name = $group->getElementName($key);
-                // prevent endless recursion in case of radios and such
-                if ($name != $elementName) {
-                    if (null !== ($v = $this->getSubmitValue($name))) {
-                        $value[$name] = $v;
-                    }
-                }
-            }
-        }
-        return $value;
-    } // end func getSubmitValue
-
-    // }}}
-    // {{{ _reindexFiles()
-
-   /**
-    * A helper function to change the indexes in $_FILES array
-    *
-    * @param  mixed   Some value from the $_FILES array
-    * @param  string  The key from the $_FILES array that should be appended
-    * @return array
-    */
-    function _reindexFiles($value, $key)
-    {
-        if (!is_array($value)) {
-            return array($key => $value);
-        } else {
-            $ret = array();
-            foreach ($value as $k => $v) {
-                $ret[$k] = $this->_reindexFiles($v, $key);
-            }
-            return $ret;
-        }
-    }
-
-    // }}}
-    // {{{ getElementError()
-
-    /**
-     * Returns error corresponding to validated element
-     *
-     * @param     string    $element        Name of form element to check
-     * @since     1.0
-     * @access    public
-     * @return    string    error message corresponding to checked element
-     */
-    function getElementError($element)
-    {
-        if (isset($this->_errors[$element])) {
-            return $this->_errors[$element];
-        }
-    } // end func getElementError
-
-    // }}}
-    // {{{ setElementError()
-
-    /**
-     * Set error message for a form element
-     *
-     * @param     string    $element    Name of form element to set error for
-     * @param     string    $message    Error message, if empty then removes the current error message
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setElementError($element, $message = null)
-    {
-        if (!empty($message)) {
-            $this->_errors[$element] = $message;
-        } else {
-            unset($this->_errors[$element]);
-        }
-    } // end func setElementError
-
-     // }}}
-     // {{{ getElementType()
-
-     /**
-      * Returns the type of the given element
-      *
-      * @param      string    $element    Name of form element
-      * @since      1.1
-      * @access     public
-      * @return     string    Type of the element, false if the element is not found
-      */
-     function getElementType($element)
-     {
-         if (isset($this->_elementIndex[$element])) {
-             return $this->_elements[$this->_elementIndex[$element]]->getType();
-         }
-         return false;
-     } // end func getElementType
-
-     // }}}
-     // {{{ updateElementAttr()
-
-    /**
-     * Updates Attributes for one or more elements
-     *
-     * @param      mixed    $elements   Array of element names/objects or string of elements to be updated
-     * @param      mixed    $attrs      Array or sting of html attributes
-     * @since      2.10
-     * @access     public
-     * @return     void
-     */
-    function updateElementAttr($elements, $attrs)
-    {
-        if (is_string($elements)) {
-            $elements = preg_split('/[ ]?,[ ]?/', $elements);
-        }
-        foreach (array_keys($elements) as $key) {
-            if (is_object($elements[$key]) && is_a($elements[$key], 'HTML_QuickForm_element')) {
-                $elements[$key]->updateAttributes($attrs);
-            } elseif (isset($this->_elementIndex[$elements[$key]])) {
-                $this->_elements[$this->_elementIndex[$elements[$key]]]->updateAttributes($attrs);
-                if (isset($this->_duplicateIndex[$elements[$key]])) {
-                    foreach ($this->_duplicateIndex[$elements[$key]] as $index) {
-                        $this->_elements[$index]->updateAttributes($attrs);
-                    }
-                }
-            }
-        }
-    } // end func updateElementAttr
-
-    // }}}
-    // {{{ removeElement()
-
-    /**
-     * Removes an element
-     *
-     * The method "unlinks" an element from the form, returning the reference
-     * to the element object. If several elements named $elementName exist,
-     * it removes the first one, leaving the others intact.
-     *
-     * @param string    $elementName The element name
-     * @param boolean   $removeRules True if rules for this element are to be removed too
-     * @access public
-     * @since 2.0
-     * @return HTML_QuickForm_element    a reference to the removed element
-     * @throws HTML_QuickForm_Error
-     */
-    function &removeElement($elementName, $removeRules = true)
-    {
-        if (!isset($this->_elementIndex[$elementName])) {
-            $error = PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$elementName' does not exist in HTML_QuickForm::removeElement()", 'HTML_QuickForm_Error', true);
-            return $error;
-        }
-        $el =& $this->_elements[$this->_elementIndex[$elementName]];
-        unset($this->_elements[$this->_elementIndex[$elementName]]);
-        if (empty($this->_duplicateIndex[$elementName])) {
-            unset($this->_elementIndex[$elementName]);
-        } else {
-            $this->_elementIndex[$elementName] = array_shift($this->_duplicateIndex[$elementName]);
-        }
-        if ($removeRules) {
-            $this->_required = array_diff($this->_required, array($elementName));
-            unset($this->_rules[$elementName], $this->_errors[$elementName]);
-            if ('group' == $el->getType()) {
-                foreach (array_keys($el->getElements()) as $key) {
-                    unset($this->_rules[$el->getElementName($key)]);
-                }
-            }
-        }
-        return $el;
-    } // end func removeElement
-
-    // }}}
-    // {{{ addRule()
-
-    /**
-     * Adds a validation rule for the given field
-     *
-     * If the element is in fact a group, it will be considered as a whole.
-     * To validate grouped elements as separated entities,
-     * use addGroupRule instead of addRule.
-     *
-     * @param    string     $element       Form element name
-     * @param    string     $message       Message to display for invalid data
-     * @param    string     $type          Rule type, use getRegisteredRules() to get types
-     * @param    string     $format        (optional)Required for extra rule data
-     * @param    string     $validation    (optional)Where to perform validation: "server", "client"
-     * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?
-     * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist
-     * @since    1.0
-     * @access   public
-     * @throws   HTML_QuickForm_Error
-     */
-    function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false)
-    {
-        if (!$force) {
-            if (!is_array($element) && !$this->elementExists($element)) {
-                return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
-            } elseif (is_array($element)) {
-                foreach ($element as $el) {
-                    if (!$this->elementExists($el)) {
-                        return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$el' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
-                    }
-                }
-            }
-        }
-        if (false === ($newName = $this->isRuleRegistered($type, true))) {
-            return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
-        } elseif (is_string($newName)) {
-            $type = $newName;
-        }
-        if (is_array($element)) {
-            $dependent = $element;
-            $element   = array_shift($dependent);
-        } else {
-            $dependent = null;
-        }
-        if ($type == 'required' || $type == 'uploadedfile') {
-            $this->_required[] = $element;
-        }
-        if (!isset($this->_rules[$element])) {
-            $this->_rules[$element] = array();
-        }
-        if ($validation == 'client') {
-            $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
-        }
-        $this->_rules[$element][] = array(
-            'type'        => $type,
-            'format'      => $format,
-            'message'     => $message,
-            'validation'  => $validation,
-            'reset'       => $reset,
-            'dependent'   => $dependent
-        );
-    } // end func addRule
-
-    // }}}
-    // {{{ addGroupRule()
-
-    /**
-     * Adds a validation rule for the given group of elements
-     *
-     * Only groups with a name can be assigned a validation rule
-     * Use addGroupRule when you need to validate elements inside the group.
-     * Use addRule if you need to validate the group as a whole. In this case,
-     * the same rule will be applied to all elements in the group.
-     * Use addRule if you need to validate the group against a function.
-     *
-     * @param    string     $group         Form group name
-     * @param    mixed      $arg1          Array for multiple elements or error message string for one element
-     * @param    string     $type          (optional)Rule type use getRegisteredRules() to get types
-     * @param    string     $format        (optional)Required for extra rule data
-     * @param    int        $howmany       (optional)How many valid elements should be in the group
-     * @param    string     $validation    (optional)Where to perform validation: "server", "client"
-     * @param    bool       $reset         Client-side: whether to reset the element's value to its original state if validation failed.
-     * @since    2.5
-     * @access   public
-     * @throws   HTML_QuickForm_Error
-     */
-    function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false)
-    {
-        if (!$this->elementExists($group)) {
-            return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Group '$group' does not exist in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
-        }
-
-        $groupObj =& $this->getElement($group);
-        if (is_array($arg1)) {
-            $required = 0;
-            foreach ($arg1 as $elementIndex => $rules) {
-                $elementName = $groupObj->getElementName($elementIndex);
-                foreach ($rules as $rule) {
-                    $format = (isset($rule[2])) ? $rule[2] : null;
-                    $validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server';
-                    $reset = isset($rule[4]) && $rule[4];
-                    $type = $rule[1];
-                    if (false === ($newName = $this->isRuleRegistered($type, true))) {
-                        return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
-                    } elseif (is_string($newName)) {
-                        $type = $newName;
-                    }
-
-                    $this->_rules[$elementName][] = array(
-                                                        'type'        => $type,
-                                                        'format'      => $format,
-                                                        'message'     => $rule[0],
-                                                        'validation'  => $validation,
-                                                        'reset'       => $reset,
-                                                        'group'       => $group);
-
-                    if ('required' == $type || 'uploadedfile' == $type) {
-                        $groupObj->_required[] = $elementName;
-                        $this->_required[] = $elementName;
-                        $required++;
-                    }
-                    if ('client' == $validation) {
-                        $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
-                    }
-                }
-            }
-            if ($required > 0 && count($groupObj->getElements()) == $required) {
-                $this->_required[] = $group;
-            }
-        } elseif (is_string($arg1)) {
-            if (false === ($newName = $this->isRuleRegistered($type, true))) {
-                return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
-            } elseif (is_string($newName)) {
-                $type = $newName;
-            }
-
-            // addGroupRule() should also handle <select multiple>
-            if (is_a($groupObj, 'html_quickform_group')) {
-                // Radios need to be handled differently when required
-                if ($type == 'required' && $groupObj->getGroupType() == 'radio') {
-                    $howmany = ($howmany == 0) ? 1 : $howmany;
-                } else {
-                    $howmany = ($howmany == 0) ? count($groupObj->getElements()) : $howmany;
-                }
-            }
-
-            $this->_rules[$group][] = array('type'       => $type,
-                                            'format'     => $format,
-                                            'message'    => $arg1,
-                                            'validation' => $validation,
-                                            'howmany'    => $howmany,
-                                            'reset'      => $reset);
-            if ($type == 'required') {
-                $this->_required[] = $group;
-            }
-            if ($validation == 'client') {
-                $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_attributes['id'] . '; } catch(e) { return true; } return myValidator(this);'));
-            }
-        }
-    } // end func addGroupRule
-
-    // }}}
-    // {{{ addFormRule()
-
-   /**
-    * Adds a global validation rule
-    *
-    * This should be used when for a rule involving several fields or if
-    * you want to use some completely custom validation for your form.
-    * The rule function/method should return true in case of successful
-    * validation and array('element name' => 'error') when there were errors.
-    *
-    * @access   public
-    * @param    mixed   Callback, either function name or array(&$object, 'method')
-    * @throws   HTML_QuickForm_Error
-    */
-    function addFormRule($rule)
-    {
-        if (!is_callable($rule)) {
-            return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, 'Callback function does not exist in HTML_QuickForm::addFormRule()', 'HTML_QuickForm_Error', true);
-        }
-        $this->_formRules[] = $rule;
-    }
-
-    // }}}
-    // {{{ applyFilter()
-
-    /**
-     * Applies a data filter for the given field(s)
-     *
-     * @param    mixed     $element       Form element name or array of such names
-     * @param    mixed     $filter        Callback, either function name or array(&$object, 'method')
-     * @since    2.0
-     * @access   public
-     * @throws   HTML_QuickForm_Error
-     */
-    function applyFilter($element, $filter)
-    {
-        if (!is_callable($filter)) {
-            return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::applyFilter()", 'HTML_QuickForm_Error', true);
-        }
-        if ($element == '__ALL__') {
-            $this->_submitValues = $this->_recursiveFilter($filter, $this->_submitValues);
-        } else {
-            if (!is_array($element)) {
-                $element = array($element);
-            }
-            foreach ($element as $elName) {
-                $value = $this->getSubmitValue($elName);
-                if (null !== $value) {
-                    if (false === strpos($elName, '[')) {
-                        $this->_submitValues[$elName] = $this->_recursiveFilter($filter, $value);
-                    } else {
-                        $idx  = "['" . str_replace(
-                                    array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
-                                    $elName
-                                ) . "']";
-                        eval("\$this->_submitValues{$idx} = \$this->_recursiveFilter(\$filter, \$value);");
-                    }
-                }
-            }
-        }
-    } // end func applyFilter
-
-    // }}}
-    // {{{ _recursiveFilter()
-
-    /**
-     * Recursively apply a filter function
-     *
-     * @param     string   $filter    filter to apply
-     * @param     mixed    $value     submitted values
-     * @since     2.0
-     * @access    private
-     * @return    cleaned values
-     */
-    function _recursiveFilter($filter, $value)
-    {
-        if (is_array($value)) {
-            $cleanValues = array();
-            foreach ($value as $k => $v) {
-                $cleanValues[$k] = $this->_recursiveFilter($filter, $v);
-            }
-            return $cleanValues;
-        } else {
-            return call_user_func($filter, $value);
-        }
-    } // end func _recursiveFilter
-
-    // }}}
-    // {{{ arrayMerge()
-
-   /**
-    * Merges two arrays
-    *
-    * Merges two array like the PHP function array_merge but recursively.
-    * The main difference is that existing keys will not be renumbered
-    * if they are integers.
-    *
-    * @access   public
-    * @param    array   $a  original array
-    * @param    array   $b  array which will be merged into first one
-    * @return   array   merged array
-    */
-    function arrayMerge($a, $b)
-    {
-        foreach ($b as $k => $v) {
-            if (is_array($v)) {
-                if (isset($a[$k]) && !is_array($a[$k])) {
-                    $a[$k] = $v;
-                } else {
-                    if (!isset($a[$k])) {
-                        $a[$k] = array();
-                    }
-                    $a[$k] = HTML_QuickForm::arrayMerge($a[$k], $v);
-                }
-            } else {
-                $a[$k] = $v;
-            }
-        }
-        return $a;
-    } // end func arrayMerge
-
-    // }}}
-    // {{{ isTypeRegistered()
-
-    /**
-     * Returns whether or not the form element type is supported
-     *
-     * @param     string   $type     Form element type
-     * @since     1.0
-     * @access    public
-     * @return    boolean
-     */
-    function isTypeRegistered($type)
-    {
-        return isset($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($type)]);
-    } // end func isTypeRegistered
-
-    // }}}
-    // {{{ getRegisteredTypes()
-
-    /**
-     * Returns an array of registered element types
-     *
-     * @since     1.0
-     * @access    public
-     * @return    array
-     */
-    function getRegisteredTypes()
-    {
-        return array_keys($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']);
-    } // end func getRegisteredTypes
-
-    // }}}
-    // {{{ isRuleRegistered()
-
-    /**
-     * Returns whether or not the given rule is supported
-     *
-     * @param     string   $name    Validation rule name
-     * @param     bool     Whether to automatically register subclasses of HTML_QuickForm_Rule
-     * @since     1.0
-     * @access    public
-     * @return    mixed    true if previously registered, false if not, new rule name if auto-registering worked
-     */
-    function isRuleRegistered($name, $autoRegister = false)
-    {
-        if (is_scalar($name) && isset($GLOBALS['_HTML_QuickForm_registered_rules'][$name])) {
-            return true;
-        } elseif (!$autoRegister) {
-            return false;
-        }
-        // automatically register the rule if requested
-        include_once 'HTML/QuickForm/RuleRegistry.php';
-        $ruleName = false;
-        if (is_object($name) && is_a($name, 'html_quickform_rule')) {
-            $ruleName = !empty($name->name)? $name->name: strtolower(get_class($name));
-        } elseif (is_string($name) && class_exists($name)) {
-            $parent = strtolower($name);
-            do {
-                if ('html_quickform_rule' == strtolower($parent)) {
-                    $ruleName = strtolower($name);
-                    break;
-                }
-            } while ($parent = get_parent_class($parent));
-        }
-        if ($ruleName) {
-            $registry =& HTML_QuickForm_RuleRegistry::singleton();
-            $registry->registerRule($ruleName, null, $name);
-        }
-        return $ruleName;
-    } // end func isRuleRegistered
-
-    // }}}
-    // {{{ getRegisteredRules()
-
-    /**
-     * Returns an array of registered validation rules
-     *
-     * @since     1.0
-     * @access    public
-     * @return    array
-     */
-    function getRegisteredRules()
-    {
-        return array_keys($GLOBALS['_HTML_QuickForm_registered_rules']);
-    } // end func getRegisteredRules
-
-    // }}}
-    // {{{ isElementRequired()
-
-    /**
-     * Returns whether or not the form element is required
-     *
-     * @param     string   $element     Form element name
-     * @since     1.0
-     * @access    public
-     * @return    boolean
-     */
-    function isElementRequired($element)
-    {
-        return in_array($element, $this->_required, true);
-    } // end func isElementRequired
-
-    // }}}
-    // {{{ isElementFrozen()
-
-    /**
-     * Returns whether or not the form element is frozen
-     *
-     * @param     string   $element     Form element name
-     * @since     1.0
-     * @access    public
-     * @return    boolean
-     */
-    function isElementFrozen($element)
-    {
-         if (isset($this->_elementIndex[$element])) {
-             return $this->_elements[$this->_elementIndex[$element]]->isFrozen();
-         }
-         return false;
-    } // end func isElementFrozen
-
-    // }}}
-    // {{{ setJsWarnings()
-
-    /**
-     * Sets JavaScript warning messages
-     *
-     * @param     string   $pref        Prefix warning
-     * @param     string   $post        Postfix warning
-     * @since     1.1
-     * @access    public
-     * @return    void
-     */
-    function setJsWarnings($pref, $post)
-    {
-        $this->_jsPrefix = $pref;
-        $this->_jsPostfix = $post;
-    } // end func setJsWarnings
-
-    // }}}
-    // {{{ setRequiredNote()
-
-    /**
-     * Sets required-note
-     *
-     * @param     string   $note        Message indicating some elements are required
-     * @since     1.1
-     * @access    public
-     * @return    void
-     */
-    function setRequiredNote($note)
-    {
-        $this->_requiredNote = $note;
-    } // end func setRequiredNote
-
-    // }}}
-    // {{{ getRequiredNote()
-
-    /**
-     * Returns the required note
-     *
-     * @since     2.0
-     * @access    public
-     * @return    string
-     */
-    function getRequiredNote()
-    {
-        return $this->_requiredNote;
-    } // end func getRequiredNote
-
-    // }}}
-    // {{{ validate()
-
-    /**
-     * Performs the server side validation
-     * @access    public
-     * @since     1.0
-     * @return    boolean   true if no error found
-     * @throws    HTML_QuickForm_Error
-     */
-    function validate()
-    {
-        if (count($this->_rules) == 0 && count($this->_formRules) == 0 &&
-            $this->isSubmitted()) {
-            return (0 == count($this->_errors));
-        } elseif (!$this->isSubmitted()) {
-            return false;
-        }
-
-        include_once('HTML/QuickForm/RuleRegistry.php');
-        $registry =& HTML_QuickForm_RuleRegistry::singleton();
-
-        foreach ($this->_rules as $target => $rules) {
-            $submitValue = $this->getSubmitValue($target);
-
-            foreach ($rules as $rule) {
-                if ((isset($rule['group']) && isset($this->_errors[$rule['group']])) ||
-                     isset($this->_errors[$target])) {
-                    continue 2;
-                }
-                // If element is not required and is empty, we shouldn't validate it
-                if (!$this->isElementRequired($target)) {
-                    if (!isset($submitValue) || '' == $submitValue) {
-                        continue 2;
-                    // Fix for bug #3501: we shouldn't validate not uploaded files, either.
-                    // Unfortunately, we can't just use $element->isUploadedFile() since
-                    // the element in question can be buried in group. Thus this hack.
-                    // See also bug #12014, we should only consider a file that has
-                    // status UPLOAD_ERR_NO_FILE as not uploaded, in all other cases
-                    // validation should be performed, so that e.g. 'maxfilesize' rule
-                    // will display an error if status is UPLOAD_ERR_INI_SIZE
-                    // or UPLOAD_ERR_FORM_SIZE
-                    } elseif (is_array($submitValue)) {
-                        if (false === ($pos = strpos($target, '['))) {
-                            $isUpload = !empty($this->_submitFiles[$target]);
-                        } else {
-                            $base = str_replace(
-                                        array('\\', '\''), array('\\\\', '\\\''),
-                                        substr($target, 0, $pos)
-                                    );
-                            $idx  = "['" . str_replace(
-                                        array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
-                                        substr($target, $pos + 1, -1)
-                                    ) . "']";
-                            eval("\$isUpload = isset(\$this->_submitFiles['{$base}']['name']{$idx});");
-                        }
-                        if ($isUpload && (!isset($submitValue['error']) || UPLOAD_ERR_NO_FILE == $submitValue['error'])) {
-                            continue 2;
-                        }
-                    }
-                }
-                if (isset($rule['dependent']) && is_array($rule['dependent'])) {
-                    $values = array($submitValue);
-                    foreach ($rule['dependent'] as $elName) {
-                        $values[] = $this->getSubmitValue($elName);
-                    }
-                    $result = $registry->validate($rule['type'], $values, $rule['format'], true);
-                } elseif (is_array($submitValue) && !isset($rule['howmany'])) {
-                    $result = $registry->validate($rule['type'], $submitValue, $rule['format'], true);
-                } else {
-                    $result = $registry->validate($rule['type'], $submitValue, $rule['format'], false);
-                }
-
-                if (!$result || (!empty($rule['howmany']) && $rule['howmany'] > (int)$result)) {
-                    if (isset($rule['group'])) {
-                        $this->_errors[$rule['group']] = $rule['message'];
-                    } else {
-                        $this->_errors[$target] = $rule['message'];
-                    }
-                }
-            }
-        }
-
-        // process the global rules now
-        foreach ($this->_formRules as $rule) {
-            if (true !== ($res = call_user_func($rule, $this->_submitValues, $this->_submitFiles))) {
-                if (is_array($res)) {
-                    $this->_errors += $res;
-                } else {
-                    return PEAR::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, 'Form rule callback returned invalid value in HTML_QuickForm::validate()', 'HTML_QuickForm_Error', true);
-                }
-            }
-        }
-
-        return (0 == count($this->_errors));
-    } // end func validate
-
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Displays elements without HTML input tags
-     *
-     * @param    mixed   $elementList       array or string of element(s) to be frozen
-     * @since     1.0
-     * @access   public
-     * @throws   HTML_QuickForm_Error
-     */
-    function freeze($elementList=null)
-    {
-        if (!isset($elementList)) {
-            $this->_freezeAll = true;
-            $elementList = array();
-        } else {
-            if (!is_array($elementList)) {
-                $elementList = preg_split('/[ ]*,[ ]*/', $elementList);
-            }
-            $elementList = array_flip($elementList);
-        }
-
-        foreach (array_keys($this->_elements) as $key) {
-            $name = $this->_elements[$key]->getName();
-            if ($this->_freezeAll || isset($elementList[$name])) {
-                $this->_elements[$key]->freeze();
-                unset($elementList[$name]);
-            }
-        }
-
-        if (!empty($elementList)) {
-            return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Nonexistant element(s): '" . implode("', '", array_keys($elementList)) . "' in HTML_QuickForm::freeze()", 'HTML_QuickForm_Error', true);
-        }
-        return true;
-    } // end func freeze
-
-    // }}}
-    // {{{ isFrozen()
-
-    /**
-     * Returns whether or not the whole form is frozen
-     *
-     * @since     3.0
-     * @access    public
-     * @return    boolean
-     */
-    function isFrozen()
-    {
-         return $this->_freezeAll;
-    } // end func isFrozen
-
-    // }}}
-    // {{{ process()
-
-    /**
-     * Performs the form data processing
-     *
-     * @param    mixed     $callback        Callback, either function name or array(&$object, 'method')
-     * @param    bool      $mergeFiles      Whether uploaded files should be processed too
-     * @since    1.0
-     * @access   public
-     * @throws   HTML_QuickForm_Error
-     * @return   mixed     Whatever value the $callback function returns
-     */
-    function process($callback, $mergeFiles = true)
-    {
-        if (!is_callable($callback)) {
-            return PEAR::raiseError(null, QUICKFORM_INVALID_PROCESS, null, E_USER_WARNING, "Callback function does not exist in QuickForm::process()", 'HTML_QuickForm_Error', true);
-        }
-        $values = ($mergeFiles === true) ? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles) : $this->_submitValues;
-        return call_user_func($callback, $values);
-    } // end func process
-
-    // }}}
-    // {{{ accept()
-
-   /**
-    * Accepts a renderer
-    *
-    * @param object     An HTML_QuickForm_Renderer object
-    * @since 3.0
-    * @access public
-    * @return void
-    */
-    function accept(&$renderer)
-    {
-        $renderer->startForm($this);
-        foreach (array_keys($this->_elements) as $key) {
-            $element =& $this->_elements[$key];
-            $elementName = $element->getName();
-            $required    = ($this->isElementRequired($elementName) && !$element->isFrozen());
-            $error       = $this->getElementError($elementName);
-            $element->accept($renderer, $required, $error);
-        }
-        $renderer->finishForm($this);
-    } // end func accept
-
-    // }}}
-    // {{{ defaultRenderer()
-
-   /**
-    * Returns a reference to default renderer object
-    *
-    * @access public
-    * @since 3.0
-    * @return object a default renderer object
-    */
-    function &defaultRenderer()
-    {
-        if (!isset($GLOBALS['_HTML_QuickForm_default_renderer'])) {
-            include_once('HTML/QuickForm/Renderer/Default.php');
-            $GLOBALS['_HTML_QuickForm_default_renderer'] = new HTML_QuickForm_Renderer_Default();
-        }
-        return $GLOBALS['_HTML_QuickForm_default_renderer'];
-    } // end func defaultRenderer
-
-    // }}}
-    // {{{ toHtml ()
-
-    /**
-     * Returns an HTML version of the form
-     *
-     * @param string $in_data (optional) Any extra data to insert right
-     *               before form is rendered.  Useful when using templates.
-     *
-     * @return   string     Html version of the form
-     * @since     1.0
-     * @access   public
-     */
-    function toHtml ($in_data = null)
-    {
-        if (!is_null($in_data)) {
-            $this->addElement('html', $in_data);
-        }
-        $renderer =& $this->defaultRenderer();
-        $this->accept($renderer);
-        return $renderer->toHtml();
-    } // end func toHtml
-
-    // }}}
-    // {{{ getValidationScript()
-
-    /**
-     * Returns the client side validation script
-     *
-     * @since     2.0
-     * @access    public
-     * @return    string    Javascript to perform validation, empty string if no 'client' rules were added
-     */
-    function getValidationScript()
-    {
-        if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
-            return '';
-        }
-
-        include_once('HTML/QuickForm/RuleRegistry.php');
-        $registry =& HTML_QuickForm_RuleRegistry::singleton();
-        $test = array();
-        $js_escape = array(
-            "\r"    => '\r',
-            "\n"    => '\n',
-            "\t"    => '\t',
-            "'"     => "\\'",
-            '"'     => '\"',
-            '\\'    => '\\\\'
-        );
-
-        foreach ($this->_rules as $elementName => $rules) {
-            foreach ($rules as $rule) {
-                if ('client' == $rule['validation']) {
-                    unset($element);
-
-                    $dependent  = isset($rule['dependent']) && is_array($rule['dependent']);
-                    $rule['message'] = strtr($rule['message'], $js_escape);
-
-                    if (isset($rule['group'])) {
-                        $group    =& $this->getElement($rule['group']);
-                        // No JavaScript validation for frozen elements
-                        if ($group->isFrozen()) {
-                            continue 2;
-                        }
-                        $elements =& $group->getElements();
-                        foreach (array_keys($elements) as $key) {
-                            if ($elementName == $group->getElementName($key)) {
-                                $element =& $elements[$key];
-                                break;
-                            }
-                        }
-                    } elseif ($dependent) {
-                        $element   =  array();
-                        $element[] =& $this->getElement($elementName);
-                        foreach ($rule['dependent'] as $elName) {
-                            $element[] =& $this->getElement($elName);
-                        }
-                    } else {
-                        $element =& $this->getElement($elementName);
-                    }
-                    // No JavaScript validation for frozen elements
-                    if (is_object($element) && $element->isFrozen()) {
-                        continue 2;
-                    } elseif (is_array($element)) {
-                        foreach (array_keys($element) as $key) {
-                            if ($element[$key]->isFrozen()) {
-                                continue 3;
-                            }
-                        }
-                    }
-
-                    $test[] = $registry->getValidationScript($element, $elementName, $rule);
-                }
-            }
-        }
-        if (count($test) > 0) {
-            return
-                "\n<script type=\"text/javascript\">\n" .
-                "//<![CDATA[\n" .
-                "function validate_" . $this->_attributes['id'] . "(frm) {\n" .
-                "  var value = '';\n" .
-                "  var errFlag = new Array();\n" .
-                "  var _qfGroups = {};\n" .
-                "  _qfMsg = '';\n\n" .
-                join("\n", $test) .
-                "\n  if (_qfMsg != '') {\n" .
-                "    _qfMsg = '" . strtr($this->_jsPrefix, $js_escape) . "' + _qfMsg;\n" .
-                "    _qfMsg = _qfMsg + '\\n" . strtr($this->_jsPostfix, $js_escape) . "';\n" .
-                "    alert(_qfMsg);\n" .
-                "    return false;\n" .
-                "  }\n" .
-                "  return true;\n" .
-                "}\n" .
-                "//]]>\n" .
-                "</script>";
-        }
-        return '';
-    } // end func getValidationScript
-
-    // }}}
-    // {{{ getSubmitValues()
-
-    /**
-     * Returns the values submitted by the form
-     *
-     * @since     2.0
-     * @access    public
-     * @param     bool      Whether uploaded files should be returned too
-     * @return    array
-     */
-    function getSubmitValues($mergeFiles = false)
-    {
-        return $mergeFiles? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles): $this->_submitValues;
-    } // end func getSubmitValues
-
-    // }}}
-    // {{{ toArray()
-
-    /**
-     * Returns the form's contents in an array.
-     *
-     * The description of the array structure is in HTML_QuickForm_Renderer_Array docs
-     *
-     * @since     2.0
-     * @access    public
-     * @param     bool      Whether to collect hidden elements (passed to the Renderer's constructor)
-     * @return    array of form contents
-     */
-    function toArray($collectHidden = false)
-    {
-        include_once 'HTML/QuickForm/Renderer/Array.php';
-        $renderer = new HTML_QuickForm_Renderer_Array($collectHidden);
-        $this->accept($renderer);
-        return $renderer->toArray();
-     } // end func toArray
-
-    // }}}
-    // {{{ exportValue()
-
-    /**
-     * Returns a 'safe' element's value
-     *
-     * This method first tries to find a cleaned-up submitted value,
-     * it will return a value set by setValue()/setDefaults()/setConstants()
-     * if submitted value does not exist for the given element.
-     *
-     * @param  string   Name of an element
-     * @access public
-     * @return mixed
-     * @throws HTML_QuickForm_Error
-     */
-    function exportValue($element)
-    {
-        if (!isset($this->_elementIndex[$element])) {
-            return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
-        }
-        $value = $this->_elements[$this->_elementIndex[$element]]->exportValue($this->_submitValues, false);
-        if (isset($this->_duplicateIndex[$element])) {
-            foreach ($this->_duplicateIndex[$element] as $index) {
-                if (null !== ($v = $this->_elements[$index]->exportValue($this->_submitValues, false))) {
-                    if (is_array($value)) {
-                        $value[] = $v;
-                    } else {
-                        $value = (null === $value)? $v: array($value, $v);
-                    }
-                }
-            }
-        }
-        return $value;
-    }
-
-    // }}}
-    // {{{ exportValues()
-
-    /**
-     * Returns 'safe' elements' values
-     *
-     * Unlike getSubmitValues(), this will return only the values
-     * corresponding to the elements present in the form.
-     *
-     * @param   mixed   Array/string of element names, whose values we want. If not set then return all elements.
-     * @access  public
-     * @return  array   An assoc array of elements' values
-     * @throws  HTML_QuickForm_Error
-     */
-    function exportValues($elementList = null)
-    {
-        $values = array();
-        if (null === $elementList) {
-            // iterate over all elements, calling their exportValue() methods
-            foreach (array_keys($this->_elements) as $key) {
-                $value = $this->_elements[$key]->exportValue($this->_submitValues, true);
-                if (is_array($value)) {
-                    // This shit throws a bogus warning in PHP 4.3.x
-                    $values = HTML_QuickForm::arrayMerge($values, $value);
-                }
-            }
-        } else {
-            if (!is_array($elementList)) {
-                $elementList = array_map('trim', explode(',', $elementList));
-            }
-            foreach ($elementList as $elementName) {
-                $value = $this->exportValue($elementName);
-                if (PEAR::isError($value)) {
-                    return $value;
-                }
-                $values[$elementName] = $value;
-            }
-        }
-        return $values;
-    }
-
-    // }}}
-    // {{{ isSubmitted()
-
-   /**
-    * Tells whether the form was already submitted
-    *
-    * This is useful since the _submitFiles and _submitValues arrays
-    * may be completely empty after the trackSubmit value is removed.
-    *
-    * @access public
-    * @return bool
-    */
-    function isSubmitted()
-    {
-        return $this->_flagSubmitted;
-    }
-
-
-    // }}}
-    // {{{ isError()
-
-    /**
-     * Tell whether a result from a QuickForm method is an error (an instance of HTML_QuickForm_Error)
-     *
-     * @access public
-     * @param mixed     result code
-     * @return bool     whether $value is an error
-     * @static
-     */
-    function isError($value)
-    {
-        return (is_object($value) && is_a($value, 'html_quickform_error'));
-    } // end func isError
-
-    // }}}
-    // {{{ errorMessage()
-
-    /**
-     * Return a textual error message for an QuickForm error code
-     *
-     * @access  public
-     * @param   int     error code
-     * @return  string  error message
-     * @static
-     */
-    function errorMessage($value)
-    {
-        // make the variable static so that it only has to do the defining on the first call
-        static $errorMessages;
-
-        // define the varies error messages
-        if (!isset($errorMessages)) {
-            $errorMessages = array(
-                QUICKFORM_OK                    => 'no error',
-                QUICKFORM_ERROR                 => 'unknown error',
-                QUICKFORM_INVALID_RULE          => 'the rule does not exist as a registered rule',
-                QUICKFORM_NONEXIST_ELEMENT      => 'nonexistent html element',
-                QUICKFORM_INVALID_FILTER        => 'invalid filter',
-                QUICKFORM_UNREGISTERED_ELEMENT  => 'unregistered element',
-                QUICKFORM_INVALID_ELEMENT_NAME  => 'element already exists',
-                QUICKFORM_INVALID_PROCESS       => 'process callback does not exist',
-                QUICKFORM_DEPRECATED            => 'method is deprecated',
-                QUICKFORM_INVALID_DATASOURCE    => 'datasource is not an object'
-            );
-        }
-
-        // If this is an error object, then grab the corresponding error code
-        if (HTML_QuickForm::isError($value)) {
-            $value = $value->getCode();
-        }
-
-        // return the textual error message corresponding to the code
-        return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[QUICKFORM_ERROR];
-    } // end func errorMessage
-
-    // }}}
-} // end class HTML_QuickForm
-
-/**
- * Class for errors thrown by HTML_QuickForm package
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- */
-class HTML_QuickForm_Error extends PEAR_Error {
-
-    // {{{ properties
-
-    /**
-    * Prefix for all error messages
-    * @var string
-    */
-    var $error_message_prefix = 'QuickForm Error: ';
-
-    // }}}
-    // {{{ constructor
-
-    /**
-    * Creates a quickform error object, extending the PEAR_Error class
-    *
-    * @param int   $code the error code
-    * @param int   $mode the reaction to the error, either return, die or trigger/callback
-    * @param int   $level intensity of the error (PHP error code)
-    * @param mixed $debuginfo any information that can inform user as to nature of the error
-    */
-    function HTML_QuickForm_Error($code = QUICKFORM_ERROR, $mode = PEAR_ERROR_RETURN,
-                         $level = E_USER_NOTICE, $debuginfo = null)
-    {
-        if (is_int($code)) {
-            $this->PEAR_Error(HTML_QuickForm::errorMessage($code), $code, $mode, $level, $debuginfo);
-        } else {
-            $this->PEAR_Error("Invalid error code: $code", QUICKFORM_ERROR, $mode, $level, $debuginfo);
-        }
-    }
-
-    // }}}
-} // end class HTML_QuickForm_Error
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/DHTMLRulesTableless.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/DHTMLRulesTableless.php
deleted file mode 100644 (file)
index e0a8823..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-<?php
-/**
- * DHTML replacement for the standard JavaScript alert window for client-side
- * validation
- *
- * LICENSE:
- * 
- * Copyright (c) 2005-2007, Mark Wiesemann <wiesemann@php.net>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the 
- *      documentation and/or other materials provided with the distribution.
- *    * The names of the authors may not be used to endorse or promote products 
- *      derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category   HTML
- * @package    HTML_QuickForm_DHTMLRulesTableless
- * @author     Alexey Borzov <borz_off@cs.msu.su>
- * @author     Adam Daniel <adaniel1@eesus.jnj.com>
- * @author     Bertrand Mansion <bmansion@mamasam.com>
- * @author     Justin Patrin <papercrane@gmail.com>
- * @author     Mark Wiesemann <wiesemann@php.net>
- * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version    CVS: $Id: DHTMLRulesTableless.php,v 1.10 2007/10/24 20:36:11 wiesemann Exp $
- * @link       http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless
- */
-
-require_once 'HTML/QuickForm.php';
-
-/**
- * This is a DHTML replacement for the standard JavaScript alert window for
- * client-side validation of forms built with HTML_QuickForm
- *
- * @category   HTML
- * @package    HTML_QuickForm_DHTMLRulesTableless
- * @author     Alexey Borzov <borz_off@cs.msu.su>
- * @author     Adam Daniel <adaniel1@eesus.jnj.com>
- * @author     Bertrand Mansion <bmansion@mamasam.com>
- * @author     Justin Patrin <papercrane@gmail.com>
- * @author     Mark Wiesemann <wiesemann@php.net>
- * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version    Release: 0.3.3
- * @link       http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless
- */
-class HTML_QuickForm_DHTMLRulesTableless extends HTML_QuickForm {
-    // {{{ getValidationScript()
-
-    /**
-     * Returns the client side validation script
-     *
-     * The code here was copied from HTML_QuickForm and slightly modified to run rules per-element
-     *
-     * @access    public
-     * @return    string    Javascript to perform validation, empty string if no 'client' rules were added
-     */
-    function getValidationScript()
-    {
-        if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
-            return '';
-        }
-
-        include_once('HTML/QuickForm/RuleRegistry.php');
-        $registry =& HTML_QuickForm_RuleRegistry::singleton();
-        $test = array();
-        $js_escape = array(
-            "\r"    => '\r',
-            "\n"    => '\n',
-            "\t"    => '\t',
-            "'"     => "\\'",
-            '"'     => '\"',
-            '\\'    => '\\\\'
-        );
-
-        foreach ($this->_rules as $elementName => $rules) {
-            foreach ($rules as $rule) {
-                if ('client' == $rule['validation']) {
-                    unset($element);
-
-                    $dependent  = isset($rule['dependent']) && is_array($rule['dependent']);
-                    $rule['message'] = strtr($rule['message'], $js_escape);
-
-                    if (isset($rule['group'])) {
-                        $group    =& $this->getElement($rule['group']);
-                        // No JavaScript validation for frozen elements
-                        if ($group->isFrozen()) {
-                            continue 2;
-                        }
-                        $elements =& $group->getElements();
-                        foreach (array_keys($elements) as $key) {
-                            if ($elementName == $group->getElementName($key)) {
-                                $element =& $elements[$key];
-                                break;
-                            }
-                        }
-                    } elseif ($dependent) {
-                        $element   =  array();
-                        $element[] =& $this->getElement($elementName);
-                        foreach ($rule['dependent'] as $idx => $elName) {
-                            $element[] =& $this->getElement($elName);
-                        }
-                    } else {
-                        $element =& $this->getElement($elementName);
-                    }
-                    // No JavaScript validation for frozen elements
-                    if (is_object($element) && $element->isFrozen()) {
-                        continue 2;
-                    } elseif (is_array($element)) {
-                        foreach (array_keys($element) as $key) {
-                            if ($element[$key]->isFrozen()) {
-                                continue 3;
-                            }
-                        }
-                    }
-
-                    $test[$elementName][] = $registry->getValidationScript($element, $elementName, $rule);
-                }
-            }
-        }
-        $js = '
-<script type="text/javascript"><!--//--><![CDATA[//><!--
-qf_errorHandler = function(element, _qfMsg) {
-  div = element.parentNode;
-  var elementName = element.name.replace(/\[/, "_____");
-  var elementName = elementName.replace(/\]/, "_____");
-  if (_qfMsg != \'\') {
-    span = document.createElement("span");
-    span.className = "error";
-    _qfMsg = _qfMsg.substring(4);
-    span.appendChild(document.createTextNode(_qfMsg));
-    br = document.createElement("br");
-
-    var errorDiv = document.getElementById(elementName + \'_errorDiv\');
-    if (!errorDiv) {
-      errorDiv = document.createElement("div");
-      errorDiv.id = elementName + \'_errorDiv\';
-    } else {
-      if (   div.firstChild.textContent == \'\'
-          || _qfMsg == div.firstChild.textContent
-         ) {
-        return false;
-      }
-    }
-    while (errorDiv.firstChild) {
-      errorDiv.removeChild(errorDiv.firstChild);
-    }
-
-    errorDiv.insertBefore(br, errorDiv.firstChild);
-    errorDiv.insertBefore(span, errorDiv.firstChild);
-
-    errorDivInserted = false;
-    for (var i = element.parentNode.childNodes.length - 1; i >= 0; i--) {
-      j = i - 1;
-      if (j >= 0 && element.parentNode.childNodes[j].nodeName == "DIV") {
-        element.parentNode.insertBefore(errorDiv, element.parentNode.childNodes[i]);
-        errorDivInserted = true;
-        break;
-      }
-    }
-    if (!errorDivInserted) {
-      element.parentNode.insertBefore(errorDiv, element.parentNode.firstChild);
-    }
-
-    if (div.className.substr(div.className.length - 6, 6) != " error"
-        && div.className != "error") {
-      div.className += " error";
-    }
-
-    return false;
-  } else {
-    var errorDiv = document.getElementById(elementName + \'_errorDiv\');
-    if (errorDiv) {
-      errorDiv.parentNode.removeChild(errorDiv);
-    }
-    
-    // do not remove the error style from the div tag if there is still an error
-    // message
-    if (div.firstChild.innerHTML != "") {
-      return true;
-    }
-
-    if (div.className.substr(div.className.length - 6, 6) == " error") {
-      div.className = div.className.substr(0, div.className.length - 6);
-    } else if (div.className == "error") {
-      div.className = "";
-    }
-
-    return true;
-  }
-}';
-        $validateJS = '';
-        foreach ($test as $elementName => $jsArr) {
-            // remove group element part of the element name to avoid JS errors
-            $singleElementName = $elementName;
-            $shortNameForJS = str_replace(array('[', ']'), '__', $elementName);
-            $bracketPos = strpos($elementName, '[');
-            if ($bracketPos !== false) {
-                $singleElementName = substr($elementName, 0, $bracketPos);
-                $groupElementName = substr($elementName, $bracketPos + 1, -1);
-            }
-            if ($bracketPos === false || !$this->elementExists($singleElementName)) {
-                $groupElementName = $elementName;
-                $singleElementName = $elementName;
-            }
-            $id = str_replace('-', '_', $this->_attributes['id']);
-            $js .= '
-validate_' . $id . '_' . $shortNameForJS . ' = function(element) {
-  var value = \'\';
-  var errFlag = new Array();
-  var _qfGroups = {};
-  var _qfMsg = \'\';
-  var frm = element.parentNode;
-  while (frm && frm.nodeName != "FORM") {
-    frm = frm.parentNode;
-  }
-' . join("\n", $jsArr) . '
-  return qf_errorHandler(element, _qfMsg);
-}
-';
-            unset($element);
-            $element =& $this->getElement($singleElementName);
-            $elementNameForJS = 'frm.elements[\'' . $elementName . '\']';
-            if ($element->getType() === 'group' && $singleElementName === $elementName) {
-                $elementNameForJS = 'document.getElementById(\'' . $element->_elements[0]->getAttribute('id') . '\')';
-            }
-            $validateJS .= '
-  ret = validate_' . $id . '_' . $shortNameForJS . '('. $elementNameForJS . ') && ret;';
-            if ($element->getType() !== 'group') {  // not a group
-                $valFunc = 'validate_' . $id . '_' . $shortNameForJS . '(this)';
-                $onBlur = $element->getAttribute('onBlur');
-                $onChange = $element->getAttribute('onChange');
-                $element->updateAttributes(array('onBlur' => $onBlur . $valFunc,
-                                                 'onChange' => $onChange . $valFunc));
-            } else {  // group
-                $elements =& $element->getElements();
-                for ($i = 0; $i < count($elements); $i++) {
-                    // $groupElementName is a substring of attribute name of the element
-                    if (strpos($elements[$i]->getAttribute('name'), $groupElementName) === 0) {
-                        $valFunc = 'validate_' . $id . '_' . $shortNameForJS . '(this)';
-                        $onBlur = $elements[$i]->getAttribute('onBlur');
-                        $onChange = $elements[$i]->getAttribute('onChange');
-                        $elements[$i]->updateAttributes(array('onBlur'   => $onBlur . $valFunc,
-                                                              'onChange' => $onChange . $valFunc));
-                    }
-                }
-            }
-        }
-        $js .= '
-validate_' . $id . ' = function(frm) {
-  var ret = true;
-' . $validateJS . ';
-  return ret;
-}
-//--><!]]></script>';
-        return $js;
-    } // end func getValidationScript
-
-    // }}}
-
-    function display() {
-        $this->getValidationScript();
-        return parent::display();
-    }
-}
-
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/PageDHTMLRulesTableless.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/PageDHTMLRulesTableless.php
deleted file mode 100644 (file)
index 6d42150..0000000
+++ /dev/null
@@ -1,296 +0,0 @@
-<?php
-/**
- * DHTML replacement for the standard JavaScript alert window for client-side
- * validation
- *
- * LICENSE:
- * 
- * Copyright (c) 2005-2007, Mark Wiesemann <wiesemann@php.net>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the 
- *      documentation and/or other materials provided with the distribution.
- *    * The names of the authors may not be used to endorse or promote products 
- *      derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category   HTML
- * @package    HTML_QuickForm_DHTMLRulesTableless
- * @author     Alexey Borzov <borz_off@cs.msu.su>
- * @author     Adam Daniel <adaniel1@eesus.jnj.com>
- * @author     Bertrand Mansion <bmansion@mamasam.com>
- * @author     Justin Patrin <papercrane@gmail.com>
- * @author     Mark Wiesemann <wiesemann@php.net>
- * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version    CVS: $Id: PageDHTMLRulesTableless.php,v 1.3 2007/10/24 20:36:11 wiesemann Exp $
- * @link       http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless
- */
-
-require_once 'HTML/QuickForm/Page.php';
-
-/**
- * This is a DHTML replacement for the standard JavaScript alert window for
- * client-side validation of forms built with HTML_QuickForm
- *
- * @category   HTML
- * @package    HTML_QuickForm_DHTMLRulesTableless
- * @author     Alexey Borzov <borz_off@cs.msu.su>
- * @author     Adam Daniel <adaniel1@eesus.jnj.com>
- * @author     Bertrand Mansion <bmansion@mamasam.com>
- * @author     Justin Patrin <papercrane@gmail.com>
- * @author     Mark Wiesemann <wiesemann@php.net>
- * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version    Release: 0.3.3
- * @link       http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless
- */
-class HTML_QuickForm_PageDHTMLRulesTableless extends HTML_QuickForm_Page
-{
-   /**
-    * Class constructor
-    * 
-    * @access public
-    */
-    function HTML_QuickForm_PageDHTMLRulesTableless($formName, $method = 'post',
-        $target = '', $attributes = null)
-    {
-        $this->HTML_QuickForm_Page($formName, $method, '', $target, $attributes);
-    }
-
-    // {{{ getValidationScript()
-
-    /**
-     * Returns the client side validation script
-     *
-     * The code here was copied from HTML_QuickForm and slightly modified to run rules per-element
-     *
-     * @access    public
-     * @return    string    Javascript to perform validation, empty string if no 'client' rules were added
-     */
-    function getValidationScript()
-    {
-        if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
-            return '';
-        }
-
-        include_once('HTML/QuickForm/RuleRegistry.php');
-        $registry =& HTML_QuickForm_RuleRegistry::singleton();
-        $test = array();
-        $js_escape = array(
-            "\r"    => '\r',
-            "\n"    => '\n',
-            "\t"    => '\t',
-            "'"     => "\\'",
-            '"'     => '\"',
-            '\\'    => '\\\\'
-        );
-
-        foreach ($this->_rules as $elementName => $rules) {
-            foreach ($rules as $rule) {
-                if ('client' == $rule['validation']) {
-                    unset($element);
-
-                    $dependent  = isset($rule['dependent']) && is_array($rule['dependent']);
-                    $rule['message'] = strtr($rule['message'], $js_escape);
-
-                    if (isset($rule['group'])) {
-                        $group    =& $this->getElement($rule['group']);
-                        // No JavaScript validation for frozen elements
-                        if ($group->isFrozen()) {
-                            continue 2;
-                        }
-                        $elements =& $group->getElements();
-                        foreach (array_keys($elements) as $key) {
-                            if ($elementName == $group->getElementName($key)) {
-                                $element =& $elements[$key];
-                                break;
-                            }
-                        }
-                    } elseif ($dependent) {
-                        $element   =  array();
-                        $element[] =& $this->getElement($elementName);
-                        foreach ($rule['dependent'] as $idx => $elName) {
-                            $element[] =& $this->getElement($elName);
-                        }
-                    } else {
-                        $element =& $this->getElement($elementName);
-                    }
-                    // No JavaScript validation for frozen elements
-                    if (is_object($element) && $element->isFrozen()) {
-                        continue 2;
-                    } elseif (is_array($element)) {
-                        foreach (array_keys($element) as $key) {
-                            if ($element[$key]->isFrozen()) {
-                                continue 3;
-                            }
-                        }
-                    }
-
-                    $test[$elementName][] = $registry->getValidationScript($element, $elementName, $rule);
-                }
-            }
-        }
-        $js = '
-<script type="text/javascript"><!--//--><![CDATA[//><!--
-qf_errorHandler = function(element, _qfMsg) {
-  div = element.parentNode;
-  var elementName = element.name.replace(/\[/, "_____");
-  var elementName = elementName.replace(/\]/, "_____");
-  if (_qfMsg != \'\') {
-    span = document.createElement("span");
-    span.className = "error";
-    _qfMsg = _qfMsg.substring(4);
-    span.appendChild(document.createTextNode(_qfMsg));
-    br = document.createElement("br");
-
-    var errorDiv = document.getElementById(elementName + \'_errorDiv\');
-    if (!errorDiv) {
-      errorDiv = document.createElement("div");
-      errorDiv.id = elementName + \'_errorDiv\';
-    } else {
-      if (   div.firstChild.textContent == \'\'
-          || _qfMsg == div.firstChild.textContent
-         ) {
-        return false;
-      }
-    }
-    while (errorDiv.firstChild) {
-      errorDiv.removeChild(errorDiv.firstChild);
-    }
-
-    errorDiv.insertBefore(br, errorDiv.firstChild);
-    errorDiv.insertBefore(span, errorDiv.firstChild);
-
-    errorDivInserted = false;
-    for (var i = element.parentNode.childNodes.length - 1; i >= 0; i--) {
-      j = i - 1;
-      if (j >= 0 && element.parentNode.childNodes[j].nodeName == "DIV") {
-        element.parentNode.insertBefore(errorDiv, element.parentNode.childNodes[i]);
-        errorDivInserted = true;
-        break;
-      }
-    }
-    if (!errorDivInserted) {
-      element.parentNode.insertBefore(errorDiv, element.parentNode.firstChild);
-    }
-
-    if (div.className.substr(div.className.length - 6, 6) != " error"
-        && div.className != "error") {
-      div.className += " error";
-    }
-
-    return false;
-  } else {
-    var errorDiv = document.getElementById(elementName + \'_errorDiv\');
-    if (errorDiv) {
-      errorDiv.parentNode.removeChild(errorDiv);
-    }
-    
-    // do not remove the error style from the div tag if there is still an error
-    // message
-    if (div.firstChild.innerHTML != "") {
-      return true;
-    }
-
-    if (div.className.substr(div.className.length - 6, 6) == " error") {
-      div.className = div.className.substr(0, div.className.length - 6);
-    } else if (div.className == "error") {
-      div.className = "";
-    }
-
-    return true;
-  }
-}';
-        $validateJS = '';
-        foreach ($test as $elementName => $jsArr) {
-            // remove group element part of the element name to avoid JS errors
-            $singleElementName = $elementName;
-            $shortNameForJS = str_replace(array('[', ']'), '__', $elementName);
-            $bracketPos = strpos($elementName, '[');
-            if ($bracketPos !== false) {
-                $singleElementName = substr($elementName, 0, $bracketPos);
-                $groupElementName = substr($elementName, $bracketPos + 1, -1);
-            }
-            if ($bracketPos === false || !$this->elementExists($singleElementName)) {
-                $groupElementName = $elementName;
-                $singleElementName = $elementName;
-            }
-            $id = str_replace('-', '_', $this->_attributes['id']);
-            $js .= '
-validate_' . $id . '_' . $shortNameForJS . ' = function(element) {
-  var value = \'\';
-  var errFlag = new Array();
-  var _qfGroups = {};
-  var _qfMsg = \'\';
-  var frm = element.parentNode;
-  while (frm && frm.nodeName != "FORM") {
-    frm = frm.parentNode;
-  }
-' . join("\n", $jsArr) . '
-  return qf_errorHandler(element, _qfMsg);
-}
-';
-            unset($element);
-            $element =& $this->getElement($singleElementName);
-            $elementNameForJS = 'frm.elements[\'' . $elementName . '\']';
-            if ($element->getType() === 'group' && $singleElementName === $elementName) {
-                $elementNameForJS = 'document.getElementById(\'' . $element->_elements[0]->getAttribute('id') . '\')';
-            }
-            $validateJS .= '
-  ret = validate_' . $id . '_' . $shortNameForJS . '('. $elementNameForJS . ') && ret;';
-            if ($element->getType() !== 'group') {  // not a group
-                $valFunc = 'validate_' . $id . '_' . $shortNameForJS . '(this)';
-                $onBlur = $element->getAttribute('onBlur');
-                $onChange = $element->getAttribute('onChange');
-                $element->updateAttributes(array('onBlur' => $onBlur . $valFunc,
-                                                 'onChange' => $onChange . $valFunc));
-            } else {  // group
-                $elements =& $element->getElements();
-                for ($i = 0; $i < count($elements); $i++) {
-                    // $groupElementName is a substring of attribute name of the element
-                    if (strpos($elements[$i]->getAttribute('name'), $groupElementName) === 0) {
-                        $valFunc = 'validate_' . $id . '_' . $shortNameForJS . '(this)';
-                        $onBlur = $elements[$i]->getAttribute('onBlur');
-                        $onChange = $elements[$i]->getAttribute('onChange');
-                        $elements[$i]->updateAttributes(array('onBlur'   => $onBlur . $valFunc,
-                                                              'onChange' => $onChange . $valFunc));
-                    }
-                }
-            }
-        }
-        $js .= '
-validate_' . $id . ' = function (frm) {
-  var ret = true;
-' . $validateJS . ';
-  return ret;
-}
-//--><!]]></script>';
-        return $js;
-    } // end func getValidationScript
-
-    // }}}
-
-    function display() {
-        $this->getValidationScript();
-        return parent::display();
-    }
-}
-
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer.php
deleted file mode 100644 (file)
index 3a20504..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * An abstract base class for QuickForm renderers
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * An abstract base class for QuickForm renderers
- * 
- * The class implements a Visitor design pattern
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.0
- * @abstract
- */
-class HTML_QuickForm_Renderer
-{
-   /**
-    * Constructor
-    *
-    * @access public
-    */
-    function HTML_QuickForm_Renderer()
-    {
-    } // end constructor
-
-   /**
-    * Called when visiting a form, before processing any form elements
-    *
-    * @param    HTML_QuickForm  a form being visited
-    * @access   public
-    * @return   void 
-    * @abstract
-    */
-    function startForm(&$form)
-    {
-        return;
-    } // end func startForm
-
-   /**
-    * Called when visiting a form, after processing all form elements
-    * 
-    * @param    HTML_QuickForm  a form being visited
-    * @access   public
-    * @return   void 
-    * @abstract
-    */
-    function finishForm(&$form)
-    {
-        return;
-    } // end func finishForm
-
-   /**
-    * Called when visiting a header element
-    *
-    * @param    HTML_QuickForm_header   a header element being visited
-    * @access   public
-    * @return   void 
-    * @abstract
-    */
-    function renderHeader(&$header)
-    {
-        return;
-    } // end func renderHeader
-
-   /**
-    * Called when visiting an element
-    *
-    * @param    HTML_QuickForm_element  form element being visited
-    * @param    bool                    Whether an element is required
-    * @param    string                  An error message associated with an element
-    * @access   public
-    * @return   void 
-    * @abstract
-    */
-    function renderElement(&$element, $required, $error)
-    {
-        return;
-    } // end func renderElement
-
-   /**
-    * Called when visiting a hidden element
-    * 
-    * @param    HTML_QuickForm_element  a hidden element being visited
-    * @access   public
-    * @return   void
-    * @abstract 
-    */
-    function renderHidden(&$element)
-    {
-        return;
-    } // end func renderHidden
-
-   /**
-    * Called when visiting a raw HTML/text pseudo-element
-    * 
-    * Only implemented in Default renderer. Usage of 'html' elements is 
-    * discouraged, templates should be used instead.
-    *
-    * @param    HTML_QuickForm_html     a 'raw html' element being visited
-    * @access   public
-    * @return   void 
-    * @abstract
-    */
-    function renderHtml(&$data)
-    {
-        return;
-    } // end func renderHtml
-
-   /**
-    * Called when visiting a group, before processing any group elements
-    *
-    * @param    HTML_QuickForm_group    A group being visited
-    * @param    bool                    Whether a group is required
-    * @param    string                  An error message associated with a group
-    * @access   public
-    * @return   void 
-    * @abstract
-    */
-    function startGroup(&$group, $required, $error)
-    {
-        return;
-    } // end func startGroup
-
-   /**
-    * Called when visiting a group, after processing all group elements
-    *
-    * @param    HTML_QuickForm_group    A group being visited
-    * @access   public
-    * @return   void 
-    * @abstract
-    */
-    function finishGroup(&$group)
-    {
-        return;
-    } // end func finishGroup
-} // end class HTML_QuickForm_Renderer
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Array.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Array.php
deleted file mode 100644 (file)
index 81c62e1..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A concrete renderer for HTML_QuickForm, makes an array of form contents
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Thomas Schulz <ths@4bconsult.de>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * An abstract base class for QuickForm renderers
- */
-require_once 'HTML/QuickForm/Renderer.php';
-
-/**
- * A concrete renderer for HTML_QuickForm, makes an array of form contents
- *
- * Based on old HTML_QuickForm::toArray() code.
- *
- * The form array structure is the following:
- * <pre>
- * array(
- *   'frozen'           => 'whether the form is frozen',
- *   'javascript'       => 'javascript for client-side validation',
- *   'attributes'       => 'attributes for <form> tag',
- *   'requirednote      => 'note about the required elements',
- *   // if we set the option to collect hidden elements
- *   'hidden'           => 'collected html of all hidden elements',
- *   // if there were some validation errors:
- *   'errors' => array(
- *     '1st element name' => 'Error for the 1st element',
- *     ...
- *     'nth element name' => 'Error for the nth element'
- *   ),
- *   // if there are no headers in the form:
- *   'elements' => array(
- *     element_1,
- *     ...
- *     element_N
- *   )
- *   // if there are headers in the form:
- *   'sections' => array(
- *     array(
- *       'header'   => 'Header text for the first header',
- *       'name'     => 'Header name for the first header',
- *       'elements' => array(
- *          element_1,
- *          ...
- *          element_K1
- *       )
- *     ),
- *     ...
- *     array(
- *       'header'   => 'Header text for the Mth header',
- *       'name'     => 'Header name for the Mth header',
- *       'elements' => array(
- *          element_1,
- *          ...
- *          element_KM
- *       )
- *     )
- *   )
- * );
- * </pre>
- *
- * where element_i is an array of the form:
- * <pre>
- * array(
- *   'name'      => 'element name',
- *   'value'     => 'element value',
- *   'type'      => 'type of the element',
- *   'frozen'    => 'whether element is frozen',
- *   'label'     => 'label for the element',
- *   'required'  => 'whether element is required',
- *   'error'     => 'error associated with the element',
- *   'style'     => 'some information about element style (e.g. for Smarty)',
- *   // if element is not a group
- *   'html'      => 'HTML for the element'
- *   // if element is a group
- *   'separator' => 'separator for group elements',
- *   'elements'  => array(
- *     element_1,
- *     ...
- *     element_N
- *   )
- * );
- * </pre>
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Thomas Schulz <ths@4bconsult.de>
- * @version     Release: 3.2.16
- * @since       3.0
- */
-class HTML_QuickForm_Renderer_Array extends HTML_QuickForm_Renderer
-{
-   /**#@+
-    * @access private
-    */
-   /**
-    * An array being generated
-    * @var array
-    */
-    var $_ary;
-
-   /**
-    * Number of sections in the form (i.e. number of headers in it)
-    * @var integer
-    */
-    var $_sectionCount;
-
-   /**
-    * Current section number
-    * @var integer
-    */
-    var $_currentSection;
-
-   /**
-    * Array representing current group
-    * @var array
-    */
-    var $_currentGroup = null;
-
-   /**
-    * Additional style information for different elements
-    * @var array
-    */
-    var $_elementStyles = array();
-
-   /**
-    * true: collect all hidden elements into string; false: process them as usual form elements
-    * @var bool
-    */
-    var $_collectHidden = false;
-
-   /**
-    * true:  render an array of labels to many labels, $key 0 named 'label', the rest "label_$key"
-    * false: leave labels as defined
-    * @var bool
-    */
-    var $_staticLabels = false;
-   /**#@-*/
-
-   /**
-    * Constructor
-    *
-    * @param  bool    true: collect all hidden elements into string; false: process them as usual form elements
-    * @param  bool    true: render an array of labels to many labels, $key 0 to 'label' and the oterh to "label_$key"
-    * @access public
-    */
-    function HTML_QuickForm_Renderer_Array($collectHidden = false, $staticLabels = false)
-    {
-        $this->HTML_QuickForm_Renderer();
-        $this->_collectHidden = $collectHidden;
-        $this->_staticLabels  = $staticLabels;
-    } // end constructor
-
-
-   /**
-    * Returns the resultant array
-    *
-    * @access public
-    * @return array
-    */
-    function toArray()
-    {
-        return $this->_ary;
-    }
-
-
-    function startForm(&$form)
-    {
-        $this->_ary = array(
-            'frozen'            => $form->isFrozen(),
-            'javascript'        => $form->getValidationScript(),
-            'attributes'        => $form->getAttributes(true),
-            'requirednote'      => $form->getRequiredNote(),
-            'errors'            => array()
-        );
-        if ($this->_collectHidden) {
-            $this->_ary['hidden'] = '';
-        }
-        $this->_elementIdx     = 1;
-        $this->_currentSection = null;
-        $this->_sectionCount   = 0;
-    } // end func startForm
-
-
-    function renderHeader(&$header)
-    {
-        $this->_ary['sections'][$this->_sectionCount] = array(
-            'header' => $header->toHtml(),
-            'name'   => $header->getName()
-        );
-        $this->_currentSection = $this->_sectionCount++;
-    } // end func renderHeader
-
-
-    function renderElement(&$element, $required, $error)
-    {
-        $elAry = $this->_elementToArray($element, $required, $error);
-        if (!empty($error)) {
-            $this->_ary['errors'][$elAry['name']] = $error;
-        }
-        $this->_storeArray($elAry);
-    } // end func renderElement
-
-
-    function renderHidden(&$element)
-    {
-        if ($this->_collectHidden) {
-            $this->_ary['hidden'] .= $element->toHtml() . "\n";
-        } else {
-            $this->renderElement($element, false, null);
-        }
-    } // end func renderHidden
-
-
-    function startGroup(&$group, $required, $error)
-    {
-        $this->_currentGroup = $this->_elementToArray($group, $required, $error);
-        if (!empty($error)) {
-            $this->_ary['errors'][$this->_currentGroup['name']] = $error;
-        }
-    } // end func startGroup
-
-
-    function finishGroup(&$group)
-    {
-        $this->_storeArray($this->_currentGroup);
-        $this->_currentGroup = null;
-    } // end func finishGroup
-
-
-   /**
-    * Creates an array representing an element
-    *
-    * @access private
-    * @param  HTML_QuickForm_element    element being processed
-    * @param  bool                      Whether an element is required
-    * @param  string                    Error associated with the element
-    * @return array
-    */
-    function _elementToArray(&$element, $required, $error)
-    {
-        $ret = array(
-            'name'      => $element->getName(),
-            'value'     => $element->getValue(),
-            'type'      => $element->getType(),
-            'frozen'    => $element->isFrozen(),
-            'required'  => $required,
-            'error'     => $error
-        );
-        // render label(s)
-        $labels = $element->getLabel();
-        if (is_array($labels) && $this->_staticLabels) {
-            foreach($labels as $key => $label) {
-                $key = is_int($key)? $key + 1: $key;
-                if (1 === $key) {
-                    $ret['label'] = $label;
-                } else {
-                    $ret['label_' . $key] = $label;
-                }
-            }
-        } else {
-            $ret['label'] = $labels;
-        }
-
-        // set the style for the element
-        if (isset($this->_elementStyles[$ret['name']])) {
-            $ret['style'] = $this->_elementStyles[$ret['name']];
-        }
-        if ('group' == $ret['type']) {
-            $ret['separator'] = $element->_separator;
-            $ret['elements']  = array();
-        } else {
-            $ret['html']      = $element->toHtml();
-        }
-        return $ret;
-    }
-
-
-   /**
-    * Stores an array representation of an element in the form array
-    *
-    * @access private
-    * @param array  Array representation of an element
-    * @return void
-    */
-    function _storeArray($elAry)
-    {
-        // where should we put this element...
-        if (is_array($this->_currentGroup) && ('group' != $elAry['type'])) {
-            $this->_currentGroup['elements'][] = $elAry;
-        } elseif (isset($this->_currentSection)) {
-            $this->_ary['sections'][$this->_currentSection]['elements'][] = $elAry;
-        } else {
-            $this->_ary['elements'][] = $elAry;
-        }
-    }
-
-
-   /**
-    * Sets a style to use for element rendering
-    *
-    * @param mixed      element name or array ('element name' => 'style name')
-    * @param string     style name if $elementName is not an array
-    * @access public
-    * @return void
-    */
-    function setElementStyle($elementName, $styleName = null)
-    {
-        if (is_array($elementName)) {
-            $this->_elementStyles = array_merge($this->_elementStyles, $elementName);
-        } else {
-            $this->_elementStyles[$elementName] = $styleName;
-        }
-    }
-}
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ArraySmarty.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ArraySmarty.php
deleted file mode 100644 (file)
index d1e20f1..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A static renderer for HTML_QuickForm, makes an array of form content
- * useful for a Smarty template
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Thomas Schulz <ths@4bconsult.de>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * A concrete renderer for HTML_QuickForm, makes an array of form contents
- */ 
-require_once 'HTML/QuickForm/Renderer/Array.php';
-
-/**
- * A static renderer for HTML_QuickForm, makes an array of form content
- * useful for a Smarty template
- *
- * Based on old HTML_QuickForm::toArray() code and ITStatic renderer.
- *
- * The form array structure is the following:
- * <pre>
- * Array (
- *  [frozen]       => whether the complete form is frozen'
- *  [javascript]   => javascript for client-side validation
- *  [attributes]   => attributes for <form> tag
- *  [hidden]       => html of all hidden elements
- *  [requirednote] => note about the required elements
- *  [errors] => Array
- *      (
- *          [1st_element_name] => Error for the 1st element
- *          ...
- *          [nth_element_name] => Error for the nth element
- *      )
- *
- *  [header] => Array
- *      (
- *          [1st_header_name] => Header text for the 1st header
- *          ...
- *          [nth_header_name] => Header text for the nth header
- *      )
- *
- *  [1st_element_name] => Array for the 1st element
- *  ...
- *  [nth_element_name] => Array for the nth element
- * </pre>
- *
- * where an element array has the form:
- * <pre>
- *      (
- *          [name]      => element name
- *          [value]     => element value,
- *          [type]      => type of the element
- *          [frozen]    => whether element is frozen
- *          [label]     => label for the element
- *          [required]  => whether element is required
- * // if element is not a group:
- *          [html]      => HTML for the element
- * // if element is a group:
- *          [separator] => separator for group elements
- *          [1st_gitem_name] => Array for the 1st element in group
- *          ...
- *          [nth_gitem_name] => Array for the nth element in group
- *      )
- * )
- * </pre>
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Thomas Schulz <ths@4bconsult.de>
- * @version     Release: 3.2.16
- * @since       3.0
- */
-class HTML_QuickForm_Renderer_ArraySmarty extends HTML_QuickForm_Renderer_Array
-{
-   /**#@+
-    * @access private
-    */
-   /**
-    * The Smarty template engine instance
-    * @var object
-    */
-    var $_tpl = null;
-
-   /**
-    * Current element index
-    * @var integer
-    */
-    var $_elementIdx = 0;
-
-    /**
-    * The current element index inside a group
-    * @var integer
-    */
-    var $_groupElementIdx = 0;
-
-   /**
-    * How to handle the required tag for required fields
-    * @var string
-    * @see      setRequiredTemplate()
-    */
-    var $_required = '';
-
-   /**
-    * How to handle error messages in form validation
-    * @var string
-    * @see      setErrorTemplate()
-    */
-    var $_error = '';
-   /**#@-*/
-
-   /**
-    * Constructor
-    *
-    * @param  Smarty  reference to the Smarty template engine instance
-    * @param  bool    true: render an array of labels to many labels, $key 0 to 'label' and the oterh to "label_$key"
-    * @param  bool    true: collect all hidden elements into string; false: process them as usual form elements
-    * @access public
-    */
-    function HTML_QuickForm_Renderer_ArraySmarty(&$tpl, $staticLabels = false, $collectHidden = true)
-    {
-        $this->HTML_QuickForm_Renderer_Array($collectHidden, $staticLabels);
-        $this->_tpl =& $tpl;
-    } // end constructor
-
-   /**
-    * Called when visiting a header element
-    *
-    * @param    HTML_QuickForm_header   header element being visited
-    * @access   public
-    * @return   void
-    */
-    function renderHeader(&$header)
-    {
-        if ($name = $header->getName()) {
-            $this->_ary['header'][$name] = $header->toHtml();
-        } else {
-            $this->_ary['header'][$this->_sectionCount] = $header->toHtml();
-        }
-        $this->_currentSection = $this->_sectionCount++;
-    } // end func renderHeader
-
-   /**
-    * Called when visiting a group, before processing any group elements
-    *
-    * @param    HTML_QuickForm_group    group being visited
-    * @param    bool                    Whether a group is required
-    * @param    string                  An error message associated with a group
-    * @access   public
-    * @return   void
-    */
-    function startGroup(&$group, $required, $error)
-    {
-        parent::startGroup($group, $required, $error);
-        $this->_groupElementIdx = 1;
-    } // end func startGroup
-
-   /**
-    * Creates an array representing an element containing
-    * the key for storing this
-    *
-    * @access private
-    * @param  HTML_QuickForm_element    form element being visited
-    * @param  bool                      Whether an element is required
-    * @param  string                    Error associated with the element
-    * @return array
-    */
-    function _elementToArray(&$element, $required, $error)
-    {
-        $ret = parent::_elementToArray($element, $required, $error);
-
-        if ('group' == $ret['type']) {
-            $ret['html'] = $element->toHtml();
-            // we don't need the elements, see the array structure
-            unset($ret['elements']);
-        }
-        if (($required || $error) && !empty($this->_required)){
-            $this->_renderRequired($ret['label'], $ret['html'], $required, $error);
-        }
-        if ($error && !empty($this->_error)) {
-            $this->_renderError($ret['label'], $ret['html'], $error);
-            $ret['error'] = $error;
-        }
-        // create keys for elements grouped by native group or name
-        if (strstr($ret['name'], '[') or $this->_currentGroup) {
-            // Fix for bug #8123: escape backslashes and quotes to prevent errors 
-            // in eval(). The code below seems to handle the case where element
-            // name has unbalanced square brackets. Dunno whether we really
-            // need this after the fix for #8123, but I'm wary of making big
-            // changes to this code.  
-            preg_match('/([^]]*)\\[([^]]*)\\]/', $ret['name'], $matches);
-            if (isset($matches[1])) {
-                $sKeysSub = substr_replace($ret['name'], '', 0, strlen($matches[1]));
-                $sKeysSub = str_replace(
-                    array('\\',   '\'',   '['  ,   ']', '[\'\']'),
-                    array('\\\\', '\\\'', '[\'', '\']', '[]'    ),
-                    $sKeysSub
-                );
-                $sKeys = '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $matches[1]) . '\']' . $sKeysSub;
-            } else {
-                $sKeys = '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret['name']) . '\']';
-            }
-            // special handling for elements in native groups
-            if ($this->_currentGroup) {
-                // skip unnamed group items unless radios: no name -> no static access
-                // identification: have the same key string as the parent group
-                if ($this->_currentGroup['keys'] == $sKeys and 'radio' != $ret['type']) {
-                    return false;
-                }
-                // reduce string of keys by remove leading group keys
-                if (0 === strpos($sKeys, $this->_currentGroup['keys'])) {
-                    $sKeys = substr_replace($sKeys, '', 0, strlen($this->_currentGroup['keys']));
-                }
-            }
-        // element without a name
-        } elseif ($ret['name'] == '') {
-            $sKeys = '[\'element_' . $this->_elementIdx . '\']';
-        // other elements
-        } else {
-            $sKeys = '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret['name']) . '\']';
-        }
-        // for radios: add extra key from value
-        if ('radio' == $ret['type'] and substr($sKeys, -2) != '[]') {
-            $sKeys .= '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret['value']) . '\']';
-        }
-        $this->_elementIdx++;
-        $ret['keys'] = $sKeys;
-        return $ret;
-    } // end func _elementToArray
-
-   /**
-    * Stores an array representation of an element in the form array
-    *
-    * @access private
-    * @param array  Array representation of an element
-    * @return void
-    */
-    function _storeArray($elAry)
-    {
-        if ($elAry) {
-            $sKeys = $elAry['keys'];
-            unset($elAry['keys']);
-            // where should we put this element...
-            if (is_array($this->_currentGroup) && ('group' != $elAry['type'])) {
-                $toEval = '$this->_currentGroup' . $sKeys . ' = $elAry;';
-            } else {
-                $toEval = '$this->_ary' . $sKeys . ' = $elAry;';
-            }
-            eval($toEval);
-        }
-        return;
-    }
-
-   /**
-    * Called when an element is required
-    *
-    * This method will add the required tag to the element label and/or the element html
-    * such as defined with the method setRequiredTemplate.
-    *
-    * @param    string      The element label
-    * @param    string      The element html rendering
-    * @param    boolean     The element required
-    * @param    string      The element error
-    * @see      setRequiredTemplate()
-    * @access   private
-    * @return   void
-    */
-    function _renderRequired(&$label, &$html, &$required, &$error)
-    {
-        $this->_tpl->assign(array(
-            'label'    => $label,
-            'html'     => $html,
-            'required' => $required,
-            'error'    => $error
-        ));
-        if (!empty($label) && strpos($this->_required, $this->_tpl->left_delimiter . '$label') !== false) {
-            $label = $this->_tplFetch($this->_required);
-        }
-        if (!empty($html) && strpos($this->_required, $this->_tpl->left_delimiter . '$html') !== false) {
-            $html = $this->_tplFetch($this->_required);
-        }
-        $this->_tpl->clear_assign(array('label', 'html', 'required'));
-    } // end func _renderRequired
-
-   /**
-    * Called when an element has a validation error
-    *
-    * This method will add the error message to the element label or the element html
-    * such as defined with the method setErrorTemplate. If the error placeholder is not found
-    * in the template, the error will be displayed in the form error block.
-    *
-    * @param    string      The element label
-    * @param    string      The element html rendering
-    * @param    string      The element error
-    * @see      setErrorTemplate()
-    * @access   private
-    * @return   void
-    */
-    function _renderError(&$label, &$html, &$error)
-    {
-        $this->_tpl->assign(array('label' => '', 'html' => '', 'error' => $error));
-        $error = $this->_tplFetch($this->_error);
-        $this->_tpl->assign(array('label' => $label, 'html'  => $html));
-
-        if (!empty($label) && strpos($this->_error, $this->_tpl->left_delimiter . '$label') !== false) {
-            $label = $this->_tplFetch($this->_error);
-        } elseif (!empty($html) && strpos($this->_error, $this->_tpl->left_delimiter . '$html') !== false) {
-            $html = $this->_tplFetch($this->_error);
-        }
-        $this->_tpl->clear_assign(array('label', 'html', 'error'));
-    } // end func _renderError
-
-   /**
-    * Process an template sourced in a string with Smarty
-    *
-    * Smarty has no core function to render    a template given as a string.
-    * So we use the smarty eval plugin function        to do this.
-    *
-    * @param    string      The template source
-    * @access   private
-    * @return   void
-    */
-    function _tplFetch($tplSource)
-    {
-        if (!function_exists('smarty_function_eval')) {
-            require SMARTY_DIR . '/plugins/function.eval.php';
-        }
-        return smarty_function_eval(array('var' => $tplSource), $this->_tpl);
-    }// end func _tplFetch
-
-   /**
-    * Sets the way required elements are rendered
-    *
-    * You can use {$label} or {$html} placeholders to let the renderer know where
-    * where the element label or the element html are positionned according to the
-    * required tag. They will be replaced accordingly with the right value.    You
-    * can use the full smarty syntax here, especially a custom modifier for I18N.
-    * For example:
-    * {if $required}<span style="color: red;">*</span>{/if}{$label|translate}
-    * will put a red star in front of the label if the element is required and
-    * translate the label.
-    *
-    *
-    * @param    string      The required element template
-    * @access   public
-    * @return   void
-    */
-    function setRequiredTemplate($template)
-    {
-        $this->_required = $template;
-    } // end func setRequiredTemplate
-
-   /**
-    * Sets the way elements with validation errors are rendered
-    *
-    * You can use {$label} or {$html} placeholders to let the renderer know where
-    * where the element label or the element html are positionned according to the
-    * error message. They will be replaced accordingly with the right value.
-    * The error message will replace the {$error} placeholder.
-    * For example:
-    * {if $error}<span style="color: red;">{$error}</span>{/if}<br />{$html}
-    * will put the error message in red on top of the element html.
-    *
-    * If you want all error messages to be output in the main error block, use
-    * the {$form.errors} part of the rendered array that collects all raw error
-    * messages.
-    *
-    * If you want to place all error messages manually, do not specify {$html}
-    * nor {$label}.
-    *
-    * Groups can have special layouts. With this kind of groups, you have to
-    * place the formated error message manually. In this case, use {$form.group.error}
-    * where you want the formated error message to appear in the form.
-    *
-    * @param    string      The element error template
-    * @access   public
-    * @return   void
-    */
-    function setErrorTemplate($template)
-    {
-        $this->_error = $template;
-    } // end func setErrorTemplate
-}
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Default.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Default.php
deleted file mode 100644 (file)
index 74c5ce1..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A concrete renderer for HTML_QuickForm, based on QuickForm 2.x built-in one
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * An abstract base class for QuickForm renderers
- */
-require_once 'HTML/QuickForm/Renderer.php';
-
-/**
- * A concrete renderer for HTML_QuickForm, based on QuickForm 2.x built-in one
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.0
- */
-class HTML_QuickForm_Renderer_Default extends HTML_QuickForm_Renderer
-{
-   /**
-    * The HTML of the form  
-    * @var      string
-    * @access   private
-    */
-    var $_html;
-
-   /**
-    * Header Template string
-    * @var      string
-    * @access   private
-    */
-    var $_headerTemplate = 
-        "\n\t<tr>\n\t\t<td style=\"white-space: nowrap; background-color: #CCCCCC;\" align=\"left\" valign=\"top\" colspan=\"2\"><b>{header}</b></td>\n\t</tr>";
-
-   /**
-    * Element template string
-    * @var      string
-    * @access   private
-    */
-    var $_elementTemplate = 
-        "\n\t<tr>\n\t\t<td align=\"right\" valign=\"top\"><!-- BEGIN required --><span style=\"color: #ff0000\">*</span><!-- END required --><b>{label}</b></td>\n\t\t<td valign=\"top\" align=\"left\"><!-- BEGIN error --><span style=\"color: #ff0000\">{error}</span><br /><!-- END error -->\t{element}</td>\n\t</tr>";
-
-   /**
-    * Form template string
-    * @var      string
-    * @access   private
-    */
-    var $_formTemplate = 
-        "\n<form{attributes}>\n<div>\n{hidden}<table border=\"0\">\n{content}\n</table>\n</div>\n</form>";
-
-   /**
-    * Required Note template string
-    * @var      string
-    * @access   private
-    */
-    var $_requiredNoteTemplate = 
-        "\n\t<tr>\n\t\t<td></td>\n\t<td align=\"left\" valign=\"top\">{requiredNote}</td>\n\t</tr>";
-
-   /**
-    * Array containing the templates for customised elements
-    * @var      array
-    * @access   private
-    */
-    var $_templates = array();
-
-   /**
-    * Array containing the templates for group wraps.
-    * 
-    * These templates are wrapped around group elements and groups' own
-    * templates wrap around them. This is set by setGroupTemplate().
-    * 
-    * @var      array
-    * @access   private
-    */
-    var $_groupWraps = array();
-
-   /**
-    * Array containing the templates for elements within groups
-    * @var      array
-    * @access   private
-    */
-    var $_groupTemplates = array();
-
-   /**
-    * True if we are inside a group 
-    * @var      bool
-    * @access   private
-    */
-    var $_inGroup = false;
-
-   /**
-    * Array with HTML generated for group elements
-    * @var      array
-    * @access   private
-    */
-    var $_groupElements = array();
-
-   /**
-    * Template for an element inside a group
-    * @var      string
-    * @access   private
-    */
-    var $_groupElementTemplate = '';
-
-   /**
-    * HTML that wraps around the group elements
-    * @var      string
-    * @access   private
-    */
-    var $_groupWrap = '';
-
-   /**
-    * HTML for the current group
-    * @var      string
-    * @access   private
-    */
-    var $_groupTemplate = '';
-    
-   /**
-    * Collected HTML of the hidden fields
-    * @var      string
-    * @access   private
-    */
-    var $_hiddenHtml = '';
-
-   /**
-    * Constructor
-    *
-    * @access public
-    */
-    function HTML_QuickForm_Renderer_Default()
-    {
-        $this->HTML_QuickForm_Renderer();
-    } // end constructor
-
-   /**
-    * returns the HTML generated for the form
-    *
-    * @access public
-    * @return string
-    */
-    function toHtml()
-    {
-        // _hiddenHtml is cleared in finishForm(), so this only matters when
-        // finishForm() was not called (e.g. group::toHtml(), bug #3511)
-        return $this->_hiddenHtml . $this->_html;
-    } // end func toHtml
-    
-   /**
-    * Called when visiting a form, before processing any form elements
-    *
-    * @param    HTML_QuickForm  form object being visited
-    * @access   public
-    * @return   void
-    */
-    function startForm(&$form)
-    {
-        $this->_html = '';
-        $this->_hiddenHtml = '';
-    } // end func startForm
-
-   /**
-    * Called when visiting a form, after processing all form elements
-    * Adds required note, form attributes, validation javascript and form content.
-    * 
-    * @param    HTML_QuickForm  form object being visited
-    * @access   public
-    * @return   void
-    */
-    function finishForm(&$form)
-    {
-        // add a required note, if one is needed
-        if (!empty($form->_required) && !$form->_freezeAll) {
-            $this->_html .= str_replace('{requiredNote}', $form->getRequiredNote(), $this->_requiredNoteTemplate);
-        }
-        // add form attributes and content
-        $html = str_replace('{attributes}', $form->getAttributes(true), $this->_formTemplate);
-        if (strpos($this->_formTemplate, '{hidden}')) {
-            $html = str_replace('{hidden}', $this->_hiddenHtml, $html);
-        } else {
-            $this->_html .= $this->_hiddenHtml;
-        }
-        $this->_hiddenHtml = '';
-        $this->_html = str_replace('{content}', $this->_html, $html);
-        // add a validation script
-        if ('' != ($script = $form->getValidationScript())) {
-            $this->_html = $script . "\n" . $this->_html;
-        }
-    } // end func finishForm
-      
-   /**
-    * Called when visiting a header element
-    *
-    * @param    HTML_QuickForm_header   header element being visited
-    * @access   public
-    * @return   void
-    */
-    function renderHeader(&$header)
-    {
-        $name = $header->getName();
-        if (!empty($name) && isset($this->_templates[$name])) {
-            $this->_html .= str_replace('{header}', $header->toHtml(), $this->_templates[$name]);
-        } else {
-            $this->_html .= str_replace('{header}', $header->toHtml(), $this->_headerTemplate);
-        }
-    } // end func renderHeader
-
-   /**
-    * Helper method for renderElement
-    *
-    * @param    string      Element name
-    * @param    mixed       Element label (if using an array of labels, you should set the appropriate template)
-    * @param    bool        Whether an element is required
-    * @param    string      Error message associated with the element
-    * @access   private
-    * @see      renderElement()
-    * @return   string      Html for element
-    */
-    function _prepareTemplate($name, $label, $required, $error)
-    {
-        if (is_array($label)) {
-            $nameLabel = array_shift($label);
-        } else {
-            $nameLabel = $label;
-        }
-        if (isset($this->_templates[$name])) {
-            $html = str_replace('{label}', $nameLabel, $this->_templates[$name]);
-        } else {
-            $html = str_replace('{label}', $nameLabel, $this->_elementTemplate);
-        }
-        if ($required) {
-            $html = str_replace('<!-- BEGIN required -->', '', $html);
-            $html = str_replace('<!-- END required -->', '', $html);
-        } else {
-            $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->.*<!-- END required -->([ \t\n\r]*)?/isU", '', $html);
-        }
-        if (isset($error)) {
-            $html = str_replace('{error}', $error, $html);
-            $html = str_replace('<!-- BEGIN error -->', '', $html);
-            $html = str_replace('<!-- END error -->', '', $html);
-        } else {
-            $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN error -->.*<!-- END error -->([ \t\n\r]*)?/isU", '', $html);
-        }
-        if (is_array($label)) {
-            foreach($label as $key => $text) {
-                $key  = is_int($key)? $key + 2: $key;
-                $html = str_replace("{label_{$key}}", $text, $html);
-                $html = str_replace("<!-- BEGIN label_{$key} -->", '', $html);
-                $html = str_replace("<!-- END label_{$key} -->", '', $html);
-            }
-        }
-        if (strpos($html, '{label_')) {
-            $html = preg_replace('/\s*<!-- BEGIN label_(\S+) -->.*<!-- END label_\1 -->\s*/is', '', $html);
-        }
-        return $html;
-    } // end func _prepareTemplate
-
-   /**
-    * Renders an element Html
-    * Called when visiting an element
-    *
-    * @param HTML_QuickForm_element form element being visited
-    * @param bool                   Whether an element is required
-    * @param string                 An error message associated with an element
-    * @access public
-    * @return void
-    */
-    function renderElement(&$element, $required, $error)
-    {
-        if (!$this->_inGroup) {
-            $html = $this->_prepareTemplate($element->getName(), $element->getLabel(), $required, $error);
-            $this->_html .= str_replace('{element}', $element->toHtml(), $html);
-
-        } elseif (!empty($this->_groupElementTemplate)) {
-            $html = str_replace('{label}', $element->getLabel(), $this->_groupElementTemplate);
-            if ($required) {
-                $html = str_replace('<!-- BEGIN required -->', '', $html);
-                $html = str_replace('<!-- END required -->', '', $html);
-            } else {
-                $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->.*<!-- END required -->([ \t\n\r]*)?/isU", '', $html);
-            }
-            $this->_groupElements[] = str_replace('{element}', $element->toHtml(), $html);
-
-        } else {
-            $this->_groupElements[] = $element->toHtml();
-        }
-    } // end func renderElement
-   
-   /**
-    * Renders an hidden element
-    * Called when visiting a hidden element
-    * 
-    * @param HTML_QuickForm_element     form element being visited
-    * @access public
-    * @return void
-    */
-    function renderHidden(&$element)
-    {
-        $this->_hiddenHtml .= $element->toHtml() . "\n";
-    } // end func renderHidden
-
-   /**
-    * Called when visiting a raw HTML/text pseudo-element
-    * 
-    * @param  HTML_QuickForm_html   element being visited
-    * @access public
-    * @return void
-    */
-    function renderHtml(&$data)
-    {
-        $this->_html .= $data->toHtml();
-    } // end func renderHtml
-
-   /**
-    * Called when visiting a group, before processing any group elements
-    *
-    * @param HTML_QuickForm_group   group being visited
-    * @param bool       Whether a group is required
-    * @param string     An error message associated with a group
-    * @access public
-    * @return void
-    */
-    function startGroup(&$group, $required, $error)
-    {
-        $name = $group->getName();
-        $this->_groupTemplate        = $this->_prepareTemplate($name, $group->getLabel(), $required, $error);
-        $this->_groupElementTemplate = empty($this->_groupTemplates[$name])? '': $this->_groupTemplates[$name];
-        $this->_groupWrap            = empty($this->_groupWraps[$name])? '': $this->_groupWraps[$name];
-        $this->_groupElements        = array();
-        $this->_inGroup              = true;
-    } // end func startGroup
-
-   /**
-    * Called when visiting a group, after processing all group elements
-    *
-    * @param    HTML_QuickForm_group    group being visited
-    * @access   public
-    * @return   void
-    */
-    function finishGroup(&$group)
-    {
-        $separator = $group->_separator;
-        if (is_array($separator)) {
-            $count = count($separator);
-            $html  = '';
-            for ($i = 0; $i < count($this->_groupElements); $i++) {
-                $html .= (0 == $i? '': $separator[($i - 1) % $count]) . $this->_groupElements[$i];
-            }
-        } else {
-            if (is_null($separator)) {
-                $separator = '&nbsp;';
-            }
-            $html = implode((string)$separator, $this->_groupElements);
-        }
-        if (!empty($this->_groupWrap)) {
-            $html = str_replace('{content}', $html, $this->_groupWrap);
-        }
-        $this->_html   .= str_replace('{element}', $html, $this->_groupTemplate);
-        $this->_inGroup = false;
-    } // end func finishGroup
-
-    /**
-     * Sets element template 
-     *
-     * @param       string      The HTML surrounding an element 
-     * @param       string      (optional) Name of the element to apply template for
-     * @access      public
-     * @return      void
-     */
-    function setElementTemplate($html, $element = null)
-    {
-        if (is_null($element)) {
-            $this->_elementTemplate = $html;
-        } else {
-            $this->_templates[$element] = $html;
-        }
-    } // end func setElementTemplate
-
-
-    /**
-     * Sets template for a group wrapper 
-     * 
-     * This template is contained within a group-as-element template 
-     * set via setTemplate() and contains group's element templates, set
-     * via setGroupElementTemplate()
-     *
-     * @param       string      The HTML surrounding group elements
-     * @param       string      Name of the group to apply template for
-     * @access      public
-     * @return      void
-     */
-    function setGroupTemplate($html, $group)
-    {
-        $this->_groupWraps[$group] = $html;
-    } // end func setGroupTemplate
-
-    /**
-     * Sets element template for elements within a group
-     *
-     * @param       string      The HTML surrounding an element 
-     * @param       string      Name of the group to apply template for
-     * @access      public
-     * @return      void
-     */
-    function setGroupElementTemplate($html, $group)
-    {
-        $this->_groupTemplates[$group] = $html;
-    } // end func setGroupElementTemplate
-
-    /**
-     * Sets header template
-     *
-     * @param       string      The HTML surrounding the header 
-     * @access      public
-     * @return      void
-     */
-    function setHeaderTemplate($html)
-    {
-        $this->_headerTemplate = $html;
-    } // end func setHeaderTemplate
-
-    /**
-     * Sets form template 
-     *
-     * @param     string    The HTML surrounding the form tags 
-     * @access    public
-     * @return    void
-     */
-    function setFormTemplate($html)
-    {
-        $this->_formTemplate = $html;
-    } // end func setFormTemplate
-
-    /**
-     * Sets the note indicating required fields template
-     *
-     * @param       string      The HTML surrounding the required note 
-     * @access      public
-     * @return      void
-     */
-    function setRequiredNoteTemplate($html)
-    {
-        $this->_requiredNoteTemplate = $html;
-    } // end func setRequiredNoteTemplate
-
-    /**
-     * Clears all the HTML out of the templates that surround notes, elements, etc.
-     * Useful when you want to use addData() to create a completely custom form look
-     *
-     * @access  public
-     * @return  void
-     */
-    function clearAllTemplates()
-    {
-        $this->setElementTemplate('{element}');
-        $this->setFormTemplate("\n\t<form{attributes}>{content}\n\t</form>\n");
-        $this->setRequiredNoteTemplate('');
-        $this->_templates = array();
-    } // end func clearAllTemplates
-} // end class HTML_QuickForm_Renderer_Default
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ITDynamic.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ITDynamic.php
deleted file mode 100644 (file)
index 02a0d35..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A concrete renderer for HTML_QuickForm, using Integrated Templates.
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * An abstract base class for QuickForm renderers
- */
-require_once 'HTML/QuickForm/Renderer.php';
-
-/**
- * A concrete renderer for HTML_QuickForm, using Integrated Templates.
- * 
- * This is a "dynamic" renderer, which means that concrete form look 
- * is defined at runtime. This also means that you can define 
- * <b>one</b> template file for <b>all</b> your forms. That template
- * should contain a block for every element 'look' appearing in your 
- * forms and also some special blocks (consult the examples). If a
- * special block is not set for an element, the renderer falls back to
- * a default one.
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.0
- */
-class HTML_QuickForm_Renderer_ITDynamic extends HTML_QuickForm_Renderer
-{
-   /**#@+
-    * @access private
-    */
-   /**
-    * A template class (HTML_Template_ITX or HTML_Template_Sigma) instance
-    * @var HTML_Template_ITX|HTML_Template_Sigma
-    */
-    var $_tpl = null;
-
-   /**
-    * The errors that were not shown near concrete fields go here
-    * @var array
-    */
-    var $_errors = array();
-
-   /**
-    * Show the block with required note?
-    * @var bool
-    */
-    var $_showRequired = false;
-
-   /**
-    * A separator for group elements
-    * @var mixed
-    */
-    var $_groupSeparator = null;
-
-   /**
-    * The current element index inside a group
-    * @var integer
-    */
-    var $_groupElementIdx = 0;
-
-   /**
-    * Blocks to use for different elements  
-    * @var array
-    */
-    var $_elementBlocks = array();
-
-   /**
-    * Block to use for headers
-    * @var string
-    */
-    var $_headerBlock = null;
-   /**#@-*/
-
-
-   /**
-    * Constructor
-    *
-    * @param HTML_Template_ITX|HTML_Template_Sigma     Template object to use
-    */
-    function HTML_QuickForm_Renderer_ITDynamic(&$tpl)
-    {
-        $this->HTML_QuickForm_Renderer();
-        $this->_tpl =& $tpl;
-        $this->_tpl->setCurrentBlock('qf_main_loop');
-    }
-
-
-    function finishForm(&$form)
-    {
-        // display errors above form
-        if (!empty($this->_errors) && $this->_tpl->blockExists('qf_error_loop')) {
-            foreach ($this->_errors as $error) {
-                $this->_tpl->setVariable('qf_error', $error);
-                $this->_tpl->parse('qf_error_loop');
-            }
-        }
-        // show required note
-        if ($this->_showRequired) {
-            $this->_tpl->setVariable('qf_required_note', $form->getRequiredNote());
-        }
-        // assign form attributes
-        $this->_tpl->setVariable('qf_attributes', $form->getAttributes(true));
-        // assign javascript validation rules
-        $this->_tpl->setVariable('qf_javascript', $form->getValidationScript());
-    }
-      
-
-    function renderHeader(&$header)
-    {
-        $blockName = $this->_matchBlock($header);
-        if ('qf_header' == $blockName && isset($this->_headerBlock)) {
-            $blockName = $this->_headerBlock;
-        }
-        $this->_tpl->setVariable('qf_header', $header->toHtml());
-        $this->_tpl->parse($blockName);
-        $this->_tpl->parse('qf_main_loop');
-    }
-
-
-    function renderElement(&$element, $required, $error)
-    {
-        $blockName = $this->_matchBlock($element);
-        // are we inside a group?
-        if ('qf_main_loop' != $this->_tpl->currentBlock) {
-            if (0 != $this->_groupElementIdx && $this->_tpl->placeholderExists('qf_separator', $blockName)) {
-                if (is_array($this->_groupSeparator)) {
-                    $this->_tpl->setVariable('qf_separator', $this->_groupSeparator[($this->_groupElementIdx - 1) % count($this->_groupSeparator)]);
-                } else {
-                    $this->_tpl->setVariable('qf_separator', (string)$this->_groupSeparator);
-                }
-            }
-            $this->_groupElementIdx++;
-
-        } elseif(!empty($error)) {
-            // show the error message or keep it for later use
-            if ($this->_tpl->blockExists($blockName . '_error')) {
-                $this->_tpl->setVariable('qf_error', $error);
-            } else {
-                $this->_errors[] = $error;
-            }
-        }
-        // show an '*' near the required element
-        if ($required) {
-            $this->_showRequired = true;
-            if ($this->_tpl->blockExists($blockName . '_required')) {
-                $this->_tpl->touchBlock($blockName . '_required');
-            }
-        }
-        // Prepare multiple labels
-        $labels = $element->getLabel();
-        if (is_array($labels)) {
-            $mainLabel = array_shift($labels);
-        } else {
-            $mainLabel = $labels;
-        }
-        // render the element itself with its main label
-        $this->_tpl->setVariable('qf_element', $element->toHtml());
-        if ($this->_tpl->placeholderExists('qf_label', $blockName)) {
-            $this->_tpl->setVariable('qf_label', $mainLabel);
-        }
-        // render extra labels, if any
-        if (is_array($labels)) {
-            foreach($labels as $key => $label) {
-                $key = is_int($key)? $key + 2: $key;
-                if ($this->_tpl->blockExists($blockName . '_label_' . $key)) {
-                    $this->_tpl->setVariable('qf_label_' . $key, $label);
-                }
-            }
-        }
-        $this->_tpl->parse($blockName);
-        $this->_tpl->parseCurrentBlock();
-    }
-   
-
-    function renderHidden(&$element)
-    {
-        $this->_tpl->setVariable('qf_hidden', $element->toHtml());
-        $this->_tpl->parse('qf_hidden_loop');
-    }
-
-
-    function startGroup(&$group, $required, $error)
-    {
-        $blockName = $this->_matchBlock($group);
-        $this->_tpl->setCurrentBlock($blockName . '_loop');
-        $this->_groupElementIdx = 0;
-        $this->_groupSeparator  = is_null($group->_separator)? '&nbsp;': $group->_separator;
-        // show an '*' near the required element
-        if ($required) {
-            $this->_showRequired = true;
-            if ($this->_tpl->blockExists($blockName . '_required')) {
-                $this->_tpl->touchBlock($blockName . '_required');
-            }
-        }
-        // show the error message or keep it for later use
-        if (!empty($error)) {
-            if ($this->_tpl->blockExists($blockName . '_error')) {
-                $this->_tpl->setVariable('qf_error', $error);
-            } else {
-                $this->_errors[] = $error;
-            }
-        }
-        $this->_tpl->setVariable('qf_group_label', $group->getLabel());
-    }
-
-
-    function finishGroup(&$group)
-    {
-        $this->_tpl->parse($this->_matchBlock($group));
-        $this->_tpl->setCurrentBlock('qf_main_loop');
-        $this->_tpl->parseCurrentBlock();
-    }
-
-
-   /**
-    * Returns the name of a block to use for element rendering
-    * 
-    * If a name was not explicitly set via setElementBlock(), it tries
-    * the names '{prefix}_{element type}' and '{prefix}_{element}', where
-    * prefix is either 'qf' or the name of the current group's block
-    * 
-    * @param HTML_QuickForm_element     form element being rendered
-    * @access private
-    * @return string    block name
-    */
-    function _matchBlock(&$element)
-    {
-        $name = $element->getName();
-        $type = $element->getType();
-        if (isset($this->_elementBlocks[$name]) && $this->_tpl->blockExists($this->_elementBlocks[$name])) {
-            if (('group' == $type) || ($this->_elementBlocks[$name] . '_loop' != $this->_tpl->currentBlock)) {
-                return $this->_elementBlocks[$name];
-            }
-        }
-        if ('group' != $type && 'qf_main_loop' != $this->_tpl->currentBlock) {
-            $prefix = substr($this->_tpl->currentBlock, 0, -5); // omit '_loop' postfix
-        } else {
-            $prefix = 'qf';
-        }
-        if ($this->_tpl->blockExists($prefix . '_' . $type)) {
-            return $prefix . '_' . $type;
-        } elseif ($this->_tpl->blockExists($prefix . '_' . $name)) {
-            return $prefix . '_' . $name;
-        } else {
-            return $prefix . '_element';
-        }
-    }
-
-
-   /**
-    * Sets the block to use for element rendering
-    * 
-    * @param mixed      element name or array ('element name' => 'block name')
-    * @param string     block name if $elementName is not an array
-    * @access public
-    * @return void
-    */
-    function setElementBlock($elementName, $blockName = null)
-    {
-        if (is_array($elementName)) {
-            $this->_elementBlocks = array_merge($this->_elementBlocks, $elementName);
-        } else {
-            $this->_elementBlocks[$elementName] = $blockName;
-        }
-    }
-
-
-   /**
-    * Sets the name of a block to use for header rendering
-    *
-    * @param string     block name
-    * @access public
-    * @return void
-    */
-    function setHeaderBlock($blockName)
-    {
-        $this->_headerBlock = $blockName;
-    }
-}
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ITStatic.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ITStatic.php
deleted file mode 100644 (file)
index e699707..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A static renderer for HTML_QuickForm compatible 
- * with HTML_Template_IT and HTML_Template_Sigma.
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * An abstract base class for QuickForm renderers
- */
-require_once 'HTML/QuickForm/Renderer.php';
-
-/**
- * A static renderer for HTML_QuickForm compatible 
- * with HTML_Template_IT and HTML_Template_Sigma.
- *
- * As opposed to the dynamic renderer, this renderer needs
- * every elements and labels in the form to be specified by
- * placeholders at the position you want them to be displayed.
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.0
- */
-class HTML_QuickForm_Renderer_ITStatic extends HTML_QuickForm_Renderer
-{
-   /**#@+
-    * @access private
-    */
-   /**
-    * An HTML_Template_IT or some other API compatible Template instance
-    * @var object
-    */
-    var $_tpl = null;
-
-   /**
-    * Rendered form name
-    * @var string
-    */
-    var $_formName = 'form';
-
-   /**
-    * The errors that were not shown near concrete fields go here
-    * @var array
-    */
-    var $_errors = array();
-
-   /**
-    * Show the block with required note?
-    * @var bool
-    */
-    var $_showRequired = false;
-
-   /**
-    * Which group are we currently parsing ?
-    * @var string
-    */
-    var $_inGroup;
-
-   /**
-    * Index of the element in its group
-    * @var int
-    */
-    var $_elementIndex = 0;
-
-   /**
-    * If elements have been added with the same name
-    * @var array
-    */
-    var $_duplicateElements = array();
-
-   /**
-    * How to handle the required tag for required fields
-    * @var string
-    */
-    var $_required = '{label}<font size="1" color="red">*</font>';
-
-   /**
-    * How to handle error messages in form validation
-    * @var string
-    */
-    var $_error = '<font color="red">{error}</font><br />{html}';
-
-   /**
-    * Collected HTML for hidden elements, if needed  
-    * @var string
-    */
-    var $_hidden = '';
-   /**#@-*/
-
-   /**
-    * Constructor
-    *
-    * @param HTML_Template_IT|HTML_Template_Sigma   Template object to use
-    */
-    function HTML_QuickForm_Renderer_ITStatic(&$tpl)
-    {
-        $this->HTML_QuickForm_Renderer();
-        $this->_tpl =& $tpl;
-    } // end constructor
-
-   /**
-    * Called when visiting a form, before processing any form elements
-    *
-    * @param    HTML_QuickForm  form object being visited
-    * @access   public
-    * @return   void
-    */
-    function startForm(&$form)
-    {
-        $this->_formName = $form->getAttribute('id');
-
-        if (count($form->_duplicateIndex) > 0) {
-            // Take care of duplicate elements
-            foreach ($form->_duplicateIndex as $elementName => $indexes) {
-                $this->_duplicateElements[$elementName] = 0;
-            }
-        }
-    } // end func startForm
-
-   /**
-    * Called when visiting a form, after processing all form elements
-    * 
-    * @param    HTML_QuickForm  form object being visited
-    * @access   public
-    * @return   void
-    */
-    function finishForm(&$form)
-    {
-        // display errors above form
-        if (!empty($this->_errors) && $this->_tpl->blockExists($this->_formName.'_error_loop')) {
-            foreach ($this->_errors as $error) {
-                $this->_tpl->setVariable($this->_formName.'_error', $error);
-                $this->_tpl->parse($this->_formName.'_error_loop');
-            }
-        }
-        // show required note
-        if ($this->_showRequired) {
-            $this->_tpl->setVariable($this->_formName.'_required_note', $form->getRequiredNote());
-        }
-        // add hidden elements, if collected
-        if (!empty($this->_hidden)) {
-            $this->_tpl->setVariable($this->_formName . '_hidden', $this->_hidden);
-        }
-        // assign form attributes
-        $this->_tpl->setVariable($this->_formName.'_attributes', $form->getAttributes(true));
-        // assign javascript validation rules
-        $this->_tpl->setVariable($this->_formName.'_javascript', $form->getValidationScript());
-    } // end func finishForm
-
-   /**
-    * Called when visiting a header element
-    *
-    * @param    HTML_QuickForm_header   header element being visited
-    * @access   public
-    * @return   void
-    */
-    function renderHeader(&$header)
-    {
-        $name = $header->getName();
-        $varName = $this->_formName.'_header';
-
-        // Find placeHolder
-        if (!empty($name) && $this->_tpl->placeHolderExists($this->_formName.'_header_'.$name)) {
-            $varName = $this->_formName.'_header_'.$name;
-        }
-        $this->_tpl->setVariable($varName, $header->toHtml());
-    } // end func renderHeader
-
-   /**
-    * Called when visiting an element
-    *
-    * @param    HTML_QuickForm_element  form element being visited
-    * @param    bool                    Whether an element is required
-    * @param    string                  An error message associated with an element
-    * @access   public
-    * @return   void
-    */
-    function renderElement(&$element, $required, $error)
-    {
-        $name = $element->getName();
-
-        // are we inside a group?
-        if (!empty($this->_inGroup)) {
-            $varName = $this->_formName.'_'.str_replace(array('[', ']'), '_', $name);
-            if (substr($varName, -2) == '__') {
-                // element name is of type : group[]
-                $varName = $this->_inGroup.'_'.$this->_elementIndex.'_';
-                $this->_elementIndex++;
-            }
-            if ($varName != $this->_inGroup) {
-                $varName .= '_' == substr($varName, -1)? '': '_';
-                // element name is of type : group[name]
-                $label = $element->getLabel();
-                $html = $element->toHtml();
-
-                if ($required && !$element->isFrozen()) {
-                    $this->_renderRequired($label, $html);
-                    $this->_showRequired = true;
-                }
-                if (!empty($label)) {
-                    if (is_array($label)) {
-                        foreach ($label as $key => $value) {
-                            $this->_tpl->setVariable($varName.'label_'.$key, $value);
-                        }
-                    } else {
-                        $this->_tpl->setVariable($varName.'label', $label);
-                    }
-                }
-                $this->_tpl->setVariable($varName.'html', $html);
-            }
-
-        } else {
-
-            $name = str_replace(array('[', ']'), array('_', ''), $name);
-
-            if (isset($this->_duplicateElements[$name])) {
-                // Element is a duplicate
-                $varName = $this->_formName.'_'.$name.'_'.$this->_duplicateElements[$name];
-                $this->_duplicateElements[$name]++;
-            } else {
-                $varName = $this->_formName.'_'.$name;
-            }
-
-            $label = $element->getLabel();
-            $html = $element->toHtml();
-
-            if ($required) {
-                $this->_showRequired = true;
-                $this->_renderRequired($label, $html);
-            }
-            if (!empty($error)) {
-                $this->_renderError($label, $html, $error);
-            }
-            if (is_array($label)) {
-                foreach ($label as $key => $value) {
-                    $this->_tpl->setVariable($varName.'_label_'.$key, $value);
-                }
-            } else {
-                $this->_tpl->setVariable($varName.'_label', $label);
-            }
-            $this->_tpl->setVariable($varName.'_html', $html);
-        }
-    } // end func renderElement
-
-   /**
-    * Called when visiting a hidden element
-    * 
-    * @param    HTML_QuickForm_element  hidden element being visited
-    * @access   public
-    * @return   void
-    */
-    function renderHidden(&$element)
-    {
-        if ($this->_tpl->placeholderExists($this->_formName . '_hidden')) {
-            $this->_hidden .= $element->toHtml();
-        } else {
-            $name = $element->getName();
-            $name = str_replace(array('[', ']'), array('_', ''), $name);
-            $this->_tpl->setVariable($this->_formName.'_'.$name.'_html', $element->toHtml());
-        }
-    } // end func renderHidden
-
-   /**
-    * Called when visiting a group, before processing any group elements
-    *
-    * @param    HTML_QuickForm_group    group being visited
-    * @param    bool                    Whether a group is required
-    * @param    string                  An error message associated with a group
-    * @access   public
-    * @return   void
-    */
-    function startGroup(&$group, $required, $error)
-    {
-        $name = $group->getName();
-        $varName = $this->_formName.'_'.$name;
-
-        $this->_elementIndex = 0;
-
-        $html = $this->_tpl->placeholderExists($varName.'_html') ? $group->toHtml() : '';
-        $label = $group->getLabel();
-
-        if ($required) {
-            $this->_renderRequired($label, $html);
-        }
-        if (!empty($error)) {
-            $this->_renderError($label, $html, $error);
-        }
-        if (!empty($html)) {
-            $this->_tpl->setVariable($varName.'_html', $html);
-        } else {
-            // Uses error blocks to set the special groups layout error
-            // <!-- BEGIN form_group_error -->{form_group_error}<!-- END form_group_error -->
-            if (!empty($error)) {
-                if ($this->_tpl->placeholderExists($varName.'_error')) {
-                    if ($this->_tpl->blockExists($this->_formName . '_error_block')) {
-                        $this->_tpl->setVariable($this->_formName . '_error', $error);
-                        $error = $this->_getTplBlock($this->_formName . '_error_block');
-                    } elseif (strpos($this->_error, '{html}') !== false || strpos($this->_error, '{label}') !== false) {
-                        $error = str_replace('{error}', $error, $this->_error);
-                    }
-                }
-                $this->_tpl->setVariable($varName . '_error', $error);
-                array_pop($this->_errors);
-            }
-        }
-        if (is_array($label)) {
-            foreach ($label as $key => $value) {
-                $this->_tpl->setVariable($varName.'_label_'.$key, $value);
-            }
-        } else {
-            $this->_tpl->setVariable($varName.'_label', $label);
-        }
-        $this->_inGroup = $varName;
-    } // end func startGroup
-
-   /**
-    * Called when visiting a group, after processing all group elements
-    *
-    * @param    HTML_QuickForm_group    group being visited
-    * @access   public
-    * @return   void
-    */
-    function finishGroup(&$group)
-    {
-        $this->_inGroup = '';
-    } // end func finishGroup
-
-   /**
-    * Sets the way required elements are rendered
-    *
-    * You can use {label} or {html} placeholders to let the renderer know where
-    * where the element label or the element html are positionned according to the
-    * required tag. They will be replaced accordingly with the right value.
-    * For example:
-    * <font color="red">*</font>{label}
-    * will put a red star in front of the label if the element is required.
-    *
-    * @param    string      The required element template
-    * @access   public
-    * @return   void
-    */
-    function setRequiredTemplate($template)
-    {
-        $this->_required = $template;
-    } // end func setRequiredTemplate
-
-   /**
-    * Sets the way elements with validation errors are rendered
-    *
-    * You can use {label} or {html} placeholders to let the renderer know where
-    * where the element label or the element html are positionned according to the
-    * error message. They will be replaced accordingly with the right value.
-    * The error message will replace the {error} place holder.
-    * For example:
-    * <font color="red">{error}</font><br />{html}
-    * will put the error message in red on top of the element html.
-    *
-    * If you want all error messages to be output in the main error block, do not specify
-    * {html} nor {label}.
-    *
-    * Groups can have special layouts. With this kind of groups, the renderer will need
-    * to know where to place the error message. In this case, use error blocks like:
-    * <!-- BEGIN form_group_error -->{form_group_error}<!-- END form_group_error -->
-    * where you want the error message to appear in the form.
-    *
-    * @param    string      The element error template
-    * @access   public
-    * @return   void
-    */
-    function setErrorTemplate($template)
-    {
-        $this->_error = $template;
-    } // end func setErrorTemplate
-
-   /**
-    * Called when an element is required
-    *
-    * This method will add the required tag to the element label and/or the element html
-    * such as defined with the method setRequiredTemplate
-    *
-    * @param    string      The element label
-    * @param    string      The element html rendering
-    * @see      setRequiredTemplate()
-    * @access   private
-    * @return   void
-    */
-    function _renderRequired(&$label, &$html)
-    {
-        if ($this->_tpl->blockExists($tplBlock = $this->_formName . '_required_block')) {
-            if (!empty($label) && $this->_tpl->placeholderExists($this->_formName . '_label', $tplBlock)) {
-                $this->_tpl->setVariable($this->_formName . '_label', is_array($label)? $label[0]: $label);
-                if (is_array($label)) {
-                    $label[0] = $this->_getTplBlock($tplBlock);
-                } else {
-                    $label    = $this->_getTplBlock($tplBlock);
-                }
-            }
-            if (!empty($html) && $this->_tpl->placeholderExists($this->_formName . '_html', $tplBlock)) {
-                $this->_tpl->setVariable($this->_formName . '_html', $html);
-                $html = $this->_getTplBlock($tplBlock);
-            }
-        } else {
-            if (!empty($label) && strpos($this->_required, '{label}') !== false) {
-                if (is_array($label)) {
-                    $label[0] = str_replace('{label}', $label[0], $this->_required);
-                } else {
-                    $label = str_replace('{label}', $label, $this->_required);
-                }
-            }
-            if (!empty($html) && strpos($this->_required, '{html}') !== false) {
-                $html = str_replace('{html}', $html, $this->_required);
-            }
-        }
-    } // end func _renderRequired
-
-   /**
-    * Called when an element has a validation error
-    *
-    * This method will add the error message to the element label or the element html
-    * such as defined with the method setErrorTemplate. If the error placeholder is not found
-    * in the template, the error will be displayed in the form error block.
-    *
-    * @param    string      The element label
-    * @param    string      The element html rendering
-    * @param    string      The element error
-    * @see      setErrorTemplate()
-    * @access   private
-    * @return   void
-    */
-    function _renderError(&$label, &$html, $error)
-    {
-        if ($this->_tpl->blockExists($tplBlock = $this->_formName . '_error_block')) {
-            $this->_tpl->setVariable($this->_formName . '_error', $error);
-            if (!empty($label) && $this->_tpl->placeholderExists($this->_formName . '_label', $tplBlock)) {
-                $this->_tpl->setVariable($this->_formName . '_label', is_array($label)? $label[0]: $label);
-                if (is_array($label)) {
-                    $label[0] = $this->_getTplBlock($tplBlock);
-                } else {
-                    $label    = $this->_getTplBlock($tplBlock);
-                }
-            } elseif (!empty($html) && $this->_tpl->placeholderExists($this->_formName . '_html', $tplBlock)) {
-                $this->_tpl->setVariable($this->_formName . '_html', $html);
-                $html = $this->_getTplBlock($tplBlock);
-            }
-            // clean up after ourselves
-            $this->_tpl->setVariable($this->_formName . '_error', null);
-        } elseif (!empty($label) && strpos($this->_error, '{label}') !== false) {
-            if (is_array($label)) {
-                $label[0] = str_replace(array('{label}', '{error}'), array($label[0], $error), $this->_error);
-            } else {
-                $label = str_replace(array('{label}', '{error}'), array($label, $error), $this->_error);
-            }
-        } elseif (!empty($html) && strpos($this->_error, '{html}') !== false) {
-            $html = str_replace(array('{html}', '{error}'), array($html, $error), $this->_error);
-        } else {
-            $this->_errors[] = $error;
-        }
-    }// end func _renderError
-
-
-   /**
-    * Returns the block's contents
-    *
-    * The method is needed because ITX and Sigma implement clearing
-    * the block contents on get() a bit differently
-    *
-    * @param    string  Block name
-    * @return   string  Block contents
-    */
-    function _getTplBlock($block)
-    {
-        $this->_tpl->parse($block);
-        if (is_a($this->_tpl, 'html_template_sigma')) {
-            $ret = $this->_tpl->get($block, true);
-        } else {
-            $oldClear = $this->_tpl->clearCache;
-            $this->_tpl->clearCache = true;
-            $ret = $this->_tpl->get($block);
-            $this->_tpl->clearCache = $oldClear;
-        }
-        return $ret;
-    }
-} // end class HTML_QuickForm_Renderer_ITStatic
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Object.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Object.php
deleted file mode 100644 (file)
index afd3aa6..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A concrete renderer for HTML_QuickForm, makes an object from form contents
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Ron McClain <ron@humaniq.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * An abstract base class for QuickForm renderers
- */
-require_once 'HTML/QuickForm/Renderer.php';
-
-/**
- * A concrete renderer for HTML_QuickForm, makes an object from form contents
- *
- * Based on HTML_Quickform_Renderer_Array code
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Ron McClain <ron@humaniq.com>
- * @version     Release: 3.2.16
- * @since       3.1.1
- */
-class HTML_QuickForm_Renderer_Object extends HTML_QuickForm_Renderer
-{
-   /**#@+
-    * @access private
-    */
-    /**
-     * The object being generated
-     * @var QuickformForm
-     */
-    var $_obj= null;
-
-    /**
-     * Number of sections in the form (i.e. number of headers in it)
-     * @var integer $_sectionCount
-     */
-    var $_sectionCount;
-
-    /**
-    * Current section number
-    * @var integer $_currentSection
-    */
-    var $_currentSection;
-
-    /**
-    * Object representing current group
-    * @var object $_currentGroup
-    */
-    var $_currentGroup = null;
-
-    /**
-     * Class of Element Objects
-     * @var object $_elementType
-     */
-    var $_elementType = 'QuickFormElement';
-
-    /**
-    * Additional style information for different elements  
-    * @var array $_elementStyles
-    */
-    var $_elementStyles = array();
-
-    /**
-    * true: collect all hidden elements into string; false: process them as usual form elements
-    * @var bool $_collectHidden
-    */
-    var $_collectHidden = false;
-   /**#@-*/
-
-
-    /**
-     * Constructor
-     *
-     * @param bool    true: collect all hidden elements
-     * @access public
-     */
-    function HTML_QuickForm_Renderer_Object($collecthidden = false) 
-    {
-        $this->HTML_QuickForm_Renderer();
-        $this->_collectHidden = $collecthidden;
-        $this->_obj = new QuickformForm;
-    }
-
-    /**
-     * Return the rendered Object
-     * @access public
-     */
-    function toObject() 
-    {
-        return $this->_obj;
-    }
-
-    /**
-     * Set the class of the form elements.  Defaults to QuickformElement.
-     * @param string   Name of element class
-     * @access public
-     */
-    function setElementType($type)
-    {
-        $this->_elementType = $type;
-    }
-
-    function startForm(&$form) 
-    {
-        $this->_obj->frozen = $form->isFrozen();
-        $this->_obj->javascript = $form->getValidationScript();
-        $this->_obj->attributes = $form->getAttributes(true);
-        $this->_obj->requirednote = $form->getRequiredNote();
-        $this->_obj->errors = new StdClass;
-
-        if($this->_collectHidden) {
-            $this->_obj->hidden = '';
-        }
-        $this->_elementIdx = 1;
-        $this->_currentSection = null;
-        $this->_sectionCount = 0;
-    } // end func startForm
-
-    function renderHeader(&$header) 
-    {
-        $hobj = new StdClass;
-        $hobj->header = $header->toHtml();
-        $this->_obj->sections[$this->_sectionCount] = $hobj;
-        $this->_currentSection = $this->_sectionCount++;
-    }
-
-    function renderElement(&$element, $required, $error) 
-    {
-        $elObj = $this->_elementToObject($element, $required, $error);
-        if(!empty($error)) {
-            $name = $elObj->name;
-            $this->_obj->errors->$name = $error;
-        }
-        $this->_storeObject($elObj);
-    } // end func renderElement
-
-    function renderHidden(&$element)
-    {
-        if($this->_collectHidden) {
-            $this->_obj->hidden .= $element->toHtml() . "\n";
-        } else {
-            $this->renderElement($element, false, null);
-        }
-    } //end func renderHidden
-
-    function startGroup(&$group, $required, $error) 
-    {
-        $this->_currentGroup = $this->_elementToObject($group, $required, $error);
-        if(!empty($error)) {
-            $name = $this->_currentGroup->name;
-            $this->_obj->errors->$name = $error;
-        }
-    } // end func startGroup
-
-    function finishGroup(&$group) 
-    {
-        $this->_storeObject($this->_currentGroup);
-        $this->_currentGroup = null;
-    } // end func finishGroup
-
-    /**
-     * Creates an object representing an element
-     *
-     * @access private
-     * @param HTML_QuickForm_element    form element being rendered
-     * @param required bool         Whether an element is required
-     * @param error string    Error associated with the element
-     * @return object
-     */
-    function _elementToObject(&$element, $required, $error) 
-    {
-        if($this->_elementType) {
-            $ret = new $this->_elementType;
-        }
-        $ret->name = $element->getName();
-        $ret->value = $element->getValue();
-        $ret->type = $element->getType();
-        $ret->frozen = $element->isFrozen();
-        $labels = $element->getLabel();
-        if (is_array($labels)) {
-            $ret->label = array_shift($labels);
-            foreach ($labels as $key => $label) {
-                $key = is_int($key)? $key + 2: $key;
-                $ret->{'label_' . $key} = $label;
-            }
-        } else {
-            $ret->label = $labels;
-        }
-        $ret->required = $required;
-        $ret->error = $error;
-
-        if(isset($this->_elementStyles[$ret->name])) {
-            $ret->style = $this->_elementStyles[$ret->name];
-            $ret->styleTemplate = "styles/". $ret->style .".html";
-        }
-        if($ret->type == 'group') {
-            $ret->separator = $element->_separator;
-            $ret->elements = array();
-        } else {
-            $ret->html = $element->toHtml();
-        }
-        return $ret;
-    }
-
-    /** 
-     * Stores an object representation of an element in the form array
-     *
-     * @access private
-     * @param QuickformElement     Object representation of an element
-     * @return void
-     */
-    function _storeObject($elObj) 
-    {
-        $name = $elObj->name;
-        if(is_object($this->_currentGroup) && $elObj->type != 'group') {
-            $this->_currentGroup->elements[] = $elObj;
-        } elseif (isset($this->_currentSection)) {
-            $this->_obj->sections[$this->_currentSection]->elements[] = $elObj;
-        } else {
-            $this->_obj->elements[] = $elObj;
-        }
-    }
-
-    function setElementStyle($elementName, $styleName = null)
-    {
-        if(is_array($elementName)) {
-            $this->_elementStyles = array_merge($this->_elementStyles, $elementName);
-        } else {
-            $this->_elementStyles[$elementName] = $styleName;
-        }
-    }
-
-} // end class HTML_QuickForm_Renderer_Object
-
-
-
-/**
- * Convenience class for the form object passed to outputObject()
- * 
- * Eg.
- * <pre>  
- * {form.outputJavaScript():h}
- * {form.outputHeader():h}
- *   <table>
- *     <tr>
- *       <td>{form.name.label:h}</td><td>{form.name.html:h}</td>
- *     </tr>
- *   </table>
- * </form>
- * </pre>
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Ron McClain <ron@humaniq.com>
- * @version     Release: 3.2.16
- * @since       3.1.1
- */
-class QuickformForm
-{
-   /**
-    * Whether the form has been frozen
-    * @var boolean $frozen
-    */
-    var $frozen;
-
-   /**
-    * Javascript for client-side validation
-    * @var string $javascript
-    */
-    var $javascript;
-
-   /**
-    * Attributes for form tag
-    * @var string $attributes
-    */
-    var $attributes;
-
-   /**
-    * Note about required elements
-    * @var string $requirednote
-    */
-    var $requirednote;
-
-   /**
-    * Collected html of all hidden variables
-    * @var string $hidden
-    */
-    var $hidden;
-
-   /**
-    * Set if there were validation errors.  
-    * StdClass object with element names for keys and their
-    * error messages as values
-    * @var object $errors
-    */
-    var $errors;
-
-   /**
-    * Array of QuickformElementObject elements.  If there are headers in the form
-    * this will be empty and the elements will be in the 
-    * separate sections
-    * @var array $elements
-    */
-    var $elements;
-
-   /**
-    * Array of sections contained in the document
-    * @var array $sections
-    */
-    var $sections;
-
-   /**
-    * Output &lt;form&gt; header
-    * {form.outputHeader():h} 
-    * @return string    &lt;form attributes&gt;
-    */
-    function outputHeader()
-    {
-        return "<form " . $this->attributes . ">\n";
-    }
-
-   /**
-    * Output form javascript
-    * {form.outputJavaScript():h}
-    * @return string    Javascript
-    */
-    function outputJavaScript()
-    {
-        return $this->javascript;
-    }
-} // end class QuickformForm
-
-
-/**
- * Convenience class describing a form element.
- *
- * The properties defined here will be available from 
- * your flexy templates by referencing
- * {form.zip.label:h}, {form.zip.html:h}, etc.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Ron McClain <ron@humaniq.com>
- * @version     Release: 3.2.16
- * @since       3.1.1
- */
-class QuickformElement
-{
-    /**
-     * Element name
-     * @var string $name
-     */
-    var $name;
-
-    /**
-     * Element value
-     * @var mixed $value
-     */
-    var $value;
-
-    /**
-     * Type of element
-     * @var string $type
-     */
-    var $type;
-
-    /**
-     * Whether the element is frozen
-     * @var boolean $frozen
-     */
-    var $frozen;
-
-    /**
-     * Label for the element
-     * @var string $label
-     */
-    var $label;
-
-    /**
-     * Whether element is required
-     * @var boolean $required
-     */
-    var $required;
-
-    /**
-     * Error associated with the element
-     * @var string $error
-     */
-    var $error;
-
-    /**
-     * Some information about element style
-     * @var string $style
-     */
-    var $style;
-
-    /**
-     * HTML for the element
-     * @var string $html
-     */
-    var $html;
-
-    /**
-     * If element is a group, the group separator
-     * @var mixed $separator
-     */
-    var $separator;
-
-    /**
-     * If element is a group, an array of subelements
-     * @var array $elements
-     */
-    var $elements;
-
-    function isType($type)
-    {
-        return ($this->type == $type);
-    }
-
-    function notFrozen()
-    {
-        return !$this->frozen;
-    }
-
-    function isButton()
-    {
-        return ($this->type == "submit" || $this->type == "reset");
-    }
-
-
-   /**
-    * XXX: why does it use Flexy when all other stuff here does not depend on it?
-    */
-    function outputStyle()
-    {
-        ob_start();
-        HTML_Template_Flexy::staticQuickTemplate('styles/' . $this->style . '.html', $this);
-        $ret = ob_get_contents();
-        ob_end_clean();
-        return $ret;
-    }
-} // end class QuickformElement
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ObjectFlexy.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/ObjectFlexy.php
deleted file mode 100644 (file)
index 048e556..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * QuickForm renderer for Flexy template engine, static version.
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Ron McClain <ron@humaniq.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * A concrete renderer for HTML_QuickForm, makes an object from form contents
- */ 
-require_once 'HTML/QuickForm/Renderer/Object.php';
-
-/**
- * QuickForm renderer for Flexy template engine, static version.
- * 
- * A static renderer for HTML_Quickform.  Makes a QuickFormFlexyObject
- * from the form content suitable for use with a Flexy template
- *
- * Usage:
- * <code>
- * $form =& new HTML_QuickForm('form', 'POST');
- * $template =& new HTML_Template_Flexy();
- * $renderer =& new HTML_QuickForm_Renderer_ObjectFlexy(&$template);
- * $renderer->setHtmlTemplate("html.html");
- * $renderer->setLabelTemplate("label.html");
- * $form->accept($renderer);
- * $view = new StdClass;
- * $view->form = $renderer->toObject();
- * $template->compile("mytemplate.html");
- * </code>
- *
- * Based on the code for HTML_QuickForm_Renderer_ArraySmarty
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Ron McClain <ron@humaniq.com>
- * @version     Release: 3.2.16
- * @since       3.1.1
- */
-class HTML_QuickForm_Renderer_ObjectFlexy extends HTML_QuickForm_Renderer_Object
-{
-   /**#@+
-    * @access private
-    */
-    /**
-     * HTML_Template_Flexy instance
-     * @var object $_flexy
-     */
-    var $_flexy;
-
-    /**
-     * Current element index
-     * @var integer $_elementIdx
-     */
-    var $_elementIdx;
-
-    /**
-     * The current element index inside a group
-     * @var integer $_groupElementIdx
-     */
-    var $_groupElementIdx = 0;
-
-    /**
-     * Name of template file for form html
-     * @var string $_html
-     * @see     setRequiredTemplate()
-     */
-    var $_html = '';
-
-    /**
-     * Name of template file for form labels
-     * @var string $label
-     * @see        setErrorTemplate()
-     */
-    var $label = '';
-
-    /**
-     * Class of the element objects, so you can add your own
-     * element methods
-     * @var string $_elementType
-     */
-    var $_elementType = 'QuickformFlexyElement';
-   /**#@-*/
-
-    /**
-     * Constructor
-     *
-     * @param HTML_Template_Flexy   template object to use
-     * @public
-     */
-    function HTML_QuickForm_Renderer_ObjectFlexy(&$flexy)
-    {
-        $this->HTML_QuickForm_Renderer_Object(true);
-        $this->_obj = new QuickformFlexyForm();
-        $this->_flexy =& $flexy;
-    } // end constructor
-
-    function renderHeader(&$header)
-    {
-        if($name = $header->getName()) {
-            $this->_obj->header->$name = $header->toHtml();
-        } else {
-            $this->_obj->header[$this->_sectionCount] = $header->toHtml();
-        }
-        $this->_currentSection = $this->_sectionCount++;
-    } // end func renderHeader
-
-    function startGroup(&$group, $required, $error)
-    {
-        parent::startGroup($group, $required, $error);
-        $this->_groupElementIdx = 1;
-    } //end func startGroup
-
-    /**
-     * Creates an object representing an element containing
-     * the key for storing this
-     *
-     * @access private
-     * @param HTML_QuickForm_element    form element being rendered
-     * @param bool        Whether an element is required
-     * @param string    Error associated with the element
-     * @return object
-     */
-    function _elementToObject(&$element, $required, $error)
-    {
-        $ret = parent::_elementToObject($element, $required, $error);
-        if($ret->type == 'group') {
-            $ret->html = $element->toHtml();
-            unset($ret->elements);
-        }
-        if(!empty($this->_label)) {
-            $this->_renderLabel($ret);
-        }
-
-        if(!empty($this->_html)) {
-            $this->_renderHtml($ret);
-            $ret->error = $error;
-        }
-
-        // Create an element key from the name
-        if (false !== ($pos = strpos($ret->name, '[')) || is_object($this->_currentGroup)) {
-            if (!$pos) {
-                $keys = '->{\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret->name) . '\'}';
-            } else {
-                $keys = '->{\'' . str_replace(
-                            array('\\', '\'', '[', ']'), array('\\\\', '\\\'', '\'}->{\'', ''), 
-                            $ret->name
-                        ) . '\'}';
-            }
-            // special handling for elements in native groups
-            if (is_object($this->_currentGroup)) {
-                // skip unnamed group items unless radios: no name -> no static access
-                // identification: have the same key string as the parent group
-                if ($this->_currentGroup->keys == $keys && 'radio' != $ret->type) {
-                    return false;
-                }
-                // reduce string of keys by remove leading group keys
-                if (0 === strpos($keys, $this->_currentGroup->keys)) {
-                    $keys = substr_replace($keys, '', 0, strlen($this->_currentGroup->keys));
-                }
-            }
-        } elseif (0 == strlen($ret->name)) {
-            $keys = '->{\'element_' . $this->_elementIdx . '\'}';
-        } else {
-            $keys = '->{\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret->name) . '\'}';
-        }
-        // for radios: add extra key from value
-        if ('radio' == $ret->type && '[]' != substr($keys, -2)) {
-            $keys .= '->{\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $ret->value) . '\'}';
-        }
-        $ret->keys = $keys;
-        $this->_elementIdx++;
-        return $ret;
-    }
-
-    /**
-     * Stores an object representation of an element in the 
-     * QuickformFormObject instance
-     *
-     * @access private
-     * @param QuickformElement  Object representation of an element
-     * @return void
-     */
-    function _storeObject($elObj) 
-    {
-        if ($elObj) {
-            $keys = $elObj->keys;
-            unset($elObj->keys);
-            if(is_object($this->_currentGroup) && ('group' != $elObj->type)) {
-                $code = '$this->_currentGroup' . $keys . ' = $elObj;';
-            } else {
-                $code = '$this->_obj' . $keys . ' = $elObj;';
-            }
-            eval($code);
-        }
-    }
-
-    /**
-     * Set the filename of the template to render html elements.
-     * In your template, {html} is replaced by the unmodified html.
-     * If the element is required, {required} will be true.
-     * Eg.
-     * <pre>
-     * {if:error}
-     *   <font color="red" size="1">{error:h}</font><br />
-     * {end:}
-     * {html:h}
-     * </pre>
-     *
-     * @access public
-     * @param string   Filename of template
-     * @return void
-     */
-    function setHtmlTemplate($template)
-    {
-        $this->_html = $template;
-    } 
-
-    /**
-     * Set the filename of the template to render form labels
-     * In your template, {label} is replaced by the unmodified label.
-     * {error} will be set to the error, if any.  {required} will
-     * be true if this is a required field
-     * Eg.
-     * <pre>
-     * {if:required}
-     * <font color="orange" size="1">*</font>
-     * {end:}
-     * {label:h}
-     * </pre>
-     *
-     * @access public
-     * @param string   Filename of template
-     * @return void
-     */
-    function setLabelTemplate($template) 
-    {
-        $this->_label = $template;
-    }
-
-    function _renderLabel(&$ret)
-    {
-        $this->_flexy->compile($this->_label);
-        $ret->label = $this->_flexy->bufferedOutputObject($ret);
-    }
-
-    function _renderHtml(&$ret)
-    {
-        $this->_flexy->compile($this->_html);
-        $ret->html = $this->_flexy->bufferedOutputObject($ret);
-    }
-} // end class HTML_QuickForm_Renderer_ObjectFlexy
-
-/**
- * Adds nothing to QuickformForm, left for backwards compatibility
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @ignore
- */
-class QuickformFlexyForm extends QuickformForm
-{
-}
-
-/**
- * Adds nothing to QuickformElement, left for backwards compatibility
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @ignore
- */
-class QuickformFlexyElement extends QuickformElement
-{
-}
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/QuickHtml.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/QuickHtml.php
deleted file mode 100644 (file)
index 13a0c4e..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A renderer that makes it quick and easy to create customized forms.
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Jason Rust <jrust@rustyparts.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * A concrete renderer for HTML_QuickForm, based on QuickForm 2.x built-in one
- */ 
-require_once 'HTML/QuickForm/Renderer/Default.php';
-
-/**
- * A renderer that makes it quick and easy to create customized forms.
- *
- * This renderer has three main distinctives: an easy way to create
- * custom-looking forms, the ability to separate the creation of form
- * elements from their display, and being able to use QuickForm in
- * widget-based template systems.  See the online docs for more info.
- * For a usage example see: docs/renderers/QuickHtml_example.php
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Jason Rust <jrust@rustyparts.com>
- * @version     Release: 3.2.16
- * @since       3.1.1
- */
-class HTML_QuickForm_Renderer_QuickHtml extends HTML_QuickForm_Renderer_Default {
-    // {{{ properties
-
-    /**
-     * The array of rendered elements
-     * @var array
-     */
-    var $renderedElements = array();
-
-    // }}}
-    // {{{ constructor
-    
-    /**
-     * Constructor
-     *
-     * @access public
-     * @return void
-     */
-    function HTML_QuickForm_Renderer_QuickHtml()
-    {
-        $this->HTML_QuickForm_Renderer_Default();
-        // The default templates aren't used for this renderer
-        $this->clearAllTemplates();
-    } // end constructor
-
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * returns the HTML generated for the form
-     *
-     * @param string $data (optional) Any extra data to put before the end of the form
-     *
-     * @access public
-     * @return string
-     */
-    function toHtml($data = '')
-    {
-        // Render any elements that haven't been rendered explicitly by elementToHtml()
-        foreach (array_keys($this->renderedElements) as $key) {
-            if (!$this->renderedElements[$key]['rendered']) {
-                $this->renderedElements[$key]['rendered'] = true;
-                $data .= $this->renderedElements[$key]['html'] . "\n";
-            }
-        }
-
-        // Insert the extra data and form elements at the end of the form
-        $this->_html = str_replace('</form>', $data . "\n</form>", $this->_html);
-        return $this->_html;
-    } // end func toHtml
-
-    // }}}
-    // {{{ elementToHtml()
-
-    /**
-     * Gets the html for an element and marks it as rendered.
-     *
-     * @param string $elementName The element name
-     * @param string $elementValue (optional) The value of the element.  This is only useful
-     *               for elements that have the same name (i.e. radio and checkbox), but
-     *               different values
-     *
-     * @access public
-     * @return string The html for the QuickForm element
-     * @throws HTML_QuickForm_Error
-     */
-    function elementToHtml($elementName, $elementValue = null)
-    {
-        $elementKey = null;
-        // Find the key for the element
-        foreach ($this->renderedElements as $key => $data) {
-            if ($data['name'] == $elementName && 
-                // See if the value must match as well
-                (is_null($elementValue) ||
-                 $data['value'] == $elementValue)) {
-                $elementKey = $key;
-                break;
-            }
-        }
-
-        if (is_null($elementKey)) {
-            $msg = is_null($elementValue) ? "Element $elementName does not exist." : 
-                "Element $elementName with value of $elementValue does not exist.";
-            return PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, $msg, 'HTML_QuickForm_Error', true);
-        } else {
-            if ($this->renderedElements[$elementKey]['rendered']) {
-                $msg = is_null($elementValue) ? "Element $elementName has already been rendered." : 
-                    "Element $elementName with value of $elementValue has already been rendered.";
-                return PEAR::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, $msg, 'HTML_QuickForm_Error', true);
-            } else {
-                $this->renderedElements[$elementKey]['rendered'] = true;
-                return $this->renderedElements[$elementKey]['html'];
-            }
-        }
-    } // end func elementToHtml
-
-    // }}}
-    // {{{ renderElement()
-
-    /**
-     * Gets the html for an element and adds it to the array by calling
-     * parent::renderElement()
-     *
-     * @param HTML_QuickForm_element    form element being visited
-     * @param bool                      Whether an element is required
-     * @param string                    An error message associated with an element
-     *
-     * @access public
-     * @return mixed HTML string of element if $immediateRender is set, else we just add the
-     *               html to the global _html string 
-     */
-    function renderElement(&$element, $required, $error)
-    {
-        $this->_html = '';
-        parent::renderElement($element, $required, $error);
-        if (!$this->_inGroup) {
-            $this->renderedElements[] = array(
-                    'name' => $element->getName(), 
-                    'value' => $element->getValue(), 
-                    'html' => $this->_html, 
-                    'rendered' => false);
-        }
-        $this->_html = '';
-    } // end func renderElement
-
-    // }}}
-    // {{{ renderHidden()
-
-    /**
-     * Gets the html for a hidden element and adds it to the array.
-     * 
-     * @param HTML_QuickForm_element    hidden form element being visited
-     * @access public
-     * @return void
-     */
-    function renderHidden(&$element)
-    {
-        $this->renderedElements[] = array(
-                'name' => $element->getName(), 
-                'value' => $element->getValue(), 
-                'html' => $element->toHtml(), 
-                'rendered' => false);
-    } // end func renderHidden
-    
-    // }}}
-    // {{{ finishGroup()
-
-    /**
-     * Gets the html for the group element and adds it to the array by calling
-     * parent::finishGroup()
-     *
-     * @param    HTML_QuickForm_group   group being visited
-     * @access   public
-     * @return   void
-     */
-    function finishGroup(&$group)
-    {
-        $this->_html = '';
-        parent::finishGroup($group);
-        $this->renderedElements[] = array(
-                'name' => $group->getName(), 
-                'value' => $group->getValue(), 
-                'html' => $this->_html, 
-                'rendered' => false);
-        $this->_html = '';
-    } // end func finishGroup
-
-    // }}}
-} // end class HTML_QuickForm_Renderer_QuickHtml
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Tableless.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Renderer/Tableless.php
deleted file mode 100644 (file)
index 92cb7bb..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-<?php
-/**
- * Replacement for the default renderer of HTML_QuickForm that uses only XHTML
- * and CSS but no table tags, and generates fully valid XHTML output
- *
- * PHP versions 4 and 5
- *
- * LICENSE:
- *
- * Copyright (c) 2005-2007, Mark Wiesemann <wiesemann@php.net>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *    * Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *    * Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *    * The names of the authors may not be used to endorse or promote products
- *      derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @category   HTML
- * @package    HTML_QuickForm_Renderer_Tableless
- * @author     Alexey Borzov <borz_off@cs.msu.su>
- * @author     Adam Daniel <adaniel1@eesus.jnj.com>
- * @author     Bertrand Mansion <bmansion@mamasam.com>
- * @author     Mark Wiesemann <wiesemann@php.net>
- * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version    CVS: $Id: Tableless.php 271939 2008-12-26 20:22:30Z wiesemann $
- * @link       http://pear.php.net/package/HTML_QuickForm_Renderer_Tableless
- */
-
-require_once 'HTML/QuickForm/Renderer/Default.php';
-
-/**
- * Replacement for the default renderer of HTML_QuickForm that uses only XHTML
- * and CSS but no table tags, and generates fully valid XHTML output
- *
- * You need to specify a stylesheet like the one that you find in
- * data/stylesheet.css to make this work.
- *
- * @category   HTML
- * @package    HTML_QuickForm_Renderer_Tableless
- * @author     Alexey Borzov <borz_off@cs.msu.su>
- * @author     Adam Daniel <adaniel1@eesus.jnj.com>
- * @author     Bertrand Mansion <bmansion@mamasam.com>
- * @author     Mark Wiesemann <wiesemann@php.net>
- * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version    Release: 0.6.2
- * @link       http://pear.php.net/package/HTML_QuickForm_Renderer_Tableless
- */
-class HTML_QuickForm_Renderer_Tableless extends HTML_QuickForm_Renderer_Default
-{
-   /**
-    * Header Template string
-    * @var      string
-    * @access   private
-    */
-    var $_headerTemplate = "\n\t\t<legend>{header}</legend>\n\t\t<ol>";
-
-   /**
-    * Element template string
-    * @var      string
-    * @access   private
-    */
-    var $_elementTemplate =
-        "\n\t\t\t<li><label class=\"element\"><!-- BEGIN required --><span class=\"required\">*</span><!-- END required -->{label}</label><div class=\"element<!-- BEGIN error --> error<!-- END error -->\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</div></li>";
-
-   /**
-    * Form template string
-    * @var      string
-    * @access   private
-    */
-    var $_formTemplate =
-        "\n<form{attributes}>\n\t<div style=\"display: none;\">\n{hidden}\t</div>\n{content}\n</form>";
-
-   /**
-    * Template used when opening a fieldset
-    * @var      string
-    * @access   private
-    */
-    var $_openFieldsetTemplate = "\n\t<fieldset{id}{attributes}>";
-
-   /**
-    * Template used when opening a hidden fieldset
-    * (i.e. a fieldset that is opened when there is no header element)
-    * @var      string
-    * @access   private
-    */
-    var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden{class}\">\n\t\t<ol>";
-
-   /**
-    * Template used when closing a fieldset
-    * @var      string
-    * @access   private
-    */
-    var $_closeFieldsetTemplate = "\n\t\t</ol>\n\t</fieldset>";
-
-   /**
-    * Required Note template string
-    * @var      string
-    * @access   private
-    */
-    var $_requiredNoteTemplate =
-        "\n\t\t\t<li class=\"reqnote\"><label class=\"element\">&nbsp;</label>{requiredNote}</li>";
-
-   /**
-    * How many fieldsets are open
-    * @var      integer
-    * @access   private
-    */
-   var $_fieldsetsOpen = 0;
-
-   /**
-    * Array of element names that indicate the end of a fieldset
-    * (a new one will be opened when the next header element occurs)
-    * @var      array
-    * @access   private
-    */
-    var $_stopFieldsetElements = array();
-
-   /**
-    * Name of the currently active group
-    * @var      string
-    * @access   private
-    */
-    var $_currentGroupName = '';
-
-   /**
-    * Constructor
-    *
-    * @access public
-    */
-    function HTML_QuickForm_Renderer_Tableless()
-    {
-        $this->HTML_QuickForm_Renderer_Default();
-    } // end constructor
-
-   /**
-    * Called when visiting a header element
-    *
-    * @param    object     An HTML_QuickForm_header element being visited
-    * @access   public
-    * @return   void
-    */
-    function renderHeader(&$header)
-    {
-        $name = $header->getName();
-        $id = empty($name) ? '' : ' id="' . $name . '"';
-        if (!empty($name) && isset($this->_templates[$name])) {
-            $header_html = str_replace('{header}', $header->toHtml(), $this->_templates[$name]);
-        } else {
-            $header_html = str_replace('{header}', $header->toHtml(), $this->_headerTemplate);
-        }
-        $attributes = $header->getAttributes();
-        $strAttr = '';
-        if (is_array($attributes)) {
-            $charset = HTML_Common::charset();
-            foreach ($attributes as $key => $value) {
-                if ($key == 'name') {
-                    continue;
-                }
-                $strAttr .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT, $charset) . '"';
-            }
-        }
-        if ($this->_fieldsetsOpen > 0) {
-            $this->_html .= $this->_closeFieldsetTemplate;
-            $this->_fieldsetsOpen--;
-        }
-        $openFieldsetTemplate = str_replace('{id}', $id, $this->_openFieldsetTemplate);
-        $openFieldsetTemplate = str_replace('{attributes}',
-                                            $strAttr,
-                                            $openFieldsetTemplate);
-        $this->_html .= $openFieldsetTemplate . $header_html;
-        $this->_fieldsetsOpen++;
-    } // end func renderHeader
-
-   /**
-    * Renders an element Html
-    * Called when visiting an element
-    *
-    * @param object     An HTML_QuickForm_element object being visited
-    * @param bool       Whether an element is required
-    * @param string     An error message associated with an element
-    * @access public
-    * @return void
-    */
-    function renderElement(&$element, $required, $error)
-    {
-        $this->_handleStopFieldsetElements($element->getName());
-        if (!$this->_inGroup) {
-            $html = $this->_prepareTemplate($element->getName(), $element->getLabel(), $required, $error);
-            // the following lines (until the "elseif") were changed / added
-            // compared to the default renderer
-            $element_html = $element->toHtml();
-            if (!is_null($element->getAttribute('id'))) {
-                $id = $element->getAttribute('id');
-            } else {
-                $id = $element->getName();
-            }
-            if ($element->getType() != 'static' && !empty($id)) {
-                $html = str_replace('<label', '<label for="' . $id . '"', $html);
-                $element_html = preg_replace(preg_quote('#name="' . $id . '#'),
-                                             'id="' . $id . '" name="' . $id,
-                                             $element_html,
-                                             1);
-            }
-            $this->_html .= str_replace('{element}', $element_html, $html);
-        } elseif (!empty($this->_groupElementTemplate)) {
-            $html = str_replace('{label}', $element->getLabel(), $this->_groupElementTemplate);
-            if ($required) {
-                $html = str_replace('<!-- BEGIN required -->', '', $html);
-                $html = str_replace('<!-- END required -->', '', $html);
-            } else {
-                $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->(\s|\S)*<!-- END required -->([ \t\n\r]*)?/i", '', $html);
-            }
-            $this->_groupElements[] = str_replace('{element}', $element->toHtml(), $html);
-
-        } else {
-            $element_html = $element->toHtml();
-            // add "id" attribute to first element of the group
-            if (count($this->_groupElements) === 0) {
-                if (!is_null($element->getAttribute('id'))) {
-                    $id = $element->getAttribute('id');
-                } else {
-                    $id = $element->getName();
-                }
-                $groupId = $this->_currentGroupName;
-                if ($element->getType() != 'static' && !empty($id)) {
-                    $element_html = preg_replace(preg_quote('#name="' . $id . '#'),
-                                                 'id="' . $groupId . '" name="' . $id,
-                                                 $element_html,
-                                                 1);
-                }
-            }
-            $this->_groupElements[] = $element_html;
-        }
-    } // end func renderElement
-
-   /**
-    * Renders an hidden element
-    * Called when visiting a hidden element
-    *
-    * @param object     An HTML_QuickForm_hidden object being visited
-    * @access public
-    * @return void
-    */
-    function renderHidden(&$element)
-    {
-        if (!is_null($element->getAttribute('id'))) {
-            $id = $element->getAttribute('id');
-        } else {
-            $id = $element->getName();
-        }
-        $html = $element->toHtml();
-        if (!empty($id)) {
-            $html = str_replace('name="' . $id,
-                                'id="' . $id . '" name="' . $id,
-                                $html);
-        }
-        $this->_hiddenHtml .= $html . "\n";
-    } // end func renderHidden
-
-   /**
-    * Called when visiting a group, before processing any group elements
-    *
-    * @param object     An HTML_QuickForm_group object being visited
-    * @param bool       Whether a group is required
-    * @param string     An error message associated with a group
-    * @access public
-    * @return void
-    */
-    function startGroup(&$group, $required, $error)
-    {
-        $this->_handleStopFieldsetElements($group->getName());
-        $name = $group->getName();
-        $this->_groupTemplate        = $this->_prepareTemplate($name, $group->getLabel(), $required, $error);
-        $this->_groupTemplate        = str_replace('<label', '<label for="' . $name . '"', $this->_groupTemplate);
-        $this->_groupElementTemplate = empty($this->_groupTemplates[$name])? '': $this->_groupTemplates[$name];
-        $this->_groupWrap            = empty($this->_groupWraps[$name])? '': $this->_groupWraps[$name];
-        $this->_groupElements        = array();
-        $this->_inGroup              = true;
-        $this->_currentGroupName     = $name;
-    } // end func startGroup
-
-    /**
-    * Called when visiting a group, after processing all group elements
-    *
-    * @param    object      An HTML_QuickForm_group object being visited
-    * @access   public
-    * @return   void
-    */
-    function finishGroup(&$group)
-    {
-        $separator = $group->_separator;
-        if (is_array($separator)) {
-            $count = count($separator);
-            $html  = '';
-            for ($i = 0; $i < count($this->_groupElements); $i++) {
-                $html .= (0 == $i? '': $separator[($i - 1) % $count]) . $this->_groupElements[$i];
-            }
-        } else {
-            if (is_null($separator)) {
-                $separator = '&nbsp;';
-            }
-            $html = implode((string)$separator, $this->_groupElements);
-        }
-        if (!empty($this->_groupWrap)) {
-            $html = str_replace('{content}', $html, $this->_groupWrap);
-        }
-        if (!is_null($group->getAttribute('id'))) {
-            $id = $group->getAttribute('id');
-        } else {
-            $id = $group->getName();
-        }
-        $groupTemplate = $this->_groupTemplate;
-
-        $this->_html   .= str_replace('{element}', $html, $groupTemplate);
-        $this->_inGroup = false;
-    } // end func finishGroup
-
-    /**
-    * Called when visiting a form, before processing any form elements
-    *
-    * @param    object      An HTML_QuickForm object being visited
-    * @access   public
-    * @return   void
-    */
-    function startForm(&$form)
-    {
-        $this->_fieldsetsOpen = 0;
-        parent::startForm($form);
-    } // end func startForm
-
-   /**
-    * Called when visiting a form, after processing all form elements
-    * Adds required note, form attributes, validation javascript and form content.
-    *
-    * @param    object      An HTML_QuickForm object being visited
-    * @access   public
-    * @return   void
-    */
-    function finishForm(&$form)
-    {
-        // add a required note, if one is needed
-        if (!empty($form->_required) && !$form->_freezeAll) {
-            $requiredNote = $form->getRequiredNote();
-            // replace default required note by DOM/XHTML optimized note
-            if ($requiredNote == '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>') {
-                $requiredNote = '<span class="required">*</span> denotes required field';
-            }
-            $this->_html .= str_replace('{requiredNote}', $requiredNote, $this->_requiredNoteTemplate);
-        }
-        // close the open fieldset
-        if ($this->_fieldsetsOpen > 0) {
-            $this->_html .= $this->_closeFieldsetTemplate;
-            $this->_fieldsetsOpen--;
-        }
-        // add form attributes and content
-        $html = str_replace('{attributes}', $form->getAttributes(true), $this->_formTemplate);
-        if (strpos($this->_formTemplate, '{hidden}')) {
-            $html = str_replace('{hidden}', $this->_hiddenHtml, $html);
-        } else {
-            $this->_html .= $this->_hiddenHtml;
-        }
-        $this->_hiddenHtml = '';
-        $this->_html = str_replace('{content}', $this->_html, $html);
-        $this->_html = str_replace('></label>', '>&nbsp;</label>', $this->_html);
-        // add a validation script
-        if ('' != ($script = $form->getValidationScript())) {
-            $this->_html = $script . "\n" . $this->_html;
-        }
-    } // end func finishForm
-
-    /**
-     * Sets the template used when opening a fieldset
-     *
-     * @param       string      The HTML used when opening a fieldset
-     * @access      public
-     * @return      void
-     */
-    function setOpenFieldsetTemplate($html)
-    {
-        $this->_openFieldsetTemplate = $html;
-    } // end func setOpenFieldsetTemplate
-
-    /**
-     * Sets the template used when opening a hidden fieldset
-     * (i.e. a fieldset that is opened when there is no header element)
-     *
-     * @param       string      The HTML used when opening a hidden fieldset
-     * @access      public
-     * @return      void
-     */
-    function setOpenHiddenFieldsetTemplate($html)
-    {
-        $this->_openHiddenFieldsetTemplate = $html;
-    } // end func setOpenHiddenFieldsetTemplate
-
-    /**
-     * Sets the template used when closing a fieldset
-     *
-     * @param       string      The HTML used when closing a fieldset
-     * @access      public
-     * @return      void
-     */
-    function setCloseFieldsetTemplate($html)
-    {
-        $this->_closeFieldsetTemplate = $html;
-    } // end func setCloseFieldsetTemplate
-
-    /**
-     * Adds one or more element names that indicate the end of a fieldset
-     * (a new one will be opened when a the next header element occurs)
-     *
-     * @param       mixed      Element name(s) (as array or string)
-     * @param       string     (optional) Class name for the fieldset(s)
-     * @access      public
-     * @return      void
-     */
-    function addStopFieldsetElements($element, $class = '')
-    {
-        if (is_array($element)) {
-            $elements = array();
-            foreach ($element as $name) {
-                $elements[$name] = $class;
-            }
-            $this->_stopFieldsetElements = array_merge($this->_stopFieldsetElements,
-                                                       $elements);
-        } else {
-            $this->_stopFieldsetElements[$element] = $class;
-        }
-    } // end func addStopFieldsetElements
-
-    /**
-     * Handle element/group names that indicate the end of a group
-     *
-     * @param string     The name of the element or group
-     * @access private
-     * @return void
-     */
-    function _handleStopFieldsetElements($element)
-    {
-        // if the element/group name indicates the end of a fieldset, close
-        // the fieldset
-        if (   array_key_exists($element, $this->_stopFieldsetElements)
-            && $this->_fieldsetsOpen > 0
-           ) {
-            $this->_html .= $this->_closeFieldsetTemplate;
-            $this->_fieldsetsOpen--;
-        }
-        // if no fieldset was opened, we need to open a hidden one here to get
-        // XHTML validity
-        if ($this->_fieldsetsOpen === 0) {
-            $replace = '';
-            if (   array_key_exists($element, $this->_stopFieldsetElements)
-                && $this->_stopFieldsetElements[$element] != ''
-               ) {
-                $replace = ' ' . $this->_stopFieldsetElements[$element];
-            }
-            $this->_html .= str_replace('{class}', $replace,
-                                        $this->_openHiddenFieldsetTemplate);
-            $this->_fieldsetsOpen++;
-        }
-    } // end func _handleStopFieldsetElements
-
-    /**
-     * Sets element template
-     *
-     * @param   string    The HTML surrounding an element
-     * @param   mixed     (optional) Name(s) of the element to apply template
-     *                    for (either single element name as string or multiple
-     *                    element names as an array)
-     * @access  public
-     * @return  void
-     */
-    function setElementTemplate($html, $element = null)
-    {
-        if (is_null($element)) {
-            $this->_elementTemplate = $html;
-        } elseif (is_array($element)) {
-            foreach ($element as $name) {
-                $this->_templates[$name] = $html;
-            }
-        } else {
-            $this->_templates[$element] = $html;
-        }
-    } // end func setElementTemplate
-
-} // end class HTML_QuickForm_Renderer_Default
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule.php
deleted file mode 100644 (file)
index 9d95020..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Abstract base class for QuickForm validation rules 
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Abstract base class for QuickForm validation rules 
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.2
- * @abstract
- */
-class HTML_QuickForm_Rule
-{
-   /**
-    * Name of the rule to use in validate method
-    *
-    * This property is used in more global rules like Callback and Regex
-    * to determine which callback and which regex is to be used for validation
-    *
-    * @var  string
-    * @access   public
-    */
-    var $name;
-
-   /**
-    * Validates a value
-    * 
-    * @access public
-    * @abstract
-    */
-    function validate($value)
-    {
-        return true;
-    }
-
-   /**
-    * Sets the rule name
-    *
-    * @param  string    rule name
-    * @access public
-    */
-    function setName($ruleName)
-    {
-        $this->name = $ruleName;
-    }
-
-    /**
-     * Returns the javascript test (the test should return true if the value is INVALID)
-     *
-     * @param     mixed     Options for the rule
-     * @access    public
-     * @return    array     first element is code to setup validation, second is the check itself
-     * @abstract
-     */
-    function getValidationScript($options = null)
-    {
-        return array('', '');
-    }
-}
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Callback.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Callback.php
deleted file mode 100644 (file)
index 1557506..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Validates values using callback functions or methods
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Abstract base class for QuickForm validation rules 
- */
-require_once 'HTML/QuickForm/Rule.php';
-
-/**
- * Validates values using callback functions or methods
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_Rule_Callback extends HTML_QuickForm_Rule
-{
-    /**
-     * Array of callbacks
-     *
-     * Array is in the format:
-     * $_data['rulename'] = array('functionname', 'classname');
-     * If the callback is not a method, then the class name is not set.
-     *
-     * @var     array
-     * @access  private
-     */
-    var $_data = array();
-
-   /**
-    * Whether to use BC mode for specific rules
-    * 
-    * Previous versions of QF passed element's name as a first parameter
-    * to validation functions, but not to validation methods. This behaviour
-    * is emulated if you are using 'function' as rule type when registering.
-    * 
-    * @var array
-    * @access private
-    */
-    var $_BCMode = array();
-
-    /**
-     * Validates a value using a callback
-     *
-     * @param     string    $value      Value to be checked
-     * @param     mixed     $options    Options for callback
-     * @access    public
-     * @return    boolean   true if value is valid
-     */
-    function validate($value, $options = null)
-    {
-        if (isset($this->_data[$this->name])) {
-            $callback = $this->_data[$this->name];
-            if (isset($callback[1])) {
-                return call_user_func(array($callback[1], $callback[0]), $value, $options);
-            } elseif ($this->_BCMode[$this->name]) {
-                return $callback[0]('', $value, $options);
-            } else {
-                return $callback[0]($value, $options);
-            }
-        } elseif (is_callable($options)) {
-            return call_user_func($options, $value);
-        } else {
-            return true;
-        }
-    } // end func validate
-
-    /**
-     * Adds new callbacks to the callbacks list
-     *
-     * @param     string    $name       Name of rule
-     * @param     string    $callback   Name of function or method
-     * @param     string    $class      Name of class containing the method
-     * @param     bool      $BCMode     Backwards compatibility mode 
-     * @access    public
-     */
-    function addData($name, $callback, $class = null, $BCMode = false)
-    {
-        if (!empty($class)) {
-            $this->_data[$name] = array($callback, $class);
-        } else {
-            $this->_data[$name] = array($callback);
-        }
-        $this->_BCMode[$name] = $BCMode;
-    } // end func addData
-
-
-    function getValidationScript($options = null)
-    {
-        if (isset($this->_data[$this->name])) {
-            $callback = $this->_data[$this->name][0];
-            $params   = ($this->_BCMode[$this->name]? "'', {jsVar}": '{jsVar}') .
-                        (isset($options)? ", '{$options}'": '');
-        } else {
-            $callback = is_array($options)? $options[1]: $options;
-            $params   = '{jsVar}';
-        }
-        return array('', "{jsVar} != '' && !{$callback}({$params})");
-    } // end func getValidationScript
-
-} // end class HTML_QuickForm_Rule_Callback
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Compare.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Compare.php
deleted file mode 100644 (file)
index 82d38c7..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Rule to compare two form fields
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Abstract base class for QuickForm validation rules 
- */
-require_once 'HTML/QuickForm/Rule.php';
-
-/**
- * Rule to compare two form fields
- * 
- * The most common usage for this is to ensure that the password 
- * confirmation field matches the password field
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_Rule_Compare extends HTML_QuickForm_Rule
-{
-   /**
-    * Possible operators to use
-    * @var array
-    * @access private
-    */
-    var $_operators = array(
-        'eq'  => '===',
-        'neq' => '!==',
-        'gt'  => '>',
-        'gte' => '>=',
-        'lt'  => '<',
-        'lte' => '<=',
-        '=='  => '===',
-        '!='  => '!=='
-    );
-
-
-   /**
-    * Returns the operator to use for comparing the values
-    * 
-    * @access private
-    * @param  string     operator name
-    * @return string     operator to use for validation
-    */
-    function _findOperator($name)
-    {
-        if (empty($name)) {
-            return '===';
-        } elseif (isset($this->_operators[$name])) {
-            return $this->_operators[$name];
-        } elseif (in_array($name, $this->_operators)) {
-            return $name;
-        } else {
-            return '===';
-        }
-    }
-
-
-    function validate($values, $operator = null)
-    {
-        $operator = $this->_findOperator($operator);
-        if ('===' != $operator && '!==' != $operator) {
-            $compareFn = create_function('$a, $b', 'return floatval($a) ' . $operator . ' floatval($b);');
-        } else {
-            $compareFn = create_function('$a, $b', 'return strval($a) ' . $operator . ' strval($b);');
-        }
-        
-        return $compareFn($values[0], $values[1]);
-    }
-
-
-    function getValidationScript($operator = null)
-    {
-        $operator = $this->_findOperator($operator);
-        if ('===' != $operator && '!==' != $operator) {
-            $check = "!(Number({jsVar}[0]) {$operator} Number({jsVar}[1]))";
-        } else {
-            $check = "!(String({jsVar}[0]) {$operator} String({jsVar}[1]))";
-        }
-        return array('', "'' != {jsVar}[0] && {$check}");
-    }
-}
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Email.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Email.php
deleted file mode 100644 (file)
index d38acd5..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Email validation rule
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Abstract base class for QuickForm validation rules 
- */
-require_once 'HTML/QuickForm/Rule.php';
-
-/**
- * Email validation rule
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_Rule_Email extends HTML_QuickForm_Rule
-{
-    var $regex = '/^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/';
-
-    /**
-     * Validates an email address
-     *
-     * @param     string    $email          Email address
-     * @param     boolean   $checkDomain    True if dns check should be performed
-     * @access    public
-     * @return    boolean   true if email is valid
-     */
-    function validate($email, $checkDomain = false)
-    {
-        // Fix for bug #10799: add 'D' modifier to regex
-        if (preg_match($this->regex . 'D', $email)) {
-            if ($checkDomain && function_exists('checkdnsrr')) {
-                $tokens = explode('@', $email);
-                if (checkdnsrr($tokens[1], 'MX') || checkdnsrr($tokens[1], 'A')) {
-                    return true;
-                }
-                return false;
-            }
-            return true;
-        }
-        return false;
-    } // end func validate
-
-
-    function getValidationScript($options = null)
-    {
-        return array("  var regex = " . $this->regex . ";\n", "{jsVar} != '' && !regex.test({jsVar})");
-    } // end func getValidationScript
-
-} // end class HTML_QuickForm_Rule_Email
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Range.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Range.php
deleted file mode 100644 (file)
index 14118f5..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Checks that the length of value is within range
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Abstract base class for QuickForm validation rules 
- */
-require_once 'HTML/QuickForm/Rule.php';
-
-/**
- * Checks that the length of value is within range
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_Rule_Range extends HTML_QuickForm_Rule
-{
-    /**
-     * Validates a value using a range comparison
-     *
-     * @param     string    $value      Value to be checked
-     * @param     mixed     $options    Int for length, array for range
-     * @access    public
-     * @return    boolean   true if value is valid
-     */
-    function validate($value, $options = null)
-    {
-        $length = strlen($value);
-        switch ($this->name) {
-            case 'minlength': return ($length >= $options);
-            case 'maxlength': return ($length <= $options);
-            default:          return ($length >= $options[0] && $length <= $options[1]);
-        }
-    } // end func validate
-
-
-    function getValidationScript($options = null)
-    {
-        switch ($this->name) {
-            case 'minlength': 
-                $test = '{jsVar}.length < '.$options;
-                break;
-            case 'maxlength': 
-                $test = '{jsVar}.length > '.$options;
-                break;
-            default: 
-                $test = '({jsVar}.length < '.$options[0].' || {jsVar}.length > '.$options[1].')';
-        }
-        return array('', "{jsVar} != '' && {$test}");
-    } // end func getValidationScript
-
-} // end class HTML_QuickForm_Rule_Range
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Regex.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Regex.php
deleted file mode 100644 (file)
index 2d3d702..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Validates values using regular expressions
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Abstract base class for QuickForm validation rules 
- */
-require_once 'HTML/QuickForm/Rule.php';
-
-/**
- * Validates values using regular expressions
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_Rule_Regex extends HTML_QuickForm_Rule
-{
-    /**
-     * Array of regular expressions
-     *
-     * Array is in the format:
-     * $_data['rulename'] = 'pattern';
-     *
-     * @var     array
-     * @access  private
-     */
-    var $_data = array(
-                    'lettersonly'   => '/^[a-zA-Z]+$/',
-                    'alphanumeric'  => '/^[a-zA-Z0-9]+$/',
-                    'numeric'       => '/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/',
-                    'nopunctuation' => '/^[^().\/\*\^\?#!@$%+=,\"\'><~\[\]{}]+$/',
-                    'nonzero'       => '/^-?[1-9][0-9]*/'
-                    );
-
-    /**
-     * Validates a value using a regular expression
-     *
-     * @param     string    $value      Value to be checked
-     * @param     string    $regex      Regular expression
-     * @access    public
-     * @return    boolean   true if value is valid
-     */
-    function validate($value, $regex = null)
-    {
-        // Fix for bug #10799: add 'D' modifier to regex
-        if (isset($this->_data[$this->name])) {
-            if (!preg_match($this->_data[$this->name] . 'D', $value)) {
-                return false;
-            }
-        } else {
-            if (!preg_match($regex . 'D', $value)) {
-                return false;
-            }
-        }
-        return true;
-    } // end func validate
-
-    /**
-     * Adds new regular expressions to the list
-     *
-     * @param     string    $name       Name of rule
-     * @param     string    $pattern    Regular expression pattern
-     * @access    public
-     */
-    function addData($name, $pattern)
-    {
-        $this->_data[$name] = $pattern;
-    } // end func addData
-
-
-    function getValidationScript($options = null)
-    {
-        $regex = isset($this->_data[$this->name]) ? $this->_data[$this->name] : $options;
-
-        // bug #12376, converting unicode escapes and stripping 'u' modifier
-        if ($pos = strpos($regex, 'u', strrpos($regex, '/'))) {
-            $regex = substr($regex, 0, $pos) . substr($regex, $pos + 1);
-            $regex = preg_replace('/(?<!\\\\)(?>\\\\\\\\)*\\\\x{([a-fA-F0-9]+)}/', '\\u$1', $regex);
-        }
-
-        return array("  var regex = " . $regex . ";\n", "{jsVar} != '' && !regex.test({jsVar})");
-    } // end func getValidationScript
-
-} // end class HTML_QuickForm_Rule_Regex
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Required.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/Rule/Required.php
deleted file mode 100644 (file)
index 26ff62f..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Required elements validation
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Abstract base class for QuickForm validation rules 
- */
-require_once 'HTML/QuickForm/Rule.php';
-
-/**
- * Required elements validation
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_Rule_Required extends HTML_QuickForm_Rule
-{
-    /**
-     * Checks if an element is empty
-     *
-     * @param     string    $value      Value to check
-     * @param     mixed     $options    Not used yet
-     * @access    public
-     * @return    boolean   true if value is not empty
-     */
-    function validate($value, $options = null)
-    {
-        if (is_array($value)) {
-            return (bool) $value;
-        } else if ((string)$value == '') {
-            return false;
-        }
-        return true;
-    } // end func validate
-
-
-    function getValidationScript($options = null)
-    {
-        return array('', "{jsVar} == ''");
-    } // end func getValidationScript
-
-} // end class HTML_QuickForm_Rule_Required
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/RuleRegistry.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/RuleRegistry.php
deleted file mode 100644 (file)
index 3d23716..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Registers rule objects and uses them for validation
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Registers rule objects and uses them for validation
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_RuleRegistry
-{
-    /**
-     * Array containing references to used rules
-     * @var     array
-     * @access  private
-     */
-    var $_rules = array();
-
-
-    /**
-     * Returns a singleton of HTML_QuickForm_RuleRegistry
-     *
-     * Usually, only one RuleRegistry object is needed, this is the reason
-     * why it is recommended to use this method to get the validation object. 
-     *
-     * @access    public
-     * @static
-     * @return    HTML_QuickForm_RuleRegistry
-     */
-    function &singleton()
-    {
-        static $obj;
-        if (!isset($obj)) {
-            $obj = new HTML_QuickForm_RuleRegistry();
-        }
-        return $obj;
-    } // end func singleton
-
-    /**
-     * Registers a new validation rule
-     *
-     * In order to use a custom rule in your form, you need to register it
-     * first. For regular expressions, one can directly use the 'regex' type
-     * rule in addRule(), this is faster than registering the rule.
-     *
-     * Functions and methods can be registered. Use the 'function' type.
-     * When registering a method, specify the class name as second parameter.
-     *
-     * You can also register an HTML_QuickForm_Rule subclass with its own
-     * validate() method.
-     *
-     * @param     string    $ruleName   Name of validation rule
-     * @param     string    $type       Either: 'regex', 'function' or null
-     * @param     string    $data1      Name of function, regular expression or
-     *                                  HTML_QuickForm_Rule object class name
-     * @param     string    $data2      Object parent of above function or HTML_QuickForm_Rule file path
-     * @access    public
-     * @return    void
-     */
-    function registerRule($ruleName, $type, $data1, $data2 = null)
-    {
-        $type = strtolower($type);
-        if ($type == 'regex') {
-            // Regular expression
-            $rule =& $this->getRule('regex');
-            $rule->addData($ruleName, $data1);
-            $GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = $GLOBALS['_HTML_QuickForm_registered_rules']['regex'];
-
-        } elseif ($type == 'function' || $type == 'callback') {
-            // Callback function
-            $rule =& $this->getRule('callback');
-            $rule->addData($ruleName, $data1, $data2, 'function' == $type);
-            $GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = $GLOBALS['_HTML_QuickForm_registered_rules']['callback'];
-
-        } elseif (is_object($data1)) {
-            // An instance of HTML_QuickForm_Rule
-            $this->_rules[strtolower(get_class($data1))] = $data1;
-            $GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = array(strtolower(get_class($data1)), null);
-
-        } else {
-            // Rule class name
-            $GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName] = array(strtolower($data1), $data2);
-        }
-    } // end func registerRule
-
-    /**
-     * Returns a reference to the requested rule object
-     *
-     * @param     string   $ruleName        Name of the requested rule
-     * @access    public
-     * @return    HTML_QuickForm_Rule
-     */
-    function &getRule($ruleName)
-    {
-        list($class, $path) = $GLOBALS['_HTML_QuickForm_registered_rules'][$ruleName];
-
-        if (!isset($this->_rules[$class])) {
-            if (!empty($path)) {
-                include_once($path);
-            }
-            $this->_rules[$class] = new $class();
-        }
-        $this->_rules[$class]->setName($ruleName);
-        return $this->_rules[$class];
-    } // end func getRule
-
-    /**
-     * Performs validation on the given values
-     *
-     * @param     string   $ruleName        Name of the rule to be used
-     * @param     mixed    $values          Can be a scalar or an array of values 
-     *                                      to be validated
-     * @param     mixed    $options         Options used by the rule
-     * @param     mixed    $multiple        Whether to validate an array of values altogether
-     * @access    public
-     * @return    mixed    true if no error found, int of valid values (when an array of values is given) or false if error
-     */
-    function validate($ruleName, $values, $options = null, $multiple = false)
-    {
-        $rule =& $this->getRule($ruleName);
-
-        if (is_array($values) && !$multiple) {
-            $result = 0;
-            foreach ($values as $value) {
-                if ($rule->validate($value, $options) === true) {
-                    $result++;
-                }
-            }
-            return ($result == 0) ? false : $result;
-        } else {
-            return $rule->validate($values, $options);
-        }
-    } // end func validate
-
-    /**
-     * Returns the validation test in javascript code
-     *
-     * @param     array|HTML_QuickForm_element  Element(s) the rule applies to
-     * @param     string                        Element name, in case $element is 
-     *                                          not an array
-     * @param     array                         Rule data
-     * @access    public
-     * @return    string    JavaScript for the rule
-     */
-    function getValidationScript(&$element, $elementName, $ruleData)
-    {
-        $reset =  (isset($ruleData['reset'])) ? $ruleData['reset'] : false;
-        $rule  =& $this->getRule($ruleData['type']);
-        if (!is_array($element)) {
-            list($jsValue, $jsReset) = $this->_getJsValue($element, $elementName, $reset, null);
-        } else {
-            $jsValue = "  value = new Array();\n";
-            $jsReset = '';
-            for ($i = 0; $i < count($element); $i++) {
-                list($tmp_value, $tmp_reset) = $this->_getJsValue($element[$i], $element[$i]->getName(), $reset, $i);
-                $jsValue .= "\n" . $tmp_value;
-                $jsReset .= $tmp_reset;
-            }
-        }
-        $jsField = isset($ruleData['group'])? $ruleData['group']: $elementName;
-        list ($jsPrefix, $jsCheck) = $rule->getValidationScript($ruleData['format']);
-        if (!isset($ruleData['howmany'])) {
-            $js = $jsValue . "\n" . $jsPrefix . 
-                  "  if (" . str_replace('{jsVar}', 'value', $jsCheck) . " && !errFlag['{$jsField}']) {\n" .
-                  "    errFlag['{$jsField}'] = true;\n" .
-                  "    _qfMsg = _qfMsg + '\\n - {$ruleData['message']}';\n" .
-                  $jsReset .
-                  "  }\n";
-        } else {
-            $js = $jsValue . "\n" . $jsPrefix . 
-                  "  var res = 0;\n" .
-                  "  for (var i = 0; i < value.length; i++) {\n" .
-                  "    if (!(" . str_replace('{jsVar}', 'value[i]', $jsCheck) . ")) {\n" .
-                  "      res++;\n" .
-                  "    }\n" .
-                  "  }\n" . 
-                  "  if (res < {$ruleData['howmany']} && !errFlag['{$jsField}']) {\n" . 
-                  "    errFlag['{$jsField}'] = true;\n" .
-                  "    _qfMsg = _qfMsg + '\\n - {$ruleData['message']}';\n" .
-                  $jsReset .
-                  "  }\n";
-        }
-        return $js;
-    } // end func getValidationScript
-
-
-   /**
-    * Returns JavaScript to get and to reset the element's value 
-    * 
-    * @access private
-    * @param  HTML_QuickForm_element    element being processed
-    * @param  string                    element's name
-    * @param  bool                      whether to generate JavaScript to reset 
-    *                                   the value
-    * @param  integer                   value's index in the array (only used for
-    *                                   multielement rules)
-    * @return array     first item is value javascript, second is reset
-    */
-    function _getJsValue(&$element, $elementName, $reset = false, $index = null)
-    {
-        $jsIndex = isset($index)? '[' . $index . ']': '';
-        $tmp_reset = $reset? "    var field = frm.elements['$elementName'];\n": '';
-        if (is_a($element, 'html_quickform_group')) {
-            $value = "  _qfGroups['{$elementName}'] = {";
-            $elements =& $element->getElements();
-            for ($i = 0, $count = count($elements); $i < $count; $i++) {
-                $append = ($elements[$i]->getType() == 'select' && $elements[$i]->getMultiple())? '[]': '';
-                $value .= "'" . $element->getElementName($i) . $append . "': true" .
-                          ($i < $count - 1? ', ': '');
-            }
-            $value .=
-                "};\n" .
-                "  value{$jsIndex} = new Array();\n" .
-                "  var valueIdx = 0;\n" .
-                "  for (var i = 0; i < frm.elements.length; i++) {\n" .
-                "    var _element = frm.elements[i];\n" .
-                "    if (_element.name in _qfGroups['{$elementName}']) {\n" . 
-                "      switch (_element.type) {\n" .
-                "        case 'checkbox':\n" .
-                "        case 'radio':\n" .
-                "          if (_element.checked) {\n" .
-                "            value{$jsIndex}[valueIdx++] = _element.value;\n" .
-                "          }\n" .
-                "          break;\n" .
-                "        case 'select-one':\n" .
-                "          if (-1 != _element.selectedIndex) {\n" .
-                "            value{$jsIndex}[valueIdx++] = _element.options[_element.selectedIndex].value;\n" .
-                "          }\n" .
-                "          break;\n" .
-                "        case 'select-multiple':\n" .
-                "          var tmpVal = new Array();\n" .
-                "          var tmpIdx = 0;\n" .
-                "          for (var j = 0; j < _element.options.length; j++) {\n" .
-                "            if (_element.options[j].selected) {\n" .
-                "              tmpVal[tmpIdx++] = _element.options[j].value;\n" .
-                "            }\n" .
-                "          }\n" .
-                "          if (tmpIdx > 0) {\n" .
-                "            value{$jsIndex}[valueIdx++] = tmpVal;\n" .
-                "          }\n" .
-                "          break;\n" .
-                "        default:\n" .
-                "          value{$jsIndex}[valueIdx++] = _element.value;\n" .
-                "      }\n" .
-                "    }\n" .
-                "  }\n";
-            if ($reset) {
-                $tmp_reset =
-                    "    for (var i = 0; i < frm.elements.length; i++) {\n" .
-                    "      var _element = frm.elements[i];\n" .
-                    "      if (_element.name in _qfGroups['{$elementName}']) {\n" . 
-                    "        switch (_element.type) {\n" .
-                    "          case 'checkbox':\n" .
-                    "          case 'radio':\n" .
-                    "            _element.checked = _element.defaultChecked;\n" .
-                    "            break;\n" .
-                    "          case 'select-one':\n" .
-                    "          case 'select-multiple':\n" .
-                    "            for (var j = 0; j < _element.options.length; j++) {\n" .
-                    "              _element.options[j].selected = _element.options[j].defaultSelected;\n" .
-                    "            }\n" .
-                    "            break;\n" .
-                    "          default:\n" .
-                    "            _element.value = _element.defaultValue;\n" .
-                    "        }\n" .
-                    "      }\n" .
-                    "    }\n";
-            }
-
-        } elseif ($element->getType() == 'select') {
-            if ($element->getMultiple()) {
-                $elementName .= '[]';
-                $value =
-                    "  value{$jsIndex} = new Array();\n" .
-                    "  var valueIdx = 0;\n" .
-                    "  for (var i = 0; i < frm.elements['{$elementName}'].options.length; i++) {\n" . 
-                    "    if (frm.elements['{$elementName}'].options[i].selected) {\n" .
-                    "      value{$jsIndex}[valueIdx++] = frm.elements['{$elementName}'].options[i].value;\n" .
-                    "    }\n" .
-                    "  }\n";
-            } else {
-                $value = "  value{$jsIndex} = frm.elements['{$elementName}'].selectedIndex == -1? '': frm.elements['{$elementName}'].options[frm.elements['{$elementName}'].selectedIndex].value;\n";
-            }
-            if ($reset) {
-                $tmp_reset .= 
-                    "    for (var i = 0; i < field.options.length; i++) {\n" .
-                    "      field.options[i].selected = field.options[i].defaultSelected;\n" .
-                    "    }\n";
-            }
-
-        } elseif ($element->getType() == 'checkbox') {
-            if (is_a($element, 'html_quickform_advcheckbox')) {
-                $value = "  value{$jsIndex} = frm.elements['$elementName'][1].checked? frm.elements['$elementName'][1].value: frm.elements['$elementName'][0].value;\n";
-                $tmp_reset .= $reset ? "    field[1].checked = field[1].defaultChecked;\n" : '';
-            } else {
-                $value = "  value{$jsIndex} = frm.elements['$elementName'].checked? '1': '';\n";
-                $tmp_reset .= $reset ? "    field.checked = field.defaultChecked;\n" : '';
-            }
-
-        } elseif ($element->getType() == 'radio') {
-            $value = "  value{$jsIndex} = '';\n" .
-                     // Fix for bug #5644
-                     "  var els = 'length' in frm.elements['$elementName']? frm.elements['$elementName']: [ frm.elements['$elementName'] ];\n" .
-                     "  for (var i = 0; i < els.length; i++) {\n" .
-                     "    if (els[i].checked) {\n" .
-                     "      value{$jsIndex} = els[i].value;\n" .
-                     "    }\n" .
-                     "  }";
-            if ($reset) {
-                $tmp_reset .= "    for (var i = 0; i < field.length; i++) {\n" .
-                              "      field[i].checked = field[i].defaultChecked;\n" .
-                              "    }";
-            }
-
-        } else {
-            $value = "  value{$jsIndex} = frm.elements['$elementName'].value;";
-            $tmp_reset .= ($reset) ? "    field.value = field.defaultValue;\n" : '';
-        }
-        return array($value, $tmp_reset);
-    }
-} // end class HTML_QuickForm_RuleRegistry
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/advcheckbox.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/advcheckbox.php
deleted file mode 100644 (file)
index 6d72be6..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for an advanced checkbox type field
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Jason Rust <jrust@php.net>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * HTML class for a checkbox type field
- */
-require_once 'HTML/QuickForm/checkbox.php';
-
-/**
- * HTML class for an advanced checkbox type field
- *
- * Basically this fixes a problem that HTML has had
- * where checkboxes can only pass a single value (the
- * value of the checkbox when checked).  A value for when
- * the checkbox is not checked cannot be passed, and 
- * furthermore the checkbox variable doesn't even exist if
- * the checkbox was submitted unchecked.
- *
- * It works by prepending a hidden field with the same name and
- * another "unchecked" value to the checbox. If the checkbox is
- * checked, PHP overwrites the value of the hidden field with
- * its value. 
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Jason Rust <jrust@php.net>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       2.0
- */
-class HTML_QuickForm_advcheckbox extends HTML_QuickForm_checkbox
-{
-    // {{{ properties
-
-    /**
-     * The values passed by the hidden elment
-     *
-     * @var array
-     * @access private
-     */
-    var $_values = null;
-
-    /**
-     * The default value
-     *
-     * @var boolean
-     * @access private
-     */
-    var $_currentValue = null;
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $elementLabel   (optional)Input field label 
-     * @param     string    $text           (optional)Text to put after the checkbox
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @param     mixed     $values         (optional)Values to pass if checked or not checked 
-     *
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_advcheckbox($elementName=null, $elementLabel=null, $text=null, $attributes=null, $values=null)
-    {
-        $this->HTML_QuickForm_checkbox($elementName, $elementLabel, $text, $attributes);
-        $this->setValues($values);
-    } //end constructor
-    
-    // }}}
-    // {{{ getPrivateName()
-
-    /**
-     * Gets the private name for the element
-     *
-     * @param   string  $elementName The element name to make private
-     *
-     * @access public
-     * @return string
-     *
-     * @deprecated          Deprecated since 3.2.6, both generated elements have the same name
-     */
-    function getPrivateName($elementName)
-    {
-        return '__'.$elementName;
-    }
-
-    // }}}
-    // {{{ getOnclickJs()
-
-    /**
-     * Create the javascript for the onclick event which will
-     * set the value of the hidden field
-     *
-     * @param     string    $elementName    The element name
-     *
-     * @access public
-     * @return string
-     *
-     * @deprecated          Deprecated since 3.2.6, this element no longer uses any javascript
-     */
-    function getOnclickJs($elementName)
-    {
-        $onclickJs = 'if (this.checked) { this.form[\''.$elementName.'\'].value=\''.addcslashes($this->_values[1], '\'').'\'; }';
-        $onclickJs .= 'else { this.form[\''.$elementName.'\'].value=\''.addcslashes($this->_values[0], '\'').'\'; }';
-        return $onclickJs;
-    }
-
-    // }}}
-    // {{{ setValues()
-
-    /**
-     * Sets the values used by the hidden element
-     *
-     * @param   mixed   $values The values, either a string or an array
-     *
-     * @access public
-     * @return void
-     */
-    function setValues($values)
-    {
-        if (empty($values)) {
-            // give it default checkbox behavior
-            $this->_values = array('', 1);
-        } elseif (is_scalar($values)) {
-            // if it's string, then assume the value to 
-            // be passed is for when the element is checked
-            $this->_values = array('', $values);
-        } else {
-            $this->_values = $values;
-        }
-        $this->updateAttributes(array('value' => $this->_values[1]));
-        $this->setChecked($this->_currentValue == $this->_values[1]);
-    }
-
-    // }}}
-    // {{{ setValue()
-
-   /**
-    * Sets the element's value
-    * 
-    * @param    mixed   Element's value
-    * @access   public
-    */
-    function setValue($value)
-    {
-        $this->setChecked(isset($this->_values[1]) && $value == $this->_values[1]);
-        $this->_currentValue = $value;
-    }
-
-    // }}}
-    // {{{ getValue()
-
-   /**
-    * Returns the element's value
-    *
-    * @access   public
-    * @return   mixed
-    */
-    function getValue()
-    {
-        if (is_array($this->_values)) {
-            return $this->_values[$this->getChecked()? 1: 0];
-        } else {
-            return null;
-        }
-    }
-
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the checkbox element in HTML
-     * and the additional hidden element in HTML
-     * 
-     * @access    public
-     * @return    string
-     */
-    function toHtml()
-    {
-        if ($this->_flagFrozen) {
-            return parent::toHtml();
-        } else {
-            return '<input' . $this->_getAttrString(array(
-                        'type'  => 'hidden', 
-                        'name'  => $this->getName(), 
-                        'value' => $this->_values[0]
-                   )) . ' />' . parent::toHtml();
-            
-        }
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getFrozenHtml()
-
-   /**
-    * Unlike checkbox, this has to append a hidden input in both
-    * checked and non-checked states
-    */
-    function getFrozenHtml()
-    {
-        return ($this->getChecked()? '<tt>[x]</tt>': '<tt>[ ]</tt>') .
-               $this->_getPersistantData();
-    }
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    $event  Name of event
-     * @param     mixed     $arg    event arguments
-     * @param     object    &$caller calling object
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        switch ($event) {
-            case 'updateValue':
-                // constant values override both default and submitted ones
-                // default values are overriden by submitted
-                $value = $this->_findValue($caller->_constantValues);
-                if (null === $value) {
-                    $value = $this->_findValue($caller->_submitValues);
-                    if (null === $value) {
-                        $value = $this->_findValue($caller->_defaultValues);
-                    }
-                }
-                if (null !== $value) {
-                    $this->setValue($value);
-                }
-                break;
-            default:
-                parent::onQuickFormEvent($event, $arg, $caller);
-        }
-        return true;
-    } // end func onQuickFormLoad
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * This element has a value even if it is not checked, thus we override
-    * checkbox's behaviour here
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        $value = $this->_findValue($submitValues);
-        if (null === $value) {
-            $value = $this->getValue();
-        } elseif (is_array($this->_values) && ($value != $this->_values[0]) && ($value != $this->_values[1])) {
-            $value = null;
-        }
-        return $this->_prepareValue($value, $assoc);
-    }
-    // }}}
-} //end class HTML_QuickForm_advcheckbox
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/autocomplete.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/autocomplete.php
deleted file mode 100644 (file)
index bb6fe31..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for an autocomplete element
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Matteo Di Giovinazzo <matteodg@infinito.it>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * HTML class for a text field
- */
-require_once 'HTML/QuickForm/text.php';
-
-/**
- * HTML class for an autocomplete element
- *
- * Creates an HTML input text element that
- * at every keypressed javascript event checks in an array of options
- * if there's a match and autocompletes the text in case of match.
- *
- * For the JavaScript code thanks to Martin Honnen and Nicholas C. Zakas
- * See {@link http://www.faqts.com/knowledge_base/view.phtml/aid/13562} and
- * {@link http://www.sitepoint.com/article/1220}
- *
- * Example:
- * <code>
- * $autocomplete =& $form->addElement('autocomplete', 'fruit', 'Favourite fruit:');
- * $options = array("Apple", "Orange", "Pear", "Strawberry");
- * $autocomplete->setOptions($options);
- * </code>
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Matteo Di Giovinazzo <matteodg@infinito.it>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_autocomplete extends HTML_QuickForm_text
-{
-    // {{{ properties
-
-    /**
-     * Options for the autocomplete input text element
-     *
-     * @var       array
-     * @access    private
-     */
-    var $_options = array();
-
-    /**
-     * "One-time" javascript (containing functions), see bug #4611
-     *
-     * @var     string
-     * @access  private
-     */
-    var $_js = '';
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     *
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $elementLabel   (optional)Input field label in form
-     * @param     array     $options        (optional)Autocomplete options
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string
-     *                                      or an associative array. Date format is passed along the attributes.
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_autocomplete($elementName = null, $elementLabel = null, $options = null, $attributes = null)
-    {
-        $this->HTML_QuickForm_text($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        $this->_type = 'autocomplete';
-        if (isset($options)) {
-            $this->setOptions($options);
-        }
-    } //end constructor
-
-    // }}}
-    // {{{ setOptions()
-
-    /**
-     * Sets the options for the autocomplete input text element
-     *
-     * @param     array    $options    Array of options for the autocomplete input text element
-     * @access    public
-     * @return    void
-     */
-    function setOptions($options)
-    {
-        $this->_options = array_values($options);
-    } // end func setOptions
-
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns Html for the autocomplete input text element
-     *
-     * @access      public
-     * @return      string
-     */
-    function toHtml()
-    {
-        // prevent problems with grouped elements
-        $arrayName = str_replace(array('[', ']'), array('__', ''), $this->getName()) . '_values';
-
-        $this->updateAttributes(array(
-            'onkeypress' => 'return window.autocomplete(this, event, ' . $arrayName . ');'
-        ));
-        if ($this->_flagFrozen) {
-            $js = '';
-        } else {
-            $js = "<script type=\"text/javascript\">\n//<![CDATA[\n";
-            if (!defined('HTML_QUICKFORM_AUTOCOMPLETE_EXISTS')) {
-                $this->_js .= <<<EOS
-
-/* begin javascript for autocomplete */
-function setSelectionRange(input, selectionStart, selectionEnd) {
-    if (input.setSelectionRange) {
-        input.setSelectionRange(selectionStart, selectionEnd);
-    }
-    else if (input.createTextRange) {
-        var range = input.createTextRange();
-        range.collapse(true);
-        range.moveEnd("character", selectionEnd);
-        range.moveStart("character", selectionStart);
-        range.select();
-    }
-    input.focus();
-}
-
-function setCaretToPosition(input, position) {
-    setSelectionRange(input, position, position);
-}
-
-function replaceSelection (input, replaceString) {
-       var len = replaceString.length;
-    if (input.setSelectionRange) {
-        var selectionStart = input.selectionStart;
-        var selectionEnd = input.selectionEnd;
-
-        input.value = input.value.substring(0, selectionStart) + replaceString + input.value.substring(selectionEnd);
-               input.selectionStart  = selectionStart + len;
-               input.selectionEnd  = selectionStart + len;
-    }
-    else if (document.selection) {
-        var range = document.selection.createRange();
-               var saved_range = range.duplicate();
-
-        if (range.parentElement() == input) {
-            range.text = replaceString;
-                       range.moveEnd("character", saved_range.selectionStart + len);
-                       range.moveStart("character", saved_range.selectionStart + len);
-                       range.select();
-        }
-    }
-    input.focus();
-}
-
-
-function autocompleteMatch (text, values) {
-    for (var i = 0; i < values.length; i++) {
-        if (values[i].toUpperCase().indexOf(text.toUpperCase()) == 0) {
-            return values[i];
-        }
-    }
-
-    return null;
-}
-
-function autocomplete(textbox, event, values) {
-    if (textbox.setSelectionRange || textbox.createTextRange) {
-        switch (event.keyCode) {
-            case 38:    // up arrow
-            case 40:    // down arrow
-            case 37:    // left arrow
-            case 39:    // right arrow
-            case 33:    // page up
-            case 34:    // page down
-            case 36:    // home
-            case 35:    // end
-            case 13:    // enter
-            case 9:     // tab
-            case 27:    // esc
-            case 16:    // shift
-            case 17:    // ctrl
-            case 18:    // alt
-            case 20:    // caps lock
-            case 8:     // backspace
-            case 46:    // delete
-                return true;
-                break;
-
-            default:
-                var c = String.fromCharCode(
-                    (event.charCode == undefined) ? event.keyCode : event.charCode
-                );
-                replaceSelection(textbox, c);
-                sMatch = autocompleteMatch(textbox.value, values);
-                var len = textbox.value.length;
-
-                if (sMatch != null) {
-                    textbox.value = sMatch;
-                    setSelectionRange(textbox, len, textbox.value.length);
-                }
-                return false;
-        }
-    }
-    else {
-        return true;
-    }
-}
-/* end javascript for autocomplete */
-
-EOS;
-                define('HTML_QUICKFORM_AUTOCOMPLETE_EXISTS', true);
-            }
-            $jsEscape = array(
-                "\r"    => '\r',
-                "\n"    => '\n',
-                "\t"    => '\t',
-                "'"     => "\\'",
-                '"'     => '\"',
-                '\\'    => '\\\\'
-            );
-
-            $js .= $this->_js;
-            $js .= 'var ' . $arrayName . " = new Array();\n";
-            for ($i = 0; $i < count($this->_options); $i++) {
-                $js .= $arrayName . '[' . $i . "] = '" . strtr($this->_options[$i], $jsEscape) . "';\n";
-            }
-            $js .= "//]]>\n</script>";
-        }
-        return $js . parent::toHtml();
-    }// end func toHtml
-
-    // }}}
-} // end class HTML_QuickForm_autocomplete
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/button.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/button.php
deleted file mode 100644 (file)
index e658cd4..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for an <input type="button" /> elements
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for an <input type="button" /> elements
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_button extends HTML_QuickForm_input
-{
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $value          (optional)Input field value
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_button($elementName=null, $value=null, $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
-        $this->_persistantFreeze = false;
-        $this->setValue($value);
-        $this->setType('button');
-    } //end constructor
-    
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Freeze the element so that only its value is returned
-     * 
-     * @access    public
-     * @return    void
-     */
-    function freeze()
-    {
-        return false;
-    } //end func freeze
-
-    // }}}
-} //end class HTML_QuickForm_button
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/checkbox.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/checkbox.php
deleted file mode 100644 (file)
index 0bebe08..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a checkbox type field
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for a checkbox type field
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_checkbox extends HTML_QuickForm_input
-{
-    // {{{ properties
-
-    /**
-     * Checkbox display text
-     * @var       string
-     * @since     1.1
-     * @access    private
-     */
-    var $_text = '';
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $elementLabel   (optional)Input field value
-     * @param     string    $text           (optional)Checkbox display text
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_checkbox($elementName=null, $elementLabel=null, $text='', $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        $this->_text = $text;
-        $this->setType('checkbox');
-        $this->updateAttributes(array('value'=>1));
-        $this->_generateId();
-    } //end constructor
-    
-    // }}}
-    // {{{ setChecked()
-
-    /**
-     * Sets whether a checkbox is checked
-     * 
-     * @param     bool    $checked  Whether the field is checked or not
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setChecked($checked)
-    {
-        if (!$checked) {
-            $this->removeAttribute('checked');
-        } else {
-            $this->updateAttributes(array('checked'=>'checked'));
-        }
-    } //end func setChecked
-
-    // }}}
-    // {{{ getChecked()
-
-    /**
-     * Returns whether a checkbox is checked
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    bool
-     */
-    function getChecked()
-    {
-        return (bool)$this->getAttribute('checked');
-    } //end func getChecked
-    
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the checkbox element in HTML
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function toHtml()
-    {
-        if (0 == strlen($this->_text)) {
-            $label = '';
-        } elseif ($this->_flagFrozen) {
-            $label = $this->_text;
-        } else {
-            $label = '<label for="' . $this->getAttribute('id') . '">' . $this->_text . '</label>';
-        }
-        return HTML_QuickForm_input::toHtml() . $label;
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getFrozenHtml()
-    {
-        if ($this->getChecked()) {
-            return '<tt>[x]</tt>' .
-                   $this->_getPersistantData();
-        } else {
-            return '<tt>[ ]</tt>';
-        }
-    } //end func getFrozenHtml
-
-    // }}}
-    // {{{ setText()
-
-    /**
-     * Sets the checkbox text
-     * 
-     * @param     string    $text  
-     * @since     1.1
-     * @access    public
-     * @return    void
-     */
-    function setText($text)
-    {
-        $this->_text = $text;
-    } //end func setText
-
-    // }}}
-    // {{{ getText()
-
-    /**
-     * Returns the checkbox text 
-     * 
-     * @since     1.1
-     * @access    public
-     * @return    string
-     */
-    function getText()
-    {
-        return $this->_text;
-    } //end func getText
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets the value of the form element
-     *
-     * @param     string    $value      Default value of the form element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setValue($value)
-    {
-        return $this->setChecked($value);
-    } // end func setValue
-
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns the value of the form element
-     *
-     * @since     1.0
-     * @access    public
-     * @return    bool
-     */
-    function getValue()
-    {
-        return $this->getChecked();
-    } // end func getValue
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    $event  Name of event
-     * @param     mixed     $arg    event arguments
-     * @param     object    &$caller calling object
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        switch ($event) {
-            case 'updateValue':
-                // constant values override both default and submitted ones
-                // default values are overriden by submitted
-                $value = $this->_findValue($caller->_constantValues);
-                if (null === $value) {
-                    // if no boxes were checked, then there is no value in the array
-                    // yet we don't want to display default value in this case
-                    if ($caller->isSubmitted()) {
-                        $value = $this->_findValue($caller->_submitValues);
-                    } else {
-                        $value = $this->_findValue($caller->_defaultValues);
-                    }
-                }
-                if (null !== $value || $caller->isSubmitted()) {
-                    $this->setChecked($value);
-                }
-                break;
-            case 'setGroupValue':
-                $this->setChecked($arg);
-                break;
-            default:
-                parent::onQuickFormEvent($event, $arg, $caller);
-        }
-        return true;
-    } // end func onQuickFormEvent
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * Return true if the checkbox is checked, null if it is not checked (getValue() returns false)
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        $value = $this->_findValue($submitValues);
-        if (null === $value) {
-            $value = $this->getChecked()? true: null;
-        }
-        return $this->_prepareValue($value, $assoc);
-    }
-    
-    // }}}
-} //end class HTML_QuickForm_checkbox
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/date.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/date.php
deleted file mode 100644 (file)
index c14cca8..0000000
+++ /dev/null
@@ -1,544 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Class for a group of elements used to input dates (and times).
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Class for a group of form elements
- */
-require_once 'HTML/QuickForm/group.php';
-/**
- * Class for <select></select> elements
- */
-require_once 'HTML/QuickForm/select.php';
-
-/**
- * Class for a group of elements used to input dates (and times).
- *
- * Inspired by original 'date' element but reimplemented as a subclass
- * of HTML_QuickForm_group
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.1
- */
-class HTML_QuickForm_date extends HTML_QuickForm_group
-{
-    // {{{ properties
-
-   /**
-    * Various options to control the element's display.
-    *
-    * @access   private
-    * @var      array
-    */
-    var $_options = array(
-        'language'         => 'en',
-        'format'           => 'dMY',
-        'minYear'          => 2001,
-        'maxYear'          => null, // set in the constructor
-        'addEmptyOption'   => false,
-        'emptyOptionValue' => '',
-        'emptyOptionText'  => '&nbsp;',
-        'optionIncrement'  => array('i' => 1, 's' => 1)
-    );
-
-   /**
-    * These complement separators, they are appended to the resultant HTML
-    * @access   private
-    * @var      array
-    */
-    var $_wrap = array('', '');
-
-   /**
-    * Options in different languages
-    *
-    * Note to potential translators: to avoid encoding problems please send
-    * your translations with "weird" letters encoded as HTML Unicode entities
-    *
-    * @access   private
-    * @var      array
-    */
-    var $_locale = array(
-        'en'    => array (
-            'weekdays_short'=> array ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'),
-            'weekdays_long' => array ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
-            'months_long'   => array ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
-        ),
-        'de'    => array (
-            'weekdays_short'=> array ('So', 'Mon', 'Di', 'Mi', 'Do', 'Fr', 'Sa'),
-            'weekdays_long' => array ('Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'),
-            'months_short'  => array ('Jan', 'Feb', 'M&#xe4;rz', 'April', 'Mai', 'Juni', 'Juli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dez'),
-            'months_long'   => array ('Januar', 'Februar', 'M&#xe4;rz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember')
-        ),
-        'fr'    => array (
-            'weekdays_short'=> array ('Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'),
-            'weekdays_long' => array ('Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'),
-            'months_short'  => array ('Jan', 'F&#xe9;v', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Ao&#xfb;t', 'Sep', 'Oct', 'Nov', 'D&#xe9;c'),
-            'months_long'   => array ('Janvier', 'F&#xe9;vrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Ao&#xfb;t', 'Septembre', 'Octobre', 'Novembre', 'D&#xe9;cembre')
-        ),
-        'hu'    => array (
-            'weekdays_short'=> array ('V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'),
-            'weekdays_long' => array ('vas&#xe1;rnap', 'h&#xe9;tf&#x151;', 'kedd', 'szerda', 'cs&#xfc;t&#xf6;rt&#xf6;k', 'p&#xe9;ntek', 'szombat'),
-            'months_short'  => array ('jan', 'feb', 'm&#xe1;rc', '&#xe1;pr', 'm&#xe1;j', 'j&#xfa;n', 'j&#xfa;l', 'aug', 'szept', 'okt', 'nov', 'dec'),
-            'months_long'   => array ('janu&#xe1;r', 'febru&#xe1;r', 'm&#xe1;rcius', '&#xe1;prilis', 'm&#xe1;jus', 'j&#xfa;nius', 'j&#xfa;lius', 'augusztus', 'szeptember', 'okt&#xf3;ber', 'november', 'december')
-        ),
-        'pl'    => array (
-            'weekdays_short'=> array ('Nie', 'Pn', 'Wt', '&#x15a;r', 'Czw', 'Pt', 'Sob'),
-            'weekdays_long' => array ('Niedziela', 'Poniedzia&#x142;ek', 'Wtorek', '&#x15a;roda', 'Czwartek', 'Pi&#x105;tek', 'Sobota'),
-            'months_short'  => array ('Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Pa&#x17a;', 'Lis', 'Gru'),
-            'months_long'   => array ('Stycze&#x144;', 'Luty', 'Marzec', 'Kwiecie&#x144;', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpie&#x144;', 'Wrzesie&#x144;', 'Pa&#x17a;dziernik', 'Listopad', 'Grudzie&#x144;')
-        ),
-        'sl'    => array (
-            'weekdays_short'=> array ('Ned', 'Pon', 'Tor', 'Sre', 'Cet', 'Pet', 'Sob'),
-            'weekdays_long' => array ('Nedelja', 'Ponedeljek', 'Torek', 'Sreda', 'Cetrtek', 'Petek', 'Sobota'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Avg', 'Sep', 'Okt', 'Nov', 'Dec'),
-            'months_long'   => array ('Januar', 'Februar', 'Marec', 'April', 'Maj', 'Junij', 'Julij', 'Avgust', 'September', 'Oktober', 'November', 'December')
-        ),
-        'ru'    => array (
-            'weekdays_short'=> array ('&#x412;&#x441;', '&#x41f;&#x43d;', '&#x412;&#x442;', '&#x421;&#x440;', '&#x427;&#x442;', '&#x41f;&#x442;', '&#x421;&#x431;'),
-            'weekdays_long' => array ('&#x412;&#x43e;&#x441;&#x43a;&#x440;&#x435;&#x441;&#x435;&#x43d;&#x44c;&#x435;', '&#x41f;&#x43e;&#x43d;&#x435;&#x434;&#x435;&#x43b;&#x44c;&#x43d;&#x438;&#x43a;', '&#x412;&#x442;&#x43e;&#x440;&#x43d;&#x438;&#x43a;', '&#x421;&#x440;&#x435;&#x434;&#x430;', '&#x427;&#x435;&#x442;&#x432;&#x435;&#x440;&#x433;', '&#x41f;&#x44f;&#x442;&#x43d;&#x438;&#x446;&#x430;', '&#x421;&#x443;&#x431;&#x431;&#x43e;&#x442;&#x430;'),
-            'months_short'  => array ('&#x42f;&#x43d;&#x432;', '&#x424;&#x435;&#x432;', '&#x41c;&#x430;&#x440;', '&#x410;&#x43f;&#x440;', '&#x41c;&#x430;&#x439;', '&#x418;&#x44e;&#x43d;', '&#x418;&#x44e;&#x43b;', '&#x410;&#x432;&#x433;', '&#x421;&#x435;&#x43d;', '&#x41e;&#x43a;&#x442;', '&#x41d;&#x43e;&#x44f;', '&#x414;&#x435;&#x43a;'),
-            'months_long'   => array ('&#x42f;&#x43d;&#x432;&#x430;&#x440;&#x44c;', '&#x424;&#x435;&#x432;&#x440;&#x430;&#x43b;&#x44c;', '&#x41c;&#x430;&#x440;&#x442;', '&#x410;&#x43f;&#x440;&#x435;&#x43b;&#x44c;', '&#x41c;&#x430;&#x439;', '&#x418;&#x44e;&#x43d;&#x44c;', '&#x418;&#x44e;&#x43b;&#x44c;', '&#x410;&#x432;&#x433;&#x443;&#x441;&#x442;', '&#x421;&#x435;&#x43d;&#x442;&#x44f;&#x431;&#x440;&#x44c;', '&#x41e;&#x43a;&#x442;&#x44f;&#x431;&#x440;&#x44c;', '&#x41d;&#x43e;&#x44f;&#x431;&#x440;&#x44c;', '&#x414;&#x435;&#x43a;&#x430;&#x431;&#x440;&#x44c;')
-        ),
-        'es'    => array (
-            'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mi&#xe9;', 'Jue', 'Vie', 'S&#xe1;b'),
-            'weekdays_long' => array ('Domingo', 'Lunes', 'Martes', 'Mi&#xe9;rcoles', 'Jueves', 'Viernes', 'S&#xe1;bado'),
-            'months_short'  => array ('Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'),
-            'months_long'   => array ('Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre')
-        ),
-        'da'    => array (
-            'weekdays_short'=> array ('S&#xf8;n', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#xf8;r'),
-            'weekdays_long' => array ('S&#xf8;ndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'L&#xf8;rdag'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
-            'months_long'   => array ('Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December')
-        ),
-        'is'    => array (
-            'weekdays_short'=> array ('Sun', 'M&#xe1;n', '&#xde;ri', 'Mi&#xf0;', 'Fim', 'F&#xf6;s', 'Lau'),
-            'weekdays_long' => array ('Sunnudagur', 'M&#xe1;nudagur', '&#xde;ri&#xf0;judagur', 'Mi&#xf0;vikudagur', 'Fimmtudagur', 'F&#xf6;studagur', 'Laugardagur'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'Ma&#xed;', 'J&#xfa;n', 'J&#xfa;l', '&#xc1;g&#xfa;', 'Sep', 'Okt', 'N&#xf3;v', 'Des'),
-            'months_long'   => array ('Jan&#xfa;ar', 'Febr&#xfa;ar', 'Mars', 'Apr&#xed;l', 'Ma&#xed;', 'J&#xfa;n&#xed;', 'J&#xfa;l&#xed;', '&#xc1;g&#xfa;st', 'September', 'Okt&#xf3;ber', 'N&#xf3;vember', 'Desember')
-        ),
-        'it'    => array (
-            'weekdays_short'=> array ('Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'),
-            'weekdays_long' => array ('Domenica', 'Luned&#xec;', 'Marted&#xec;', 'Mercoled&#xec;', 'Gioved&#xec;', 'Venerd&#xec;', 'Sabato'),
-            'months_short'  => array ('Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'),
-            'months_long'   => array ('Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre')
-        ),
-        'sk'    => array (
-            'weekdays_short'=> array ('Ned', 'Pon', 'Uto', 'Str', '&#x8a;tv', 'Pia', 'Sob'),
-            'weekdays_long' => array ('Nede&#x17e;a', 'Pondelok', 'Utorok', 'Streda', '&#x8a;tvrtok', 'Piatok', 'Sobota'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'M&#xe1;j', 'J&#xfa;n', 'J&#xfa;l', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
-            'months_long'   => array ('Janu&#xe1;r', 'Febru&#xe1;r', 'Marec', 'Apr&#xed;l', 'M&#xe1;j', 'J&#xfa;n', 'J&#xfa;l', 'August', 'September', 'Okt&#xf3;ber', 'November', 'December')
-        ),
-        'cs'    => array (
-            'weekdays_short'=> array ('Ne', 'Po', '&#xda;t', 'St', '&#x10c;t', 'P&#xe1;', 'So'),
-            'weekdays_long' => array ('Ned&#x11b;le', 'Pond&#x11b;l&#xed;', '&#xda;ter&#xfd;', 'St&#x159;eda', '&#x10c;tvrtek', 'P&#xe1;tek', 'Sobota'),
-            'months_short'  => array ('Led', '&#xda;no', 'B&#x159;e', 'Dub', 'Kv&#x11b;', '&#x10c;en', '&#x10c;ec', 'Srp', 'Z&#xe1;&#x159;', '&#x158;&#xed;j', 'Lis', 'Pro'),
-            'months_long'   => array ('Leden', '&#xda;nor', 'B&#x159;ezen', 'Duben', 'Kv&#x11b;ten', '&#x10c;erven', '&#x10c;ervenec', 'Srpen', 'Z&#xe1;&#x159;&#xed;', '&#x158;&#xed;jen', 'Listopad', 'Prosinec')
-        ),
-        'hy'    => array (
-            'weekdays_short'=> array ('&#x53f;&#x580;&#x56f;', '&#x535;&#x580;&#x56f;', '&#x535;&#x580;&#x584;', '&#x549;&#x580;&#x584;', '&#x540;&#x576;&#x563;', '&#x548;&#x582;&#x580;', '&#x547;&#x562;&#x569;'),
-            'weekdays_long' => array ('&#x53f;&#x56b;&#x580;&#x561;&#x56f;&#x56b;', '&#x535;&#x580;&#x56f;&#x578;&#x582;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x535;&#x580;&#x565;&#x584;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x549;&#x578;&#x580;&#x565;&#x584;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x540;&#x56b;&#x576;&#x563;&#x577;&#x561;&#x562;&#x569;&#x56b;', '&#x548;&#x582;&#x580;&#x562;&#x561;&#x569;', '&#x547;&#x561;&#x562;&#x561;&#x569;'),
-            'months_short'  => array ('&#x540;&#x576;&#x57e;', '&#x553;&#x57f;&#x580;', '&#x544;&#x580;&#x57f;', '&#x531;&#x57a;&#x580;', '&#x544;&#x575;&#x57d;', '&#x540;&#x576;&#x57d;', '&#x540;&#x56c;&#x57d;', '&#x555;&#x563;&#x57d;', '&#x54d;&#x57a;&#x57f;', '&#x540;&#x56f;&#x57f;', '&#x546;&#x575;&#x574;', '&#x534;&#x56f;&#x57f;'),
-            'months_long'   => array ('&#x540;&#x578;&#x582;&#x576;&#x57e;&#x561;&#x580;', '&#x553;&#x565;&#x57f;&#x580;&#x57e;&#x561;&#x580;', '&#x544;&#x561;&#x580;&#x57f;', '&#x531;&#x57a;&#x580;&#x56b;&#x56c;', '&#x544;&#x561;&#x575;&#x56b;&#x57d;', '&#x540;&#x578;&#x582;&#x576;&#x56b;&#x57d;', '&#x540;&#x578;&#x582;&#x56c;&#x56b;&#x57d;', '&#x555;&#x563;&#x578;&#x57d;&#x57f;&#x578;&#x57d;', '&#x54d;&#x565;&#x57a;&#x57f;&#x565;&#x574;&#x562;&#x565;&#x580;', '&#x540;&#x578;&#x56f;&#x57f;&#x565;&#x574;&#x562;&#x565;&#x580;', '&#x546;&#x578;&#x575;&#x565;&#x574;&#x562;&#x565;&#x580;', '&#x534;&#x565;&#x56f;&#x57f;&#x565;&#x574;&#x562;&#x565;&#x580;')
-        ),
-        'nl'    => array (
-            'weekdays_short'=> array ('Zo', 'Ma', 'Di', 'Wo', 'Do', 'Vr', 'Za'),
-            'weekdays_long' => array ('Zondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
-            'months_long'   => array ('Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December')
-        ),
-        'et'    => array (
-            'weekdays_short'=> array ('P', 'E', 'T', 'K', 'N', 'R', 'L'),
-            'weekdays_long' => array ('P&#xfc;hap&#xe4;ev', 'Esmasp&#xe4;ev', 'Teisip&#xe4;ev', 'Kolmap&#xe4;ev', 'Neljap&#xe4;ev', 'Reede', 'Laup&#xe4;ev'),
-            'months_short'  => array ('Jaan', 'Veebr', 'M&#xe4;rts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'),
-            'months_long'   => array ('Jaanuar', 'Veebruar', 'M&#xe4;rts', 'Aprill', 'Mai', 'Juuni', 'Juuli', 'August', 'September', 'Oktoober', 'November', 'Detsember')
-        ),
-        'tr'    => array (
-            'weekdays_short'=> array ('Paz', 'Pzt', 'Sal', '&#xc7;ar', 'Per', 'Cum', 'Cts'),
-            'weekdays_long' => array ('Pazar', 'Pazartesi', 'Sal&#x131;', '&#xc7;ar&#x15f;amba', 'Per&#x15f;embe', 'Cuma', 'Cumartesi'),
-            'months_short'  => array ('Ock', '&#x15e;bt', 'Mrt', 'Nsn', 'Mys', 'Hzrn', 'Tmmz', 'A&#x11f;st', 'Eyl', 'Ekm', 'Ksm', 'Arlk'),
-            'months_long'   => array ('Ocak', '&#x15e;ubat', 'Mart', 'Nisan', 'May&#x131;s', 'Haziran', 'Temmuz', 'A&#x11f;ustos', 'Eyl&#xfc;l', 'Ekim', 'Kas&#x131;m', 'Aral&#x131;k')
-        ),
-        'no'    => array (
-            'weekdays_short'=> array ('S&#xf8;n', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#xf8;r'),
-            'weekdays_long' => array ('S&#xf8;ndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'L&#xf8;rdag'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'),
-            'months_long'   => array ('Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Desember')
-        ),
-        'eo'    => array (
-            'weekdays_short'=> array ('Dim', 'Lun', 'Mar', 'Mer', '&#x134;a&#x16D;', 'Ven', 'Sab'),
-            'weekdays_long' => array ('Diman&#x109;o', 'Lundo', 'Mardo', 'Merkredo', '&#x134;a&#x16D;do', 'Vendredo', 'Sabato'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'A&#x16D;g', 'Sep', 'Okt', 'Nov', 'Dec'),
-            'months_long'   => array ('Januaro', 'Februaro', 'Marto', 'Aprilo', 'Majo', 'Junio', 'Julio', 'A&#x16D;gusto', 'Septembro', 'Oktobro', 'Novembro', 'Decembro')
-        ),
-        'ua'    => array (
-            'weekdays_short'=> array('&#x41d;&#x434;&#x43b;', '&#x41f;&#x43d;&#x434;', '&#x412;&#x442;&#x440;', '&#x421;&#x440;&#x434;', '&#x427;&#x442;&#x432;', '&#x41f;&#x442;&#x43d;', '&#x421;&#x431;&#x442;'),
-            'weekdays_long' => array('&#x41d;&#x435;&#x434;&#x456;&#x43b;&#x44f;', '&#x41f;&#x43e;&#x43d;&#x435;&#x434;&#x456;&#x43b;&#x43e;&#x43a;', '&#x412;&#x456;&#x432;&#x442;&#x43e;&#x440;&#x43e;&#x43a;', '&#x421;&#x435;&#x440;&#x435;&#x434;&#x430;', '&#x427;&#x435;&#x442;&#x432;&#x435;&#x440;', '&#x41f;\'&#x44f;&#x442;&#x43d;&#x438;&#x446;&#x44f;', '&#x421;&#x443;&#x431;&#x43e;&#x442;&#x430;'),
-            'months_short'  => array('&#x421;&#x456;&#x447;', '&#x41b;&#x44e;&#x442;', '&#x411;&#x435;&#x440;', '&#x41a;&#x432;&#x456;', '&#x422;&#x440;&#x430;', '&#x427;&#x435;&#x440;', '&#x41b;&#x438;&#x43f;', '&#x421;&#x435;&#x440;', '&#x412;&#x435;&#x440;', '&#x416;&#x43e;&#x432;', '&#x41b;&#x438;&#x441;', '&#x413;&#x440;&#x443;'),
-            'months_long'   => array('&#x421;&#x456;&#x447;&#x435;&#x43d;&#x44c;', '&#x41b;&#x44e;&#x442;&#x438;&#x439;', '&#x411;&#x435;&#x440;&#x435;&#x437;&#x435;&#x43d;&#x44c;', '&#x41a;&#x432;&#x456;&#x442;&#x435;&#x43d;&#x44c;', '&#x422;&#x440;&#x430;&#x432;&#x435;&#x43d;&#x44c;', '&#x427;&#x435;&#x440;&#x432;&#x435;&#x43d;&#x44c;', '&#x41b;&#x438;&#x43f;&#x435;&#x43d;&#x44c;', '&#x421;&#x435;&#x440;&#x43f;&#x435;&#x43d;&#x44c;', '&#x412;&#x435;&#x440;&#x435;&#x441;&#x435;&#x43d;&#x44c;', '&#x416;&#x43e;&#x432;&#x442;&#x435;&#x43d;&#x44c;', '&#x41b;&#x438;&#x441;&#x442;&#x43e;&#x43f;&#x430;&#x434;', '&#x413;&#x440;&#x443;&#x434;&#x435;&#x43d;&#x44c;')
-        ),
-        'ro'    => array (
-            'weekdays_short'=> array ('Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sam'),
-            'weekdays_long' => array ('Duminica', 'Luni', 'Marti', 'Miercuri', 'Joi', 'Vineri', 'Sambata'),
-            'months_short'  => array ('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
-            'months_long'   => array ('Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie')
-        ),
-        'he'    => array (
-            'weekdays_short'=> array ('&#1512;&#1488;&#1513;&#1493;&#1503;', '&#1513;&#1504;&#1497;', '&#1513;&#1500;&#1497;&#1513;&#1497;', '&#1512;&#1489;&#1497;&#1506;&#1497;', '&#1495;&#1502;&#1497;&#1513;&#1497;', '&#1513;&#1497;&#1513;&#1497;', '&#1513;&#1489;&#1514;'),
-            'weekdays_long' => array ('&#1497;&#1493;&#1501; &#1512;&#1488;&#1513;&#1493;&#1503;', '&#1497;&#1493;&#1501; &#1513;&#1504;&#1497;', '&#1497;&#1493;&#1501; &#1513;&#1500;&#1497;&#1513;&#1497;', '&#1497;&#1493;&#1501; &#1512;&#1489;&#1497;&#1506;&#1497;', '&#1497;&#1493;&#1501; &#1495;&#1502;&#1497;&#1513;&#1497;', '&#1497;&#1493;&#1501; &#1513;&#1497;&#1513;&#1497;', '&#1513;&#1489;&#1514;'),
-            'months_short'  => array ('&#1497;&#1504;&#1493;&#1488;&#1512;', '&#1508;&#1489;&#1512;&#1493;&#1488;&#1512;', '&#1502;&#1512;&#1509;', '&#1488;&#1508;&#1512;&#1497;&#1500;', '&#1502;&#1488;&#1497;', '&#1497;&#1493;&#1504;&#1497;', '&#1497;&#1493;&#1500;&#1497;', '&#1488;&#1493;&#1490;&#1493;&#1505;&#1496;', '&#1505;&#1508;&#1496;&#1502;&#1489;&#1512;', '&#1488;&#1493;&#1511;&#1496;&#1493;&#1489;&#1512;', '&#1504;&#1493;&#1489;&#1502;&#1489;&#1512;', '&#1491;&#1510;&#1502;&#1489;&#1512;'),
-            'months_long'   => array ('&#1497;&#1504;&#1493;&#1488;&#1512;', '&#1508;&#1489;&#1512;&#1493;&#1488;&#1512;', '&#1502;&#1512;&#1509;', '&#1488;&#1508;&#1512;&#1497;&#1500;', '&#1502;&#1488;&#1497;', '&#1497;&#1493;&#1504;&#1497;', '&#1497;&#1493;&#1500;&#1497;', '&#1488;&#1493;&#1490;&#1493;&#1505;&#1496;', '&#1505;&#1508;&#1496;&#1502;&#1489;&#1512;', '&#1488;&#1493;&#1511;&#1496;&#1493;&#1489;&#1512;', '&#1504;&#1493;&#1489;&#1502;&#1489;&#1512;', '&#1491;&#1510;&#1502;&#1489;&#1512;')
-        ),
-        'sv'    => array (
-            'weekdays_short'=> array ('S&#xf6;n', 'M&#xe5;n', 'Tis', 'Ons', 'Tor', 'Fre', 'L&#xf6;r'),
-            'weekdays_long' => array ('S&#xf6;ndag', 'M&#xe5;ndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'L&#xf6;rdag'),
-            'months_short'  => array ('Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'),
-            'months_long'   => array ('Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December')
-        ),
-        'pt'    => array (
-            'weekdays_short'=> array ('Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'S&aacute;b'),
-            'weekdays_long' => array ('Domingo', 'Segunda-feira', 'Ter&ccedil;a-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'S&aacute;bado'),
-            'months_short'  => array ('Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'),
-            'months_long'   => array ('Janeiro', 'Fevereiro', 'Mar&ccedil;o', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro')
-        ),
-        'tw'    => array (
-            'weekdays_short'=> array ('&#36913;&#26085;','&#36913;&#19968;', '&#36913;&#20108;','&#36913;&#19977;', '&#36913;&#22235;','&#36913;&#20116;', '&#36913;&#20845;'),
-            'weekdays_long' => array ('&#26143;&#26399;&#26085;', '&#26143;&#26399;&#19968;', '&#26143;&#26399;&#20108;', '&#26143;&#26399;&#19977;', '&#26143;&#26399;&#22235;', '&#26143;&#26399;&#20116;', '&#26143;&#26399;&#20845;'),
-            'months_short'  => array ('&#19968;&#26376;', '&#20108;&#26376;', '&#19977;&#26376;', '&#22235;&#26376;', '&#20116;&#26376;', '&#20845;&#26376;', '&#19971;&#26376;', '&#20843;&#26376;', '&#20061;&#26376;', '&#21313;&#26376;', '&#21313;&#19968;&#26376;', '&#21313;&#20108;&#26376;'),
-            'months_long'   => array ('&#19968;&#26376;', '&#20108;&#26376;', '&#19977;&#26376;', '&#22235;&#26376;', '&#20116;&#26376;', '&#20845;&#26376;', '&#19971;&#26376;', '&#20843;&#26376;', '&#20061;&#26376;', '&#21313;&#26376;', '&#21313;&#19968;&#26376;', '&#21313;&#20108;&#26376;')
-        ),
-        'pt-br' => array (
-            'weekdays_short'=> array ('Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'S&aacute;b'),
-            'weekdays_long' => array ('Domingo', 'Segunda', 'Ter&ccedil;a', 'Quarta', 'Quinta', 'Sexta', 'S&aacute;bado'),
-            'months_short'  => array ('Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'),
-            'months_long'   => array ('Janeiro', 'Fevereiro', 'Mar&ccedil;o', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro')
-        ),
-        'sr'    => array (
-            'weekdays_short'=> array ('&#1053;&#1077;&#1076;', '&#1055;&#1086;&#1085;', '&#1059;&#1090;&#1086;', '&#1057;&#1088;&#1077;', '&#1063;&#1077;&#1090;', '&#1055;&#1077;&#1090;', '&#1057;&#1091;&#1073;'),
-            'weekdays_long' => array ('&#1053;&#1077;&#1076;&#1077;&#1113;&#1072;', '&#1055;&#1086;&#1085;&#1077;&#1076;&#1077;&#1113;&#1072;&#1082;', '&#1059;&#1090;&#1086;&#1088;&#1072;&#1082;', '&#1057;&#1088;&#1077;&#1076;&#1072;', '&#1063;&#1077;&#1090;&#1074;&#1088;&#1090;&#1072;&#1082;', '&#1055;&#1077;&#1090;&#1072;&#1082;', '&#1057;&#1091;&#1073;&#1086;&#1090;&#1072;'),
-            'months_short'  => array ('&#1032;&#1072;&#1085;', '&#1060;&#1077;&#1073;', '&#1052;&#1072;&#1088;', '&#1040;&#1087;&#1088;', '&#1052;&#1072;&#1112;', '&#1032;&#1091;&#1085;', '&#1032;&#1091;&#1083;', '&#1040;&#1074;&#1075;', '&#1057;&#1077;&#1087;', '&#1054;&#1082;&#1090;', '&#1053;&#1086;&#1074;', '&#1044;&#1077;&#1094;'),
-            'months_long'   => array ('&#1032;&#1072;&#1085;&#1091;&#1072;&#1088;', '&#1060;&#1077;&#1073;&#1088;&#1091;&#1072;&#1088;', '&#1052;&#1072;&#1088;&#1090;', '&#1040;&#1087;&#1088;&#1080;&#1083;', '&#1052;&#1072;&#1112;', '&#1032;&#1091;&#1085;', '&#1032;&#1091;&#1083;', '&#1040;&#1074;&#1075;&#1091;&#1089;&#1090;', '&#1057;&#1077;&#1087;&#1090;&#1077;&#1084;&#1073;&#1072;&#1088;', '&#1054;&#1082;&#1090;&#1086;&#1073;&#1072;&#1088;', '&#1053;&#1086;&#1074;&#1077;&#1084;&#1073;&#1072;&#1088;', '&#1044;&#1077;&#1094;&#1077;&#1084;&#1073;&#1072;&#1088;')
-        ),
-        'el' => array (
-            'weekdays_short'=> array ('&#916;&#949;&#965;', '&#932;&#961;&#943;', '&#932;&#949;&#964;', '&#928;&#941;&#956;', '&#928;&#945;&#961;', '&#931;&#940;&#946;', '&#922;&#965;&#961;'),
-            'weekdays_long' => array ('&#916;&#949;&#965;&#964;&#941;&#961;&#945;', '&#932;&#961;&#943;&#964;&#951;', '&#932;&#949;&#964;&#940;&#961;&#964;&#951;', '&#928;&#941;&#956;&#960;&#964;&#951;', '&#928;&#945;&#961;&#945;&#963;&#954;&#949;&#965;&#942;', '&#931;&#940;&#946;&#946;&#945;&#964;&#959;', '&#922;&#965;&#961;&#953;&#945;&#954;&#942;'),
-            'months_short'  => array ('&#921;&#945;&#957;', '&#934;&#949;&#946;', '&#924;&#940;&#961;', '&#913;&#960;&#961;', '&#924;&#940;&#970;', 'Io&#973;&#957;', '&#921;&#959;&#973;&#955;', '&#913;&#973;&#947;', '&#931;&#949;&#960;', '&#927;&#954;&#964;', '&#925;&#959;&#941;', '&#916;&#949;&#954;'),
-            'months_long'   => array ('&#921;&#945;&#957;&#959;&#965;&#940;&#961;&#953;&#959;&#962;', '&#934;&#949;&#946;&#961;&#959;&#965;&#940;&#961;&#953;&#959;&#962;', '&#924;&#940;&#961;&#964;&#953;&#959;&#962;', '&#913;&#960;&#961;&#943;&#955;&#953;&#959;&#962;', '&#924;&#940;&#970;&#959;&#962;', '&#921;&#959;&#973;&#957;&#953;&#959;&#962;', 'Io&#973;&#955;&#953;&#959;&#962;', '&#913;&#973;&#947;&#959;&#965;&#963;&#964;&#959;&#962;', '&#931;&#949;&#960;&#964;&#941;&#956;&#946;&#961;&#953;&#959;&#962;', '&#927;&#954;&#964;&#974;&#946;&#961;&#953;&#959;&#962;', '&#925;&#959;&#941;&#956;&#946;&#961;&#953;&#959;&#962;', '&#916;&#949;&#954;&#941;&#956;&#946;&#961;&#953;&#959;&#962;')
-        )
-    );
-
-    // }}}
-    // {{{ constructor
-
-   /**
-    * Class constructor
-    *
-    * The following keys may appear in $options array:
-    * - 'language': date language
-    * - 'format': Format of the date, based on PHP's date() function.
-    *   The following characters are currently recognised in format string:
-    *   <pre>
-    *       D => Short names of days
-    *       l => Long names of days
-    *       d => Day numbers
-    *       M => Short names of months
-    *       F => Long names of months
-    *       m => Month numbers
-    *       Y => Four digit year
-    *       y => Two digit year
-    *       h => 12 hour format
-    *       H => 23 hour  format
-    *       i => Minutes
-    *       s => Seconds
-    *       a => am/pm
-    *       A => AM/PM
-    *   </pre>
-    * - 'minYear': Minimum year in year select
-    * - 'maxYear': Maximum year in year select
-    * - 'addEmptyOption': Should an empty option be added to the top of
-    *    each select box?
-    * - 'emptyOptionValue': The value passed by the empty option.
-    * - 'emptyOptionText': The text displayed for the empty option.
-    * - 'optionIncrement': Step to increase the option values by (works for 'i' and 's')
-    *
-    * @access   public
-    * @param    string  Element's name
-    * @param    mixed   Label(s) for an element
-    * @param    array   Options to control the element's display
-    * @param    mixed   Either a typical HTML attribute string or an associative array
-    */
-    function HTML_QuickForm_date($elementName = null, $elementLabel = null, $options = array(), $attributes = null)
-    {
-        $this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        $this->_appendName = true;
-        $this->_type = 'date';
-
-        // http://pear.php.net/bugs/bug.php?id=18171
-        $this->_options['maxYear'] = date('Y');
-
-        // set the options, do not bother setting bogus ones
-        if (is_array($options)) {
-            foreach ($options as $name => $value) {
-                if ('language' == $name) {
-                    $this->_options['language'] = isset($this->_locale[$value])? $value: 'en';
-                } elseif (isset($this->_options[$name])) {
-                    if (is_array($value) && is_array($this->_options[$name])) {
-                        $this->_options[$name] = @array_merge($this->_options[$name], $value);
-                    } else {
-                        $this->_options[$name] = $value;
-                    }
-                }
-            }
-        }
-    }
-
-    // }}}
-    // {{{ _createElements()
-
-    function _createElements()
-    {
-        $this->_separator = $this->_elements = array();
-        $separator =  '';
-        $locale    =& $this->_locale[$this->_options['language']];
-        $backslash =  false;
-        for ($i = 0, $length = strlen($this->_options['format']); $i < $length; $i++) {
-            $sign = $this->_options['format']{$i};
-            if ($backslash) {
-                $backslash  = false;
-                $separator .= $sign;
-            } else {
-                $loadSelect = true;
-                switch ($sign) {
-                    case 'D':
-                        // Sunday is 0 like with 'w' in date()
-                        $options = $locale['weekdays_short'];
-                        break;
-                    case 'l':
-                        $options = $locale['weekdays_long'];
-                        break;
-                    case 'd':
-                        $options = $this->_createOptionList(1, 31);
-                        break;
-                    case 'M':
-                        $options = $locale['months_short'];
-                        array_unshift($options , '');
-                        unset($options[0]);
-                        break;
-                    case 'm':
-                        $options = $this->_createOptionList(1, 12);
-                        break;
-                    case 'F':
-                        $options = $locale['months_long'];
-                        array_unshift($options , '');
-                        unset($options[0]);
-                        break;
-                    case 'Y':
-                        $options = $this->_createOptionList(
-                            $this->_options['minYear'],
-                            $this->_options['maxYear'],
-                            $this->_options['minYear'] > $this->_options['maxYear']? -1: 1
-                        );
-                        break;
-                    case 'y':
-                        $options = $this->_createOptionList(
-                            $this->_options['minYear'],
-                            $this->_options['maxYear'],
-                            $this->_options['minYear'] > $this->_options['maxYear']? -1: 1
-                        );
-                        array_walk($options, create_function('&$v,$k','$v = substr($v,-2);'));
-                        break;
-                    case 'h':
-                        $options = $this->_createOptionList(1, 12);
-                        break;
-                    case 'g':
-                        $options = $this->_createOptionList(1, 12);
-                        array_walk($options, create_function('&$v,$k', '$v = intval($v);'));
-                        break;
-                    case 'H':
-                        $options = $this->_createOptionList(0, 23);
-                        break;
-                    case 'i':
-                        $options = $this->_createOptionList(0, 59, $this->_options['optionIncrement']['i']);
-                        break;
-                    case 's':
-                        $options = $this->_createOptionList(0, 59, $this->_options['optionIncrement']['s']);
-                        break;
-                    case 'a':
-                        $options = array('am' => 'am', 'pm' => 'pm');
-                        break;
-                    case 'A':
-                        $options = array('AM' => 'AM', 'PM' => 'PM');
-                        break;
-                    case 'W':
-                        $options = $this->_createOptionList(1, 53);
-                        break;
-                    case '\\':
-                        $backslash  = true;
-                        $loadSelect = false;
-                        break;
-                    default:
-                        $separator .= (' ' == $sign? '&nbsp;': $sign);
-                        $loadSelect = false;
-                }
-
-                if ($loadSelect) {
-                    if (0 < count($this->_elements)) {
-                        $this->_separator[] = $separator;
-                    } else {
-                        $this->_wrap[0] = $separator;
-                    }
-                    $separator = '';
-                    // Should we add an empty option to the top of the select?
-                    if (!is_array($this->_options['addEmptyOption']) && $this->_options['addEmptyOption'] ||
-                        is_array($this->_options['addEmptyOption']) && !empty($this->_options['addEmptyOption'][$sign])) {
-
-                        // Using '+' array operator to preserve the keys
-                        if (is_array($this->_options['emptyOptionText']) && !empty($this->_options['emptyOptionText'][$sign])) {
-                            $options = array($this->_options['emptyOptionValue'] => $this->_options['emptyOptionText'][$sign]) + $options;
-                        } else {
-                            $options = array($this->_options['emptyOptionValue'] => $this->_options['emptyOptionText']) + $options;
-                        }
-                    }
-                    $this->_elements[] =& new HTML_QuickForm_select($sign, null, $options, $this->getAttributes());
-                }
-            }
-        }
-        $this->_wrap[1] = $separator . ($backslash? '\\': '');
-    }
-
-    // }}}
-    // {{{ _createOptionList()
-
-   /**
-    * Creates an option list containing the numbers from the start number to the end, inclusive
-    *
-    * @param    int     The start number
-    * @param    int     The end number
-    * @param    int     Increment by this value
-    * @access   private
-    * @return   array   An array of numeric options.
-    */
-    function _createOptionList($start, $end, $step = 1)
-    {
-        for ($i = $start, $options = array(); $start > $end? $i >= $end: $i <= $end; $i += $step) {
-            $options[$i] = sprintf('%02d', $i);
-        }
-        return $options;
-    }
-
-    // }}}
-    // {{{ _trimLeadingZeros()
-
-   /**
-    * Trims leading zeros from the (numeric) string
-    *
-    * @param    string  A numeric string, possibly with leading zeros
-    * @return   string  String with leading zeros removed
-    */
-    function _trimLeadingZeros($str)
-    {
-        if (0 == strcmp($str, $this->_options['emptyOptionValue'])) {
-            return $str;
-        }
-        $trimmed = ltrim($str, '0');
-        return strlen($trimmed)? $trimmed: '0';
-    }
-
-    // }}}
-    // {{{ setValue()
-
-    function setValue($value)
-    {
-        if (empty($value)) {
-            $value = array();
-        } elseif (is_scalar($value)) {
-            if (!is_numeric($value)) {
-                $value = strtotime($value);
-            }
-            // might be a unix epoch, then we fill all possible values
-            $arr = explode('-', date('w-j-n-Y-g-G-i-s-a-A-W', (int)$value));
-            $value = array(
-                'D' => $arr[0],
-                'l' => $arr[0],
-                'd' => $arr[1],
-                'M' => $arr[2],
-                'm' => $arr[2],
-                'F' => $arr[2],
-                'Y' => $arr[3],
-                'y' => $arr[3],
-                'h' => $arr[4],
-                'g' => $arr[4],
-                'H' => $arr[5],
-                'i' => $this->_trimLeadingZeros($arr[6]),
-                's' => $this->_trimLeadingZeros($arr[7]),
-                'a' => $arr[8],
-                'A' => $arr[9],
-                'W' => $this->_trimLeadingZeros($arr[10])
-            );
-        } else {
-            $value = array_map(array($this, '_trimLeadingZeros'), $value);
-        }
-        parent::setValue($value);
-    }
-
-    // }}}
-    // {{{ toHtml()
-
-    function toHtml()
-    {
-        include_once('HTML/QuickForm/Renderer/Default.php');
-        $renderer =& new HTML_QuickForm_Renderer_Default();
-        $renderer->setElementTemplate('{element}');
-        parent::accept($renderer);
-        return $this->_wrap[0] . $renderer->toHtml() . $this->_wrap[1];
-    }
-
-    // }}}
-    // {{{ accept()
-
-    function accept(&$renderer, $required = false, $error = null)
-    {
-        $renderer->renderElement($this, $required, $error);
-    }
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        if ('updateValue' == $event) {
-            // we need to call setValue(), 'cause the default/constant value
-            // may be in fact a timestamp, not an array
-            return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller);
-        } else {
-            return parent::onQuickFormEvent($event, $arg, $caller);
-        }
-    }
-
-    // }}}
-}
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/element.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/element.php
deleted file mode 100644 (file)
index caa35b0..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Base class for form elements
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for all HTML classes
- */
-require_once 'HTML/Common.php';
-/**
- * Static utility methods
- */
-require_once 'HTML/QuickForm/utils.php';
-
-/**
- * Base class for form elements
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       1.0
- * @abstract
- */
-class HTML_QuickForm_element extends HTML_Common
-{
-    // {{{ properties
-
-    /**
-     * Label of the field
-     * @var       string
-     * @since     1.3
-     * @access    private
-     */
-    var $_label = '';
-
-    /**
-     * Form element type
-     * @var       string
-     * @since     1.0
-     * @access    private
-     */
-    var $_type = '';
-
-    /**
-     * Flag to tell if element is frozen
-     * @var       boolean
-     * @since     1.0
-     * @access    private
-     */
-    var $_flagFrozen = false;
-
-    /**
-     * Does the element support persistant data when frozen
-     * @var       boolean
-     * @since     1.3
-     * @access    private
-     */
-    var $_persistantFreeze = false;
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     *
-     * @param    string     Name of the element
-     * @param    mixed      Label(s) for the element
-     * @param    mixed      Associative array of tag attributes or HTML attributes name="value" pairs
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_element($elementName=null, $elementLabel=null, $attributes=null)
-    {
-        HTML_Common::HTML_Common($attributes);
-        if (isset($elementName)) {
-            $this->setName($elementName);
-        }
-        if (isset($elementLabel)) {
-            $this->setLabel($elementLabel);
-        }
-    } //end constructor
-
-    // }}}
-    // {{{ apiVersion()
-
-    /**
-     * Returns the current API version
-     *
-     * @since     1.0
-     * @access    public
-     * @return    float
-     */
-    function apiVersion()
-    {
-        return 3.2;
-    } // end func apiVersion
-
-    // }}}
-    // {{{ getType()
-
-    /**
-     * Returns element type
-     *
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getType()
-    {
-        return $this->_type;
-    } // end func getType
-
-    // }}}
-    // {{{ setName()
-
-    /**
-     * Sets the input field name
-     *
-     * @param     string    $name   Input field name attribute
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setName($name)
-    {
-        // interface method
-    } //end func setName
-
-    // }}}
-    // {{{ getName()
-
-    /**
-     * Returns the element name
-     *
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getName()
-    {
-        // interface method
-    } //end func getName
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets the value of the form element
-     *
-     * @param     string    $value      Default value of the form element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setValue($value)
-    {
-        // interface
-    } // end func setValue
-
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns the value of the form element
-     *
-     * @since     1.0
-     * @access    public
-     * @return    mixed
-     */
-    function getValue()
-    {
-        // interface
-        return null;
-    } // end func getValue
-
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Freeze the element so that only its value is returned
-     *
-     * @access    public
-     * @return    void
-     */
-    function freeze()
-    {
-        $this->_flagFrozen = true;
-    } //end func freeze
-
-    // }}}
-    // {{{ unfreeze()
-
-   /**
-    * Unfreezes the element so that it becomes editable
-    *
-    * @access public
-    * @return void
-    * @since  3.2.4
-    */
-    function unfreeze()
-    {
-        $this->_flagFrozen = false;
-    }
-
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags
-     *
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getFrozenHtml()
-    {
-        $value = $this->getValue();
-        return (strlen($value)? htmlspecialchars($value): '&nbsp;') .
-               $this->_getPersistantData();
-    } //end func getFrozenHtml
-
-    // }}}
-    // {{{ _getPersistantData()
-
-   /**
-    * Used by getFrozenHtml() to pass the element's value if _persistantFreeze is on
-    *
-    * @access private
-    * @return string
-    */
-    function _getPersistantData()
-    {
-        if (!$this->_persistantFreeze) {
-            return '';
-        } else {
-            $id = $this->getAttribute('id');
-            return '<input' . $this->_getAttrString(array(
-                       'type'  => 'hidden',
-                       'name'  => $this->getName(),
-                       'value' => $this->getValue()
-                   ) + (isset($id)? array('id' => $id): array())) . ' />';
-        }
-    }
-
-    // }}}
-    // {{{ isFrozen()
-
-    /**
-     * Returns whether or not the element is frozen
-     *
-     * @since     1.3
-     * @access    public
-     * @return    bool
-     */
-    function isFrozen()
-    {
-        return $this->_flagFrozen;
-    } // end func isFrozen
-
-    // }}}
-    // {{{ setPersistantFreeze()
-
-    /**
-     * Sets wether an element value should be kept in an hidden field
-     * when the element is frozen or not
-     *
-     * @param     bool    $persistant   True if persistant value
-     * @since     2.0
-     * @access    public
-     * @return    void
-     */
-    function setPersistantFreeze($persistant=false)
-    {
-        $this->_persistantFreeze = $persistant;
-    } //end func setPersistantFreeze
-
-    // }}}
-    // {{{ setLabel()
-
-    /**
-     * Sets display text for the element
-     *
-     * @param     string    $label  Display text for the element
-     * @since     1.3
-     * @access    public
-     * @return    void
-     */
-    function setLabel($label)
-    {
-        $this->_label = $label;
-    } //end func setLabel
-
-    // }}}
-    // {{{ getLabel()
-
-    /**
-     * Returns display text for the element
-     *
-     * @since     1.3
-     * @access    public
-     * @return    string
-     */
-    function getLabel()
-    {
-        return $this->_label;
-    } //end func getLabel
-
-    // }}}
-    // {{{ _findValue()
-
-    /**
-     * Tries to find the element value from the values array
-     *
-     * @since     2.7
-     * @access    private
-     * @return    mixed
-     */
-    function _findValue(&$values)
-    {
-        if (empty($values)) {
-            return null;
-        }
-        $elementName = $this->getName();
-        if (isset($values[$elementName])) {
-            return $values[$elementName];
-        } elseif (strpos($elementName, '[')) {
-
-            $keys = str_replace(
-                array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
-                $elementName
-            );
-            $arrayKeys = explode("']['", $keys);
-            return HTML_QuickForm_utils::recursiveValue($values, $arrayKeys);
-
-        } else {
-            return null;
-        }
-    } //end func _findValue
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    $event  Name of event
-     * @param     mixed     $arg    event arguments
-     * @param     object    &$caller calling object
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        switch ($event) {
-            case 'createElement':
-                $className = get_class($this);
-                $this->$className($arg[0], $arg[1], $arg[2], $arg[3], $arg[4]);
-                break;
-            case 'addElement':
-                $this->onQuickFormEvent('createElement', $arg, $caller);
-                $this->onQuickFormEvent('updateValue', null, $caller);
-                break;
-            case 'updateValue':
-                // constant values override both default and submitted ones
-                // default values are overriden by submitted
-                $value = $this->_findValue($caller->_constantValues);
-                if (null === $value) {
-                    $value = $this->_findValue($caller->_submitValues);
-                    if (null === $value) {
-                        $value = $this->_findValue($caller->_defaultValues);
-                    }
-                }
-                if (null !== $value) {
-                    $this->setValue($value);
-                }
-                break;
-            case 'setGroupValue':
-                $this->setValue($arg);
-        }
-        return true;
-    } // end func onQuickFormEvent
-
-    // }}}
-    // {{{ accept()
-
-   /**
-    * Accepts a renderer
-    *
-    * @param HTML_QuickForm_Renderer    renderer object
-    * @param bool                       Whether an element is required
-    * @param string                     An error message associated with an element
-    * @access public
-    * @return void
-    */
-    function accept(&$renderer, $required=false, $error=null)
-    {
-        $renderer->renderElement($this, $required, $error);
-    } // end func accept
-
-    // }}}
-    // {{{ _generateId()
-
-   /**
-    * Automatically generates and assigns an 'id' attribute for the element.
-    *
-    * Currently used to ensure that labels work on radio buttons and
-    * checkboxes. Per idea of Alexander Radivanovich.
-    *
-    * @access private
-    * @return void
-    */
-    function _generateId()
-    {
-        static $idx = 1;
-
-        if (!$this->getAttribute('id')) {
-            $this->updateAttributes(array('id' => 'qf_' . substr(md5(microtime() . $idx++), 0, 6)));
-        }
-    } // end func _generateId
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * Returns a 'safe' element's value
-    *
-    * @param  array   array of submitted values to search
-    * @param  bool    whether to return the value as associative array
-    * @access public
-    * @return mixed
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        $value = $this->_findValue($submitValues);
-        if (null === $value) {
-            $value = $this->getValue();
-        }
-        return $this->_prepareValue($value, $assoc);
-    }
-
-    // }}}
-    // {{{ _prepareValue()
-
-   /**
-    * Used by exportValue() to prepare the value for returning
-    *
-    * @param  mixed   the value found in exportValue()
-    * @param  bool    whether to return the value as associative array
-    * @access private
-    * @return mixed
-    */
-    function _prepareValue($value, $assoc)
-    {
-        if (null === $value) {
-            return null;
-        } elseif (!$assoc) {
-            return $value;
-        } else {
-            $name = $this->getName();
-            if (!strpos($name, '[')) {
-                return array($name => $value);
-            } else {
-
-                $keys = str_replace(
-                    array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
-                    $name
-                );
-                $keysArray = explode("']['", $keys);
-                return HTML_QuickForm_utils::recursiveBuild($keysArray, $value);
-            }
-        }
-    }
-
-    // }}}
-} // end class HTML_QuickForm_element
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/file.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/file.php
deleted file mode 100644 (file)
index 02b220d..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a file upload field
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-// register file-related rules
-if (class_exists('HTML_QuickForm')) {
-    HTML_QuickForm::registerRule('uploadedfile', 'callback', '_ruleIsUploadedFile', 'HTML_QuickForm_file');
-    HTML_QuickForm::registerRule('maxfilesize', 'callback', '_ruleCheckMaxFileSize', 'HTML_QuickForm_file');
-    HTML_QuickForm::registerRule('mimetype', 'callback', '_ruleCheckMimeType', 'HTML_QuickForm_file');
-    HTML_QuickForm::registerRule('filename', 'callback', '_ruleCheckFileName', 'HTML_QuickForm_file');
-}
-
-/**
- * HTML class for a file upload field
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_file extends HTML_QuickForm_input
-{
-    // {{{ properties
-
-   /**
-    * Uploaded file data, from $_FILES
-    * @var array
-    */
-    var $_value = null;
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    Input field name attribute
-     * @param     string    Input field label
-     * @param     mixed     (optional)Either a typical HTML attribute string 
-     *                      or an associative array
-     * @since     1.0
-     * @access    public
-     */
-    function HTML_QuickForm_file($elementName=null, $elementLabel=null, $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
-        $this->setType('file');
-    } //end constructor
-    
-    // }}}
-    // {{{ setSize()
-
-    /**
-     * Sets size of file element
-     * 
-     * @param     int    Size of file element
-     * @since     1.0
-     * @access    public
-     */
-    function setSize($size)
-    {
-        $this->updateAttributes(array('size' => $size));
-    } //end func setSize
-    
-    // }}}
-    // {{{ getSize()
-
-    /**
-     * Returns size of file element
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    int
-     */
-    function getSize()
-    {
-        return $this->getAttribute('size');
-    } //end func getSize
-
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Freeze the element so that only its value is returned
-     * 
-     * @access    public
-     * @return    bool
-     */
-    function freeze()
-    {
-        return false;
-    } //end func freeze
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets value for file element.
-     * 
-     * Actually this does nothing. The function is defined here to override
-     * HTML_Quickform_input's behaviour of setting the 'value' attribute. As
-     * no sane user-agent uses <input type="file">'s value for anything 
-     * (because of security implications) we implement file's value as a 
-     * read-only property with a special meaning.
-     * 
-     * @param     mixed    Value for file element
-     * @since     3.0
-     * @access    public
-     */
-    function setValue($value)
-    {
-        return null;
-    } //end func setValue
-    
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns information about the uploaded file
-     *
-     * @since     3.0
-     * @access    public
-     * @return    array
-     */
-    function getValue()
-    {
-        return $this->_value;
-    } // end func getValue
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    Name of event
-     * @param     mixed     event arguments
-     * @param     object    calling object
-     * @since     1.0
-     * @access    public
-     * @return    bool
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        switch ($event) {
-            case 'updateValue':
-                if ($caller->getAttribute('method') == 'get') {
-                    return PEAR::raiseError('Cannot add a file upload field to a GET method form');
-                }
-                $this->_value = $this->_findValue();
-                $caller->updateAttributes(array('enctype' => 'multipart/form-data'));
-                $caller->setMaxFileSize();
-                break;
-            case 'addElement':
-                $this->onQuickFormEvent('createElement', $arg, $caller);
-                return $this->onQuickFormEvent('updateValue', null, $caller);
-                break;
-            case 'createElement':
-                $className = get_class($this);
-                $this->$className($arg[0], $arg[1], $arg[2]);
-                break;
-        }
-        return true;
-    } // end func onQuickFormEvent
-
-    // }}}
-    // {{{ moveUploadedFile()
-
-    /**
-     * Moves an uploaded file into the destination 
-     * 
-     * @param    string  Destination directory path
-     * @param    string  New file name
-     * @access   public
-     * @return   bool    Whether the file was moved successfully
-     */
-    function moveUploadedFile($dest, $fileName = '')
-    {
-        if ($dest != ''  && substr($dest, -1) != '/') {
-            $dest .= '/';
-        }
-        $fileName = ($fileName != '') ? $fileName : basename($this->_value['name']);
-        return move_uploaded_file($this->_value['tmp_name'], $dest . $fileName); 
-    } // end func moveUploadedFile
-    
-    // }}}
-    // {{{ isUploadedFile()
-
-    /**
-     * Checks if the element contains an uploaded file
-     *
-     * @access    public
-     * @return    bool      true if file has been uploaded, false otherwise
-     */
-    function isUploadedFile()
-    {
-        return $this->_ruleIsUploadedFile($this->_value);
-    } // end func isUploadedFile
-
-    // }}}
-    // {{{ _ruleIsUploadedFile()
-
-    /**
-     * Checks if the given element contains an uploaded file
-     *
-     * @param     array     Uploaded file info (from $_FILES)
-     * @access    private
-     * @return    bool      true if file has been uploaded, false otherwise
-     */
-    function _ruleIsUploadedFile($elementValue)
-    {
-        if ((isset($elementValue['error']) && $elementValue['error'] == 0) ||
-            (!empty($elementValue['tmp_name']) && $elementValue['tmp_name'] != 'none')) {
-            return is_uploaded_file($elementValue['tmp_name']);
-        } else {
-            return false;
-        }
-    } // end func _ruleIsUploadedFile
-    
-    // }}}
-    // {{{ _ruleCheckMaxFileSize()
-
-    /**
-     * Checks that the file does not exceed the max file size
-     *
-     * @param     array     Uploaded file info (from $_FILES)
-     * @param     int       Max file size
-     * @access    private
-     * @return    bool      true if filesize is lower than maxsize, false otherwise
-     */
-    function _ruleCheckMaxFileSize($elementValue, $maxSize)
-    {
-        if (!empty($elementValue['error']) && 
-            (UPLOAD_ERR_FORM_SIZE == $elementValue['error'] || UPLOAD_ERR_INI_SIZE == $elementValue['error'])) {
-            return false;
-        }
-        if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
-            return true;
-        }
-        return ($maxSize >= @filesize($elementValue['tmp_name']));
-    } // end func _ruleCheckMaxFileSize
-
-    // }}}
-    // {{{ _ruleCheckMimeType()
-
-    /**
-     * Checks if the given element contains an uploaded file of the right mime type
-     *
-     * @param     array     Uploaded file info (from $_FILES)
-     * @param     mixed     Mime Type (can be an array of allowed types)
-     * @access    private
-     * @return    bool      true if mimetype is correct, false otherwise
-     */
-    function _ruleCheckMimeType($elementValue, $mimeType)
-    {
-        if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
-            return true;
-        }
-        if (is_array($mimeType)) {
-            return in_array($elementValue['type'], $mimeType);
-        }
-        return $elementValue['type'] == $mimeType;
-    } // end func _ruleCheckMimeType
-
-    // }}}
-    // {{{ _ruleCheckFileName()
-
-    /**
-     * Checks if the given element contains an uploaded file of the filename regex
-     *
-     * @param     array     Uploaded file info (from $_FILES)
-     * @param     string    Regular expression
-     * @access    private
-     * @return    bool      true if name matches regex, false otherwise
-     */
-    function _ruleCheckFileName($elementValue, $regex)
-    {
-        if (!HTML_QuickForm_file::_ruleIsUploadedFile($elementValue)) {
-            return true;
-        }
-        return (bool)preg_match($regex, $elementValue['name']);
-    } // end func _ruleCheckFileName
-    
-    // }}}
-    // {{{ _findValue()
-
-   /**
-    * Tries to find the element value from the values array
-    * 
-    * Needs to be redefined here as $_FILES is populated differently from 
-    * other arrays when element name is of the form foo[bar]
-    * 
-    * @param bool $sc1   unused, for signature compatibility
-    *
-    * @access    private
-    * @return    mixed
-    */
-    function _findValue(&$sc1 = null)
-    {
-        if (empty($_FILES)) {
-            return null;
-        }
-        $elementName = $this->getName();
-        if (isset($_FILES[$elementName])) {
-            return $_FILES[$elementName];
-        } elseif (false !== ($pos = strpos($elementName, '['))) {
-            $base  = str_replace(
-                        array('\\', '\''), array('\\\\', '\\\''),
-                        substr($elementName, 0, $pos)
-                    ); 
-            $idx   = "['" . str_replace(
-                        array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
-                        substr($elementName, $pos + 1, -1)
-                     ) . "']";
-            $props = array('name', 'type', 'size', 'tmp_name', 'error');
-            $code  = "if (!isset(\$_FILES['{$base}']['name']{$idx})) {\n" .
-                     "    return null;\n" .
-                     "} else {\n" .
-                     "    \$value = array();\n";
-            foreach ($props as $prop) {
-                $code .= "    \$value['{$prop}'] = \$_FILES['{$base}']['{$prop}']{$idx};\n";
-            }
-            return eval($code . "    return \$value;\n}\n");
-        } else {
-            return null;
-        }
-    }
-
-    // }}}
-} // end class HTML_QuickForm_file
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/group.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/group.php
deleted file mode 100644 (file)
index af1b27f..0000000
+++ /dev/null
@@ -1,588 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a form element group
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for form elements
- */ 
-require_once 'HTML/QuickForm/element.php';
-
-/**
- * HTML class for a form element group
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_group extends HTML_QuickForm_element
-{
-    // {{{ properties
-        
-    /**
-     * Name of the element
-     * @var       string
-     * @since     1.0
-     * @access    private
-     */
-    var $_name = '';
-
-    /**
-     * Array of grouped elements
-     * @var       array
-     * @since     1.0
-     * @access    private
-     */
-    var $_elements = array();
-
-    /**
-     * String to separate elements
-     * @var       mixed
-     * @since     2.5
-     * @access    private
-     */
-    var $_separator = null;
-
-    /**
-     * Required elements in this group
-     * @var       array
-     * @since     2.5
-     * @access    private
-     */
-    var $_required = array();
-
-   /**
-    * Whether to change elements' names to $groupName[$elementName] or leave them as is 
-    * @var      bool
-    * @since    3.0
-    * @access   private
-    */
-    var $_appendName = true;
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Group name
-     * @param     array     $elementLabel   (optional)Group label
-     * @param     array     $elements       (optional)Group elements
-     * @param     mixed     $separator      (optional)Use a string for one separator,
-     *                                      use an array to alternate the separators.
-     * @param     bool      $appendName     (optional)whether to change elements' names to
-     *                                      the form $groupName[$elementName] or leave 
-     *                                      them as is.
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_group($elementName=null, $elementLabel=null, $elements=null, $separator=null, $appendName = true)
-    {
-        $this->HTML_QuickForm_element($elementName, $elementLabel);
-        $this->_type = 'group';
-        if (isset($elements) && is_array($elements)) {
-            $this->setElements($elements);
-        }
-        if (isset($separator)) {
-            $this->_separator = $separator;
-        }
-        if (isset($appendName)) {
-            $this->_appendName = $appendName;
-        }
-    } //end constructor
-    
-    // }}}
-    // {{{ setName()
-
-    /**
-     * Sets the group name
-     * 
-     * @param     string    $name   Group name
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setName($name)
-    {
-        $this->_name = $name;
-    } //end func setName
-    
-    // }}}
-    // {{{ getName()
-
-    /**
-     * Returns the group name
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getName()
-    {
-        return $this->_name;
-    } //end func getName
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets values for group's elements
-     * 
-     * @param     mixed    Values for group's elements
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setValue($value)
-    {
-        $this->_createElementsIfNotExist();
-        foreach (array_keys($this->_elements) as $key) {
-            if (!$this->_appendName) {
-                $v = $this->_elements[$key]->_findValue($value);
-                if (null !== $v) {
-                    $this->_elements[$key]->onQuickFormEvent('setGroupValue', $v, $this);
-                }
-
-            } else {
-                $elementName = $this->_elements[$key]->getName();
-                $index       = strlen($elementName) ? $elementName : $key;
-                if (is_array($value)) {
-                    if (isset($value[$index])) {
-                        $this->_elements[$key]->onQuickFormEvent('setGroupValue', $value[$index], $this);
-                    }
-                } elseif (isset($value)) {
-                    $this->_elements[$key]->onQuickFormEvent('setGroupValue', $value, $this);
-                }
-            }
-        }
-    } //end func setValue
-    
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns the value of the group
-     *
-     * @since     1.0
-     * @access    public
-     * @return    mixed
-     */
-    function getValue()
-    {
-        $value = null;
-        foreach (array_keys($this->_elements) as $key) {
-            $element =& $this->_elements[$key];
-            switch ($element->getType()) {
-                case 'radio': 
-                    $v = $element->getChecked()? $element->getValue(): null;
-                    break;
-                case 'checkbox': 
-                    $v = $element->getChecked()? true: null;
-                    break;
-                default:
-                    $v = $element->getValue();
-            }
-            if (null !== $v) {
-                $elementName = $element->getName();
-                if (is_null($elementName)) {
-                    $value = $v;
-                } else {
-                    if (!is_array($value)) {
-                        $value = is_null($value)? array(): array($value);
-                    }
-                    if ('' === $elementName) {
-                        $value[] = $v;
-                    } else {
-                        $value[$elementName] = $v;
-                    }
-                }
-            }
-        }
-        return $value;
-    } // end func getValue
-
-    // }}}
-    // {{{ setElements()
-
-    /**
-     * Sets the grouped elements
-     *
-     * @param     array     $elements   Array of elements
-     * @since     1.1
-     * @access    public
-     * @return    void
-     */
-    function setElements($elements)
-    {
-        $this->_elements = array_values($elements);
-        if ($this->_flagFrozen) {
-            $this->freeze();
-        }
-    } // end func setElements
-
-    // }}}
-    // {{{ getElements()
-
-    /**
-     * Gets the grouped elements
-     *
-     * @since     2.4
-     * @access    public
-     * @return    array
-     */
-    function &getElements()
-    {
-        $this->_createElementsIfNotExist();
-        return $this->_elements;
-    } // end func getElements
-
-    // }}}
-    // {{{ getGroupType()
-
-    /**
-     * Gets the group type based on its elements
-     * Will return 'mixed' if elements contained in the group
-     * are of different types.
-     *
-     * @access    public
-     * @return    string    group elements type
-     */
-    function getGroupType()
-    {
-        $this->_createElementsIfNotExist();
-        $prevType = '';
-        foreach (array_keys($this->_elements) as $key) {
-            $type = $this->_elements[$key]->getType();
-            if ($type != $prevType && $prevType != '') {
-                return 'mixed';
-            }
-            $prevType = $type;
-        }
-        return $type;
-    } // end func getGroupType
-
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns Html for the group
-     * 
-     * @since       1.0
-     * @access      public
-     * @return      string
-     */
-    function toHtml()
-    {
-        include_once('HTML/QuickForm/Renderer/Default.php');
-        $renderer = new HTML_QuickForm_Renderer_Default();
-        $renderer->setElementTemplate('{element}');
-        $this->accept($renderer);
-        return $renderer->toHtml();
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getElementName()
-
-    /**
-     * Returns the element name inside the group such as found in the html form
-     * 
-     * @param     mixed     $index  Element name or element index in the group
-     * @since     3.0
-     * @access    public
-     * @return    mixed     string with element name, false if not found
-     */
-    function getElementName($index)
-    {
-        $this->_createElementsIfNotExist();
-        $elementName = false;
-        if (is_int($index) && isset($this->_elements[$index])) {
-            $elementName = $this->_elements[$index]->getName();
-            if (isset($elementName) && $elementName == '') {
-                $elementName = $index;
-            }
-            if ($this->_appendName) {
-                if (is_null($elementName)) {
-                    $elementName = $this->getName();
-                } else {
-                    $elementName = $this->getName().'['.$elementName.']';
-                }
-            }
-
-        } elseif (is_string($index)) {
-            foreach (array_keys($this->_elements) as $key) {
-                $elementName = $this->_elements[$key]->getName();
-                if ($index == $elementName) {
-                    if ($this->_appendName) {
-                        $elementName = $this->getName().'['.$elementName.']';
-                    }
-                    break;
-                } elseif ($this->_appendName && $this->getName().'['.$elementName.']' == $index) {
-                    break;
-                }
-            }
-        }
-        return $elementName;
-    } //end func getElementName
-
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags
-     * 
-     * @since     1.3
-     * @access    public
-     * @return    string
-     */
-    function getFrozenHtml()
-    {
-        $flags = array();
-        $this->_createElementsIfNotExist();
-        foreach (array_keys($this->_elements) as $key) {
-            if (false === ($flags[$key] = $this->_elements[$key]->isFrozen())) {
-                $this->_elements[$key]->freeze();
-            }
-        }
-        $html = $this->toHtml();
-        foreach (array_keys($this->_elements) as $key) {
-            if (!$flags[$key]) {
-                $this->_elements[$key]->unfreeze();
-            }
-        }
-        return $html;
-    } //end func getFrozenHtml
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    $event  Name of event
-     * @param     mixed     $arg    event arguments
-     * @param     object    &$caller calling object
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        switch ($event) {
-            case 'updateValue':
-                $this->_createElementsIfNotExist();
-                foreach (array_keys($this->_elements) as $key) {
-                    if ($this->_appendName) {
-                        $elementName = $this->_elements[$key]->getName();
-                        if (is_null($elementName)) {
-                            $this->_elements[$key]->setName($this->getName());
-                        } elseif ('' === $elementName) {
-                            $this->_elements[$key]->setName($this->getName() . '[' . $key . ']');
-                        } else {
-                            $this->_elements[$key]->setName($this->getName() . '[' . $elementName . ']');
-                        }
-                    }
-                    $this->_elements[$key]->onQuickFormEvent('updateValue', $arg, $caller);
-                    if ($this->_appendName) {
-                        $this->_elements[$key]->setName($elementName);
-                    }
-                }
-                break;
-
-            default:
-                parent::onQuickFormEvent($event, $arg, $caller);
-        }
-        return true;
-    } // end func onQuickFormEvent
-
-    // }}}
-    // {{{ accept()
-
-   /**
-    * Accepts a renderer
-    *
-    * @param HTML_QuickForm_Renderer    renderer object
-    * @param bool                       Whether a group is required
-    * @param string                     An error message associated with a group
-    * @access public
-    * @return void 
-    */
-    function accept(&$renderer, $required = false, $error = null)
-    {
-        $this->_createElementsIfNotExist();
-        $renderer->startGroup($this, $required, $error);
-        $name = $this->getName();
-        foreach (array_keys($this->_elements) as $key) {
-            $element =& $this->_elements[$key];
-            
-            if ($this->_appendName) {
-                $elementName = $element->getName();
-                if (isset($elementName)) {
-                    $element->setName($name . '['. (strlen($elementName)? $elementName: $key) .']');
-                } else {
-                    $element->setName($name);
-                }
-            }
-
-            $required = !$element->isFrozen() && in_array($element->getName(), $this->_required);
-
-            $element->accept($renderer, $required);
-
-            // restore the element's name
-            if ($this->_appendName) {
-                $element->setName($elementName);
-            }
-        }
-        $renderer->finishGroup($this);
-    } // end func accept
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * As usual, to get the group's value we access its elements and call
-    * their exportValue() methods
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        $value = null;
-        foreach (array_keys($this->_elements) as $key) {
-            $elementName = $this->_elements[$key]->getName();
-            if ($this->_appendName) {
-                if (is_null($elementName)) {
-                    $this->_elements[$key]->setName($this->getName());
-                } elseif ('' === $elementName) {
-                    $this->_elements[$key]->setName($this->getName() . '[' . $key . ']');
-                } else {
-                    $this->_elements[$key]->setName($this->getName() . '[' . $elementName . ']');
-                }
-            }
-            $v = $this->_elements[$key]->exportValue($submitValues, $assoc);
-            if ($this->_appendName) {
-                $this->_elements[$key]->setName($elementName);
-            }
-            if (null !== $v) {
-                // Make $value an array, we will use it like one
-                if (null === $value) {
-                    $value = array();
-                }
-                if ($assoc) {
-                    // just like HTML_QuickForm::exportValues()
-                    $value = HTML_QuickForm::arrayMerge($value, $v);
-                } else {
-                    // just like getValue(), but should work OK every time here
-                    if (is_null($elementName)) {
-                        $value = $v;
-                    } elseif ('' === $elementName) {
-                        $value[] = $v;
-                    } else {
-                        $value[$elementName] = $v;
-                    }
-                }
-            }
-        }
-        // do not pass the value through _prepareValue, we took care of this already
-        return $value;
-    }
-
-    // }}}
-    // {{{ _createElements()
-
-   /**
-    * Creates the group's elements.
-    * 
-    * This should be overriden by child classes that need to create their 
-    * elements. The method will be called automatically when needed, calling
-    * it from the constructor is discouraged as the constructor is usually
-    * called _twice_ on element creation, first time with _no_ parameters.
-    * 
-    * @access private
-    * @abstract
-    */
-    function _createElements()
-    {
-        // abstract
-    }
-
-    // }}}
-    // {{{ _createElementsIfNotExist()
-
-   /**
-    * A wrapper around _createElements()
-    *
-    * This method calls _createElements() if the group's _elements array
-    * is empty. It also performs some updates, e.g. freezes the created
-    * elements if the group is already frozen.
-    *
-    * @access private
-    */
-    function _createElementsIfNotExist()
-    {
-        if (empty($this->_elements)) {
-            $this->_createElements();
-            if ($this->_flagFrozen) {
-                $this->freeze();
-            }
-        }
-    }
-
-    // }}}
-    // {{{ freeze()
-
-    function freeze()
-    {
-        parent::freeze();
-        foreach (array_keys($this->_elements) as $key) {
-            $this->_elements[$key]->freeze();
-        }
-    }
-
-    // }}}
-    // {{{ unfreeze()
-
-    function unfreeze()
-    {
-        parent::unfreeze();
-        foreach (array_keys($this->_elements) as $key) {
-            $this->_elements[$key]->unfreeze();
-        }
-    }
-
-    // }}}
-    // {{{ setPersistantFreeze()
-
-    function setPersistantFreeze($persistant = false)
-    {
-        parent::setPersistantFreeze($persistant);
-        foreach (array_keys($this->_elements) as $key) {
-            $this->_elements[$key]->setPersistantFreeze($persistant);
-        }
-    }
-
-    // }}}
-} //end class HTML_QuickForm_group
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/header.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/header.php
deleted file mode 100644 (file)
index 6265a39..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A pseudo-element used for adding headers to form
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * HTML class for static data
- */ 
-require_once 'HTML/QuickForm/static.php';
-
-/**
- * A pseudo-element used for adding headers to form  
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.0
- */
-class HTML_QuickForm_header extends HTML_QuickForm_static
-{
-    // {{{ constructor
-
-   /**
-    * Class constructor
-    * 
-    * @param string $elementName    Header name
-    * @param string $text           Header text
-    * @access public
-    * @return void
-    */
-    function HTML_QuickForm_header($elementName = null, $text = null)
-    {
-        $this->HTML_QuickForm_static($elementName, null, $text);
-        $this->_type = 'header';
-    }
-
-    // }}}
-    // {{{ accept()
-
-   /**
-    * Accepts a renderer
-    *
-    * @param HTML_QuickForm_Renderer    renderer object
-    * @param bool $sc1                  unused, for signature compatibility
-    * @param bool $sc2                  unused, for signature compatibility
-    * @access public
-    * @return void 
-    */
-    function accept(&$renderer, $sc1 = false, $sc2 = null)
-    {
-        $renderer->renderHeader($this);
-    } // end func accept
-
-    // }}}
-
-} //end class HTML_QuickForm_header
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/hidden.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/hidden.php
deleted file mode 100644 (file)
index e3a9a8b..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a hidden type element
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for a hidden type element
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_hidden extends HTML_QuickForm_input
-{
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $value          (optional)Input field value
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_hidden($elementName=null, $value='', $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
-        $this->setType('hidden');
-        $this->setValue($value);
-    } //end constructor
-        
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Freeze the element so that only its value is returned
-     * 
-     * @access    public
-     * @return    void
-     */
-    function freeze()
-    {
-        return false;
-    } //end func freeze
-
-    // }}}
-    // {{{ accept()
-
-   /**
-    * Accepts a renderer
-    *
-    * @param HTML_QuickForm_Renderer    renderer object
-    * @param bool $sc1                  unused, for signature compatibility
-    * @param bool $sc2                  unused, for signature compatibility
-    * @access public
-    * @return void 
-    */
-    function accept(&$renderer, $sc1 = false, $sc2 = null)
-    {
-        $renderer->renderHidden($this);
-    } // end func accept
-
-    // }}}
-
-} //end class HTML_QuickForm_hidden
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/hiddenselect.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/hiddenselect.php
deleted file mode 100644 (file)
index be32ddf..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Hidden select pseudo-element
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Isaac Shepard <ishepard@bsiweb.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Class for <select></select> elements
- */
-require_once 'HTML/QuickForm/select.php';
-
-/**
- * Hidden select pseudo-element
- *
- * This class takes the same arguments as a select element, but instead
- * of creating a select ring it creates hidden elements for all values
- * already selected with setDefault or setConstant.  This is useful if
- * you have a select ring that you don't want visible, but you need all
- * selected values to be passed.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Isaac Shepard <ishepard@bsiweb.com>
- * @version     Release: 3.2.16
- * @since       2.1
- */
-class HTML_QuickForm_hiddenselect extends HTML_QuickForm_select
-{
-    // {{{ constructor
-        
-    /**
-     * Class constructor
-     * 
-     * @param     string    Select name attribute
-     * @param     mixed     Label(s) for the select (not used)
-     * @param     mixed     Data to be used to populate options
-     * @param     mixed     Either a typical HTML attribute string or an associative array (not used)
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_hiddenselect($elementName=null, $elementLabel=null, $options=null, $attributes=null)
-    {
-        HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        $this->_type = 'hiddenselect';
-        if (isset($options)) {
-            $this->load($options);
-        }
-    } //end constructor
-    
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the SELECT in HTML
-     *
-     * @since     1.0
-     * @access    public
-     * @return    string
-     * @throws    
-     */
-    function toHtml()
-    {
-        if (empty($this->_values)) {
-            return '';
-        }
-
-        $tabs    = $this->_getTabs();
-        $name    = $this->getPrivateName();
-        $strHtml = '';
-
-        foreach ($this->_values as $key => $val) {
-            for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
-                if ($val == $this->_options[$i]['attr']['value']) {
-                    $strHtml .= $tabs . '<input' . $this->_getAttrString(array(
-                        'type'  => 'hidden',
-                        'name'  => $name,
-                        'value' => $val
-                    )) . " />\n" ;
-                }
-            }
-        }
-
-        return $strHtml;
-    } //end func toHtml
-    
-    // }}}
-    // {{{ accept()
-
-   /**
-    * This is essentially a hidden element and should be rendered as one  
-    *
-    * @param HTML_QuickForm_Renderer    renderer object
-    * @param bool $sc1                  unused, for signature compatibility
-    * @param bool $sc2                  unused, for signature compatibility
-    */
-    function accept(&$renderer, $sc1 = false, $sc2 = null)
-    {
-        $renderer->renderHidden($this);
-    }
-
-    // }}}
-} //end class HTML_QuickForm_hiddenselect
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/hierselect.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/hierselect.php
deleted file mode 100644 (file)
index e63a8b7..0000000
+++ /dev/null
@@ -1,650 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Hierarchical select element
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Herim Vasquez <vasquezh@iro.umontreal.ca>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Class for a group of form elements
- */
-require_once 'HTML/QuickForm/group.php';
-/**
- * Class for <select></select> elements
- */
-require_once 'HTML/QuickForm/select.php';
-/**
- * Static utility methods
- */
-require_once 'HTML/QuickForm/utils.php';
-
-/**
- * Hierarchical select element
- *
- * Class to dynamically create two or more HTML Select elements
- * The first select changes the content of the second select and so on.
- * This element is considered as a group. Selects will be named
- * groupName[0], groupName[1], groupName[2]...
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Herim Vasquez <vasquezh@iro.umontreal.ca>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.1
- */
-class HTML_QuickForm_hierselect extends HTML_QuickForm_group
-{
-    // {{{ properties
-
-    /**
-     * Options for all the select elements
-     *
-     * @see       setOptions()
-     * @var       array
-     * @access    private
-     */
-    var $_options = array();
-
-    /**
-     * Number of select elements on this group
-     *
-     * @var       int
-     * @access    private
-     */
-    var $_nbElements = 0;
-
-    /**
-     * The javascript used to set and change the options
-     *
-     * @var       string
-     * @access    private
-     */
-    var $_js = '';
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     *
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $elementLabel   (optional)Input field label in form
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string
-     *                                      or an associative array. Date format is passed along the attributes.
-     * @param     mixed     $separator      (optional)Use a string for one separator,
-     *                                      use an array to alternate the separators.
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_hierselect($elementName=null, $elementLabel=null, $attributes=null, $separator=null)
-    {
-        $this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        if (isset($separator)) {
-            $this->_separator = $separator;
-        }
-        $this->_type = 'hierselect';
-        $this->_appendName = true;
-    } //end constructor
-
-    // }}}
-    // {{{ setOptions()
-
-    /**
-     * Initialize the array structure containing the options for each select element.
-     * Call the functions that actually do the magic.
-     *
-     * Format is a bit more complex than for a simple select as we need to know
-     * which options are related to the ones in the previous select:
-     *
-     * Ex:
-     * <code>
-     * // first select
-     * $select1[0] = 'Pop';
-     * $select1[1] = 'Classical';
-     * $select1[2] = 'Funeral doom';
-     *
-     * // second select
-     * $select2[0][0] = 'Red Hot Chil Peppers';
-     * $select2[0][1] = 'The Pixies';
-     * $select2[1][0] = 'Wagner';
-     * $select2[1][1] = 'Strauss';
-     * $select2[2][0] = 'Pantheist';
-     * $select2[2][1] = 'Skepticism';
-     *
-     * // If only need two selects
-     * //     - and using the deprecated functions
-     * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
-     * $sel->setMainOptions($select1);
-     * $sel->setSecOptions($select2);
-     *
-     * //     - and using the new setOptions function
-     * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
-     * $sel->setOptions(array($select1, $select2));
-     *
-     * // If you have a third select with prices for the cds
-     * $select3[0][0][0] = '15.00$';
-     * $select3[0][0][1] = '17.00$';
-     * // etc
-     *
-     * // You can now use
-     * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
-     * $sel->setOptions(array($select1, $select2, $select3));
-     * </code>
-     *
-     * @param     array    $options    Array of options defining each element
-     * @access    public
-     * @return    void
-     */
-    function setOptions($options)
-    {
-        $this->_options = $options;
-
-        if (empty($this->_elements)) {
-            $this->_nbElements = count($this->_options);
-            $this->_createElements();
-        } else {
-            // setDefaults has probably been called before this function
-            // check if all elements have been created
-            $totalNbElements = count($this->_options);
-            for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) {
-                $this->_elements[] =& new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
-                $this->_nbElements++;
-            }
-        }
-
-        $this->_setOptions();
-    } // end func setMainOptions
-
-    // }}}
-    // {{{ setMainOptions()
-
-    /**
-     * Sets the options for the first select element. Deprecated. setOptions() should be used.
-     *
-     * @param     array     $array    Options for the first select element
-     *
-     * @access    public
-     * @deprecated          Deprecated since release 3.2.2
-     * @return    void
-     */
-    function setMainOptions($array)
-    {
-        $this->_options[0] = $array;
-
-        if (empty($this->_elements)) {
-            $this->_nbElements = 2;
-            $this->_createElements();
-        }
-    } // end func setMainOptions
-
-    // }}}
-    // {{{ setSecOptions()
-
-    /**
-     * Sets the options for the second select element. Deprecated. setOptions() should be used.
-     * The main _options array is initialized and the _setOptions function is called.
-     *
-     * @param     array     $array    Options for the second select element
-     *
-     * @access    public
-     * @deprecated          Deprecated since release 3.2.2
-     * @return    void
-     */
-    function setSecOptions($array)
-    {
-        $this->_options[1] = $array;
-
-        if (empty($this->_elements)) {
-            $this->_nbElements = 2;
-            $this->_createElements();
-        } else {
-            // setDefaults has probably been called before this function
-            // check if all elements have been created
-            $totalNbElements = 2;
-            for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) {
-                $this->_elements[] =& new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
-                $this->_nbElements++;
-            }
-        }
-
-        $this->_setOptions();
-    } // end func setSecOptions
-
-    // }}}
-    // {{{ _setOptions()
-
-    /**
-     * Sets the options for each select element
-     *
-     * @access    private
-     * @return    void
-     */
-    function _setOptions()
-    {
-        $arrayKeys = array();
-        foreach (array_keys($this->_elements) AS $key) {
-            if (isset($this->_options[$key])) {
-                if ((empty($arrayKeys)) || HTML_QuickForm_utils::recursiveIsset($this->_options[$key], $arrayKeys)) {
-                    $array = empty($arrayKeys) ? $this->_options[$key] : HTML_QuickForm_utils::recursiveValue($this->_options[$key], $arrayKeys);
-                    if (is_array($array)) {
-                        $select =& $this->_elements[$key];
-                        $select->_options = array();
-                        $select->loadArray($array);
-
-                        $value = is_array($v = $select->getValue()) ? $v[0] : key($array);
-                        $arrayKeys[] = $value;
-                    }
-                }
-            }
-        }
-    } // end func _setOptions
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets values for group's elements
-     *
-     * @param     array     $value    An array of 2 or more values, for the first,
-     *                                the second, the third etc. select
-     *
-     * @access    public
-     * @return    void
-     */
-    function setValue($value)
-    {
-        // fix for bug #6766. Hope this doesn't break anything more
-        // after bug #7961. Forgot that _nbElements was used in
-        // _createElements() called in several places...
-        $this->_nbElements = max($this->_nbElements, count($value));
-        parent::setValue($value);
-        $this->_setOptions();
-    } // end func setValue
-
-    // }}}
-    // {{{ _createElements()
-
-    /**
-     * Creates all the elements for the group
-     *
-     * @access    private
-     * @return    void
-     */
-    function _createElements()
-    {
-        for ($i = 0; $i < $this->_nbElements; $i++) {
-            $this->_elements[] =& new HTML_QuickForm_select($i, null, array(), $this->getAttributes());
-        }
-    } // end func _createElements
-
-    // }}}
-    // {{{ toHtml()
-
-    function toHtml()
-    {
-        $this->_js = '';
-        if (!$this->_flagFrozen) {
-            // set the onchange attribute for each element except last
-            $keys     = array_keys($this->_elements);
-            $onChange = array();
-            for ($i = 0; $i < count($keys) - 1; $i++) {
-                $select =& $this->_elements[$keys[$i]];
-                $onChange[$i] = $select->getAttribute('onchange');
-                $select->updateAttributes(
-                    array('onchange' => '_hs_swapOptions(this.form, \'' . $this->_escapeString($this->getName()) . '\', ' . $keys[$i] . ');' . $onChange[$i])
-                );
-            }
-
-            // create the js function to call
-            if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) {
-                $this->_js .= <<<JAVASCRIPT
-function _hs_findOptions(ary, keys)
-{
-    if (ary == undefined) {
-        return {};
-    }
-    var key = keys.shift();
-    if (!key in ary) {
-        return {};
-    } else if (0 == keys.length) {
-        return ary[key];
-    } else {
-        return _hs_findOptions(ary[key], keys);
-    }
-}
-
-function _hs_findSelect(form, groupName, selectIndex)
-{
-    if (groupName+'['+ selectIndex +']' in form) {
-        return form[groupName+'['+ selectIndex +']'];
-    } else {
-        return form[groupName+'['+ selectIndex +'][]'];
-    }
-}
-
-function _hs_unescapeEntities(str)
-{
-    var div = document.createElement('div');
-    div.innerHTML = str;
-    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
-}
-
-function _hs_replaceOptions(ctl, options)
-{
-    var j = 0;
-    ctl.options.length = 0;
-    for (var i = 0; i < options.values.length; i++) {
-        ctl.options[i] = new Option(
-            (-1 == String(options.texts[i]).indexOf('&'))? options.texts[i]: _hs_unescapeEntities(options.texts[i]),
-            options.values[i], false, false
-        );
-    }
-}
-
-function _hs_setValue(ctl, value)
-{
-    var testValue = {};
-    if (value instanceof Array) {
-        for (var i = 0; i < value.length; i++) {
-            testValue[value[i]] = true;
-        }
-    } else {
-        testValue[value] = true;
-    }
-    for (var i = 0; i < ctl.options.length; i++) {
-        if (ctl.options[i].value in testValue) {
-            ctl.options[i].selected = true;
-        }
-    }
-}
-
-function _hs_swapOptions(form, groupName, selectIndex)
-{
-    var hsValue = [];
-    for (var i = 0; i <= selectIndex; i++) {
-        hsValue[i] = _hs_findSelect(form, groupName, i).value;
-    }
-
-    _hs_replaceOptions(_hs_findSelect(form, groupName, selectIndex + 1),
-                       _hs_findOptions(_hs_options[groupName][selectIndex], hsValue));
-    if (selectIndex + 1 < _hs_options[groupName].length) {
-        _hs_swapOptions(form, groupName, selectIndex + 1);
-    }
-}
-
-function _hs_onReset(form, groupNames)
-{
-    for (var i = 0; i < groupNames.length; i++) {
-        try {
-            for (var j = 0; j <= _hs_options[groupNames[i]].length; j++) {
-                _hs_setValue(_hs_findSelect(form, groupNames[i], j), _hs_defaults[groupNames[i]][j]);
-                if (j < _hs_options[groupNames[i]].length) {
-                    _hs_replaceOptions(_hs_findSelect(form, groupNames[i], j + 1),
-                                       _hs_findOptions(_hs_options[groupNames[i]][j], _hs_defaults[groupNames[i]].slice(0, j + 1)));
-                }
-            }
-        } catch (e) {
-            if (!(e instanceof TypeError)) {
-                throw e;
-            }
-        }
-    }
-}
-
-function _hs_setupOnReset(form, groupNames)
-{
-    setTimeout(function() { _hs_onReset(form, groupNames); }, 25);
-}
-
-function _hs_onReload()
-{
-    var ctl;
-    for (var i = 0; i < document.forms.length; i++) {
-        for (var j in _hs_defaults) {
-            if (ctl = _hs_findSelect(document.forms[i], j, 0)) {
-                for (var k = 0; k < _hs_defaults[j].length; k++) {
-                    _hs_setValue(_hs_findSelect(document.forms[i], j, k), _hs_defaults[j][k]);
-                }
-            }
-        }
-    }
-
-    if (_hs_prevOnload) {
-        _hs_prevOnload();
-    }
-}
-
-var _hs_prevOnload = null;
-if (window.onload) {
-    _hs_prevOnload = window.onload;
-}
-window.onload = _hs_onReload;
-
-var _hs_options = {};
-var _hs_defaults = {};
-
-JAVASCRIPT;
-                define('HTML_QUICKFORM_HIERSELECT_EXISTS', true);
-            }
-            // option lists
-            $jsParts = array();
-            for ($i = 1; $i < $this->_nbElements; $i++) {
-                $jsParts[] = $this->_convertArrayToJavascript($this->_prepareOptions($this->_options[$i], $i));
-            }
-            $this->_js .= "\n_hs_options['" . $this->_escapeString($this->getName()) . "'] = [\n" .
-                          implode(",\n", $jsParts) .
-                          "\n];\n";
-            // default value; if we don't actually have any values yet just use
-            // the first option (for single selects) or empty array (for multiple)
-            $values = array();
-            foreach (array_keys($this->_elements) as $key) {
-                if (is_array($v = $this->_elements[$key]->getValue())) {
-                    $values[] = count($v) > 1? $v: $v[0];
-                } else {
-                    // XXX: accessing the supposedly private _options array
-                    $values[] = $this->_elements[$key]->getMultiple() || empty($this->_elements[$key]->_options[0])?
-                                array():
-                                $this->_elements[$key]->_options[0]['attr']['value'];
-                }
-            }
-            $this->_js .= "_hs_defaults['" . $this->_escapeString($this->getName()) . "'] = " .
-                          $this->_convertArrayToJavascript($values) . ";\n";
-        }
-        include_once('HTML/QuickForm/Renderer/Default.php');
-        $renderer =& new HTML_QuickForm_Renderer_Default();
-        $renderer->setElementTemplate('{element}');
-        parent::accept($renderer);
-
-        if (!empty($onChange)) {
-            $keys     = array_keys($this->_elements);
-            for ($i = 0; $i < count($keys) - 1; $i++) {
-                $this->_elements[$keys[$i]]->updateAttributes(array('onchange' => $onChange[$i]));
-            }
-        }
-        return (empty($this->_js)? '': "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>") .
-               $renderer->toHtml();
-    } // end func toHtml
-
-    // }}}
-    // {{{ accept()
-
-    function accept(&$renderer, $required = false, $error = null)
-    {
-        $renderer->renderElement($this, $required, $error);
-    } // end func accept
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        if ('updateValue' == $event) {
-            // we need to call setValue() so that the secondary option
-            // matches the main option
-            return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller);
-        } else {
-            $ret = parent::onQuickFormEvent($event, $arg, $caller);
-            // add onreset handler to form to properly reset hierselect (see bug #2970)
-            if ('addElement' == $event) {
-                $onReset = $caller->getAttribute('onreset');
-                if (strlen($onReset)) {
-                    if (strpos($onReset, '_hs_setupOnReset')) {
-                        $caller->updateAttributes(array('onreset' => str_replace('_hs_setupOnReset(this, [', "_hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "', ", $onReset)));
-                    } else {
-                        $caller->updateAttributes(array('onreset' => "var temp = function() { {$onReset} } ; if (!temp()) { return false; } ; if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "']); } "));
-                    }
-                } else {
-                    $caller->updateAttributes(array('onreset' => "if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "']); } "));
-                }
-            }
-            return $ret;
-        }
-    } // end func onQuickFormEvent
-
-    // }}}
-    // {{{ _prepareOptions()
-
-   /**
-    * Prepares options for JS encoding
-    *
-    * We need to preserve order of options when adding them via javascript, so
-    * cannot use object literal and for/in loop (see bug #16603). Therefore we
-    * convert an associative array of options to two arrays of their values
-    * and texts. Backport from HTML_QuickForm2.
-    *
-    * @param    array   Options array
-    * @param    int     Depth within options array
-    * @link     http://pear.php.net/bugs/bug.php?id=16603
-    * @return   array
-    * @access   private
-    */
-    function _prepareOptions($ary, $depth)
-    {
-        if (!is_array($ary)) {
-            $ret = $ary;
-        } elseif (0 == $depth) {
-            $ret = array('values' => array_keys($ary), 'texts' => array_values($ary));
-        } else {
-            $ret = array();
-            foreach ($ary as $k => $v) {
-                $ret[$k] = $this->_prepareOptions($v, $depth - 1);
-            }
-        }
-        return $ret;
-    }
-
-    // }}}
-    // {{{ _convertArrayToJavascript()
-
-   /**
-    * Converts PHP array to its Javascript analog
-    *
-    * @access private
-    * @param  array     PHP array to convert
-    * @return string    Javascript representation of the value
-    */
-    function _convertArrayToJavascript($array)
-    {
-        if (!is_array($array)) {
-            return $this->_convertScalarToJavascript($array);
-        } elseif (count($array) && array_keys($array) != range(0, count($array) - 1)) {
-            return '{' . implode(',', array_map(
-                array($this, '_encodeNameValue'),
-                array_keys($array), array_values($array)
-            )) . '}';
-        } else {
-            return '[' . implode(',', array_map(
-                array($this, '_convertArrayToJavascript'),
-                $array
-            )) . ']';
-        }
-    }
-
-    // }}}
-    // {{{ _encodeNameValue()
-
-   /**
-    * Callback for array_map used to generate JS name-value pairs
-    *
-    * @param    mixed
-    * @param    mixed
-    * @return   string
-    */
-    function _encodeNameValue($name, $value)
-    {
-        return $this->_convertScalarToJavascript((string)$name) . ':'
-               . $this->_convertArrayToJavascript($value);
-    }
-
-    // }}}
-    // {{{ _convertScalarToJavascript()
-
-   /**
-    * Converts PHP's scalar value to its Javascript analog
-    *
-    * @access private
-    * @param  mixed     PHP value to convert
-    * @return string    Javascript representation of the value
-    */
-    function _convertScalarToJavascript($val)
-    {
-        if (is_bool($val)) {
-            return $val ? 'true' : 'false';
-        } elseif (is_int($val) || is_double($val)) {
-            return $val;
-        } elseif (is_string($val)) {
-            return "'" . $this->_escapeString($val) . "'";
-        } elseif (is_null($val)) {
-            return 'null';
-        } else {
-            // don't bother
-            return '{}';
-        }
-    }
-
-    // }}}
-    // {{{ _escapeString()
-
-   /**
-    * Quotes the string so that it can be used in Javascript string constants
-    *
-    * @access private
-    * @param  string
-    * @return string
-    */
-    function _escapeString($str)
-    {
-        return strtr($str,array(
-            "\r"    => '\r',
-            "\n"    => '\n',
-            "\t"    => '\t',
-            "'"     => "\\'",
-            '"'     => '\"',
-            '\\'    => '\\\\'
-        ));
-    }
-
-    // }}}
-} // end class HTML_QuickForm_hierselect
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/html.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/html.php
deleted file mode 100644 (file)
index 64ac858..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * A pseudo-element used for adding raw HTML to form
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * HTML class for static data
- */
-require_once 'HTML/QuickForm/static.php';
-
-/**
- * A pseudo-element used for adding raw HTML to form
- * 
- * Intended for use with the default renderer only, template-based
- * ones may (and probably will) completely ignore this
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.0
- * @deprecated  Please use the templates rather than add raw HTML via this element
- */
-class HTML_QuickForm_html extends HTML_QuickForm_static
-{
-    // {{{ constructor
-
-   /**
-    * Class constructor
-    * 
-    * @param string $text   raw HTML to add
-    * @access public
-    * @return void
-    */
-    function HTML_QuickForm_html($text = null)
-    {
-        $this->HTML_QuickForm_static(null, null, $text);
-        $this->_type = 'html';
-    }
-
-    // }}}
-    // {{{ accept()
-
-   /**
-    * Accepts a renderer
-    *
-    * @param HTML_QuickForm_Renderer    renderer object (only works with Default renderer!)
-    * @param bool $sc1                  unused, for signature compatibility
-    * @param bool $sc2                  unused, for signature compatibility
-    * @access public
-    * @return void 
-    */
-    function accept(&$renderer, $sc1 = false, $sc2 = null)
-    {
-        $renderer->renderHtml($this);
-    } // end func accept
-
-    // }}}
-
-} //end class HTML_QuickForm_html
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/image.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/image.php
deleted file mode 100644 (file)
index bf8a8aa..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for an <input type="image" /> element
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for an <input type="image" /> element
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_image extends HTML_QuickForm_input
-{
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Element name attribute
-     * @param     string    $src            (optional)Image source
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_image($elementName=null, $src='', $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
-        $this->setType('image');
-        $this->setSource($src);
-    } // end class constructor
-
-    // }}}
-    // {{{ setSource()
-
-    /**
-     * Sets source for image element
-     * 
-     * @param     string    $src  source for image element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setSource($src)
-    {
-        $this->updateAttributes(array('src' => $src));
-    } // end func setSource
-
-    // }}}
-    // {{{ setBorder()
-
-    /**
-     * Sets border size for image element
-     * 
-     * @param     string    $border  border for image element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setBorder($border)
-    {
-        $this->updateAttributes(array('border' => $border));
-    } // end func setBorder
-
-    // }}}
-    // {{{ setAlign()
-
-    /**
-     * Sets alignment for image element
-     * 
-     * @param     string    $align  alignment for image element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setAlign($align)
-    {
-        $this->updateAttributes(array('align' => $align));
-    } // end func setAlign
-
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Freeze the element so that only its value is returned
-     * 
-     * @access    public
-     * @return    void
-     */
-    function freeze()
-    {
-        return false;
-    } //end func freeze
-
-    // }}}
-
-} // end class HTML_QuickForm_image
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/input.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/input.php
deleted file mode 100644 (file)
index 0a1f3aa..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Base class for <input /> form elements
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for form elements
- */ 
-require_once 'HTML/QuickForm/element.php';
-
-/**
- * Base class for <input /> form elements
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- * @abstract
- */
-class HTML_QuickForm_input extends HTML_QuickForm_element
-{
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param    string     Input field name attribute
-     * @param    mixed      Label(s) for the input field
-     * @param    mixed      Either a typical HTML attribute string or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_input($elementName=null, $elementLabel=null, $attributes=null)
-    {
-        $this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-    } //end constructor
-
-    // }}}
-    // {{{ setType()
-
-    /**
-     * Sets the element type
-     *
-     * @param     string    $type   Element type
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setType($type)
-    {
-        $this->_type = $type;
-        $this->updateAttributes(array('type'=>$type));
-    } // end func setType
-    
-    // }}}
-    // {{{ setName()
-
-    /**
-     * Sets the input field name
-     * 
-     * @param     string    $name   Input field name attribute
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setName($name)
-    {
-        $this->updateAttributes(array('name'=>$name));
-    } //end func setName
-    
-    // }}}
-    // {{{ getName()
-
-    /**
-     * Returns the element name
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getName()
-    {
-        return $this->getAttribute('name');
-    } //end func getName
-    
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets the value of the form element
-     *
-     * @param     string    $value      Default value of the form element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setValue($value)
-    {
-        $this->updateAttributes(array('value'=>$value));
-    } // end func setValue
-
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns the value of the form element
-     *
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getValue()
-    {
-        return $this->getAttribute('value');
-    } // end func getValue
-    
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the input field in HTML
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function toHtml()
-    {
-        if ($this->_flagFrozen) {
-            return $this->getFrozenHtml();
-        } else {
-            return $this->_getTabs() . '<input' . $this->_getAttrString($this->_attributes) . ' />';
-        }
-    } //end func toHtml
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    $event  Name of event
-     * @param     mixed     $arg    event arguments
-     * @param     object    &$caller calling object
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        // do not use submit values for button-type elements
-        $type = $this->getType();
-        if (('updateValue' != $event) ||
-            ('submit' != $type && 'reset' != $type && 'image' != $type && 'button' != $type)) {
-            parent::onQuickFormEvent($event, $arg, $caller);
-        } else {
-            $value = $this->_findValue($caller->_constantValues);
-            if (null === $value) {
-                $value = $this->_findValue($caller->_defaultValues);
-            }
-            if (null !== $value) {
-                $this->setValue($value);
-            }
-        }
-        return true;
-    } // end func onQuickFormEvent
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * We don't need values from button-type elements (except submit) and files
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        $type = $this->getType();
-        if ('reset' == $type || 'image' == $type || 'button' == $type || 'file' == $type) {
-            return null;
-        } else {
-            return parent::exportValue($submitValues, $assoc);
-        }
-    }
-    
-    // }}}
-} // end class HTML_QuickForm_element
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/link.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/link.php
deleted file mode 100644 (file)
index acca0e2..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a link type field
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * HTML class for static data
- */ 
-require_once 'HTML/QuickForm/static.php';
-
-/**
- * HTML class for a link type field
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       2.0
- */
-class HTML_QuickForm_link extends HTML_QuickForm_static
-{
-    // {{{ properties
-
-    /**
-     * Link display text
-     * @var       string
-     * @since     1.0
-     * @access    private
-     */
-    var $_text = "";
-
-    // }}}
-    // {{{ constructor
-    
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementLabel   (optional)Link label
-     * @param     string    $href           (optional)Link href
-     * @param     string    $text           (optional)Link display text
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function HTML_QuickForm_link($elementName=null, $elementLabel=null, $href=null, $text=null, $attributes=null)
-    {
-        HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = false;
-        $this->_type = 'link';
-        $this->setHref($href);
-        $this->_text = $text;
-    } //end constructor
-    
-    // }}}
-    // {{{ setName()
-
-    /**
-     * Sets the input field name
-     * 
-     * @param     string    $name   Input field name attribute
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function setName($name)
-    {
-        $this->updateAttributes(array('name'=>$name));
-    } //end func setName
-    
-    // }}}
-    // {{{ getName()
-
-    /**
-     * Returns the element name
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     * @throws    
-     */
-    function getName()
-    {
-        return $this->getAttribute('name');
-    } //end func getName
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets value for textarea element
-     * 
-     * @param     string    $value  Value for password element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function setValue($value)
-    {
-        return;
-    } //end func setValue
-    
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns the value of the form element
-     *
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function getValue()
-    {
-        return;
-    } // end func getValue
-
-    
-    // }}}
-    // {{{ setHref()
-
-    /**
-     * Sets the links href
-     *
-     * @param     string    $href
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function setHref($href)
-    {
-        $this->updateAttributes(array('href'=>$href));
-    } // end func setHref
-
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the textarea element in HTML
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     * @throws    
-     */
-    function toHtml()
-    {
-        $tabs = $this->_getTabs();
-        $html = "$tabs<a".$this->_getAttrString($this->_attributes).">";
-        $html .= $this->_text;
-        $html .= "</a>";
-        return $html;
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags (in this case, value is changed to a mask)
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     * @throws    
-     */
-    function getFrozenHtml()
-    {
-        return;
-    } //end func getFrozenHtml
-
-    // }}}
-
-} //end class HTML_QuickForm_textarea
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/password.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/password.php
deleted file mode 100644 (file)
index 5d41e9a..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a password type field
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for a password type field
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_password extends HTML_QuickForm_input
-{
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $elementLabel   (optional)Input field label
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function HTML_QuickForm_password($elementName=null, $elementLabel=null, $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
-        $this->setType('password');
-    } //end constructor
-    
-    // }}}
-    // {{{ setSize()
-
-    /**
-     * Sets size of password element
-     * 
-     * @param     string    $size  Size of password field
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setSize($size)
-    {
-        $this->updateAttributes(array('size'=>$size));
-    } //end func setSize
-
-    // }}}
-    // {{{ setMaxlength()
-
-    /**
-     * Sets maxlength of password element
-     * 
-     * @param     string    $maxlength  Maximum length of password field
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setMaxlength($maxlength)
-    {
-        $this->updateAttributes(array('maxlength'=>$maxlength));
-    } //end func setMaxlength
-        
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags (in this case, value is changed to a mask)
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     * @throws    
-     */
-    function getFrozenHtml()
-    {
-        $value = $this->getValue();
-        return ('' != $value? '**********': '&nbsp;') .
-               $this->_getPersistantData();
-    } //end func getFrozenHtml
-
-    // }}}
-
-} //end class HTML_QuickForm_password
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/radio.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/radio.php
deleted file mode 100644 (file)
index 97b4eba..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a radio type element
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for a radio type element
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_radio extends HTML_QuickForm_input
-{
-    // {{{ properties
-
-    /**
-     * Radio display text
-     * @var       string
-     * @since     1.1
-     * @access    private
-     */
-    var $_text = '';
-
-    // }}}
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    Input field name attribute
-     * @param     mixed     Label(s) for a field
-     * @param     string    Text to display near the radio
-     * @param     string    Input field value
-     * @param     mixed     Either a typical HTML attribute string or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_radio($elementName=null, $elementLabel=null, $text=null, $value=null, $attributes=null)
-    {
-        $this->HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-        if (isset($value)) {
-            $this->setValue($value);
-        }
-        $this->_persistantFreeze = true;
-        $this->setType('radio');
-        $this->_text = $text;
-        $this->_generateId();
-    } //end constructor
-    
-    // }}}
-    // {{{ setChecked()
-
-    /**
-     * Sets whether radio button is checked
-     * 
-     * @param     bool    $checked  Whether the field is checked or not
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setChecked($checked)
-    {
-        if (!$checked) {
-            $this->removeAttribute('checked');
-        } else {
-            $this->updateAttributes(array('checked'=>'checked'));
-        }
-    } //end func setChecked
-
-    // }}}
-    // {{{ getChecked()
-
-    /**
-     * Returns whether radio button is checked
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getChecked()
-    {
-        return $this->getAttribute('checked');
-    } //end func getChecked
-        
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the radio element in HTML
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function toHtml()
-    {
-        if (0 == strlen($this->_text)) {
-            $label = '';
-        } elseif ($this->_flagFrozen) {
-            $label = $this->_text;
-        } else {
-            $label = '<label for="' . $this->getAttribute('id') . '">' . $this->_text . '</label>';
-        }
-        return HTML_QuickForm_input::toHtml() . $label;
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getFrozenHtml()
-    {
-        if ($this->getChecked()) {
-            return '<tt>(x)</tt>' .
-                   $this->_getPersistantData();
-        } else {
-            return '<tt>( )</tt>';
-        }
-    } //end func getFrozenHtml
-
-    // }}}
-    // {{{ setText()
-
-    /**
-     * Sets the radio text
-     * 
-     * @param     string    $text  Text to display near the radio button
-     * @since     1.1
-     * @access    public
-     * @return    void
-     */
-    function setText($text)
-    {
-        $this->_text = $text;
-    } //end func setText
-
-    // }}}
-    // {{{ getText()
-
-    /**
-     * Returns the radio text 
-     * 
-     * @since     1.1
-     * @access    public
-     * @return    string
-     */
-    function getText()
-    {
-        return $this->_text;
-    } //end func getText
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    $event  Name of event
-     * @param     mixed     $arg    event arguments
-     * @param     object    &$caller calling object
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        switch ($event) {
-            case 'updateValue':
-                // constant values override both default and submitted ones
-                // default values are overriden by submitted
-                $value = $this->_findValue($caller->_constantValues);
-                if (null === $value) {
-                    $value = $this->_findValue($caller->_submitValues);
-                    if (null === $value) {
-                        $value = $this->_findValue($caller->_defaultValues);
-                    }
-                }
-                if (!is_null($value) && $value == $this->getValue()) {
-                    $this->setChecked(true);
-                } else {
-                    $this->setChecked(false);
-                }
-                break;
-            case 'setGroupValue':
-                if ($arg == $this->getValue()) {
-                    $this->setChecked(true);
-                } else {
-                    $this->setChecked(false);
-                }
-                break;
-            default:
-                parent::onQuickFormEvent($event, $arg, $caller);
-        }
-        return true;
-    } // end func onQuickFormLoad
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * Returns the value attribute if the radio is checked, null if it is not
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        $value = $this->_findValue($submitValues);
-        if (null === $value) {
-            $value = $this->getChecked()? $this->getValue(): null;
-        } elseif ($value != $this->getValue()) {
-            $value = null;
-        }
-        return $this->_prepareValue($value, $assoc);
-    }
-    
-    // }}}
-} //end class HTML_QuickForm_radio
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/reset.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/reset.php
deleted file mode 100644 (file)
index 6c8dade..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a reset type element
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for a reset type element
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_reset extends HTML_QuickForm_input
-{
-    // {{{ constructor
-    
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $value          (optional)Input field value
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_reset($elementName=null, $value=null, $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
-        $this->setValue($value);
-        $this->setType('reset');
-    } //end constructor
-
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Freeze the element so that only its value is returned
-     * 
-     * @access    public
-     * @return    void
-     */
-    function freeze()
-    {
-        return false;
-    } //end func freeze
-
-    // }}}
-
-} //end class HTML_QuickForm_reset
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/select.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/select.php
deleted file mode 100644 (file)
index c6ada54..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Class to dynamically create an HTML SELECT
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for form elements
- */ 
-require_once 'HTML/QuickForm/element.php';
-
-/**
- * Class to dynamically create an HTML SELECT
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_select extends HTML_QuickForm_element {
-    
-    // {{{ properties
-
-    /**
-     * Contains the select options
-     *
-     * @var       array
-     * @since     1.0
-     * @access    private
-     */
-    var $_options = array();
-    
-    /**
-     * Default values of the SELECT
-     * 
-     * @var       string
-     * @since     1.0
-     * @access    private
-     */
-    var $_values = null;
-
-    // }}}
-    // {{{ constructor
-        
-    /**
-     * Class constructor
-     * 
-     * @param     string    Select name attribute
-     * @param     mixed     Label(s) for the select
-     * @param     mixed     Data to be used to populate options
-     * @param     mixed     Either a typical HTML attribute string or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_select($elementName=null, $elementLabel=null, $options=null, $attributes=null)
-    {
-        HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        $this->_type = 'select';
-        if (isset($options)) {
-            $this->load($options);
-        }
-    } //end constructor
-    
-    // }}}
-    // {{{ apiVersion()
-
-    /**
-     * Returns the current API version 
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    double
-     */
-    function apiVersion()
-    {
-        return 2.3;
-    } //end func apiVersion
-
-    // }}}
-    // {{{ setSelected()
-
-    /**
-     * Sets the default values of the select box
-     * 
-     * @param     mixed    $values  Array or comma delimited string of selected values
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setSelected($values)
-    {
-        if (is_string($values) && $this->getMultiple()) {
-            $values = preg_split("/[ ]?,[ ]?/", $values);
-        }
-        if (is_array($values)) {
-            $this->_values = array_values($values);
-        } else {
-            $this->_values = array($values);
-        }
-    } //end func setSelected
-    
-    // }}}
-    // {{{ getSelected()
-
-    /**
-     * Returns an array of the selected values
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    array of selected values
-     */
-    function getSelected()
-    {
-        return $this->_values;
-    } // end func getSelected
-
-    // }}}
-    // {{{ setName()
-
-    /**
-     * Sets the input field name
-     * 
-     * @param     string    $name   Input field name attribute
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setName($name)
-    {
-        $this->updateAttributes(array('name' => $name));
-    } //end func setName
-    
-    // }}}
-    // {{{ getName()
-
-    /**
-     * Returns the element name
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getName()
-    {
-        return $this->getAttribute('name');
-    } //end func getName
-
-    // }}}
-    // {{{ getPrivateName()
-
-    /**
-     * Returns the element name (possibly with brackets appended)
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getPrivateName()
-    {
-        if ($this->getAttribute('multiple')) {
-            return $this->getName() . '[]';
-        } else {
-            return $this->getName();
-        }
-    } //end func getPrivateName
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets the value of the form element
-     *
-     * @param     mixed    $values  Array or comma delimited string of selected values
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setValue($value)
-    {
-        $this->setSelected($value);
-    } // end func setValue
-
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns an array of the selected values
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    array of selected values
-     */
-    function getValue()
-    {
-        return $this->_values;
-    } // end func getValue
-
-    // }}}
-    // {{{ setSize()
-
-    /**
-     * Sets the select field size, only applies to 'multiple' selects
-     * 
-     * @param     int    $size  Size of select  field
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setSize($size)
-    {
-        $this->updateAttributes(array('size' => $size));
-    } //end func setSize
-    
-    // }}}
-    // {{{ getSize()
-
-    /**
-     * Returns the select field size
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    int
-     */
-    function getSize()
-    {
-        return $this->getAttribute('size');
-    } //end func getSize
-
-    // }}}
-    // {{{ setMultiple()
-
-    /**
-     * Sets the select mutiple attribute
-     * 
-     * @param     bool    $multiple  Whether the select supports multi-selections
-     * @since     1.2
-     * @access    public
-     * @return    void
-     */
-    function setMultiple($multiple)
-    {
-        if ($multiple) {
-            $this->updateAttributes(array('multiple' => 'multiple'));
-        } else {
-            $this->removeAttribute('multiple');
-        }
-    } //end func setMultiple
-    
-    // }}}
-    // {{{ getMultiple()
-
-    /**
-     * Returns the select mutiple attribute
-     * 
-     * @since     1.2
-     * @access    public
-     * @return    bool    true if multiple select, false otherwise
-     */
-    function getMultiple()
-    {
-        return (bool)$this->getAttribute('multiple');
-    } //end func getMultiple
-
-    // }}}
-    // {{{ addOption()
-
-    /**
-     * Adds a new OPTION to the SELECT
-     *
-     * @param     string    $text       Display text for the OPTION
-     * @param     string    $value      Value for the OPTION
-     * @param     mixed     $attributes Either a typical HTML attribute string 
-     *                                  or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function addOption($text, $value, $attributes=null)
-    {
-        if (null === $attributes) {
-            $attributes = array('value' => (string)$value);
-        } else {
-            $attributes = $this->_parseAttributes($attributes);
-            if (isset($attributes['selected'])) {
-                // the 'selected' attribute will be set in toHtml()
-                $this->_removeAttr('selected', $attributes);
-                if (is_null($this->_values)) {
-                    $this->_values = array($value);
-                } elseif (!in_array($value, $this->_values)) {
-                    $this->_values[] = $value;
-                }
-            }
-            $this->_updateAttrArray($attributes, array('value' => (string)$value));
-        }
-        $this->_options[] = array('text' => $text, 'attr' => $attributes);
-    } // end func addOption
-    
-    // }}}
-    // {{{ loadArray()
-
-    /**
-     * Loads the options from an associative array
-     * 
-     * @param     array    $arr     Associative array of options
-     * @param     mixed    $values  (optional) Array or comma delimited string of selected values
-     * @since     1.0
-     * @access    public
-     * @return    PEAR_Error on error or true
-     * @throws    PEAR_Error
-     */
-    function loadArray($arr, $values=null)
-    {
-        if (!is_array($arr)) {
-            return PEAR::raiseError('Argument 1 of HTML_Select::loadArray is not a valid array');
-        }
-        if (isset($values)) {
-            $this->setSelected($values);
-        }
-        foreach ($arr as $key => $val) {
-            // Warning: new API since release 2.3
-            $this->addOption($val, $key);
-        }
-        return true;
-    } // end func loadArray
-
-    // }}}
-    // {{{ loadDbResult()
-
-    /**
-     * Loads the options from DB_result object
-     * 
-     * If no column names are specified the first two columns of the result are
-     * used as the text and value columns respectively
-     * @param     object    $result     DB_result object 
-     * @param     string    $textCol    (optional) Name of column to display as the OPTION text 
-     * @param     string    $valueCol   (optional) Name of column to use as the OPTION value 
-     * @param     mixed     $values     (optional) Array or comma delimited string of selected values
-     * @since     1.0
-     * @access    public
-     * @return    PEAR_Error on error or true
-     * @throws    PEAR_Error
-     */
-    function loadDbResult(&$result, $textCol=null, $valueCol=null, $values=null)
-    {
-        if (!is_object($result) || !is_a($result, 'db_result')) {
-            return PEAR::raiseError('Argument 1 of HTML_Select::loadDbResult is not a valid DB_result');
-        }
-        if (isset($values)) {
-            $this->setValue($values);
-        }
-        $fetchMode = ($textCol && $valueCol) ? DB_FETCHMODE_ASSOC : DB_FETCHMODE_ORDERED;
-        while (is_array($row = $result->fetchRow($fetchMode)) ) {
-            if ($fetchMode == DB_FETCHMODE_ASSOC) {
-                $this->addOption($row[$textCol], $row[$valueCol]);
-            } else {
-                $this->addOption($row[0], $row[1]);
-            }
-        }
-        return true;
-    } // end func loadDbResult
-    
-    // }}}
-    // {{{ loadQuery()
-
-    /**
-     * Queries a database and loads the options from the results
-     *
-     * @param     mixed     $conn       Either an existing DB connection or a valid dsn 
-     * @param     string    $sql        SQL query string
-     * @param     string    $textCol    (optional) Name of column to display as the OPTION text 
-     * @param     string    $valueCol   (optional) Name of column to use as the OPTION value 
-     * @param     mixed     $values     (optional) Array or comma delimited string of selected values
-     * @since     1.1
-     * @access    public
-     * @return    void
-     * @throws    PEAR_Error
-     */
-    function loadQuery(&$conn, $sql, $textCol=null, $valueCol=null, $values=null)
-    {
-        if (is_string($conn)) {
-            require_once('DB.php');
-            $dbConn = &DB::connect($conn, true);
-            if (DB::isError($dbConn)) {
-                return $dbConn;
-            }
-        } elseif (is_subclass_of($conn, "db_common")) {
-            $dbConn = &$conn;
-        } else {
-            return PEAR::raiseError('Argument 1 of HTML_Select::loadQuery is not a valid type');
-        }
-        $result = $dbConn->query($sql);
-        if (DB::isError($result)) {
-            return $result;
-        }
-        $this->loadDbResult($result, $textCol, $valueCol, $values);
-        $result->free();
-        if (is_string($conn)) {
-            $dbConn->disconnect();
-        }
-        return true;
-    } // end func loadQuery
-
-    // }}}
-    // {{{ load()
-
-    /**
-     * Loads options from different types of data sources
-     *
-     * This method is a simulated overloaded method.  The arguments, other than the
-     * first are optional and only mean something depending on the type of the first argument.
-     * If the first argument is an array then all arguments are passed in order to loadArray.
-     * If the first argument is a db_result then all arguments are passed in order to loadDbResult.
-     * If the first argument is a string or a DB connection then all arguments are 
-     * passed in order to loadQuery.
-     * @param     mixed     $options     Options source currently supports assoc array or DB_result
-     * @param     mixed     $param1     (optional) See function detail
-     * @param     mixed     $param2     (optional) See function detail
-     * @param     mixed     $param3     (optional) See function detail
-     * @param     mixed     $param4     (optional) See function detail
-     * @since     1.1
-     * @access    public
-     * @return    PEAR_Error on error or true
-     * @throws    PEAR_Error
-     */
-    function load(&$options, $param1=null, $param2=null, $param3=null, $param4=null)
-    {
-        switch (true) {
-            case is_array($options):
-                return $this->loadArray($options, $param1);
-                break;
-            case (is_a($options, 'db_result')):
-                return $this->loadDbResult($options, $param1, $param2, $param3);
-                break;
-            case (is_string($options) && !empty($options) || is_subclass_of($options, "db_common")):
-                return $this->loadQuery($options, $param1, $param2, $param3, $param4);
-                break;
-        }
-    } // end func load
-    
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the SELECT in HTML
-     *
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function toHtml()
-    {
-        if ($this->_flagFrozen) {
-            return $this->getFrozenHtml();
-        } else {
-            $tabs    = $this->_getTabs();
-            $strHtml = '';
-
-            if ($this->getComment() != '') {
-                $strHtml .= $tabs . '<!-- ' . $this->getComment() . " //-->\n";
-            }
-
-            if (!$this->getMultiple()) {
-                $attrString = $this->_getAttrString($this->_attributes);
-            } else {
-                $myName = $this->getName();
-                $this->setName($myName . '[]');
-                $attrString = $this->_getAttrString($this->_attributes);
-                $this->setName($myName);
-            }
-            $strHtml .= $tabs . '<select' . $attrString . ">\n";
-
-            $strValues = is_array($this->_values)? array_map('strval', $this->_values): array();
-            foreach ($this->_options as $option) {
-                if (!empty($strValues) && in_array($option['attr']['value'], $strValues, true)) {
-                    $option['attr']['selected'] = 'selected';
-                }
-                $strHtml .= $tabs . "\t<option" . $this->_getAttrString($option['attr']) . '>' .
-                            $option['text'] . "</option>\n";
-            }
-
-            return $strHtml . $tabs . '</select>';
-        }
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getFrozenHtml()
-    {
-        $value = array();
-        if (is_array($this->_values)) {
-            foreach ($this->_values as $key => $val) {
-                for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
-                    if (0 == strcmp($val, $this->_options[$i]['attr']['value'])) {
-                        $value[$key] = $this->_options[$i]['text'];
-                        break;
-                    }
-                }
-            }
-        }
-        $html = empty($value)? '&nbsp;': join('<br />', $value);
-        if ($this->_persistantFreeze) {
-            $name = $this->getPrivateName();
-            // Only use id attribute if doing single hidden input
-            if (1 == count($value)) {
-                $id     = $this->getAttribute('id');
-                $idAttr = isset($id)? array('id' => $id): array();
-            } else {
-                $idAttr = array();
-            }
-            foreach ($value as $key => $item) {
-                $html .= '<input' . $this->_getAttrString(array(
-                             'type'  => 'hidden',
-                             'name'  => $name,
-                             'value' => $this->_values[$key]
-                         ) + $idAttr) . ' />';
-            }
-        }
-        return $html;
-    } //end func getFrozenHtml
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * We check the options and return only the values that _could_ have been
-    * selected. We also return a scalar value if select is not "multiple"
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        $value = $this->_findValue($submitValues);
-        if (is_null($value)) {
-            $value = $this->getValue();
-        } elseif(!is_array($value)) {
-            $value = array($value);
-        }
-        if (is_array($value) && !empty($this->_options)) {
-            $cleanValue = null;
-            foreach ($value as $v) {
-                for ($i = 0, $optCount = count($this->_options); $i < $optCount; $i++) {
-                    if (0 == strcmp($v, $this->_options[$i]['attr']['value'])) {
-                        $cleanValue[] = $v;
-                        break;
-                    }
-                }
-            }
-        } else {
-            $cleanValue = $value;
-        }
-        if (is_array($cleanValue) && !$this->getMultiple()) {
-            return $this->_prepareValue($cleanValue[0], $assoc);
-        } else {
-            return $this->_prepareValue($cleanValue, $assoc);
-        }
-    }
-    
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        if ('updateValue' == $event) {
-            $value = $this->_findValue($caller->_constantValues);
-            if (null === $value) {
-                $value = $this->_findValue($caller->_submitValues);
-                // Fix for bug #4465 & #5269
-                // XXX: should we push this to element::onQuickFormEvent()?
-                if (null === $value && (!$caller->isSubmitted() || !$this->getMultiple())) {
-                    $value = $this->_findValue($caller->_defaultValues);
-                }
-            }
-            if (null !== $value) {
-                $this->setValue($value);
-            }
-            return true;
-        } else {
-            return parent::onQuickFormEvent($event, $arg, $caller);
-        }
-    }
-
-    // }}}
-} //end class HTML_QuickForm_select
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/static.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/static.php
deleted file mode 100644 (file)
index acff7c3..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for static data
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Wojciech Gdela <eltehaem@poczta.onet.pl>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for form elements
- */ 
-require_once 'HTML/QuickForm/element.php';
-
-/**
- * HTML class for static data
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Wojciech Gdela <eltehaem@poczta.onet.pl>
- * @version     Release: 3.2.16
- * @since       2.7
- */
-class HTML_QuickForm_static extends HTML_QuickForm_element {
-    
-    // {{{ properties
-
-    /**
-     * Display text
-     * @var       string
-     * @access    private
-     */
-    var $_text = null;
-
-    // }}}
-    // {{{ constructor
-    
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementLabel   (optional)Label
-     * @param     string    $text           (optional)Display text
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_static($elementName=null, $elementLabel=null, $text=null)
-    {
-        HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel);
-        $this->_persistantFreeze = false;
-        $this->_type = 'static';
-        $this->_text = $text;
-    } //end constructor
-    
-    // }}}
-    // {{{ setName()
-
-    /**
-     * Sets the element name
-     * 
-     * @param     string    $name   Element name
-     * @access    public
-     * @return    void
-     */
-    function setName($name)
-    {
-        $this->updateAttributes(array('name'=>$name));
-    } //end func setName
-    
-    // }}}
-    // {{{ getName()
-
-    /**
-     * Returns the element name
-     * 
-     * @access    public
-     * @return    string
-     */
-    function getName()
-    {
-        return $this->getAttribute('name');
-    } //end func getName
-
-    // }}}
-    // {{{ setText()
-
-    /**
-     * Sets the text
-     *
-     * @param     string    $text
-     * @access    public
-     * @return    void
-     */
-    function setText($text)
-    {
-        $this->_text = $text;
-    } // end func setText
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets the text (uses the standard setValue call to emulate a form element.
-     *
-     * @param     string    $text
-     * @access    public
-     * @return    void
-     */
-    function setValue($text)
-    {
-        $this->setText($text);
-    } // end func setValue
-
-    // }}}    
-    // {{{ toHtml()
-
-    /**
-     * Returns the static text element in HTML
-     * 
-     * @access    public
-     * @return    string
-     */
-    function toHtml()
-    {
-        return $this->_getTabs() . $this->_text;
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags
-     * 
-     * @access    public
-     * @return    string
-     */
-    function getFrozenHtml()
-    {
-        return $this->toHtml();
-    } //end func getFrozenHtml
-
-    // }}}
-    // {{{ onQuickFormEvent()
-
-    /**
-     * Called by HTML_QuickForm whenever form event is made on this element
-     *
-     * @param     string    $event  Name of event
-     * @param     mixed     $arg    event arguments
-     * @param     object    &$caller calling object
-     * @since     1.0
-     * @access    public
-     * @return    void
-     * @throws    
-     */
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        switch ($event) {
-            case 'updateValue':
-                // do NOT use submitted values for static elements
-                $value = $this->_findValue($caller->_constantValues);
-                if (null === $value) {
-                    $value = $this->_findValue($caller->_defaultValues);
-                }
-                if (null !== $value) {
-                    $this->setValue($value);
-                }
-                break;
-            default:
-                parent::onQuickFormEvent($event, $arg, $caller);
-        }
-        return true;
-    } // end func onQuickFormEvent
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * We override this here because we don't want any values from static elements
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        return null;
-    }
-    
-    // }}}
-} //end class HTML_QuickForm_static
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/submit.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/submit.php
deleted file mode 100644 (file)
index cd39475..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a submit type element
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for a submit type element
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_submit extends HTML_QuickForm_input
-{
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    Input field name attribute
-     * @param     string    Input field value
-     * @param     mixed     Either a typical HTML attribute string or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_submit($elementName=null, $value=null, $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, null, $attributes);
-        $this->setValue($value);
-        $this->setType('submit');
-    } //end constructor
-    
-    // }}}
-    // {{{ freeze()
-
-    /**
-     * Freeze the element so that only its value is returned
-     * 
-     * @access    public
-     * @return    void
-     */
-    function freeze()
-    {
-        return false;
-    } //end func freeze
-
-    // }}}
-    // {{{ exportValue()
-
-   /**
-    * Only return the value if it is found within $submitValues (i.e. if
-    * this particular submit button was clicked)
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        return $this->_prepareValue($this->_findValue($submitValues), $assoc);
-    }
-
-    // }}}
-} //end class HTML_QuickForm_submit
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/text.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/text.php
deleted file mode 100644 (file)
index 76b9849..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a text field
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for <input /> form elements
- */
-require_once 'HTML/QuickForm/input.php';
-
-/**
- * HTML class for a text field
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_text extends HTML_QuickForm_input
-{
-                
-    // {{{ constructor
-
-    /**
-     * Class constructor
-     * 
-     * @param     string    $elementName    (optional)Input field name attribute
-     * @param     string    $elementLabel   (optional)Input field label
-     * @param     mixed     $attributes     (optional)Either a typical HTML attribute string 
-     *                                      or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_text($elementName=null, $elementLabel=null, $attributes=null)
-    {
-        HTML_QuickForm_input::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        $this->setType('text');
-    } //end constructor
-        
-    // }}}
-    // {{{ setSize()
-
-    /**
-     * Sets size of text field
-     * 
-     * @param     string    $size  Size of text field
-     * @since     1.3
-     * @access    public
-     * @return    void
-     */
-    function setSize($size)
-    {
-        $this->updateAttributes(array('size'=>$size));
-    } //end func setSize
-
-    // }}}
-    // {{{ setMaxlength()
-
-    /**
-     * Sets maxlength of text field
-     * 
-     * @param     string    $maxlength  Maximum length of text field
-     * @since     1.3
-     * @access    public
-     * @return    void
-     */
-    function setMaxlength($maxlength)
-    {
-        $this->updateAttributes(array('maxlength'=>$maxlength));
-    } //end func setMaxlength
-
-    // }}}
-    
-} //end class HTML_QuickForm_text
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/textarea.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/textarea.php
deleted file mode 100644 (file)
index 492c270..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * HTML class for a textarea type field
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for form elements
- */ 
-require_once 'HTML/QuickForm/element.php';
-
-/**
- * HTML class for a textarea type field
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Adam Daniel <adaniel1@eesus.jnj.com>
- * @author      Bertrand Mansion <bmansion@mamasam.com>
- * @version     Release: 3.2.16
- * @since       1.0
- */
-class HTML_QuickForm_textarea extends HTML_QuickForm_element
-{
-    // {{{ properties
-
-    /**
-     * Field value
-     * @var       string
-     * @since     1.0
-     * @access    private
-     */
-    var $_value = null;
-
-    // }}}
-    // {{{ constructor
-        
-    /**
-     * Class constructor
-     * 
-     * @param     string    Input field name attribute
-     * @param     mixed     Label(s) for a field
-     * @param     mixed     Either a typical HTML attribute string or an associative array
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function HTML_QuickForm_textarea($elementName=null, $elementLabel=null, $attributes=null)
-    {
-        HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
-        $this->_persistantFreeze = true;
-        $this->_type = 'textarea';
-    } //end constructor
-    
-    // }}}
-    // {{{ setName()
-
-    /**
-     * Sets the input field name
-     * 
-     * @param     string    $name   Input field name attribute
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setName($name)
-    {
-        $this->updateAttributes(array('name'=>$name));
-    } //end func setName
-    
-    // }}}
-    // {{{ getName()
-
-    /**
-     * Returns the element name
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getName()
-    {
-        return $this->getAttribute('name');
-    } //end func getName
-
-    // }}}
-    // {{{ setValue()
-
-    /**
-     * Sets value for textarea element
-     * 
-     * @param     string    $value  Value for textarea element
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setValue($value)
-    {
-        $this->_value = $value;
-    } //end func setValue
-    
-    // }}}
-    // {{{ getValue()
-
-    /**
-     * Returns the value of the form element
-     *
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getValue()
-    {
-        return $this->_value;
-    } // end func getValue
-
-    // }}}
-    // {{{ setWrap()
-
-    /**
-     * Sets wrap type for textarea element
-     * 
-     * @param     string    $wrap  Wrap type
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setWrap($wrap)
-    {
-        $this->updateAttributes(array('wrap' => $wrap));
-    } //end func setWrap
-    
-    // }}}
-    // {{{ setRows()
-
-    /**
-     * Sets height in rows for textarea element
-     * 
-     * @param     string    $rows  Height expressed in rows
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */
-    function setRows($rows)
-    {
-        $this->updateAttributes(array('rows' => $rows));
-    } //end func setRows
-
-    // }}}
-    // {{{ setCols()
-
-    /**
-     * Sets width in cols for textarea element
-     * 
-     * @param     string    $cols  Width expressed in cols
-     * @since     1.0
-     * @access    public
-     * @return    void
-     */ 
-    function setCols($cols)
-    {
-        $this->updateAttributes(array('cols' => $cols));
-    } //end func setCols
-
-    // }}}
-    // {{{ toHtml()
-
-    /**
-     * Returns the textarea element in HTML
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function toHtml()
-    {
-        if ($this->_flagFrozen) {
-            return $this->getFrozenHtml();
-        } else {
-            return $this->_getTabs() .
-                   '<textarea' . $this->_getAttrString($this->_attributes) . '>' .
-                   // because we wrap the form later we don't want the text indented
-                   preg_replace("/(\r\n|\n|\r)/", '&#010;', htmlspecialchars($this->_value)) .
-                   '</textarea>';
-        }
-    } //end func toHtml
-    
-    // }}}
-    // {{{ getFrozenHtml()
-
-    /**
-     * Returns the value of field without HTML tags (in this case, value is changed to a mask)
-     * 
-     * @since     1.0
-     * @access    public
-     * @return    string
-     */
-    function getFrozenHtml()
-    {
-        $value = htmlspecialchars($this->getValue());
-        if ($this->getAttribute('wrap') == 'off') {
-            $html = $this->_getTabs() . '<pre>' . $value."</pre>\n";
-        } else {
-            $html = nl2br($value)."\n";
-        }
-        return $html . $this->_getPersistantData();
-    } //end func getFrozenHtml
-
-    // }}}
-
-} //end class HTML_QuickForm_textarea
-?>
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/utils.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/utils.php
deleted file mode 100644 (file)
index 3b60679..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * utility functions
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Chuck Burgess <ashnazg@php.net>
- * @copyright   2001-2018 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Provides a collection of static methods for array manipulation.
- *
- * (courtesy of CiviCRM project (https://civicrm.org/)
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Chuck Burgess <ashnazg@php.net>
- * @version     Release: 3.2.16
- * @since       3.2
- */
-class HTML_QuickForm_utils
-{
-    /**
-     * Get a single value from an array-tree.
-     *
-     * @param   array     $values   Ex: ['foo' => ['bar' => 123]].
-     * @param   array     $path     Ex: ['foo', 'bar'].
-     * @param   mixed     $default
-     * @return  mixed               Ex 123.
-     *
-     * @access  public
-     * @static
-     */
-    function pathGet($values, $path, $default = NULL) {
-        foreach ($path as $key) {
-            if (!is_array($values) || !isset($values[$key])) {
-                return $default;
-            }
-            $values = $values[$key];
-        }
-        return $values;
-    }
-
-    /**
-     * Check if a key isset which may be several layers deep.
-     *
-     * This is a helper for when the calling function does not know how many layers deep
-     * the path array is so cannot easily check.
-     *
-     * @param   array $values
-     * @param   array $path
-     * @return  bool
-     *
-     * @access  public
-     * @static
-     */
-    function pathIsset($values, $path) {
-        foreach ($path as $key) {
-            if (!is_array($values) || !isset($values[$key])) {
-                return FALSE;
-            }
-            $values = $values[$key];
-        }
-        return TRUE;
-    }
-
-    /**
-     * Set a single value in an array tree.
-     *
-     * @param   array   $values     Ex: ['foo' => ['bar' => 123]].
-     * @param   array   $pathParts  Ex: ['foo', 'bar'].
-     * @param   mixed   $value      Ex: 456.
-     * @return  void
-     *
-     * @access  public
-     * @static
-     */
-    function pathSet(&$values, $pathParts, $value) {
-        $r = &$values;
-        $last = array_pop($pathParts);
-        foreach ($pathParts as $part) {
-            if (!isset($r[$part])) {
-                $r[$part] = array();
-            }
-            $r = &$r[$part];
-        }
-        $r[$last] = $value;
-    }
-
-    /**
-     * Check if a key isset which may be several layers deep.
-     *
-     * This is a helper for when the calling function does not know how many layers deep the
-     * path array is so cannot easily check.
-     *
-     * @param   array $array
-     * @param   array $path
-     * @return  bool
-     *
-     * @access  public
-     * @static
-     */
-    function recursiveIsset($array, $path) {
-        return self::pathIsset($array, $path);
-    }
-
-    /**
-     * Check if a key isset which may be several layers deep.
-     *
-     * This is a helper for when the calling function does not know how many layers deep the
-     * path array is so cannot easily check.
-     *
-     * @param   array   $array
-     * @param   array   $path       An array of keys,
-     *                              e.g [0, 'bob', 8] where we want to check if $array[0]['bob'][8]
-     * @param   mixed   $default    Value to return if not found.
-     * @return  bool
-     *
-     * @access  public
-     * @static
-     */
-    function recursiveValue($array, $path, $default = NULL) {
-        return self::pathGet($array, $path, $default);
-    }
-
-    /**
-     * Append the value to the array using the key provided.
-     *
-     * e.g if value is 'llama' & path is [0, 'email', 'location'] result will be
-     * [0 => ['email' => ['location' => 'llama']]
-     *
-     * @param           $path
-     * @param           $value
-     * @param   array   $source
-     * @return  array
-     *
-     * @access  public
-     * @static
-     */
-    function recursiveBuild($path, $value, $source = array()) {
-        self::pathSet($source, $path, $value);
-        return $source;
-    }
-}
-?>
\ No newline at end of file
diff --git a/cookbooks/dmca/files/default/html/HTML/QuickForm/xbutton.php b/cookbooks/dmca/files/default/html/HTML/QuickForm/xbutton.php
deleted file mode 100644 (file)
index 0737e39..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
-
-/**
- * Class for HTML 4.0 <button> element
- * 
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.01 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_01.txt If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @copyright   2001-2011 The PHP Group
- * @license     http://www.php.net/license/3_01.txt PHP License 3.01
- * @version     CVS: $Id$
- * @link        http://pear.php.net/package/HTML_QuickForm
- */
-
-/**
- * Base class for form elements
- */ 
-require_once 'HTML/QuickForm/element.php';
-
-/**
- * Class for HTML 4.0 <button> element
- * 
- * @category    HTML
- * @package     HTML_QuickForm
- * @author      Alexey Borzov <avb@php.net>
- * @version     Release: 3.2.16
- * @since       3.2.3
- */
-class HTML_QuickForm_xbutton extends HTML_QuickForm_element
-{
-   /**
-    * Contents of the <button> tag
-    * @var      string
-    * @access   private
-    */
-    var $_content; 
-
-   /**
-    * Class constructor
-    * 
-    * @param    string  Button name
-    * @param    string  Button content (HTML to add between <button></button> tags)
-    * @param    mixed   Either a typical HTML attribute string or an associative array
-    * @access   public
-    */
-    function HTML_QuickForm_xbutton($elementName = null, $elementContent = null, $attributes = null)
-    {
-        $this->HTML_QuickForm_element($elementName, null, $attributes);
-        $this->setContent($elementContent);
-        $this->setPersistantFreeze(false);
-        $this->_type = 'xbutton';
-    }
-
-
-    function toHtml()
-    {
-        return '<button' . $this->getAttributes(true) . '>' . $this->_content . '</button>';
-    }
-
-
-    function getFrozenHtml()
-    {
-        return $this->toHtml();
-    }
-
-
-    function freeze()
-    {
-        return false;
-    }
-
-
-    function setName($name)
-    {
-        $this->updateAttributes(array(
-            'name' => $name 
-        ));
-    }
-
-
-    function getName()
-    {
-        return $this->getAttribute('name');
-    }
-
-
-    function setValue($value)
-    {
-        $this->updateAttributes(array(
-            'value' => $value
-        ));
-    }
-
-
-    function getValue()
-    {
-        return $this->getAttribute('value');
-    }
-
-
-   /**
-    * Sets the contents of the button element
-    *
-    * @param    string  Button content (HTML to add between <button></button> tags)
-    */
-    function setContent($content)
-    {
-        $this->_content = $content;
-    }
-
-
-    function onQuickFormEvent($event, $arg, &$caller)
-    {
-        if ('updateValue' != $event) {
-            return parent::onQuickFormEvent($event, $arg, $caller);
-        } else {
-            $value = $this->_findValue($caller->_constantValues);
-            if (null === $value) {
-                $value = $this->_findValue($caller->_defaultValues);
-            }
-            if (null !== $value) {
-                $this->setValue($value);
-            }
-        }
-        return true;
-    }
-
-
-   /**
-    * Returns a 'safe' element's value
-    * 
-    * The value is only returned if the button's type is "submit" and if this
-    * particlular button was clicked
-    */
-    function exportValue(&$submitValues, $assoc = false)
-    {
-        if ('submit' == $this->getAttribute('type')) {
-            return $this->_prepareValue($this->_findValue($submitValues), $assoc);
-        } else {
-            return null;
-        }
-    }
-}
-?>
diff --git a/cookbooks/dmca/files/default/html/favicon.ico b/cookbooks/dmca/files/default/html/favicon.ico
deleted file mode 100644 (file)
index 27b042b..0000000
Binary files a/cookbooks/dmca/files/default/html/favicon.ico and /dev/null differ
diff --git a/cookbooks/dmca/files/default/html/index.php b/cookbooks/dmca/files/default/html/index.php
deleted file mode 100644 (file)
index 4b283d3..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-session_start();
-require_once 'HTML/QuickForm.php';
-require_once 'HTML/QuickForm/DHTMLRulesTableless.php';
-require_once 'HTML/QuickForm/Renderer/Tableless.php';
-
-function process_data ($values) {
-        echo '<h1>Thank you</h1>';
-        echo 'Your report has been submitted';
-        $email_body = 'OpenStreetMap - Claim of Copyright Infringement form:'."\n\n";
-        $email_body .= 'Automated Email - Form Posted.'."\n\n";
-        $email_body .= print_r($values, true);
-        mail('dmca@osmfoundation.org','OSM Claim of Copyright Infringement', $email_body, 'From: OSMF Copyright Form <dmca@osmfoundation.org>', '-fdmca@osmfoundation.org');
-}
-?>
-<!DOCTYPE html>
-<html>
-<head>
-<title>OpenStreetMap Legal - Claim of Copyright Infringement</title>
-<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
- <link rel="stylesheet" type="text/css" href="/style.css" />
-</head>
-<body>
-<div class="regForm">
-<?php
-// Instantiate the HTML_QuickForm object
-$form = new HTML_QuickForm_DHTMLRulesTableless('osm_legal_claim_of_copyright');
-$renderer = new HTML_QuickForm_Renderer_Tableless();
-
-$form->addElement('header', null, 'OpenStreetMap: Claim of Copyright Infringement');
-
-$form->addElement('static', null, '<p>To file a copyright infringement notification with us, you will need to send a written communication that includes the following (please consult your legal counsel or see Section 512(c)(3) of the Digital Millennium Copyright Act to confirm these requirements):</p>
-<ul><li> A physical or electronic signature of a person authorized to act on behalf of the owner of an exclusive right that is allegedly infringed.
-<li>Identification of the copyrighted work claimed to have been infringed or, if multiple copyrighted works at a single online site are covered by a single notification, a representative list of such works at that site.
-<li>Identification of the material that is claimed to be infringing or to be the subject of infringing activity and that is to be removed or access to which is to be disabled, and information reasonably sufficient to permit the service provider to locate the material. Providing URLs in the body of an email is the best way to help us locate content quickly.
-<li>Information reasonably sufficient to permit the service provider to contact the complaining party, such as an address, telephone number, and, if available, an electronic mail address at which the complaining party may be contacted.
-<li>A statement that the complaining party has a good faith belief that use of the material in the manner complained of is not authorized by the copyright owner, its agent, or the law.
-<li>A statement that the information in the notification is accurate and, under penalty of perjury, that the complaining party is authorized to act on behalf of the owner of an exclusive right that is allegedly infringed.
-</ul><p>To expedite our ability to process your request, such written notice should be sent to our designated agent via our online copyright complaint form below.</p>
-<p>This form is only for cases where you believe that material on OpenStreetMap\'s websites or in its geodata database infringes your copyright or that of your clients. For example, you claim someone has copied material from a map belonging to you. If you have come here for another reason, <a href="https://wiki.osmfoundation.org/wiki/Licence_and_Legal_FAQ/Takedown_procedure/When_To_Use_The_Form">Go here</a>.</p>');
-
-$form->addElement('text', 'url',                'URL of Allegedly Infringing Material', array('size' => 50, 'maxlength' => 255));
-$form->addRule('url', 'Please enter URL of Allegedly Infringing Material', 'required', null, 'client');
-
-$form->addElement('textarea', 'work',           'Describe the work allegedly infringed. For example, which map has been copied and what specifically has been copied.',  array('rows' => 20, 'cols' => 70));
-$form->addRule('work', 'Please describe the work allegedly infringed', 'required', null, 'client');
-
-$form->addElement('text', 'territory',          'Territories where infringement occurred', array('size' => 50, 'maxlength' => 255));
-$form->addRule('territory', 'Please enter the territories where infringement occurred', 'required', null, 'client');
-
-$form->addElement('text', 'name_first',         'First Name', array('size' => 50, 'maxlength' => 255));
-$form->addRule('name_first', 'Please enter your First Name', 'required', null, 'client');
-
-$form->addElement('text', 'name_last',          'Last Name', array('size' => 50, 'maxlength' => 255));
-$form->addRule('name_last', 'Please enter your Last Name', 'required', null, 'client');
-
-
-$form->addElement('text', 'company',            'Company Name', array('size' => 50, 'maxlength' => 255));
-$form->addElement('text', 'company_tile',       'Title/Position');
-
-$form->addElement('text', 'address',            'Street Address');
-$form->addRule('address', 'Please enter Street Address', 'required', null, 'client');
-
-$form->addElement('text', 'city',               'City', array('size' => 50, 'maxlength' => 255));
-$form->addRule('city', 'Please enter City', 'required', null, 'client');
-
-$form->addElement('text', 'state',              'State/Province', array('size' => 50, 'maxlength' => 255));
-$form->addElement('text', 'postal_code',        'Zip/Postal Code', array('size' => 50, 'maxlength' => 255));
-
-$form->addElement('text', 'country',            'Country', array('size' => 50, 'maxlength' => 255));
-$form->addRule('country', 'Please enter Country', 'required', null, 'client');
-
-$form->addElement('text', 'phone_number',       'Phone Number', array('size' => 50, 'maxlength' => 255));
-$form->addRule('phone_number', 'Please enter Phone Number', 'required', null, 'client');
-
-$form->addElement('text', 'mobile_number',      'Mobile Number', array('size' => 50, 'maxlength' => 255));
-
-$form->addElement('text', 'email',              'Email Address', array('size' => 50, 'maxlength' => 255));
-$form->addRule('email', 'Please enter Email Address', 'required', null, 'client');
-$form->addRule('email', 'Please enter a valid Email Address', 'email', null, 'client');
-
-$form->addElement('text', 'fax',                'Fax', array('size' => 50, 'maxlength' => 255));
-
-$complaint_options = array();
-$complaint_options[] = &HTML_QuickForm::createElement('checkbox', '1_of_4_owner_or_authorised', null, 'I am the owner, or an agent authorized to act on behalf of the owner, of an exclusive right that is allegedly infringed.');
-$complaint_options[] = &HTML_QuickForm::createElement('checkbox', '2_of_4_good_faith', null, 'I have a good faith belief that the use of the material in the manner complained of is not authorized by the copyright owner, its agent, or the law; and');
-$complaint_options[] = &HTML_QuickForm::createElement('checkbox', '3_of_4_accurate', null, 'This notification is accurate.');
-$complaint_options[] = &HTML_QuickForm::createElement('checkbox', '4_of_4_not_misrepresent', null, 'I acknowledge that under Section 512(f) any person who knowingly materially misrepresents that material or activity is infringing may be subject to liability for damages.');
-
-$form->addGroup($complaint_options, 'complaint_confirm', 'By checking the following boxes, I state UNDER PENALTY OF PERJURY that (choose all of the options)', '<br />');
-
-$form->addElement('text', 'signature', 'Typing your full name in this box will act as your digital signature.', array('size' => 25, 'maxlength' => 255));
-$form->addRule('signature', 'Field is required', 'required', null, 'client');
-
-$form->addElement('submit', null, 'Send');
-
-$form->removeAttribute('name');
-$form->getValidationScript();
-
-if ($form->validate()) {
-    // Do some stuff
-      $form->freeze();
-      $form->process('process_data', false);
-
-} else {
-        // Output the form
-        $form->accept($renderer);
-        echo $renderer->toHtml();
-}
-?>
-</div>
-</body>
-</html>
diff --git a/cookbooks/dmca/files/default/html/robots.txt b/cookbooks/dmca/files/default/html/robots.txt
deleted file mode 100644 (file)
index 1f53798..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-User-agent: *
-Disallow: /
diff --git a/cookbooks/dmca/files/default/html/style.css b/cookbooks/dmca/files/default/html/style.css
deleted file mode 100644 (file)
index d3efdb4..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/* Forms
------------------------------------------------------------------------------*/
-
-.regForm {
-       padding: 0;
-       margin: 0;
-       max-width: 730px;
-}
-
-.regForm fieldset {
-       padding: 15px;
-       border: 1px solid #747577;
-       margin-top: 20px;
-}
-
-.regForm legend {
-       padding: 0px 10px 0px 5px;
-       font-size: 1.1em;
-       color: #000000;
-}
-
-#regFormHeader {
-       border-style: none;
-       padding: 0px;
-       margin: 10px 0px 2px 0px;
-       font-size: 1.2em;
-}
-
-#regFormSubHeader {
-       font-size: 1em;
-       padding: 0px;
-       margin: 0px 0px 2px 0px;
-       border: none;
-}
-
-.regForm fieldset .inputbox {
-       padding:0!important;
-       padding-top:0!important;
-       padding-bottom:0!important;
-}
-
-.regForm input {
-       color: #747577;
-       padding: 6px;
-       margin-bottom: 0px;
-       margin-top: 0px;
-
-       -webkit-border-radius:5px;
-       -moz-border-radius:5px;
-       border-radius: 5px;
-       border:1px solid #ccc;
-       -webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.5);
-       -moz-box-shadow: 0 2px 4px rgba(0,0,0,0.5);
-       box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       -webkit-box-sizing: border-box;
-}
-
-.regForm textarea {
-       color: #747577;
-       padding: 6px;
-       margin-bottom: 5px;
-
-       -webkit-border-radius:5px;
-       -moz-border-radius:5px;
-       border-radius: 5px;
-       border:1px solid #ccc;
-       -webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.5);
-       -moz-box-shadow: 0 2px 4px rgba(0,0,0,0.5);
-       box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       -webkit-box-sizing: border-box;
-}
-
-.regForm select {
-       color: #747577;
-       padding: 6px;
-       margin-bottom: 5px;
-
-       -webkit-border-radius:5px;
-       -moz-border-radius:5px;
-       border-radius: 5px;
-       border:1px solid #ccc;
-       -webkit-box-shadow: 0 2px 4px rgba(0,0,0,0.5);
-       -moz-box-shadow: 0 2px 4px rgba(0,0,0,0.5);
-       box-sizing: border-box;
-       -moz-box-sizing: border-box;
-       -webkit-box-sizing: border-box;
-}
-
-.regForm button {
-       padding: 0px 5px 0px 0px;
-}
-
-.regForm ol > li {
-       list-style: none;
-       background-image: none;
-       padding: 3px 0px 5px 0px;
-       border-top: 1px solid #f0f0f0;
-       color: #747577;
-}
-
-.regForm li.formList-top {
-       border-top: none;
-       font-size: .8em;
-       padding: 10px 0px;
-}
-
-.regForm li.formList {
-       font-size: .8em;
-       padding: 10px 0px;
-}
-
-.regForm li.opt {
-       border-top: 0;
-       display: none;
-}
-
-.elementItem {
-       padding: 0;
-       display: block;
-       clear: left;
-       border-style: none;
-}
-
-.elementItemGroup {
-       padding: 0;
-       margin: 0;
-       display: block;
-       border-top: 2px solid #C0C0C0;
-}
-
-li.elementItemEnd {
-       padding: 0;
-       display: block;
-       clear: left;
-       border-style: none;
-}
-
-.elementGroup {
-       padding: 0;
-}
-
-.elementGroup ul {
-       float: left;
-       margin-left: 0px;
-       margin-top: 0px;
-       padding: 0;
-}
-
-.elementGroup li {
-       margin: 0;
-       margin-left: 0px;
-       margin-top: 2px;
-       margin-right: 5px;
-       padding: 2px 2px 2px 0px;
-       border-style: none;
-       min-width: 255px;
-       list-style: none;
-}
-
-.elementGroupEnd {
-       border-style: none;
-       margin: 0;
-       padding: 0;
-       height: 1px;
-}
-
-.regForm ol {
-       margin: 0px;
-       padding: 0px;
-}
-
-.regForm p {
-       font-size: 1.2em;
-}
-
-.regForm .error {
-       color: #ff0000;
-       font-weight: bold;
-}
-
-.regForm .required {
-       color: #ff0000;
-}
-
-.regForm label.element {
-       color: #000000;
-       padding: 0px 5px 2px 0px;
-       margin: 0px;
-}
-
-.regForm div.element {
-       color: #747577;
-       padding: 1px 0px 0px 0px;
-}
-
-.regForm div.element label {
-       padding: 0px 15px 0px 4px;
-}
-
-.regForm input[type="submit"] {
-/*     border: 1px solid #f0f0f0;*/
-       color: #747577;
-       margin: 10px 0px;
-}
-
-.regForm input[type="submit"]:hover {
-       color: #CCCCCC;
-       text-decoration: none;
-}
-
-.regForm option {
-       color: #747577;
-}
-
-.regForm .reqnote {
-       font-size: 90%;
-       color: #747577;
-       font-weight: bold;
-}
-
-.regForm input[type="radio"] {
-       border: 0;
-}
-
index 6b12e982253a2d269ed003622ad9463e13f842ec..f5a137faae69943c6bd6c9209f1a1b2116968f55 100644 (file)
@@ -6,4 +6,4 @@ description       "Configure DMCA form"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "apache"
+depends           "podman"
index 652ae8cb86dc4d8db6a9295be2b71f3acb5fff7f..2b83f8d5477bc75f7cf4259f15105a6b538f2ee5 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "apache"
+include_recipe "podman::apache"
 
-apache_module "php7.2"
-
-directory "/srv/dmca.openstreetmap.org" do
-  owner "root"
-  group "root"
-  mode 0o755
-end
-
-remote_directory "/srv/dmca.openstreetmap.org/html" do
-  source "html"
-  owner "root"
-  group "root"
-  mode 0o755
-  files_owner "root"
-  files_group "root"
-  files_mode 0o644
-end
-
-ssl_certificate "dmca.openstreetmap.org" do
-  domains ["dmca.openstreetmap.org", "dmca.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "dmca.openstreetmap.org" do
-  template "apache.erb"
-  directory "/srv/dmca.openstreetmap.org"
-  variables :aliases => ["dmca.osm.org"]
+podman_site "dmca.openstreetmap.org" do
+  image "ghcr.io/openstreetmap/dmca-website:latest"
+  aliases ["dmca.osm.org"]
 end
diff --git a/cookbooks/dns/attributes/default.rb b/cookbooks/dns/attributes/default.rb
new file mode 100644 (file)
index 0000000..5bc8153
--- /dev/null
@@ -0,0 +1,3 @@
+default[:dns][:repository] = "/var/lib/git/public/dns.git"
+
+default[:accounts][:users][:git][:status] = :role
index ee177a46b81c26c660eb0eba8e17c3145c55f7be..521b387183ea9150792bdb9d9475edc9653abbe9 100644 (file)
@@ -6,5 +6,7 @@ description       "Configure DNS management"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "git"
+depends           "accounts"
 depends           "apache"
+depends           "git"
+depends           "systemd"
index 1896e99b82e99d0049e2ad6d8a2384f2111f222a..8a0f96faf0d0c98de651cf9a284b69b24b8d9d67 100644 (file)
@@ -17,8 +17,9 @@
 # limitations under the License.
 #
 
-include_recipe "git"
+include_recipe "accounts"
 include_recipe "apache"
+include_recipe "git"
 
 geoservers = search(:node, "roles:geodns").collect(&:name).sort
 
@@ -29,27 +30,53 @@ package %w[
   parallel
   rsync
   perl
+  libdigest-sha-perl
+  libjson-xs-perl
+  libwww-perl
   libxml-treebuilder-perl
   libxml-writer-perl
   libyaml-perl
-  libwww-perl
-  libjson-xs-perl
+  libyaml-libyaml-perl
+  lockfile-progs
 ]
 
+cache_dir = Chef::Config[:file_cache_path]
+
+dnscontrol_version = "4.8.1"
+
+dnscontrol_arch = if arm?
+                    "arm64"
+                  else
+                    "amd64"
+                  end
+
+remote_file "#{cache_dir}/dnscontrol-#{dnscontrol_version}.deb" do
+  source "https://github.com/StackExchange/dnscontrol/releases/download/v#{dnscontrol_version}/dnscontrol-#{dnscontrol_version}.#{dnscontrol_arch}.deb"
+  owner "root"
+  group "root"
+  mode "644"
+  backup false
+end
+
+dpkg_package "dnscontrol" do
+  source "#{cache_dir}/dnscontrol-#{dnscontrol_version}.deb"
+  version "#{dnscontrol_version}"
+end
+
 directory "/srv/dns.openstreetmap.org" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 remote_directory "/srv/dns.openstreetmap.org/html" do
   source "html"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o644
+  files_mode "644"
 end
 
 zones = []
@@ -61,7 +88,7 @@ Dir.glob("/var/lib/dns/json/*.json").each do |kmlfile|
     source "zone.html.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables :zone => zone
   end
 
@@ -72,7 +99,7 @@ template "/srv/dns.openstreetmap.org/html/index.html" do
   source "index.html.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   variables :zones => zones
 end
 
@@ -91,7 +118,7 @@ template "/usr/local/bin/dns-update" do
   source "dns-update.erb"
   owner "root"
   group "git"
-  mode 0o750
+  mode "750"
   variables :passwords => passwords, :geoservers => geoservers
 end
 
@@ -105,28 +132,59 @@ end
 directory "/var/lib/dns" do
   owner "git"
   group "git"
-  mode 0o2775
+  mode "2775"
   notifies :run, "execute[dns-update]"
 end
 
+template "/var/lib/dns/creds.json" do
+  source "creds.json.erb"
+  owner "git"
+  group "git"
+  mode "440"
+  variables :passwords => passwords
+end
+
+template "/var/lib/dns/include/geo.js" do
+  source "geo.js.erb"
+  owner "git"
+  group "git"
+  mode "440"
+  variables :geoservers => geoservers
+  only_if { ::Dir.exist?("/var/lib/dns/include") }
+end
+
 cookbook_file "#{node[:dns][:repository]}/hooks/post-receive" do
   source "post-receive"
   owner "git"
   group "git"
-  mode 0o750
+  mode "750"
+  only_if { ::Dir.exist?("#{node[:dns][:repository]}/hooks") }
 end
 
 template "/usr/local/bin/dns-check" do
   source "dns-check.erb"
   owner "root"
   group "git"
-  mode 0o750
+  mode "750"
   variables :passwords => passwords, :geoservers => geoservers
 end
 
-template "/etc/cron.d/dns" do
-  source "cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+systemd_service "dns-check" do
+  description "Rebuild DNS zones with GeoDNS changes"
+  exec_start "/usr/local/bin/dns-check"
+  user "git"
+  runtime_max_sec 90
+  sandbox :enable_network => true
+  proc_subset "all"
+  read_write_paths "/var/lib/dns"
+end
+
+systemd_timer "dns-check" do
+  description "Rebuild DNS zones with GeoDNS changes"
+  on_boot_sec "3m"
+  on_unit_active_sec "3m"
+end
+
+service "dns-check.timer" do
+  action [:enable, :start]
 end
index 0021d3e8205b763b4796f74f553884de517a328c..210f234fe5ad7b7570f643814008f5cf1ae02d34 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -26,7 +26,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent / https://<%= @name %>/
@@ -41,7 +41,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   DocumentRoot <%= @directory %>/html
diff --git a/cookbooks/dns/templates/default/creds.json.erb b/cookbooks/dns/templates/default/creds.json.erb
new file mode 100644 (file)
index 0000000..0317436
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "gandi_v5": {
+    "TYPE": "GANDI_V5",
+    "apikey": "<%= @passwords["gandi"] %>",
+    "sharing_id": "7028b616-ba65-11e7-8343-00163ec31f40"
+  },
+  "cloudflare": {
+    "TYPE": "CLOUDFLAREAPI",
+    "accountid": "049c95aba02c95fc1e78a9d255282e0f",
+    "accountname": "OpenStreetMap",
+    "apitoken": "<%= @passwords["cloudflare"] %>"
+  }
+}
index ca38dddc83f98bf565333ba182b6cc38a34cbab6..09f061b67db9c420872c7cac08093edfe1cd97f8 100755 (executable)
@@ -1,10 +1,12 @@
 #!/bin/sh
 
-export RSYNC_PASSWORD="<%= @passwords["rsync"] %>"
 export GEODNS_SERVERS="<%= @geoservers.join(" ") %>"
-export PINGDOM_USERNAME="pingdom@openstreetmap.org"
-export PINGDOM_PASSWORD="<%= @passwords["pingdom"] %>"
 export STATUSCAKE_USERNAME="OpenStreetMap"
 export STATUSCAKE_APIKEY="<%= @passwords["statuscake"] %>"
+export PATH=/usr/local/bin:$PATH
 
-make --quiet --jobs --directory=/var/lib/dns --assume-new=lib/countries.xml update > /dev/null
+lockfile-create --use-pid /var/lib/dns/update || exit 1
+
+make --quiet --jobs --directory=/var/lib/dns update_primary > /dev/null
+
+lockfile-remove /var/lib/dns/update
index 401c5c74f05bbac9e1020f334d8db6f91e4e8fa3..a16016b56887284449c23a01089ca1ddf672ca28 100755 (executable)
@@ -4,15 +4,15 @@
 
 umask 0002
 
-export RSYNC_PASSWORD="<%= @passwords["rsync"] %>"
 export GEODNS_SERVERS="<%= @geoservers.join(" ") %>"
-export PINGDOM_USERNAME="pingdom@openstreetmap.org"
-export PINGDOM_PASSWORD="<%= @passwords["pingdom"] %>"
 export STATUSCAKE_USERNAME="OpenStreetMap"
 export STATUSCAKE_APIKEY="<%= @passwords["statuscake"] %>"
+export PATH=/usr/local/bin:$PATH
 
 cd /var/lib/dns
 
+lockfile-create --use-pid update || exit 1
+
 if [ ! -d .git ]
 then
   git clone /var/lib/git/public/dns.git /var/lib/dns
@@ -20,4 +20,6 @@ fi
 
 git pull -q
 
-make --jobs update
+make --jobs check update
+
+lockfile-remove update
diff --git a/cookbooks/dns/templates/default/geo.js.erb b/cookbooks/dns/templates/default/geo.js.erb
new file mode 100644 (file)
index 0000000..ecc4d1c
--- /dev/null
@@ -0,0 +1,5 @@
+var GEO_NS_RECORDS = [
+<% @geoservers.each do |server| -%>
+  NS("geo", "<%= server %>."),
+<% end -%>
+];
index 3bf01af60011dde3fdcdb2a87720eb8552be7a0f..fb34d94bd3bdaee8504647e4d76a90f8ee610b10 100644 (file)
@@ -6,7 +6,7 @@
     <link rel="stylesheet" href="dns.css" type="text/css" media="all" />
     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="anonymous" />
     <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js" integrity="sha512-C7BBF9irt5R7hqbUm2uxtODlUVs+IsNu2UULGuZN7gM+k/mmeG4xvIEac01BtQa4YIkUpp23zZC4wIwuXaPMQA==" crossorigin="anonymous"></script>
-    <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
     <script type="text/javascript" src="dns.js"></script>
   </head>
   <body onload="createMap('map', 'json/<%= @zone %>.json')">
diff --git a/cookbooks/docker/metadata.rb b/cookbooks/docker/metadata.rb
new file mode 100644 (file)
index 0000000..0ed59aa
--- /dev/null
@@ -0,0 +1,10 @@
+name              "docker"
+maintainer        "OpenStreetMap Administrators"
+maintainer_email  "admins@openstreetmap.org"
+license           "Apache-2.0"
+description       "Installs and configures the docker daemon"
+
+version           "1.0.0"
+supports          "ubuntu"
+depends           "apt"
+depends           "systemd"
diff --git a/cookbooks/docker/recipes/default.rb b/cookbooks/docker/recipes/default.rb
new file mode 100644 (file)
index 0000000..1c8643d
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# Cookbook:: docker
+# Recipe:: default
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt::docker"
+
+package %w[
+  docker-ce
+  docker-ce-cli
+  containerd.io
+  docker-compose-plugin
+]
+
+directory "/etc/docker" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+template "/etc/docker/daemon.json" do
+  source "daemon.json.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+service "containerd" do
+  action [:enable, :start]
+  subscribes :restart, "template[/etc/docker/daemon.json]"
+end
+
+service "docker" do
+  action [:enable, :start]
+  subscribes :restart, "template[/etc/docker/daemon.json]"
+end
+
+systemd_service "docker-system-prune" do
+  description "Cleanup up unused docker images and containers"
+  after ["docker.service"]
+  wants ["docker.service"]
+  user "root"
+  exec_start "/usr/bin/docker system prune --all --force"
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+end
+
+systemd_timer "docker-system-prune" do
+  description "Cleanup up unused docker images and containers"
+  on_boot_sec "2h"
+  on_unit_active_sec "7d"
+  randomized_delay_sec "4h"
+end
+
+service "docker-system-prune.timer" do
+  action [:enable, :start]
+end
diff --git a/cookbooks/docker/templates/default/daemon.json.erb b/cookbooks/docker/templates/default/daemon.json.erb
new file mode 100644 (file)
index 0000000..c2a4bd2
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "exec-opts": ["native.cgroupdriver=systemd"],
+  "log-driver": "json-file",
+  "log-opts": {
+    "max-size": "100m"
+  },
+  "storage-driver": "overlay2",
+  "experimental": true,
+  "ipv6": true,
+  "ip6tables": true,
+  "fixed-cidr-v6": "fd9e:d0ce:beef::/48"
+}
diff --git a/cookbooks/donate/README.md b/cookbooks/donate/README.md
deleted file mode 100644 (file)
index fbe8e60..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# Donate Cookbook
-
-This cookbook installs the donate.openstreetmap.org site
diff --git a/cookbooks/donate/recipes/default.rb b/cookbooks/donate/recipes/default.rb
deleted file mode 100644 (file)
index 1b3ede3..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# Cookbook:: donate
-# Recipe:: default
-#
-# Copyright:: 2016, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-include_recipe "apache"
-include_recipe "mysql"
-include_recipe "git"
-
-package %w[
-  php
-  php-cli
-  php-curl
-  php-mysql
-  php-gd
-]
-
-apache_module "php7.2"
-
-apache_module "headers"
-
-passwords = data_bag_item("donate", "passwords")
-
-database_password = passwords["database"]
-
-mysql_user "donate@localhost" do
-  password database_password
-end
-
-mysql_database "donate" do
-  permissions "donate@localhost" => :all
-end
-
-directory "/srv/donate.openstreetmap.org" do
-  owner "donate"
-  group "donate"
-  mode 0o755
-end
-
-git "/srv/donate.openstreetmap.org" do
-  action :sync
-  repository "git://github.com/osmfoundation/donation-drive.git"
-  user "donate"
-  group "donate"
-end
-
-directory "/srv/donate.openstreetmap.org/data" do
-  owner "donate"
-  group "donate"
-  mode 0o755
-end
-
-template "/srv/donate.openstreetmap.org/scripts/db-connect.inc.php" do
-  source "db-connect.inc.php.erb"
-  owner "root"
-  group "donate"
-  mode 0o644
-  variables :passwords => passwords
-end
-
-ssl_certificate "donate.openstreetmap.org" do
-  domains ["donate.openstreetmap.org", "donate.openstreetmap.com",
-           "donate.openstreetmap.net", "donate.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "donate.openstreetmap.org" do
-  template "apache.erb"
-end
-
-template "/etc/cron.d/osmf-donate" do
-  source "cron.erb"
-  owner "root"
-  group "root"
-  mode 0o600
-  variables :passwords => passwords
-end
-
-template "/etc/cron.daily/osmf-donate-backup" do
-  source "backup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o750
-  variables :passwords => passwords
-end
diff --git a/cookbooks/donate/templates/default/apache.erb b/cookbooks/donate/templates/default/apache.erb
deleted file mode 100644 (file)
index 9404ad1..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<% [80, 443].each do |port| -%>
-<VirtualHost *:<%= port %>>
-
-  ServerName donate.openstreetmap.org
-  ServerAlias donate.openstreetmap.com
-  ServerAlias donate.openstreetmap.net
-  ServerAlias donate.osm.org
-
-  ServerAdmin webmaster@openstreetmap.org
-
-<% if port == 80 -%>
-  RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-  RedirectPermanent / https://donate.openstreetmap.org/
-<% end -%>
-<% if port == 443 -%>
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/donate.openstreetmap.org.pem
-  SSLCertificateKeyFile /etc/ssl/private/donate.openstreetmap.org.key
-<% end -%>
-
-  CustomLog /var/log/apache2/donate.openstreetmap.org-access.log combined
-  ErrorLog /var/log/apache2/donate.openstreetmap.org-error.log
-
-  Options -Indexes
-
-  DocumentRoot /srv/donate.openstreetmap.org
-
-  php_admin_value open_basedir /srv/donate.openstreetmap.org/:/usr/share/php/:/tmp/
-  php_admin_value disable_functions "exec,shell_exec,system,passthru,popen,proc_open"
-
-  # Alias Dynamic Content to data folder to avoid serving dummy git content
-  Alias /donors-eur.csv /srv/donate.openstreetmap.org/data/donors-eur.csv
-  Alias /donors.csv /srv/donate.openstreetmap.org/data/donors.csv
-
-  # Redirect previous compaigns to homepage
-  Redirect permanent /domain https://donate.openstreetmap.org/
-  Redirect permanent /memorial https://donate.openstreetmap.org/
-  Redirect permanent /server2011 https://donate.openstreetmap.org/
-  Redirect permanent /server2013 https://donate.openstreetmap.org/
-  Redirect permanent /server2015 https://donate.openstreetmap.org/
-
-  <Directory /srv/donate.openstreetmap.org>
-       Require all granted
-  </Directory>
-
-  <Directory /srv/donate.openstreetmap.org/scripts>
-    Require all denied
-  </Directory>
-
-  <Directory ~ "\.svn">
-    Require all denied
-  </Directory>
-
-  <Directory ~ "\.git">
-    Require all denied
-  </Directory>
-
-  <Files ~ "~$">
-    Require all denied
-  </Files>
-
-  # Enable deflate compression on .csv files if possible
-  <IfModule mod_deflate.c>
-    DeflateCompressionLevel 9
-    AddOutputFilterByType DEFLATE text/csv
-  </IfModule>
-
-  <IfModule mod_expires.c>
-    ExpiresDefault "access plus 15 minutes"
-    ExpiresByType text/html "access plus 5 minutes"
-    ExpiresByType text/csv "access plus 1 minute"
-  </IfModule>
-</VirtualHost>
-
-<% end -%>
diff --git a/cookbooks/donate/templates/default/backup.cron.erb b/cookbooks/donate/templates/default/backup.cron.erb
deleted file mode 100644 (file)
index 92b66cf..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-T=$(mktemp -d -t -p /var/tmp osm-donate.XXXXXXXXXX)
-D=$(date +%Y-%m-%d)
-B=osm-donate-$D.tar.gz
-
-mkdir $T/osm-donate-$D
-echo '[mysqldump]' > $T/mysqldump.opts
-echo 'user=donate' >> $T/mysqldump.opts
-echo 'password=<%= @passwords["database"] %>' >> $T/mysqldump.opts
-mysqldump --defaults-file=$T/mysqldump.opts --opt donate > $T/osm-donate-$D/osm-donate.sql
-ln -s /srv/donate.openstreetmap.org $T/osm-donate-$D/www
-
-export GZIP="--rsyncable -9"
-export RSYNC_RSH="ssh -ax"
-
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B osm-donate-$D
-nice rsync --preallocate --fuzzy $T/$B backup::backup
-
-rm -rf $T
diff --git a/cookbooks/donate/templates/default/cron.erb b/cookbooks/donate/templates/default/cron.erb
deleted file mode 100644 (file)
index 42d6c77..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-*/2 * * * * donate cd /srv/donate.openstreetmap.org/scripts/; /usr/bin/php /srv/donate.openstreetmap.org/scripts/update_csv_donate2016.php
diff --git a/cookbooks/donate/templates/default/db-connect.inc.php.erb b/cookbooks/donate/templates/default/db-connect.inc.php.erb
deleted file mode 100644 (file)
index c4cea1f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-$_DB_H = new mysqli('localhost','donate','<%= @passwords['database'] %>','donate');
-if ($_DB_H->connect_errno) {
-    die('DB Connect Error: ' . $_DB_H->connect_errno);
-}
-$_DB_H->report_mode = MYSQLI_REPORT_ERROR;
-$_DB_H->query('set @@sql_mode = \'\'');
-$_DB_H->query('SET NAMES \'utf8\'');
index a2a643412d568305b6c98022938f9e93653e6c7d..52f6b95990150821ebc0d5680225e4de0c7b2af2 100644 (file)
@@ -1,7 +1,6 @@
-default[:elasticsearch][:version] = "1.7"
+default[:elasticsearch][:version] = "6.x"
+default[:elasticsearch][:cluster][:name] = "default"
 default[:elasticsearch][:cluster][:routing][:allocation][:disk][:watermark][:low] = "85%"
 default[:elasticsearch][:cluster][:routing][:allocation][:disk][:watermark][:high] = "90%"
 default[:elasticsearch][:cluster][:routing][:allocation][:disk][:watermark][:flood_stage] = "95%"
 default[:elasticsearch][:path][:data] = "/var/lib/elasticsearch"
-
-default[:apt][:sources] |= ["elasticsearch#{node[:elasticsearch][:version]}"]
index 9bab57ae284c0241541563328cce4a559905dc16..e1301a39b5d9f23a107cb9a8729f9472314335c5 100644 (file)
@@ -6,3 +6,5 @@ description       "Installs and configures a elasticsearch server"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "apt"
+depends           "prometheus"
index d2ba1d31b6a1fb5f1527cca3c44f25f3ec85c66b..a48ee99879c4dd049afa5eab2eebcdb3e57ce265 100644 (file)
 # limitations under the License.
 #
 
-package %w[
-  default-jre-headless
-  elasticsearch
-]
+include_recipe "prometheus"
+
+case node[:elasticsearch][:version]
+when "6.x" then include_recipe "apt::elasticsearch6"
+when "7.x" then include_recipe "apt::elasticsearch7"
+when "8.x" then include_recipe "apt::elasticsearch8"
+end
+
+package "default-jre-headless"
+package "elasticsearch"
 
 template "/etc/elasticsearch/elasticsearch.yml" do
   source "elasticsearch.yml.erb"
   user "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :restart, "service[elasticsearch]"
 end
 
@@ -34,3 +40,7 @@ service "elasticsearch" do
   action [:enable, :start]
   supports :status => true, :restart => true
 end
+
+prometheus_exporter "elasticsearch" do
+  port 9114
+end
index 77b8d87166fceea30b8efa16f70d4f6bdf782350..638ce5765b1c10ac1c5ab3285eed85ef4db91412 100644 (file)
@@ -3,6 +3,8 @@ default[:exim][:relay_to_domains] = []
 default[:exim][:relay_from_hosts] = ["127.0.0.1", "::1"]
 default[:exim][:daemon_smtp_ports] = [25]
 default[:exim][:trusted_users] = []
+default[:exim][:queue_run_max] = 1
+default[:exim][:smtp_accept_max] = 20
 default[:exim][:smarthost_name] = nil
 default[:exim][:smarthost_via] = "mail.openstreetmap.org:26"
 default[:exim][:routes] = {}
similarity index 52%
rename from cookbooks/exim/files/default/noreply/forum
rename to cookbooks/exim/files/default/noreply/community
index c2f80aac6fd09e41c8e522933c181ea729d62861..8633e7913e2c025069d2e97c04ac612028b35a46 100644 (file)
@@ -1,8 +1,8 @@
 This is an automated response to your email, which was sent to an
 unattended address.
 
-If you are having technical problems with the forums then please
-contact support@openstreetmap.org for assistance.
+You can not reply to this email, please use the
+community.openstreetmap.org web site instead.
 
 Thank you,
 
index 169d2f6b684fd8140c4a38b0de8af92c97917c80..3ad49cf0af8636431ede0cff63d28c8ba25a29de 100644 (file)
@@ -2,13 +2,13 @@ This is an automated response to your email, which was sent to an
 unattended address.
 
 If you were trying to confirm your email address after signing
-up for an account, or after changing your email address, then you 
+up for an account, or after changing your email address, then you
 should click on the link in the original email you received.
 
 If you need help using OpenStreetMap then you should try our
-question and answer site:
+community site:
 
-  https://help.openstreetmap.org/
+  https://community.openstreetmap.org/
 
 If you are having technical problems with the web site then please
 contact support@openstreetmap.org for assistance.
index 754ee82ded64e89f82675b5125278125a0150852..89611b11a248bb3300436ee097285b12114de86a 100644 (file)
@@ -6,6 +6,8 @@ description       "Installs and configures exim"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
+depends           "apache"
 depends           "networking"
+depends           "prometheus"
 depends           "ssl"
-depends           "apache"
index 94133183a5ee06760e2632e278e5cbcc419118db..7354e93d363d2daf763cfc096213db53f7e3e6a1 100644 (file)
 #
 
 include_recipe "networking"
+include_recipe "prometheus"
 
 package %w[
   exim4
   openssl
   ssl-cert
+  mailutils
 ]
 
-package "exim4-daemon-heavy" if File.exist?("/var/run/clamav/clamd.ctl")
+package "exim4-daemon-heavy" do
+  only_if { ::File.exist?("/var/run/clamav/clamd.ctl") }
+end
+
+group "Debian-exim" do
+  action :modify
+  members "clamav"
+  append true
+  only_if { ::File.exist?("/var/run/clamav/clamd.ctl") }
+end
 
 group "ssl-cert" do
   action :modify
@@ -50,7 +61,7 @@ else
     key_file "/etc/ssl/private/exim.key"
     owner "root"
     group "ssl-cert"
-    mode 0o640
+    mode "640"
     org "OpenStreetMap"
     email "postmaster@openstreetmap.org"
     common_name node[:fqdn]
@@ -73,22 +84,106 @@ end
 relay_from_hosts = node[:exim][:relay_from_hosts]
 
 if node[:exim][:smarthost_name]
-  search(:node, "exim_smarthost_via:#{node[:exim][:smarthost_name]}\\:*").each do |host|
+  search(:node, "exim_smarthost_via:*?").each do |host|
     relay_from_hosts |= host.ipaddresses(:role => :external)
   end
+
+  domains = node[:exim][:certificate_names].select { |c| c =~ /^a\.mx\./ }.collect { |c| c.sub(/^a\.mx./, "") }
+  primary_domain = domains.first
+
+  directory "/srv/mta-sts.#{primary_domain}" do
+    owner "root"
+    group "root"
+    mode "755"
+  end
+
+  domains.each do |domain|
+    template "/srv/mta-sts.#{primary_domain}/#{domain}.txt" do
+      source "mta-sts.erb"
+      owner "root"
+      group "root"
+      mode "644"
+      variables :domain => domain
+    end
+  end
+
+  ssl_certificate "mta-sts.#{primary_domain}" do
+    domains domains.collect { |d| "mta-sts.#{d}" }
+    notifies :reload, "service[apache2]"
+  end
+
+  apache_site "mta-sts.#{primary_domain}" do
+    template "apache-mta-sts.erb"
+    directory "/srv/mta-sts.#{primary_domain}"
+    variables :domains => domains
+  end
 end
 
 file "/etc/exim4/blocked-senders" do
   owner "root"
   group "Debian-exim"
-  mode 0o644
+  mode "644"
+end
+
+file "/etc/exim4/blocked-sender-domains" do
+  owner "root"
+  group "Debian-exim"
+  mode "644"
+end
+
+file "/etc/exim4/detaint" do
+  owner "root"
+  group "Debian-exim"
+  mode "644"
+  content "*"
+end
+
+if node[:exim][:dkim_selectors]
+  keys = data_bag_item("exim", "dkim")
+
+  template "/etc/exim4/dkim-domains" do
+    owner "root"
+    source "dkim-domains.erb"
+    group "Debian-exim"
+    mode "644"
+  end
+
+  template "/etc/exim4/dkim-selectors" do
+    owner "root"
+    source "dkim-selectors.erb"
+    group "Debian-exim"
+    mode "644"
+  end
+
+  directory "/etc/exim4/dkim-keys" do
+    owner "root"
+    group "Debian-exim"
+    mode "755"
+  end
+
+  node[:exim][:dkim_selectors].each do |domain, _selector|
+    file "/etc/exim4/dkim-keys/#{domain}" do
+      content keys[domain].join("\n")
+      owner "root"
+      group "Debian-exim"
+      mode "640"
+    end
+  end
+end
+
+template "/etc/default/exim4" do
+  source "default.erb"
+  owner "root"
+  group "root"
+  mode "044"
+  notifies :restart, "service[exim4]"
 end
 
 template "/etc/exim4/exim4.conf" do
   source "exim4.conf.erb"
   owner "root"
   group "Debian-exim"
-  mode 0o644
+  mode "644"
   variables :relay_to_domains => relay_to_domains.sort,
             :relay_from_hosts => relay_from_hosts.sort
   notifies :restart, "service[exim4]"
@@ -115,53 +210,64 @@ template "/etc/aliases" do
   source "aliases.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 remote_directory "/etc/exim4/noreply" do
   source "noreply"
   owner "root"
   group "Debian-exim"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "Debian-exim"
-  files_mode 0o755
+  files_mode "755"
   purge true
 end
 
-munin_plugin "exim_mailqueue"
-munin_plugin "exim_mailstats"
+template "/etc/mail.rc" do
+  source "mail.rc.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+prometheus_exporter "exim" do
+  port 9636
+  user "Debian-exim"
+  protect_proc "default"
+end
 
 if node[:exim][:smarthost_name]
-  node[:exim][:daemon_smtp_ports].each do |port|
-    firewall_rule "accept-inbound-smtp-#{port}" do
-      action :accept
-      source "net"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports port
-      source_ports "1024:"
-    end
+  firewall_rule "accept-inbound-smtp" do
+    action :accept
+    context :incoming
+    protocol :tcp
+    dest_ports node[:exim][:daemon_smtp_ports]
+    source_ports "1024-65535"
   end
 else
-  node[:exim][:daemon_smtp_ports].each do |port|
-    firewall_rule "accept-inbound-smtp-#{port}" do
-      action :accept
-      source "bm:mail.openstreetmap.org"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports port
-      source_ports "1024:"
-    end
+  smarthosts = []
+
+  search(:node, "exim_smarthost_name:*?").each do |host|
+    smarthosts |= host.ipaddresses(:role => :external)
+  end
+
+  firewall_rule "accept-inbound-smtp" do
+    action :accept
+    context :incoming
+    protocol :tcp
+    source smarthosts
+    dest_ports node[:exim][:daemon_smtp_ports]
+    source_ports "1024-65535"
+    not_if { smarthosts.empty? }
   end
 end
 
 if node[:exim][:smarthost_via]
   firewall_rule "deny-outbound-smtp" do
     action :reject
-    source "fw"
-    dest "net"
-    proto "tcp:syn"
+    context :outgoing
+    protocol :tcp
     dest_ports "smtp"
   end
 end
diff --git a/cookbooks/exim/templates/default/apache-mta-sts.erb b/cookbooks/exim/templates/default/apache-mta-sts.erb
new file mode 100644 (file)
index 0000000..da7ccdd
--- /dev/null
@@ -0,0 +1,34 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<VirtualHost *:80>
+  ServerName <%= @name %>
+<% @domains.drop(1).each do |domain| -%>
+  ServerAlias mta-sts.<%= domain %>
+<% end -%>
+  ServerAdmin webmaster@openstreetmap.org
+
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
+  RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
+</VirtualHost>
+<% @domains.each do |domain| -%>
+
+<VirtualHost *:443>
+  ServerName mta-sts.<%= domain %>
+  ServerAdmin webmaster@openstreetmap.org
+
+  SSLEngine on
+  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
+  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
+
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
+  Alias /.well-known/mta-sts.txt <%= @directory %>/<%= domain %>.txt
+</VirtualHost>
+<% end -%>
+
+<Directory <%= @directory %>>
+  Require all granted
+</Directory>
index f7a5c8ada7a72a4b4063ade86d5edc72538d02bf..505a63a4d3cbad6a3ffd9acf5fb4dddde216d087 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -26,7 +26,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent / https://<%= @name %>/
@@ -41,6 +41,6 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 </VirtualHost>
diff --git a/cookbooks/exim/templates/default/default.erb b/cookbooks/exim/templates/default/default.erb
new file mode 100644 (file)
index 0000000..569e367
--- /dev/null
@@ -0,0 +1,30 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<% if node.platform?("ubuntu") && node[:lsb][:release].to_f >= 22.04 -%>
+# options for update-exim4.conf
+UPEX4OPTS=''
+# options for exim4
+EXIMSERVICE='-bdf -q30s'
+<% else -%>
+# 'combined' -   one daemon running queue and listening on SMTP port
+# 'no'       -   no daemon running the queue
+# 'separate' -   two separate daemons
+# 'ppp'      -   only run queue with /etc/ppp/ip-up.d/exim4.
+# 'nodaemon' - no daemon is started at all.
+# 'queueonly' - only a queue running daemon is started, no SMTP listener.
+# setting this to 'no' will also disable queueruns from /etc/ppp/ip-up.d/exim4
+QUEUERUNNER='combined'
+# how often should we run the queue
+QUEUEINTERVAL='30s'
+# options common to quez-runner and listening daemon
+COMMONOPTIONS=''
+# more options for the daemon/process running the queue (applies to the one
+# started in /etc/ppp/ip-up.d/exim4, too.
+QUEUERUNNEROPTIONS=''
+# special flags given to exim directly after the -q. See exim(8)
+QFLAGS=''
+# options for daemon listening on port 25
+SMTPLISTENEROPTIONS=''
+<% end -%>
+# only warn once about each error
+E4BCD_WATCH_PANICLOG='no'
diff --git a/cookbooks/exim/templates/default/dkim-domains.erb b/cookbooks/exim/templates/default/dkim-domains.erb
new file mode 100644 (file)
index 0000000..992ac39
--- /dev/null
@@ -0,0 +1,3 @@
+<% node[:exim][:dkim_selectors].each do |domain, _selector| -%>
+*.<%= domain %>: <%= domain %>
+<% end -%>
diff --git a/cookbooks/exim/templates/default/dkim-selectors.erb b/cookbooks/exim/templates/default/dkim-selectors.erb
new file mode 100644 (file)
index 0000000..13078fa
--- /dev/null
@@ -0,0 +1,3 @@
+<% node[:exim][:dkim_selectors].each do |domain, selector| -%>
+<%= domain %>: <%= selector %>
+<% end -%>
index 0a4f1d04f249c3b4bde08863dddac8ffb701f80a..ffc8be609f4d9f2f360cd37dd9015a063db908ee 100644 (file)
@@ -42,6 +42,7 @@
 ######################################################################
 #                    MAIN CONFIGURATION SETTINGS                     #
 ######################################################################
+#
 
 # Specify your host's canonical name here. This should normally be the fully
 # qualified "official" name of your host. If this option is not set, the
@@ -93,18 +94,20 @@ hostlist   relay_from_hosts = <; <%= @relay_from_hosts.join(" ; ") %>
 # to any other host on the Internet. Such a setting commonly refers to a
 # complete local network as well as the localhost. For example:
 #
-# hostlist relay_from_hosts = 127.0.0.1 : 192.168.0.0/16
+# hostlist relay_from_hosts = <; 127.0.0.1 ; ::1 ; 192.168.0.0/16
 #
 # The "/16" is a bit mask (CIDR notation), not a number of hosts. Note that you
 # have to include 127.0.0.1 if you want to allow processes on your host to send
 # SMTP mail by using the loopback address. A number of MUAs use this method of
-# sending mail.
+# sending mail.  Often, connections are made to "localhost", which might be ::1
+# on IPv6-enabled hosts.  Do not forget CIDR for your IPv6 networks.
 
 # All three of these lists may contain many different kinds of item, including
 # wildcarded names, regular expressions, and file lookups. See the reference
 # manual for details. The lists above are used in the access control lists for
 # checking incoming messages. The names of these ACLs are defined here:
 
+acl_smtp_mail = acl_check_mail
 acl_smtp_rcpt = acl_check_rcpt
 acl_smtp_data = acl_check_data
 
@@ -144,11 +147,7 @@ spamd_address = 127.0.0.1 783
 
 # Allow any client to use TLS.
 
-tls_advertise_hosts = <; !127.0.0.1 ; !::1
-
-# Configured TLS cipher selection.
-
-tls_require_ciphers = <%= node[:ssl][:gnutls_ciphers] %>:%SERVER_PRECEDENCE
+tls_advertise_hosts = *
 
 # Specify the location of the Exim server's TLS certificate and private key.
 # The private key must not be encrypted (password protected). You can put
@@ -164,6 +163,10 @@ tls_certificate = /etc/ssl/certs/exim.pem
 tls_privatekey = /etc/ssl/private/exim.key
 <% end -%>
 
+# Configure TLS cipher selection.
+
+tls_require_ciphers = <%= node[:ssl][:gnutls_ciphers] %>:%SERVER_PRECEDENCE
+
 # In order to support roaming users who wish to send email from anywhere,
 # you may want to make Exim listen on other ports as well as port 25, in
 # case these users need to send email from a network that blocks port 25.
@@ -233,18 +236,26 @@ never_users = root
 host_lookup = *
 
 
-# The settings below, which are actually the same as the defaults in the
-# code, cause Exim to make RFC 1413 (ident) callbacks for all incoming SMTP
-# calls. You can limit the hosts to which these calls are made, and/or change
-# the timeout that is used. If you set the timeout to zero, all RFC 1413 calls
-# are disabled. RFC 1413 calls are cheap and can provide useful information
-# for tracing problem messages, but some hosts and firewalls have problems
-# with them. This can result in a timeout instead of an immediate refused
-# connection, leading to delays on starting up SMTP sessions. (The default was
-# reduced from 30s to 5s for release 4.61.)
+# The settings below cause Exim to make RFC 1413 (ident) callbacks
+# for all incoming SMTP calls. You can limit the hosts to which these
+# calls are made, and/or change the timeout that is used. If you set
+# the timeout to zero, all RFC 1413 calls are disabled. RFC 1413 calls
+# are cheap and can provide useful information for tracing problem
+# messages, but some hosts and firewalls have problems with them.
+# This can result in a timeout instead of an immediate refused
+# connection, leading to delays on starting up SMTP sessions.
+# (The default was reduced from 30s to 5s for release 4.61. and to
+# disabled for release 4.86)
+#
+#rfc1413_hosts = *
+#rfc1413_query_timeout = 5s
 
-rfc1413_hosts = *
-rfc1413_query_timeout = 5s
+
+# Enable an efficiency feature.  We advertise the feature; clients
+# may request to use it.  For multi-recipient mails we then can
+# reject or accept per-user after the message is received.
+#
+prdr_enable = true
 
 
 # By default, Exim expects all envelope addresses to be fully qualified, that
@@ -260,6 +271,12 @@ rfc1413_query_timeout = 5s
 # and/or qualify_recipient (see above).
 
 
+# Unless you run a high-volume site you probably want more logging
+# detail than the default.  Adjust to suit.
+
+log_selector = +all -skip_delivery
+
+
 # If you want Exim to support the "percent hack" for certain domains,
 # uncomment the following line and provide a list of domains. The "percent
 # hack" is the feature by which mail addressed to x%y@z (where z is one of
@@ -304,10 +321,37 @@ timeout_frozen_after = 7d
 # split_spool_directory = true
 
 
-# Log just about everything we can log so that we have the best
-# possible chance of knowing what's going on.
+# If you're in a part of the world where ASCII is not sufficient for most
+# text, then you're probably familiar with RFC2047 message header extensions.
+# By default, Exim adheres to the specification, including a limit of 76
+# characters to a line, with encoded words fitting within a line.
+# If you wish to use decoded headers in message filters in such a way
+# that successful decoding of malformed messages matters, you may wish to
+# configure Exim to be more lenient.
+#
+# check_rfc2047_length = false
+#
+# In particular, the Exim maintainers have had multiple reports of problems
+# from Russian administrators of issues until they disable this check,
+# because of some popular, yet buggy, mail composition software.
 
-log_selector = +all -skip_delivery
+
+# If you wish to be strictly RFC compliant, or if you know you'll be
+# exchanging email with systems that are not 8-bit clean, then you may
+# wish to disable advertising 8BITMIME.  Uncomment this option to do so.
+
+# accept_8bitmime = false
+
+
+# Exim does not make use of environment variables itself. However,
+# libraries that Exim uses (e.g. LDAP) depend on specific environment settings.
+# There are two lists: keep_environment for the variables we trust, and
+# add_environment for variables we want to set to a specific value.
+# Note that TZ is handled separately by the timezone runtime option
+# and TIMEZONE_DEFAULT buildtime option.
+
+# keep_environment = ^LDAP
+# add_environment = PATH=/usr/bin::/bin
 
 
 # Define trusted users.
@@ -315,10 +359,15 @@ log_selector = +all -skip_delivery
 trusted_users = <%= node[:exim][:trusted_users].join(" : ") %>
 
 
-# Don't keep any environment when starting programs - this is the
-# default but setting it stops exim warning
+# Do all deliveries via a limited set of queues.
 
-keep_environment =
+queue_only = true
+queue_run_max = <%= node[:exim][:queue_run_max] %>
+
+
+# Maximum number of simultaneous SMTP connections
+
+smtp_accept_max = <%= node[:exim][:smtp_accept_max] %>
 
 
 
@@ -329,6 +378,13 @@ keep_environment =
 
 begin acl
 
+# This access control list is used for the MAIL command in an incoming
+# SMTP message.
+
+acl_check_mail:
+
+  accept
+
 # This access control list is used for every RCPT command in an incoming
 # SMTP message. The tests are run in order until the address is either
 # accepted or denied.
@@ -384,7 +440,7 @@ acl_check_rcpt:
 
   deny    message       = Restricted characters in address
           domains       = !+local_domains
-          local_parts   = ^[./|] : ^.*[@!] : ^.*/\\.\\./
+          local_parts   = ^[./|] : ^.*[@%!] : ^.*/\\.\\./
   #############################################################################
 
   # Block bounces to selected addresses
@@ -398,6 +454,10 @@ acl_check_rcpt:
           message       = Rejected because $sender_address is blacklisted\nQueries to postmaster@$qualify_domain
           !hosts        = +relay_from_hosts
 
+  deny    sender_domains= partial-lsearch;/etc/exim4/blocked-sender-domains
+          message       = Rejected because $sender_address is blacklisted\nQueries to postmaster@$qualify_domain
+          !hosts        = +relay_from_hosts
+
   # Accept mail to postmaster in any local domain, regardless of the source,
   # and without verifying the sender.
 
@@ -454,7 +514,11 @@ acl_check_rcpt:
   # relay domains is to use a callout (add /callout), but please read the
   # documentation about callouts before doing this.
 
-  require verify = recipient
+  deny    domains = +relay_to_domains
+         !verify  = recipient/callout=use_sender
+
+  deny    domains = !+relay_to_domains
+         !verify  = recipient
 
 <% if node[:exim][:dns_blacklists] -%>
   # Deny any messages from hosts in certain blacklists.
@@ -513,9 +577,13 @@ acl_check_data:
          !hosts      = +relay_from_hosts
           message    = This message failed local spam checks.
 
-  # Accept the message.
+  # Accept messages from relay hosts without modification.
 
-  accept
+  accept  hosts      = +relay_from_hosts
+
+  # Accept messages from external hosts and add authentication results.
+
+  accept  add_header = :at_start:${authresults {$primary_hostname}}
 
 
 
@@ -610,6 +678,9 @@ noreply:
 <% else -%>
   transport = <%= name %>
 <% end -%>
+<% if details[:case_sensitive] -%>
+  caseful_local_part
+<% end -%>
 
 <% end -%>
 
@@ -641,7 +712,7 @@ smarthost:
 dnslookup:
   driver = dnslookup
   domains = ! +local_domains
-  transport = remote_smtp
+  transport = signed_smtp
   same_domain_copy_routing = yes
   ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
   no_more
@@ -669,6 +740,21 @@ remote_smtp:
   tls_require_ciphers = <%= node[:ssl][:gnutls_ciphers] %>:%LATEST_RECORD_VERSION
 
 
+# This transport is used for delivering DKIM signed messages over SMTP connections.
+
+signed_smtp:
+  driver = smtp
+  connect_timeout = 1m
+  dkim_domain = ${lookup{${domain:$h_from:}}partial-lsearch{/etc/exim4/dkim-domains}{$value}}
+  dkim_selector = ${lookup{$dkim_domain}lsearch{/etc/exim4/dkim-selectors}{$value}}
+  dkim_private_key = /etc/exim4/dkim-keys/${dkim_domain}
+  dkim_identity = ${lc:${address:$h_from:}}
+  dkim_timestamps = 1209600
+  multi_domain = false
+  hosts_try_dane =
+  tls_require_ciphers = <%= node[:ssl][:gnutls_ciphers] %>:%LATEST_RECORD_VERSION
+
+
 # This transport is used for handling pipe deliveries generated by alias or
 # .forward files. If the pipe generates any standard output, it is returned
 # to the sender of the message as a delivery error. Set return_fail_output
@@ -718,7 +804,7 @@ noreply:
   to = $sender_address
   subject = Re: $header_subject:
   headers = MIME-Version: 1.0\nContent-Type: text/plain; charset=utf-8
-  file = /etc/exim4/noreply/$local_part
+  file = ${lookup{$local_part}dsearch,filter=file,ret=full{/etc/exim4/noreply}}
   user = Debian-exim
   group = Debian-exim
 
similarity index 63%
rename from cookbooks/munin/templates/default/diskstats.erb
rename to cookbooks/exim/templates/default/mail.rc.erb
index aa9f65e2db79597dfa0c5813f5b7b1bab6866126..253cebb10219cd57242690a953ec92da48fea65a 100644 (file)
@@ -1,4 +1,3 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-[diskstats]
-env.exclude fd0
+set sendmail="smtp://localhost"
diff --git a/cookbooks/exim/templates/default/mta-sts.erb b/cookbooks/exim/templates/default/mta-sts.erb
new file mode 100644 (file)
index 0000000..bd237b1
--- /dev/null
@@ -0,0 +1,4 @@
+version: STSv1
+mode: enforce
+mx: *.mx.<%= @domain %>
+max_age: 31536000
index 6ff596b4369fc4223311194a84f0cea4a4dc3042..8a1dfe995913542e4fbf03f5e7d64c862f34ea89 100644 (file)
@@ -6,3 +6,4 @@ description       "Configures fail2ban"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "prometheus"
index a002fe13196fc2ff4debb663dd25392a4f30a57a..216572989067f79898af72f859da3b28462a1284 100644 (file)
 # limitations under the License.
 #
 
-package "fail2ban"
+include_recipe "prometheus"
+
+package %w[
+  fail2ban
+  python3-systemd
+  ruby-webrick
+]
+
+if platform?("debian")
+  package "python3-inotify"
+else
+  package "gamin"
+end
 
 template "/etc/fail2ban/jail.d/00-default.conf" do
   source "jail.default.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
+  notifies :restart, "service[fail2ban]"
+end
+
+template "/etc/fail2ban/paths-overrides.local" do
+  source "paths-overrides.local.erb"
+  owner "root"
+  group "root"
+  mode "644"
   notifies :restart, "service[fail2ban]"
 end
 
@@ -31,4 +51,8 @@ service "fail2ban" do
   action [:enable, :start]
 end
 
-munin_plugin "fail2ban"
+prometheus_exporter "fail2ban" do
+  port 9635
+  user "root"
+  restrict_address_families "AF_UNIX"
+end
index d37ba4bb2e83a64a5035df4438493b3e17202948..13a7782950875e3929df01f5fc5027ffc22392d7 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :filter, :kind_of => String, :name_attribute => true
+property :filter, :kind_of => String, :name_property => true
 property :source, :kind_of => String
 property :failregex, :kind_of => [String, Array]
 property :ignoreregex, :kind_of => [String, Array]
@@ -30,7 +32,7 @@ action :create do
       source new_resource.source
       owner "root"
       group "root"
-      mode 0o644
+      mode "644"
     end
   else
     template "/etc/fail2ban/filter.d/#{new_resource.filter}.conf" do
@@ -38,7 +40,7 @@ action :create do
       source "filter.erb"
       owner "root"
       group "root"
-      mode 0o644
+      mode "644"
       variables :failregex => new_resource.failregex,
                 :ignoreregex => new_resource.ignoreregex
     end
index c07914d2cd4280bbaec8e824941b144c1f441b67..e5801c065bbd8d3acfa1644460133b9d310da19f 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :jail, :kind_of => String, :name_attribute => true
+property :jail, :kind_of => String, :name_property => true
 property :filter, :kind_of => String
+property :backend, :kind_of => String
+property :journalmatch, :kind_of => String
 property :logpath, :kind_of => String
 property :protocol, :kind_of => String
 property :ports, :kind_of => Array, :default => []
+property :bantime, :kind_of => [Integer, String]
+property :findtime, :kind_of => [Integer, String]
 property :maxretry, :kind_of => Integer
 property :ignoreips, :kind_of => Array
 
@@ -33,12 +39,16 @@ action :create do
     source "jail.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables :name => new_resource.jail,
               :filter => new_resource.filter,
+              :backend => new_resource.backend,
+              :journalmatch => new_resource.journalmatch,
               :logpath => new_resource.logpath,
               :protocol => new_resource.protocol,
               :ports => new_resource.ports,
+              :bantime => new_resource.bantime,
+              :findtime => new_resource.findtime,
               :maxretry => new_resource.maxretry,
               :ignoreips => new_resource.ignoreips
   end
index fc0f8bdc8befe9ab92434d1d131adb2d3e48ae10..de2d167663f174e4082b02b1f53da8a16b55b3e7 100644 (file)
@@ -2,5 +2,6 @@
 
 [DEFAULT]
 destemail = admins@openstreetmap.org
-banaction = shorewall
+banaction = nftables[type=multiport]
+banaction_allports = nftables[type=allports]
 bantime = 14400
index 91978488c5569caaed9f077b6ced382f2ab343ea..357e09ea50da55c694600658ecabf909ee6e3704 100644 (file)
@@ -11,9 +11,21 @@ port = <%= @ports.join(",") %>
 <% if @filter -%>
 filter = <%= @filter %>
 <% end -%>
+<% if @backend -%>
+backend = <%= @backend %>
+<% end -%>
+<% if @journalmatch -%>
+journalmatch = <%= @journalmatch %>
+<% end -%>
 <% if @logpath -%>
 logpath = <%= @logpath %>
 <% end -%>
+<% if @bantime -%>
+bantime = <%= @bantime %>
+<% end -%>
+<% if @findtime -%>
+findtime = <%= @findtime %>
+<% end -%>
 <% if @maxretry -%>
 maxretry = <%= @maxretry %>
 <% end -%>
similarity index 62%
rename from cookbooks/munin/templates/default/df.erb
rename to cookbooks/fail2ban/templates/default/paths-overrides.local.erb
index 6db42e638b4f3ce4e206dfb654e773258cdf51b5..7fbd19a79242ca205e942a37cb2b6e1b5c09abf4 100644 (file)
@@ -1,4 +1,4 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-[df*]
-env.exclude_re ^/run/user/
+[DEFAULT]
+sshd_backend = systemd
diff --git a/cookbooks/forum/README.md b/cookbooks/forum/README.md
deleted file mode 100644 (file)
index 062e3f6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# Forum Cookbook
-
-This cookbook installs and configures the fluxbb forums software used at
-https://forum.openstreetmap.org
diff --git a/cookbooks/forum/recipes/default.rb b/cookbooks/forum/recipes/default.rb
deleted file mode 100644 (file)
index e75e5a3..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-#
-# Cookbook:: forum
-# Recipe:: default
-#
-# Copyright:: 2014, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-include_recipe "apache"
-include_recipe "git"
-include_recipe "mysql"
-
-passwords = data_bag_item("forum", "passwords")
-
-package %w[
-  php
-  php-cli
-  php-mysql
-  php-xml
-  php-apcu
-]
-
-apache_module "php7.2"
-apache_module "rewrite"
-
-ssl_certificate "forum.openstreetmap.org" do
-  domains ["forum.openstreetmap.org", "forum.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "forum.openstreetmap.org" do
-  template "apache.erb"
-end
-
-directory "/srv/forum.openstreetmap.org" do
-  owner "forum"
-  group "forum"
-  mode 0o755
-end
-
-git "/srv/forum.openstreetmap.org/html/" do
-  action :sync
-  repository "http://github.com/openstreetmap/openstreetmap-forum.git"
-  revision "openstreetmap-1.5.10"
-  depth 1
-  user "forum"
-  group "forum"
-  notifies :reload, "service[apache2]"
-end
-
-remote_file "/var/cache/chef/air3_v0.8.zip" do
-  action :create_if_missing
-  source "https://fluxbb.org/resources/styles/air3/releases/0.8/air3_v0.8.zip"
-  owner "root"
-  group "root"
-  mode 0o644
-  backup false
-end
-
-execute "/var/cache/chef/air3_v0.8.zip" do
-  action :nothing
-  command "unzip -o -qq /var/cache/chef/air3_v0.8.zip Air3.css Air3/*"
-  cwd "/srv/forum.openstreetmap.org/html/style"
-  user "forum"
-  group "forum"
-  subscribes :run, "remote_file[/var/cache/chef/air3_v0.8.zip]", :immediately
-end
-
-directory "/srv/forum.openstreetmap.org/html/cache/" do
-  owner "www-data"
-  group "www-data"
-  mode 0o755
-end
-
-directory "/srv/forum.openstreetmap.org/html/img/avatars/" do
-  owner "www-data"
-  group "www-data"
-  mode 0o755
-end
-
-template "/srv/forum.openstreetmap.org/html/config.php" do
-  source "config.php.erb"
-  owner "forum"
-  group "www-data"
-  mode 0o440
-  variables :passwords => passwords
-end
-
-mysql_user "forum@localhost" do
-  password passwords["database"]
-end
-
-mysql_database "forum" do
-  permissions "forum@localhost" => :all
-end
-
-template "/etc/cron.daily/forum-backup" do
-  source "backup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o750
-  variables :passwords => passwords
-end
diff --git a/cookbooks/forum/templates/default/apache.erb b/cookbooks/forum/templates/default/apache.erb
deleted file mode 100644 (file)
index e84f1e3..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:80>
-       ServerName forum.openstreetmap.org
-       ServerAlias forum.osm.org
-       ServerAdmin webmaster@openstreetmap.org
-
-       CustomLog /var/log/apache2/forum.openstreetmap.org-access.log combined
-       ErrorLog /var/log/apache2/forum.openstreetmap.org-error.log
-
-       RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-       RedirectPermanent / https://forum.openstreetmap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-       ServerAlias forum.osm.org
-       ServerAdmin webmaster@openstreetmap.org
-
-       SSLEngine on
-       SSLCertificateFile /etc/ssl/certs/forum.openstreetmap.org.pem
-       SSLCertificateKeyFile /etc/ssl/private/forum.openstreetmap.org.key
-
-       CustomLog /var/log/apache2/forum.openstreetmap.org-access.log combined
-       ErrorLog /var/log/apache2/forum.openstreetmap.org-error.log
-
-       RedirectPermanent / https://forum.openstreetmap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-       ServerName forum.openstreetmap.org
-       ServerAdmin webmaster@openstreetmap.org
-
-       SSLEngine on
-       SSLCertificateFile /etc/ssl/certs/forum.openstreetmap.org.pem
-       SSLCertificateKeyFile /etc/ssl/private/forum.openstreetmap.org.key
-
-       CustomLog /var/log/apache2/forum.openstreetmap.org-access.log combined
-       ErrorLog /var/log/apache2/forum.openstreetmap.org-error.log
-
-       DocumentRoot /srv/forum.openstreetmap.org/html
-
-       php_admin_value open_basedir /srv/forum.openstreetmap.org/html/:/usr/share/php/:/tmp/
-       php_admin_value disable_functions "exec,shell_exec,system,passthru,popen,proc_open"
-       php_value upload_max_filesize 70M
-       php_value post_max_size 100M
-</VirtualHost>
-
-<Directory /srv/forum.openstreetmap.org/html>
-       RewriteEngine on
-       RewriteRule ^config\.php$ - [F,L]
-
-       Options -Indexes
-
-       Require all granted
-</Directory>
-
-<Directory /srv/forum.openstreetmap.org/html/img>
-       php_admin_flag engine off
-</Directory>
diff --git a/cookbooks/forum/templates/default/backup.cron.erb b/cookbooks/forum/templates/default/backup.cron.erb
deleted file mode 100644 (file)
index c3475b8..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-T=$(mktemp -d -t -p /var/tmp forum.XXXXXXXXXX)
-D=$(date +%Y-%m-%d)
-B=forum-$D.tar.gz
-
-mkdir $T/forum-$D
-echo '[mysqldump]' > $T/mysqldump.opts
-echo 'user=forum' >> $T/mysqldump.opts
-echo 'password=<%= @passwords["database"] %>' >> $T/mysqldump.opts
-mysqldump --defaults-file=$T/mysqldump.opts --opt forum > $T/forum-$D/forum.sql
-ln -s /srv/forum.openstreetmap.org $T/forum-$D/www
-
-export GZIP="--rsyncable -9"
-export RSYNC_RSH="ssh -ax"
-
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B forum-$D
-nice rsync --preallocate --fuzzy $T/$B backup::backup
-
-rm -rf $T
diff --git a/cookbooks/forum/templates/default/config.php.erb b/cookbooks/forum/templates/default/config.php.erb
deleted file mode 100644 (file)
index 91ca738..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-$db_type = 'mysqli';
-$db_host = 'localhost';
-$db_name = 'forum';
-$db_username = 'forum';
-$db_password = '<%= @passwords["database"] %>';
-$db_prefix = 'osm_';
-$p_connect = false;
-
-$cookie_name = 'forum_cookie';
-$cookie_domain = '';
-$cookie_path = '/';
-$cookie_secure = 1;
-$cookie_seed = '<%= @passwords["cookie_seed"] %>';
-
-define('PUN', 1);
index 8aa8882960c6f4a9a071e6e3736f8bc07dc2a7ee..8c581fe93f04c50deff1d60bcd784929bbe789b7 100644 (file)
@@ -7,5 +7,5 @@ description       "Installs and configures foundation services"
 version           "1.0.0"
 supports          "ubuntu"
 depends           "apache"
-depends           "git"
 depends           "mediawiki"
+depends           "podman"
index d951a2a0dca8e7699d25615ea7286acdb4aa590c..597733e42416e008b449199128009b0689f66f42 100644 (file)
@@ -24,22 +24,21 @@ passwords = data_bag_item("foundation", "passwords")
 mediawiki_site "board.osmfoundation.org" do
   sitename "OSMF Board Wiki"
   metanamespace "OSMFBoard"
-  directory "/srv/board.osmfoundation.org"
+  fpm_prometheus_port 11004
   database_name "board-wiki"
   database_user "board-wikiuser"
   database_password passwords["board"]["database"]
   admin_password passwords["board"]["admin"]
   logo "/Wiki.png"
   email_contact "webmaster@openstreetmap.org"
-  email_sender "webmaster@openstreetmap.org"
+  email_sender "wiki@noreply.openstreetmap.org"
   email_sender_name "OSMF Board Wiki"
   private_site true
-  recaptcha_public_key "6LflIQATAAAAAMXyDWpba-FgipVzE-aGF4HIR59N"
-  recaptcha_private_key passwords["board"]["recaptcha"]
+  version "1.39"
 end
 
 cookbook_file "/srv/board.osmfoundation.org/Wiki.png" do
   owner node[:mediawiki][:user]
   group node[:mediawiki][:group]
-  mode 0o644
+  mode "644"
 end
index 13238888e2cfd346ac200916e81a5b4e4e8865b0..b8fb93f61f2a9bbc00156d3a6d26e3b03258c265 100644 (file)
@@ -24,22 +24,22 @@ passwords = data_bag_item("foundation", "passwords")
 mediawiki_site "dwg.osmfoundation.org" do
   sitename "OSMF Data Working Group Wiki"
   metanamespace "OSMFDWG"
-  directory "/srv/dwg.osmfoundation.org"
+  fpm_prometheus_port 11002
   database_name "dwg-wiki"
   database_user "dwg-wikiuser"
   database_password passwords["dwg"]["database"]
   admin_password passwords["dwg"]["admin"]
   logo "/Wiki.png"
   email_contact "webmaster@openstreetmap.org"
-  email_sender "webmaster@openstreetmap.org"
+  email_sender "wiki@noreply.openstreetmap.org"
   email_sender_name "OSMF Board Wiki"
   private_site true
-  recaptcha_public_key "6LflIQATAAAAAMXyDWpba-FgipVzE-aGF4HIR59N"
-  recaptcha_private_key passwords["dwg"]["recaptcha"]
+  extra_file_extensions %w[pptx]
+  version "1.39"
 end
 
 cookbook_file "/srv/dwg.osmfoundation.org/Wiki.png" do
   owner node[:mediawiki][:user]
   group node[:mediawiki][:group]
-  mode 0o644
+  mode "644"
 end
diff --git a/cookbooks/foundation/recipes/mastodon.rb b/cookbooks/foundation/recipes/mastodon.rb
new file mode 100644 (file)
index 0000000..51ef7a9
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Cookbook:: foundation
+# Recipe:: mastodon
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "podman::apache"
+
+podman_site "en.openstreetmap.town" do
+  image "ghcr.io/openstreetmap/en.openstreetmap.town-website:latest"
+end
index d347528c8fe3887c36e644cfbfe84c574ba3f697..e9263ba0a1cc62c26a177ebf8b9d611081fc612a 100644 (file)
@@ -24,22 +24,21 @@ passwords = data_bag_item("foundation", "passwords")
 mediawiki_site "mwg.osmfoundation.org" do
   sitename "OSMF Membership Working Group Wiki"
   metanamespace "OSMFMWG"
-  directory "/srv/mwg.osmfoundation.org"
+  fpm_prometheus_port 11003
   database_name "mwg_wiki"
   database_user "mwg_wikiuser"
   database_password passwords["mwg"]["database"]
   admin_password passwords["mwg"]["admin"]
   logo "/Wiki.png"
   email_contact "webmaster@openstreetmap.org"
-  email_sender "webmaster@openstreetmap.org"
+  email_sender "wiki@noreply.openstreetmap.org"
   email_sender_name "OSMF Board Wiki"
   private_site true
-  recaptcha_public_key "6LflIQATAAAAAMXyDWpba-FgipVzE-aGF4HIR59N"
-  recaptcha_private_key passwords["mwg"]["recaptcha"]
+  version "1.39"
 end
 
 cookbook_file "/srv/mwg.osmfoundation.org/Wiki.png" do
   owner node[:mediawiki][:user]
   group node[:mediawiki][:group]
-  mode 0o644
+  mode "644"
 end
index b60d02bac284c6394c02391ccb9ea19c59a1de1a..7054ec14a687ee766406eb67072fe9cc81bb0b0d 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "apache"
-include_recipe "git"
+include_recipe "podman::apache"
 
-package %w[
-  ruby
-  ruby-dev
-  zlib1g-dev
-]
-
-gem_package "bundler" do
-  version "1.17.3"
-end
-
-git "/srv/operations.osmfoundation.org" do
-  action :sync
-  repository "git://github.com/openstreetmap/owg-website.git"
-  user "root"
-  group "root"
-  notifies :run, "execute[/srv/operations.osmfoundation.org/Gemfile]"
-end
-
-directory "/srv/operations.osmfoundation.org/_site" do
-  mode 0o755
-  owner "nobody"
-  group "nogroup"
-end
-
-# Workaround https://github.com/jekyll/jekyll/issues/7804
-# by creating a .jekyll-cache folder
-directory "/srv/operations.osmfoundation.org/.jekyll-cache" do
-  mode 0o755
-  owner "nobody"
-  group "nogroup"
-end
-
-execute "/srv/operations.osmfoundation.org/Gemfile" do
-  action :nothing
-  command "bundle install --deployment"
-  cwd "/srv/operations.osmfoundation.org"
-  user "root"
-  group "root"
-  notifies :run, "execute[/srv/operations.osmfoundation.org]"
-end
-
-execute "/srv/operations.osmfoundation.org" do
-  action :nothing
-  command "bundle exec jekyll build --trace --baseurl=https://operations.osmfoundation.org"
-  cwd "/srv/operations.osmfoundation.org"
-  user "nobody"
-  group "nogroup"
-end
-
-ssl_certificate "operations.osmfoundation.org" do
-  domains "operations.osmfoundation.org"
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "operations.osmfoundation.org" do
-  template "apache.owg.erb"
-  directory "/srv/operations.osmfoundation.org/_site"
+podman_site "operations.osmfoundation.org" do
+  image "ghcr.io/openstreetmap/owg-website:latest"
+  aliases ["operations.openstreetmap.org", "operations.osm.org"]
 end
diff --git a/cookbooks/foundation/recipes/welcome.rb b/cookbooks/foundation/recipes/welcome.rb
new file mode 100644 (file)
index 0000000..30f58f9
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# Cookbook:: foundation
+# Recipe:: welcome
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "podman::apache"
+
+podman_site "welcome.openstreetmap.org" do
+  image "ghcr.io/osmfoundation/welcome-mat:latest"
+  aliases ["welcome.osm.org"]
+end
index b05c2ad26ca57670a6f53e913aaa73b6774fbf39..ddbe4705d6bee8b2118457fc936daa235b3cde9d 100644 (file)
@@ -21,41 +21,45 @@ include_recipe "mediawiki"
 
 passwords = data_bag_item("foundation", "passwords")
 
-mediawiki_site "wiki.osmfoundation.org" do
-  aliases ["www.osmfoundation.org", "osmfoundation.org",
+mediawiki_site "osmfoundation.org" do
+  aliases ["wiki.osmfoundation.org", "www.osmfoundation.org",
            "foundation.openstreetmap.org", "foundation.osm.org"]
   sitename "OpenStreetMap Foundation"
-  directory "/srv/wiki.osmfoundation.org"
+  fpm_max_children 20
+  fpm_start_servers 5
+  fpm_min_spare_servers 5
+  fpm_max_spare_servers 10
+  fpm_prometheus_port 11001
   database_name "osmf-wiki"
   database_user "osmf-wikiuser"
   database_password passwords["wiki"]["database"]
   admin_password passwords["wiki"]["admin"]
   skin "OSMFoundation"
-  logo "/Wiki.png"
+  logo "/w/skins/OSMFoundation/img/logo.png"
   email_contact "webmaster@openstreetmap.org"
-  email_sender "webmaster@openstreetmap.org"
+  email_sender "wiki@noreply.openstreetmap.org"
   email_sender_name "OSMF Wiki"
   private_accounts true
-  recaptcha_public_key "6LflIQATAAAAAMXyDWpba-FgipVzE-aGF4HIR59N"
-  recaptcha_private_key passwords["wiki"]["recaptcha"]
-  extra_file_extensions ["mp3"]
-end
-
-mediawiki_skin "osmf" do
-  site "wiki.osmfoundation.org"
-  repository "git://github.com/openstreetmap/mediawiki-skins-osmf.git"
-  revision "master"
+  extra_file_extensions %w[mp3 pptx]
+  version "1.39"
 end
 
 mediawiki_skin "OSMFoundation" do
-  site "wiki.osmfoundation.org"
-  repository "git://github.com/osmfoundation/osmf-mediawiki-skin.git"
+  site "osmfoundation.org"
+  repository "https://github.com/osmfoundation/osmf-mediawiki-skin.git"
   revision "master"
   legacy false
 end
 
-cookbook_file "/srv/wiki.osmfoundation.org/Wiki.png" do
+cookbook_file "/srv/osmfoundation.org/Wiki.png" do
+  owner node[:mediawiki][:user]
+  group node[:mediawiki][:group]
+  mode "644"
+end
+
+template "/srv/osmfoundation.org/robots.txt" do
   owner node[:mediawiki][:user]
   group node[:mediawiki][:group]
-  mode 0o644
+  mode "644"
+  source "robots.txt.erb"
 end
diff --git a/cookbooks/foundation/templates/default/apache.owg.erb b/cookbooks/foundation/templates/default/apache.owg.erb
deleted file mode 100644 (file)
index 1e40674..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-   ServerName <%= @name %>
-   ServerAdmin webmaster@openstreetmap.org
-
-   CustomLog /var/log/apache2/<%= @name %>-access.log combined
-   ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-   SSLEngine on
-   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-   DocumentRoot <%= @directory %>
-</VirtualHost>
-
-<VirtualHost *:80>
-   ServerName <%= @name %>
-   ServerAdmin webmaster@openstreetmap.org
-
-   CustomLog /var/log/apache2/<%= @name %>-access.log combined
-   ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-   RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
-
-<Directory <%= @directory %>>
-   Require all granted
-</Directory>
diff --git a/cookbooks/foundation/templates/default/robots.txt.erb b/cookbooks/foundation/templates/default/robots.txt.erb
new file mode 100644 (file)
index 0000000..bea20e8
--- /dev/null
@@ -0,0 +1,21 @@
+User-agent: ia_archiver
+Allow: /
+
+User-agent: 008
+Disallow: /
+
+User-agent: *
+Disallow: /index.php/
+Disallow: /wiki/Spam
+Disallow: /wiki/Donate/International_Bank_Transfers
+Allow: /w/load.php
+Allow: /w/images/
+Allow: /w/skins/
+Disallow: /w/
+Disallow: /wiki/Special:Collection
+Disallow: /wiki/Special:Random
+Disallow: /wiki/Special%3ARandom
+Disallow: /wiki/Special:Search
+
+User-agent: Exabot
+Crawl-delay: 60
index d2c42100c7aee035f1af9b8e1e00789b77f43838..9cd534a0b98d7022f9c43a845ceebcdd4d7121c5 100644 (file)
@@ -26,14 +26,14 @@ template "/etc/vsftpd.conf" do
   source "vsftpd.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 template "/etc/pam.d/vsftpd" do
   source "pam-vsftpd.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 service "vsftpd" do
@@ -45,10 +45,8 @@ end
 
 firewall_rule "accept-ftp-tcp" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "tcp"
+  context :incoming
+  protocol :tcp
   dest_ports "ftp"
-  source_ports "-"
   helper "ftp"
 end
index 4ce6925bb6c38453b91a7f646262dbdee0d7b178..b912c744291a9353452ca7fc6aa6092cf02f2c9e 100644 (file)
@@ -6,4 +6,6 @@ description       "Installs and configures a geographic DNS server"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "geoipupdate"
+depends           "networking"
 depends           "systemd"
index f24f1b8deecaadc03ec803e555e530d1a3a31b9f..a50b711411b461253de52123f894e3f3784bf230 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "geoipupdate"
+
+servers = search(:node, "roles:geodns").collect(&:name).sort
+
+servers << "dummy.example.com" if servers.empty?
+
 package %w[
-  geoipupdate
   gdnsd
 ]
 
-execute "geoipdate" do
-  command "geoipupdate"
-  user "root"
-  group "root"
-  not_if { ::File.exist?("/var/lib/GeoIP/GeoLite2-Country.mmdb") }
-end
-
 directory "/etc/gdnsd/config.d" do
   owner "nobody"
   group "nogroup"
-  mode 0o755
+  mode "755"
+end
+
+%w[nominatim].each do |zone|
+  %w[map resource weighted].each do |type|
+    template "/etc/gdnsd/config.d/#{zone}.#{type}" do
+      action :create_if_missing
+      source "zone.#{type}.erb"
+      owner "nobody"
+      group "nogroup"
+      mode "644"
+      variables :zone => zone
+    end
+  end
 end
 
 template "/etc/gdnsd/config" do
   source "config.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :restart, "service[gdnsd]"
 end
 
@@ -47,7 +58,8 @@ template "/etc/gdnsd/zones/geo.openstreetmap.org" do
   source "geo.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
+  variables :servers => servers
   notifies :restart, "service[gdnsd]"
 end
 
@@ -62,11 +74,8 @@ systemd_service "gdnsd-reload" do
   user "root"
   exec_start "/bin/systemctl reload-or-restart gdnsd"
   standard_output "null"
-  private_tmp true
-  private_devices true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  sandbox true
+  restrict_address_families "AF_UNIX"
 end
 
 systemd_path "gdnsd-reload" do
@@ -81,16 +90,14 @@ end
 
 firewall_rule "accept-dns-udp" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "udp"
+  context :incoming
+  protocol :udp
   dest_ports "domain"
 end
 
 firewall_rule "accept-dns-tcp" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "tcp:syn"
+  context :incoming
+  protocol :tcp
   dest_ports "domain"
 end
index 301985e92df1a31d1360a590a21ce478b92793ab..510e886a8641e0ae7ec294e6b456cac051c45e06 100644 (file)
@@ -1,17 +1,18 @@
 options => {
+  include_optional_ns = true
   listen => [ <%= node.ipaddresses(:role => :external).join(", ") %> ]
 }
         
 plugins => {
   geoip => {
     maps => {
-      $include{config.d/tile.map}
+      $include{config.d/nominatim.map}
     }
     resources => {
-      $include{config.d/tile.resource}
+      $include{config.d/nominatim.resource}
     }
   },
   weighted => {
-    $include{config.d/tile.weighted}
+    $include{config.d/nominatim.weighted}
   }
 }
index 7f33a37607c7272c81e02838421ab26df7d693f9..719f11a9d8e56cb33609ea2229fecf7642248a1f 100644 (file)
@@ -1,18 +1,15 @@
 $TTL 86400
 
-@      SOA     a.ns.openstreetmap.org. hostmaster.openstreetmap.org. (
-       1       ; serial
-       86400   ; refresh
-       172800  ; retry
-       604800  ; expire
-       3600    ; ncache
+@              SOA     <%= @servers.first %>. hostmaster.openstreetmap.org. (
+               3       ; serial
+               86400   ; refresh
+               7200    ; retry
+               604800  ; expire
+               3600    ; ncache
 )
 
-@      86400   NS      a.ns.openstreetmap.org.
-@      86400   NS      b.ns.openstreetmap.org.
-@      86400   NS      c.ns.openstreetmap.org.
-@      86400   NS      d.ns.openstreetmap.org.
-@      86400   NS      e.ns.openstreetmap.org.
-@      86400   NS      f.ns.openstreetmap.org.
+<% @servers.each do |server| -%>
+@              86400   NS      <%= server %>.
+<% end -%>
 
-tile   600     DYNC    geoip!tile
+nominatim      300     DYNC    geoip!nominatim
diff --git a/cookbooks/geodns/templates/default/zone.map.erb b/cookbooks/geodns/templates/default/zone.map.erb
new file mode 100644 (file)
index 0000000..25bf3ad
--- /dev/null
@@ -0,0 +1,3 @@
+<%= @zone %> => {
+  datacenters => [dummy]
+}
diff --git a/cookbooks/geodns/templates/default/zone.resource.erb b/cookbooks/geodns/templates/default/zone.resource.erb
new file mode 100644 (file)
index 0000000..3c1426b
--- /dev/null
@@ -0,0 +1,6 @@
+<%= @zone %> => {
+  map => <%= @zone %>
+  dcmap => {
+    dummy => dummy.example.com.
+  }
+}
diff --git a/cookbooks/geodns/templates/default/zone.weighted.erb b/cookbooks/geodns/templates/default/zone.weighted.erb
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/cookbooks/geoipupdate/README.md b/cookbooks/geoipupdate/README.md
new file mode 100644 (file)
index 0000000..5eb9966
--- /dev/null
@@ -0,0 +1,4 @@
+# geoipupdate Cookbook
+
+This cookbook installs and configures geoipupdate, a tool to keep MaxMind
+GeoIP databases up to date.
diff --git a/cookbooks/geoipupdate/attributes/default.rb b/cookbooks/geoipupdate/attributes/default.rb
new file mode 100644 (file)
index 0000000..a4b7535
--- /dev/null
@@ -0,0 +1,7 @@
+default[:geoipupdate][:account] = "149244"
+default[:geoipupdate][:editions] = %w[GeoLite2-ASN GeoLite2-City GeoLite2-Country]
+default[:geoipupdate][:directory] = if platform?("debian")
+                                      "/var/lib/GeoIP"
+                                    else
+                                      "/usr/share/GeoIP"
+                                    end
similarity index 56%
rename from cookbooks/munin/metadata.rb
rename to cookbooks/geoipupdate/metadata.rb
index 6af59ef18e4ec0bb2aca7e59cee34be534385038..ccc09f6261ddd230c09ca6b8ed4e88bc201a05e4 100644 (file)
@@ -1,10 +1,10 @@
-name              "munin"
+name              "geoipupdate"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures munin"
+description       "Installs and configures geoipupdate"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "apache"
-depends           "networking"
+depends           "apt"
+depends           "systemd"
diff --git a/cookbooks/geoipupdate/recipes/default.rb b/cookbooks/geoipupdate/recipes/default.rb
new file mode 100644 (file)
index 0000000..17fcc08
--- /dev/null
@@ -0,0 +1,58 @@
+#
+# Cookbook:: geoipdate
+# Recipe:: default
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apt::maxmind"
+
+license_keys = data_bag_item("geoipupdate", "license-keys")
+
+package "geoipupdate"
+
+template "/etc/GeoIP.conf" do
+  source "GeoIP.conf.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  variables :license_keys => license_keys
+end
+
+execute "geoipupdate" do
+  command "geoipupdate"
+  user "root"
+  group "root"
+  not_if { kitchen? || node[:geoipupdate][:editions].all? { |edition| ::File.exist?("#{node[:geoipupdate][:directory]}/#{edition}.mmdb") } }
+end
+
+systemd_service "geoipupdate" do
+  description "Update GeoIP databases"
+  user "root"
+  exec_start "/usr/bin/geoipupdate"
+  sandbox :enable_network => true
+  read_write_paths node[:geoipupdate][:directory]
+end
+
+systemd_timer "geoipupdate" do
+  description "Update GeoIP databases"
+  on_boot_sec "15m"
+  on_unit_active_sec "7d"
+  randomized_delay_sec "4h"
+end
+
+service "geoipupdate.timer" do
+  action [:enable, :start]
+end
diff --git a/cookbooks/geoipupdate/templates/default/GeoIP.conf.erb b/cookbooks/geoipupdate/templates/default/GeoIP.conf.erb
new file mode 100644 (file)
index 0000000..47315bd
--- /dev/null
@@ -0,0 +1,6 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+AccountID <%= node[:geoipupdate][:account] %>
+LicenseKey <%= @license_keys[node[:geoipupdate][:account]] %>
+EditionIDs <%= Array(node[:geoipupdate][:editions]).join(" ") %>
+DatabaseDirectory <%= node[:geoipupdate][:directory] %>
index 2d89a83de9e5c9765075b1169fd1a9a43c052eba..fd641f37a5b3472ec441a8acdde217a552883f14 100644 (file)
@@ -1,5 +1,7 @@
+default[:git][:host] = "git.openstreetmap.org"
 default[:git][:directory] = "/var/lib/git"
 default[:git][:public_user] = "git"
 default[:git][:public_group] = "git"
 default[:git][:private_user] = "git"
 default[:git][:private_group] = "git"
+default[:git][:private_nodes] = "fqdn:*"
index 003590d110f9e817758578e5b8094e2223aec4c6..19f53944f1871e1d42bc67489f17839eddd720e3 100644 (file)
@@ -6,5 +6,6 @@ description       "Installs and configures git"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
 depends           "networking"
index 4a98818e32880ce109eb561317d83a52f5040511..bd586e9f2c0e34165aef4fedced19cbee48bf76a 100644 (file)
 # limitations under the License.
 #
 
+node.default[:accounts][:users][:git][:status] = :role
+
+include_recipe "accounts"
+include_recipe "apt"
 include_recipe "networking"
 
 git_directory = node[:git][:directory]
@@ -24,19 +28,26 @@ git_directory = node[:git][:directory]
 directory git_directory do
   owner "root"
   group "root"
-  mode 0o775
+  mode "775"
 end
 
 directory "#{git_directory}/public" do
   owner node[:git][:public_user]
   group node[:git][:public_group]
-  mode 0o2775
+  mode "2775"
 end
 
 directory "#{git_directory}/private" do
   owner node[:git][:private_user]
   group node[:git][:private_group]
-  mode 0o2775
+  mode "2775"
+end
+
+template "/etc/gitconfig" do
+  source "gitconfig.erb"
+  owner "root"
+  group "root"
+  mode "644"
 end
 
 Dir.glob("#{git_directory}/*/*.git").each do |repository|
@@ -44,7 +55,7 @@ Dir.glob("#{git_directory}/*/*.git").each do |repository|
     source "post-update.erb"
     owner "root"
     group node[:git][:group]
-    mode 0o755
+    mode "755"
   end
 end
 
@@ -52,5 +63,5 @@ template "/etc/cron.daily/git-backup" do
   source "backup.cron.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
index 468074e2c8d027317b601246521a756a9fa3affd..bb99e482cd4257d2a999bc6ee90695dec295ec01 100644 (file)
@@ -21,6 +21,7 @@ include_recipe "apache"
 
 package "gitweb"
 
+apache_module "cgid"
 apache_module "rewrite"
 
 git_site = node[:git][:host]
@@ -29,20 +30,27 @@ template "/etc/gitweb.conf" do
   source "gitweb.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 directory "/srv/#{git_site}" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 template "/srv/#{git_site}/robots.txt" do
   source "robots.txt.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
+end
+
+template "/srv/#{git_site}/indextext.html" do
+  source "indextext.html.erb"
+  owner "root"
+  group "root"
+  mode "644"
 end
 
 ssl_certificate git_site do
index 9ec36f7d85a72d771cdfb238ce1c080c7cd670c9..3212b2b21faed3666ce2c5bf95ef19bf5dedd247 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
         ServerAdmin webmaster@openstreetmap.org
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -26,7 +26,7 @@
         SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
         SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         RedirectPermanent / https://<%= @name %>/
         SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
         SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         SetEnv GIT_PROJECT_ROOT /var/lib/git
         SetEnv GIT_HTTP_EXPORT_ALL
+        SetEnv GIT_HTTP_MAX_REQUEST_BUFFER 100M
+
+        SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
+
+        # KeepaliveTimeout longer than git config uploadpack.keepalive 5 second default
+        KeepAliveTimeout 20
+
+        RewriteEngine on
+        RewriteRule ^/cgimap\.git.* https://github.com/zerebubuth/openstreetmap-cgimap [QSD,L,R=permanent]
+        RewriteRule ^/planetdump\.git.* https://github.com/openstreetmap/planetdump [QSD,L,R=permanent]
+        RewriteRule ^/gpx-import\.git.* https://github.com/openstreetmap/gpx-import [QSD,L,R=permanent]
+        RewriteRule ^/potlatch2\.git.* https://github.com/openstreetmap/potlatch2 [QSD,L,R=permanent]
 
         ScriptAlias /public /usr/lib/git-core/git-http-backend/public
         ScriptAlias /private /usr/lib/git-core/git-http-backend/private
         <Location />
                   Require all granted
         </Location>
+<% unless @private_allowed.empty? -%>
 
         <Location /private>
                   Require ip <%= @private_allowed.sort.join(" ") %>
         </Location>
+<% end -%>
 
         <Location /private/chef.git>
                   Require all denied
index 5a9d01284e38a98015bcbab877f10b57c6425853..63882720f436b1682647d8b7d5d5323aee837a71 100644 (file)
@@ -8,10 +8,9 @@ B=git-$D.tar.gz
 
 ln -s /var/lib/git $T/git-$D
 
-export GZIP="--rsyncable -9"
 export RSYNC_RSH="ssh -ax"
 
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B git-$D
+nice tar --create --dereference --directory=$T git-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
diff --git a/cookbooks/git/templates/default/gitconfig.erb b/cookbooks/git/templates/default/gitconfig.erb
new file mode 100644 (file)
index 0000000..e5067f9
--- /dev/null
@@ -0,0 +1,6 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+[safe]
+       directory = /var/lib/chef/public
+       directory = /var/lib/chef/private
+       directory = /var/lib/dns
index 5d2eb746924b10628766b8a6f8cb700c5e3dc1a5..4cfe1c24ff081eeac9d28c64736c4203ba340e88 100644 (file)
@@ -10,7 +10,7 @@ $git_temp = "/tmp";
 #$home_link = $my_uri || "/";
 
 # html text to include at home page
-$home_text = "indextext.html";
+$home_text = "/srv/<%= node[:git][:host] %>/indextext.html";
 
 # file with project list; by default, simply scan the projectroot dir.
 $projects_list = $projectroot;
diff --git a/cookbooks/git/templates/default/indextext.html.erb b/cookbooks/git/templates/default/indextext.html.erb
new file mode 100644 (file)
index 0000000..c6493db
--- /dev/null
@@ -0,0 +1,3 @@
+<h2>Want to contribute to OpenStreetMap software?</h2>
+<p>Head over to <a href="https://github.com/openstreetmap/">github.com/openstreetmap/</a></p>
+<p>git.openstreetmap.org is an internal system we use as part of our deployment system.</p>
diff --git a/cookbooks/gps-tile/attributes/default.rb b/cookbooks/gps-tile/attributes/default.rb
new file mode 100644 (file)
index 0000000..61ab02a
--- /dev/null
@@ -0,0 +1 @@
+default[:accounts][:users][:gpstile][:status] = :role
index e5818349d92e3e34ec6ab867354d71cd23f104ba..cb62f1a177276bf4fdd171932c29255976605ff6 100644 (file)
@@ -6,7 +6,7 @@
     <link rel="stylesheet" href="map.css" type="text/css" media="all" />
     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="anonymous" />
     <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js" integrity="sha512-C7BBF9irt5R7hqbUm2uxtODlUVs+IsNu2UULGuZN7gM+k/mmeG4xvIEac01BtQa4YIkUpp23zZC4wIwuXaPMQA==" crossorigin="anonymous"></script>
-    <script src="//code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
     <script type="text/javascript" src="map.js"></script>
   </head>
   <body>
index 78acecfa55b3cfb4c3a7b7c2a9ab8ae52e0cb155..c23644f44d5e12221dec270dc92e0deacc7b2c21 100644 (file)
@@ -6,5 +6,8 @@ description       "Configures a GPS tile server"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
+depends           "git"
+depends           "memcached"
 depends           "systemd"
index 5de9d5573f326a1709a5e9caa4b7a4c725ea59d6..5fa394481259fd784b119904f6fdafa866458846 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "apache"
+include_recipe "git"
+include_recipe "memcached"
 
 package %w[
   make
@@ -35,20 +38,21 @@ package %w[
 directory "/srv/gps-tile.openstreetmap.org" do
   owner "gpstile"
   group "gpstile"
-  mode 0o755
+  mode "755"
 end
 
 git "/srv/gps-tile.openstreetmap.org/import" do
   action :sync
-  repository "git://github.com/ericfischer/gpx-import.git"
+  repository "https://github.com/e-n-f/gpx-import.git"
   revision "live"
+  depth 1
   user "gpstile"
   group "gpstile"
 end
 
 execute "/srv/gps-tile.openstreetmap.org/import/src/Makefile" do
   action :nothing
-  command "make"
+  command "make DB=none LDFLAGS=-lm"
   cwd "/srv/gps-tile.openstreetmap.org/import/src"
   user "gpstile"
   group "gpstile"
@@ -57,8 +61,9 @@ end
 
 git "/srv/gps-tile.openstreetmap.org/datamaps" do
   action :sync
-  repository "git://github.com/ericfischer/datamaps.git"
+  repository "https://github.com/e-n-f/datamaps.git"
   revision "live"
+  depth 1
   user "gpstile"
   group "gpstile"
 end
@@ -74,12 +79,25 @@ end
 
 git "/srv/gps-tile.openstreetmap.org/updater" do
   action :sync
-  repository "git://github.com/ericfischer/gpx-updater.git"
+  repository "https://github.com/openstreetmap/gpx-updater.git"
   revision "live"
+  depth 1
   user "gpstile"
   group "gpstile"
 end
 
+directory "/srv/gps-tile.openstreetmap.org/tracks" do
+  owner "gpstile"
+  group "gpstile"
+  mode "755"
+end
+
+directory "/srv/gps-tile.openstreetmap.org/shapes" do
+  owner "gpstile"
+  group "gpstile"
+  mode "755"
+end
+
 systemd_service "gps-update" do
   description "GPS tile update daemon"
   after ["network.target", "memcached.service"]
@@ -87,11 +105,9 @@ systemd_service "gps-update" do
   user "gpstile"
   working_directory "/srv/gps-tile.openstreetmap.org"
   exec_start "/srv/gps-tile.openstreetmap.org/updater/update"
-  private_tmp true
-  private_devices true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  nice 10
+  sandbox :enable_network => true
+  read_write_paths "/srv/gps-tile.openstreetmap.org"
   restart "on-failure"
 end
 
@@ -105,12 +121,13 @@ remote_directory "/srv/gps-tile.openstreetmap.org/html" do
   source "html"
   owner "gpstile"
   group "gpstile"
-  mode 0o755
+  mode "755"
   files_owner "gpstile"
   files_group "gpstile"
-  files_mode 0o644
+  files_mode "644"
 end
 
+apache_module "cgid"
 apache_module "headers"
 apache_module "rewrite"
 
index adc7a061d049c3d1bb82283aa293359677ec94dd..9adf707ddd8cd0325062e79b4b92c873e5fd8782 100644 (file)
@@ -23,7 +23,7 @@
   RedirectPermanent /gps-lines/tile /lines
 
   # Setup logging
-  CustomLog /var/log/apache2/access.log combined
+  CustomLog /var/log/apache2/access.log combined_extended
   ErrorLog /var/log/apache2/error.log
   BufferedLogs on
 
@@ -50,7 +50,7 @@
   RewriteRule (.*) https://%{SERVER_NAME}/$1 [R=permanent,L]
 
   # Setup logging
-  CustomLog /var/log/apache2/access.log combined
+  CustomLog /var/log/apache2/access.log combined_extended
   ErrorLog /var/log/apache2/error.log
   BufferedLogs on
 </VirtualHost>
index 2619fd5497745302b051851d7e3d02ffa7fd6266..218e6228e5ab476e4edc65761ceb7f31069ff399 100644 (file)
@@ -1,16 +1,23 @@
 default[:hardware][:modules] = %w[lp]
+default[:hardware][:blacklisted_modules] = %w[]
 default[:hardware][:grub][:cmdline] = %w[nomodeset]
 default[:hardware][:sensors] = {}
+default[:hardware][:hwmon] = {}
+default[:hardware][:ipmi][:excluded_sensors] = []
+default[:hardware][:ipmi][:custom_args] = []
 
 if node[:dmi] && node[:dmi][:system]
   case node[:dmi][:system][:manufacturer]
   when "HP"
-    default[:apt][:sources] |= ["management-component-pack"]
-
     case node[:dmi][:system][:product_name]
     when "ProLiant DL360 G6", "ProLiant DL360 G7", "ProLiant SE326M1R2"
       default[:hardware][:sensors][:"power_meter-*"][:power][:power1] = { :ignore => true }
     end
+
+    case node[:dmi][:system][:product_name]
+    when "ProLiant DL360 G6", "ProLiant DL360 G7", "ProLiant SE326M1R2", "ProLiant DL360e Gen8", "ProLiant DL360p Gen8"
+      default[:hardware][:ipmi][:custom_args] |= ["--workaround-flags=discretereading"]
+    end
   end
 end
 
@@ -22,25 +29,28 @@ if Chef::Util.compare_versions(node[:kernel][:release], [3, 3]).negative?
   end
 end
 
-if node[:kernel] && node[:kernel][:modules]
-  raidmods = node[:kernel][:modules].keys & %w[cciss hpsa mptsas mpt2sas mpt3sas megaraid_mm megaraid_sas aacraid]
-
-  default[:apt][:sources] |= ["hwraid"] unless raidmods.empty?
-end
-
 if node[:kernel][:modules].include?("ipmi_si")
   default[:hardware][:modules] |= ["ipmi_devintf"]
-end
 
-if File.exist?("/proc/xen")
-  default[:hardware][:watchdog] = "xen_wdt"
-elsif node[:kernel][:modules].include?("i6300esb")
-  default[:hardware][:watchdog] = "none"
+  if node[:kernel][:modules].include?("acpi_power_meter")
+    default[:hardware][:modules] |= ["acpi_ipmi"]
+  end
 end
 
-if File.exist?("sys/devices/system/cpu/cpu0/cpufreq/scaling_governor") &&
+if File.exist?("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor") &&
    File.read("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor").chomp == "ondemand"
   default[:sysfs][:cpufreq_ondemand][:comment] = "Tune the ondemand CPU frequency governor"
   default[:sysfs][:cpufreq_ondemand][:parameters][:"devices/system/cpu/cpufreq/ondemand/up_threshold"] = "25"
   default[:sysfs][:cpufreq_ondemand][:parameters][:"devices/system/cpu/cpufreq/ondemand/sampling_down_factor"] = "100"
+  default[:sysfs][:cpufreq_ondemand][:parameters][:"devices/system/cpu/cpufreq/ondemand/ignore_nice_load"] = "1"
+end
+
+energy_perf_bias = Dir.glob("/sys/devices/system/cpu/cpu*/power/energy_perf_bias")
+
+unless energy_perf_bias.empty?
+  default[:sysfs][:cpu_power_energy_perf_bias][:comment] = "Set CPU Energy-Performance Bias Preference to balance-performance"
+
+  energy_perf_bias.sort.each do |path|
+    default[:sysfs][:cpu_power_energy_perf_bias][:parameters][path.sub(%r{^/sys/}, "")] = "4"
+  end
 end
index b632a23d93aeca70395fba08666ba87b27ab7827..de57c77ebdee5f664603d04a2cf918d7ec4f8775 100644 (file)
@@ -7,8 +7,9 @@ description       "Configures hardware"
 version           "1.0.0"
 supports          "ubuntu"
 depends           "apt"
+depends           "chef"
 depends           "git"
-depends           "munin"
+depends           "prometheus"
 depends           "ohai"
 depends           "tools"
 depends           "sysfs"
index 6c14fd873e0990f720060ef36641c9efda7f0149..4122a7ac8e5172d25855e369dc17abb0d111e880 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "apt"
+include_recipe "git"
+include_recipe "prometheus"
+include_recipe "sysfs"
 include_recipe "tools"
-include_recipe "munin"
 
 ohai_plugin "hardware" do
   template "ohai.rb.erb"
 end
 
-case node[:cpu][:"0"][:vendor_id]
-when "GenuineIntel"
-  package "intel-microcode"
-when "AuthenticAMD"
-  package "amd64-microcode"
+if platform?("debian")
+  package "firmware-linux"
+end
+
+if node[:cpu] && node[:cpu][:"0"] && node[:cpu][:"0"][:vendor_id]
+  case node[:cpu][:"0"][:vendor_id]
+  when "GenuineIntel"
+    package "intel-microcode"
+  when "AuthenticAMD"
+    package "amd64-microcode"
+  end
 end
 
 if node[:dmi] && node[:dmi][:system]
@@ -47,22 +56,40 @@ end
 
 units = []
 
-if node[:roles].include?("bytemark") || node[:roles].include?("exonetric")
+if node[:roles].include?("bytemark") || node[:roles].include?("exonetric") || node[:roles].include?("prgmr")
   units << "0"
 end
 
 case manufacturer
-when "HP"
+when "HP", "HPE"
+  include_recipe "apt::management-component-pack"
+
   package "hponcfg"
 
+  execute "update-ilo" do
+    action :nothing
+    command "/usr/sbin/hponcfg -f /etc/ilo-defaults.xml"
+    not_if { kitchen? }
+  end
+
+  template "/etc/ilo-defaults.xml" do
+    source "ilo-defaults.xml.erb"
+    owner "root"
+    group "root"
+    mode "644"
+    notifies :run, "execute[update-ilo]"
+  end
+
   package "hp-health" do
     action :install
     notifies :restart, "service[hp-health]"
+    only_if { platform?("ubuntu") && node[:lsb][:release].to_f < 22.04 }
   end
 
   service "hp-health" do
     action [:enable, :start]
     supports :status => true, :restart => true
+    only_if { platform?("ubuntu") && node[:lsb][:release].to_f < 22.04 }
   end
 
   if product.end_with?("Gen8", "Gen9")
@@ -75,20 +102,29 @@ when "HP"
       action [:enable, :start]
       supports :status => true, :restart => true
     end
+  elsif product.end_with?("Gen10")
+    package "amsd" do
+      action :install
+      notifies :restart, "service[amsd]"
+    end
+
+    service "amsd" do
+      action [:enable, :start]
+      supports :status => true, :restart => true
+    end
   end
 
-  units << "1"
+  units << if product.end_with?("Gen10")
+             "0"
+           else
+             "1"
+           end
 when "TYAN"
   units << "0"
 when "TYAN Computer Corporation"
   units << "0"
 when "Supermicro"
-  case product
-  when "H8DGU", "X9SCD", "X7DBU", "X7DW3", "X9DR7/E-(J)LN4F", "X9DR3-F", "X9DRW", "SYS-1028U-TN10RT+", "SYS-2028U-TN24R4T+", "SYS-1029P-WTRT", "Super Server"
-    units << "1"
-  else
-    units << "0"
-  end
+  units << "1"
 when "IBM"
   units << "0"
 when "VMware, Inc."
@@ -116,6 +152,7 @@ end
 units.sort.uniq.each do |unit|
   service "serial-getty@ttyS#{unit}" do
     action [:enable, :start]
+    not_if { kitchen? }
   end
 end
 
@@ -142,18 +179,21 @@ if File.exist?("/etc/default/grub")
   execute "update-grub" do
     action :nothing
     command "/usr/sbin/update-grub"
+    not_if { kitchen? }
   end
 
   template "/etc/default/grub" do
     source "grub.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables :units => units, :entry => grub_entry
     notifies :run, "execute[update-grub]"
   end
 end
 
+package "initramfs-tools"
+
 execute "update-initramfs" do
   action :nothing
   command "update-initramfs -u -k all"
@@ -165,78 +205,128 @@ template "/etc/initramfs-tools/conf.d/mdadm" do
   source "initramfs-mdadm.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :run, "execute[update-initramfs]"
 end
 
-package "haveged"
-service "haveged" do
-  action [:enable, :start]
+# haveged is only required on older kernels
+# /dev/random is not blocking anymore in 5.15+
+if Chef::Util.compare_versions(node[:kernel][:release], [5, 15]).negative?
+  package "haveged"
+  service "haveged" do
+    action [:enable, :start]
+  end
+else
+  service "haveged" do
+    action [:stop, :disable]
+  end
+  package "haveged" do
+    action :remove
+  end
 end
 
-package "ipmitool" if node[:kernel][:modules].include?("ipmi_si")
+watchdog_module = %w[hpwdt sp5100_tco].find do |module_name|
+  node[:hardware][:pci]&.any? { |_, pci| pci[:modules]&.any?(module_name) }
+end
 
-package "irqbalance"
+if node[:kernel][:modules].include?("ipmi_si")
+  package "ipmitool"
+  package "freeipmi-tools"
 
-template "/etc/default/irqbalance" do
-  source "irqbalance.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+  template "/etc/prometheus/ipmi_local.yml" do
+    source "ipmi_local.yml.erb"
+    owner "root"
+    group "root"
+    mode "644"
+  end
+
+  prometheus_exporter "ipmi" do
+    port 9290
+    user "root"
+    private_devices false
+    protect_clock false
+    system_call_filter ["@system-service", "@raw-io"]
+    options "--config.file=/etc/prometheus/ipmi_local.yml"
+    subscribes :restart, "template[/etc/prometheus/ipmi_local.yml]"
+  end
+
+  watchdog_module ||= "ipmi_watchdog"
 end
 
+package "irqbalance"
+
 service "irqbalance" do
   action [:start, :enable]
   supports :status => false, :restart => true, :reload => false
-  subscribes :restart, "template[/etc/default/irqbalance]"
 end
 
-# Link Layer Discovery Protocol Daemon
 package "lldpd"
+
 service "lldpd" do
   action [:start, :enable]
   supports :status => true, :restart => true, :reload => true
 end
 
+ohai_plugin "lldp" do
+  template "lldp.rb.erb"
+end
+
+package %w[
+  rasdaemon
+  ruby-sqlite3
+]
+
+service "rasdaemon" do
+  action [:enable, :start]
+end
+
+prometheus_exporter "rasdaemon" do
+  port 9797
+  user "root"
+end
+
 tools_packages = []
 status_packages = {}
 
-node[:kernel][:modules].each_key do |modname|
-  case modname
-  when "cciss"
-    tools_packages << "ssacli"
-    status_packages["cciss-vol-status"] ||= []
-  when "hpsa"
-    tools_packages << "ssacli"
-    status_packages["cciss-vol-status"] ||= []
-  when "mptsas"
-    tools_packages << "lsiutil"
-    status_packages["mpt-status"] ||= []
-  when "mpt2sas", "mpt3sas"
-    tools_packages << "sas2ircu"
-    status_packages["sas2ircu-status"] ||= []
-  when "megaraid_mm"
-    tools_packages << "megactl"
-    status_packages["megaraid-status"] ||= []
-  when "megaraid_sas"
-    tools_packages << "megacli"
-    status_packages["megaclisas-status"] ||= []
-  when "aacraid"
-    tools_packages << "arcconf"
-    status_packages["aacraid-status"] ||= []
-  when "arcmsr"
-    tools_packages << "areca"
-  end
-end
-
-node[:block_device].each do |name, attributes|
-  next unless attributes[:vendor] == "HP" && attributes[:model] == "LOGICAL VOLUME"
-
-  if name =~ /^cciss!(c[0-9]+)d[0-9]+$/
-    status_packages["cciss-vol-status"] |= ["cciss/#{Regexp.last_match[1]}d0"]
-  else
-    Dir.glob("/sys/block/#{name}/device/scsi_generic/*").each do |sg|
-      status_packages["cciss-vol-status"] |= [File.basename(sg)]
+if node[:virtualization][:role] != "guest" ||
+   (node[:virtualization][:system] != "lxc" &&
+    node[:virtualization][:system] != "lxd" &&
+    node[:virtualization][:system] != "openvz")
+
+  node[:kernel][:modules].each_key do |modname|
+    case modname
+    when "cciss"
+      tools_packages << "ssacli"
+      status_packages["cciss-vol-status"] ||= []
+    when "hpsa"
+      tools_packages << "ssacli"
+      status_packages["cciss-vol-status"] ||= []
+    when "mptsas"
+      tools_packages << "lsiutil"
+      status_packages["mpt-status"] ||= []
+    when "mpt2sas", "mpt3sas"
+      tools_packages << "sas2ircu"
+      status_packages["sas2ircu-status"] ||= []
+    when "megaraid_sas"
+      tools_packages << "megacli"
+      status_packages["megaclisas-status"] ||= []
+    when "aacraid"
+      tools_packages << "arcconf"
+      status_packages["aacraid-status"] ||= []
+    when "arcmsr"
+      tools_packages << "areca"
+    end
+  end
+
+  node[:block_device].each do |name, attributes|
+    next unless attributes[:vendor] == "HP" && attributes[:model] == "LOGICAL VOLUME"
+
+    if name =~ /^cciss!(c[0-9]+)d[0-9]+$/
+      status_packages["cciss-vol-status"] |= ["cciss/#{Regexp.last_match[1]}d0"]
+    else
+      Dir.glob("/sys/block/#{name}/device/scsi_generic/*").each do |sg|
+        status_packages["cciss-vol-status"] |= [File.basename(sg)]
+      end
     end
   end
 end
@@ -257,8 +347,10 @@ if tools_packages.include?("areca")
   git "/opt/areca" do
     action :sync
     repository "https://git.openstreetmap.org/private/areca.git"
+    depth 1
     user "root"
     group "root"
+    not_if { kitchen? }
   end
 else
   directory "/opt/areca" do
@@ -267,92 +359,81 @@ else
   end
 end
 
-if status_packages.include?("cciss-vol-status")
-  template "/usr/local/bin/cciss-vol-statusd" do
-    source "cciss-vol-statusd.erb"
-    owner "root"
-    group "root"
-    mode 0o755
-    notifies :restart, "service[cciss-vol-statusd]"
-  end
+include_recipe "apt::hwraid" unless status_packages.empty?
 
-  systemd_service "cciss-vol-statusd" do
-    description "Check cciss_vol_status values in the background"
-    exec_start "/usr/local/bin/cciss-vol-statusd"
-    private_tmp true
-    protect_system "full"
-    protect_home true
-    no_new_privileges true
-    notifies :restart, "service[cciss-vol-statusd]"
-  end
-end
-
-%w[cciss-vol-status mpt-status sas2ircu-status megaraid-status megaclisas-status aacraid-status].each do |status_package|
+%w[cciss-vol-status mpt-status sas2ircu-status megaclisas-status aacraid-status].each do |status_package|
   if status_packages.include?(status_package)
     package status_package
 
-    template "/etc/default/#{status_package}d" do
-      source "raid.default.erb"
-      owner "root"
-      group "root"
-      mode 0o644
-      variables :devices => status_packages[status_package]
+    service "#{status_package}d" do
+      action [:stop, :disable]
     end
 
-    service "#{status_package}d" do
-      action [:start, :enable]
-      supports :status => false, :restart => true, :reload => false
-      subscribes :restart, "template[/etc/default/#{status_package}d]"
+    file "/etc/default/#{status_package}d" do
+      action :delete
     end
   else
     package status_package do
       action :purge
     end
-
-    file "/etc/default/#{status_package}d" do
-      action :delete
-    end
   end
 end
 
+systemd_service "cciss-vol-statusd" do
+  action :delete
+end
+
+template "/usr/local/bin/cciss-vol-statusd" do
+  action :delete
+end
+
 disks = if node[:hardware][:disk]
           node[:hardware][:disk][:disks]
         else
           []
         end
 
-# intel_ssds = disks.select { |d| d[:vendor] == "INTEL" && d[:model] =~ /^SSD/ }
-#
-# nvmes = if node[:hardware][:pci]
-#           node[:hardware][:pci].values.select { |pci| pci[:driver] == "nvme" }
-#         else
-#           []
-#         end
-#
-# intel_nvmes = nvmes.select { |pci| pci[:vendor_name] == "Intel Corporation" }
-#
-# if !intel_ssds.empty? || !intel_nvmes.empty?
-#   package "unzip"
-#
-#   intel_ssd_tool_version = "3.0.21"
-#
-#   remote_file "#{Chef::Config[:file_cache_path]}/Intel_SSD_Data_Center_Tool_#{intel_ssd_tool_version}_Linux.zip" do
-#     source "https://downloadmirror.intel.com/29115/eng/Intel_SSD_Data_Center_Tool_#{intel_ssd_tool_version}_Linux.zip"
-#   end
-#
-#   execute "#{Chef::Config[:file_cache_path]}/Intel_SSD_Data_Center_Tool_#{intel_ssd_tool_version}_Linux.zip" do
-#     command "unzip Intel_SSD_Data_Center_Tool_#{intel_ssd_tool_version}_Linux.zip isdct_#{intel_ssd_tool_version}-1_amd64.deb"
-#     cwd Chef::Config[:file_cache_path]
-#     user "root"
-#     group "root"
-#     not_if { File.exist?("#{Chef::Config[:file_cache_path]}/isdct_#{intel_ssd_tool_version}-1_amd64.deb") }
-#   end
-#
-#   dpkg_package "isdct" do
-#     version "#{intel_ssd_tool_version}-1"
-#     source "#{Chef::Config[:file_cache_path]}/isdct_#{intel_ssd_tool_version}-1_amd64.deb"
-#   end
-# end
+intel_ssds = disks.select { |d| d[:vendor] == "INTEL" && d[:model] =~ /^SSD/ }
+
+nvmes = if node[:hardware][:pci]
+          node[:hardware][:pci].values.select { |pci| pci[:driver] == "nvme" }
+        else
+          []
+        end
+
+unless nvmes.empty?
+  package "nvme-cli"
+end
+
+intel_nvmes = nvmes.select { |pci| pci[:vendor_name] == "Intel Corporation" }
+
+if !intel_ssds.empty? || !intel_nvmes.empty?
+  package "unzip"
+
+  sst_tool_version = "1.3"
+  sst_package_version = "#{sst_tool_version}.208-0"
+
+  # remote_file "#{Chef::Config[:file_cache_path]}/SST_CLI_Linux_#{sst_tool_version}.zip" do
+  #   source "https://downloadmirror.intel.com/743764/SST_CLI_Linux_#{sst_tool_version}.zip"
+  # end
+
+  execute "#{Chef::Config[:file_cache_path]}/SST_CLI_Linux_#{sst_tool_version}.zip" do
+    command "unzip SST_CLI_Linux_#{sst_tool_version}.zip sst_#{sst_package_version}_amd64.deb"
+    cwd Chef::Config[:file_cache_path]
+    user "root"
+    group "root"
+    not_if { ::File.exist?("#{Chef::Config[:file_cache_path]}/sst_#{sst_package_version}_amd64.deb") }
+  end
+
+  dpkg_package "sst" do
+    version "#{sst_package_version}"
+    source "#{Chef::Config[:file_cache_path]}/sst_#{sst_package_version}_amd64.deb"
+  end
+
+  dpkg_package "intelmas" do
+    action :purge
+  end
+end
 
 disks = disks.map do |disk|
   next if disk[:state] == "spun_down" || %w[unconfigured failed].any?(disk[:status])
@@ -363,31 +444,21 @@ disks = disks.map do |disk|
     if controller && controller[:device]
       device = controller[:device].sub("/dev/", "")
       smart = disk[:smart_device]
-
-      if device.start_with?("cciss/") && smart =~ /^cciss,(\d+)$/
-        array = node[:hardware][:disk][:arrays][disk[:arrays].first]
-        munin = "cciss-3#{array[:wwn]}-#{Regexp.last_match(1)}"
-      elsif smart =~ /^.*,(\d+)$/
-        munin = "#{device}-#{Regexp.last_match(1)}"
-      elsif smart =~ %r{^.*,(\d+)/(\d+)$}
-        munin = "#{device}-#{Regexp.last_match(1)}:#{Regexp.last_match(2)}"
-      end
+    elsif disk[:device]
+      device = disk[:device].sub("/dev/", "")
+      smart = disk[:smart_device]
     end
   elsif disk[:device] =~ %r{^/dev/(nvme\d+)n\d+$}
     device = Regexp.last_match(1)
-    munin = device
   elsif disk[:device]
     device = disk[:device].sub("/dev/", "")
-    munin = device
   end
 
   next if device.nil?
 
   Hash[
     :device => device,
-    :smart => smart,
-    :munin => munin,
-    :hddtemp => munin.tr("-:", "_")
+    :smart => smart
   ]
 end
 
@@ -396,18 +467,25 @@ disks = disks.compact.uniq
 if disks.count.positive?
   package "smartmontools"
 
+  template "/etc/cron.daily/update-smart-drivedb" do
+    source "update-smart-drivedb.erb"
+    owner "root"
+    group "root"
+    mode "755"
+  end
+
   template "/usr/local/bin/smartd-mailer" do
     source "smartd-mailer.erb"
     owner "root"
     group "root"
-    mode 0o755
+    mode "755"
   end
 
   template "/etc/smartd.conf" do
     source "smartd.conf.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables :disks => disks
   end
 
@@ -415,27 +493,30 @@ if disks.count.positive?
     source "smartmontools.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
   end
 
-  service "smartd" do
+  service "smartmontools" do
     action [:enable, :start]
     subscribes :reload, "template[/etc/smartd.conf]"
     subscribes :restart, "template[/etc/default/smartmontools]"
   end
 
-  # Don't try and do munin monitoring of disks behind
-  # an Areca controller as they only allow one thing to
-  # talk to the controller at a time and smartd will
-  # throw errors if it clashes with munin
-  disks = disks.reject { |disk| disk[:smart]&.start_with?("areca,") }
+  template "/etc/prometheus/collectors/smart.devices" do
+    source "smart.devices.erb"
+    owner "root"
+    group "root"
+    mode "644"
+    variables :disks => disks
+  end
 
-  disks.each do |disk|
-    munin_plugin "smart_#{disk[:munin]}" do
-      target "smart_"
-      conf "munin.smart.erb"
-      conf_variables :disk => disk
-    end
+  prometheus_collector "smart" do
+    interval "15m"
+    user "root"
+    capability_bounding_set %w[CAP_DAC_OVERRIDE CAP_SYS_ADMIN CAP_SYS_RAWIO]
+    private_devices false
+    private_users false
+    protect_clock false
   end
 else
   service "smartd" do
@@ -443,28 +524,6 @@ else
   end
 end
 
-if disks.count.positive?
-  munin_plugin "hddtemp_smartctl" do
-    conf "munin.hddtemp.erb"
-    conf_variables :disks => disks
-  end
-else
-  munin_plugin "hddtemp_smartctl" do
-    action :delete
-    conf "munin.hddtemp.erb"
-  end
-end
-
-plugins = Dir.glob("/etc/munin/plugins/smart_*").map { |p| File.basename(p) } -
-          disks.map { |d| "smart_#{d[:munin]}" }
-
-plugins.each do |plugin|
-  munin_plugin plugin do
-    action :delete
-    conf "munin.smart.erb"
-  end
-end
-
 if File.exist?("/etc/mdadm/mdadm.conf")
   mdadm_conf = edit_file "/etc/mdadm/mdadm.conf" do |line|
     line.gsub!(/^MAILADDR .*$/, "MAILADDR admins@openstreetmap.org")
@@ -475,41 +534,57 @@ if File.exist?("/etc/mdadm/mdadm.conf")
   file "/etc/mdadm/mdadm.conf" do
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     content mdadm_conf
   end
 
-  service "mdadm" do
+  service "mdmonitor" do
     action :nothing
     subscribes :restart, "file[/etc/mdadm/mdadm.conf]"
   end
 end
 
-template "/etc/modules" do
-  source "modules.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+file "/etc/modules" do
+  action :delete
 end
 
-service "kmod" do
-  action :nothing
-  subscribes :start, "template[/etc/modules]"
+node[:hardware][:modules].each do |module_name|
+  kernel_module module_name do
+    action :install
+    not_if { kitchen? }
+  end
+end
+
+node[:hardware][:blacklisted_modules].each do |module_name|
+  kernel_module module_name do
+    action :blacklist
+  end
 end
 
-if node[:hardware][:watchdog]
-  package "watchdog"
+if watchdog_module
+  kernel_module watchdog_module do
+    action :install
+  end
+
+  execute "systemctl-reload" do
+    action :nothing
+    command "systemctl daemon-reload"
+    user "root"
+    group "root"
+  end
 
-  template "/etc/default/watchdog" do
-    source "watchdog.erb"
+  directory "/etc/systemd/system.conf.d" do
     owner "root"
     group "root"
-    mode 0o644
-    variables :module => node[:hardware][:watchdog]
+    mode "755"
   end
 
-  service "watchdog" do
-    action [:enable, :start]
+  template "/etc/systemd/system.conf.d/watchdog.conf" do
+    source "watchdog.conf.erb"
+    owner "root"
+    group "root"
+    mode "644"
+    notifies :run, "execute[systemctl-reload]"
   end
 end
 
@@ -551,7 +626,7 @@ unless Dir.glob("/sys/class/hwmon/hwmon*").empty?
     source "sensors.conf.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     notifies :run, "execute[/etc/sensors.d/chef.conf]"
   end
 end
@@ -572,3 +647,14 @@ if node[:hardware][:shm_size]
     notifies :run, "execute[remount-dev-shm]"
   end
 end
+
+prometheus_collector "ohai" do
+  interval "15m"
+  user "root"
+  proc_subset "all"
+  capability_bounding_set %w[CAP_DAC_OVERRIDE CAP_SYS_ADMIN CAP_SYS_RAWIO]
+  private_devices false
+  private_users false
+  protect_clock false
+  protect_kernel_modules false
+end
diff --git a/cookbooks/hardware/templates/default/cciss-vol-statusd.erb b/cookbooks/hardware/templates/default/cciss-vol-statusd.erb
deleted file mode 100755 (executable)
index 8f25650..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/sh
-
-NAME="cciss-vol-statusd"
-STATUSFILE=/var/run/$NAME.status
-
-# Do not touch you can configure this in /etc/default/cciss-vol-statusd
-MAILTO=root   # Where to report problems
-PERIOD=600    # Seconds between each check    (default 10 minutes)
-REMIND=7200   # Seconds between each reminder (default 2 hours)
-ID=/dev/cciss/c0d0
-
-[ -e /etc/default/cciss-vol-statusd ] && . /etc/default/cciss-vol-statusd
-
-# Gracefully exit if the package has been removed.
-test -x /usr/bin/cciss_vol_status || exit 0
-
-while true ; do
-    # Check ever $PERIOD seconds, send email on every status
-    # change and repeat ever $REMIND seconds if the raid is still
-    # bad.
-    if (cciss_vol_status $ID); then
-        BADRAID=false
-    else
-        BADRAID=true
-        logger -t cciss-vol-statusd "detected non-optimal RAID status"
-    fi
-    STATUSCHANGE=false
-    if [ true = "$BADRAID" ] ; then
-        # RAID not OK
-        (cciss_vol_status $ID) > $STATUSFILE.new
-        if [ ! -f $STATUSFILE ] ; then # RAID just became broken
-            STATUSCHANGE=true
-            mv $STATUSFILE.new $STATUSFILE
-        elif cmp -s $STATUSFILE $STATUSFILE.new ; then
-            # No change.  Should we send reminder?
-            LASTTIME="`stat -c '%Z' $STATUSFILE`"
-            NOW="`date +%s`"
-            SINCELAST="`expr $NOW - $LASTTIME`"
-            if [ $REMIND -le "$SINCELAST" ]; then
-                # Time to send reminder
-                STATUSCHANGE=true
-                mv $STATUSFILE.new $STATUSFILE
-            else
-                rm $STATUSFILE.new
-            fi
-        else
-            STATUSCHANGE=true
-            mv $STATUSFILE.new $STATUSFILE
-        fi
-    else
-        # RAID OK
-        if [ -f $STATUSFILE ] ; then
-            rm $STATUSFILE
-            STATUSCHANGE=true
-        fi
-    fi
-
-    if [ true = "$STATUSCHANGE" ]; then
-        hostname="`uname -n`"
-        (
-            cat <<EOF
-This is a RAID status update from cciss-vol-statusd.  The cciss_vol_status
-program reports that one of the RAIDs changed state:
-
-EOF
-            if [ -f $STATUSFILE ] ; then
-                cat $STATUSFILE
-            else
-                (cciss_vol_status $ID)
-            fi
-            echo
-            echo "Report from $0 on $hostname"
-        ) | mail -s "info: CCISS raid status change on $hostname" $MAILTO
-    fi
-
-    sleep $PERIOD
-done
diff --git a/cookbooks/hardware/templates/default/ilo-defaults.xml.erb b/cookbooks/hardware/templates/default/ilo-defaults.xml.erb
new file mode 100644 (file)
index 0000000..feb4f8f
--- /dev/null
@@ -0,0 +1,26 @@
+<RIBCL VERSION="2.0">
+  <LOGIN USER_LOGIN="admin" PASSWORD="password">
+    <SERVER_INFO mode="write">
+      <!-- Set Server Name -->
+      <SERVER_NAME VALUE="<%= node[:fqdn] %>"/>
+    </SERVER_INFO>
+    <SERVER_INFO mode="write">
+      <!-- 1 Operating system control mode -->
+      <!-- 2 HP Static Low Power mode -->
+      <!-- 3 HP Dynamic Power Savings mode -->
+      <!-- 4 HP Static High Performance mode -->
+      <SET_HOST_POWER_SAVER HOST_POWER_SAVER="3"/>
+    </SERVER_INFO>
+    <SERVER_INFO mode="write">
+      <!-- Set Auto Power Yes -->
+      <SERVER_AUTO_PWR VALUE="Yes"/>
+    </SERVER_INFO>
+    <SERVER_INFO mode="write">
+      <!-- Set Auto Power after random delay -->
+      <SERVER_AUTO_PWR VALUE="RANDOM"/>
+      <!-- Unset max power cap -->
+      <!-- Disable for now -->
+      <!-- SET_POWER_CAP POWER_CAP="0" -->
+    </SERVER_INFO>
+  </LOGIN>
+</RIBCL>
diff --git a/cookbooks/hardware/templates/default/ipmi_local.yml.erb b/cookbooks/hardware/templates/default/ipmi_local.yml.erb
new file mode 100644 (file)
index 0000000..b6ebbd6
--- /dev/null
@@ -0,0 +1,18 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+modules:
+  default:
+    collectors:
+      - bmc
+      - ipmi
+      - dcmi
+      - chassis
+    custom_args:
+      ipmi:
+<% node[:hardware][:ipmi][:custom_args].each do |arg| -%>
+        - <%= arg %>
+<% end -%>
+    exclude_sensor_ids:
+<% node[:hardware][:ipmi][:excluded_sensors].each do |sensor| -%>
+      - <%= sensor %>
+<% end -%>
diff --git a/cookbooks/hardware/templates/default/irqbalance.erb b/cookbooks/hardware/templates/default/irqbalance.erb
deleted file mode 100644 (file)
index 4a10bd2..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-# Configuration for the irqbalance daemon
-
-# Should irqbalance be enabled?
-ENABLED="1"
-# Balance the IRQs only once?
-ONESHOT="0"
-
-# irqbalance maintainer recommends ignore hint policy
-# http://sourceforge.net/p/e1000/bugs/394/?page=1
-DOPTIONS="--hintpolicy=ignore"
diff --git a/cookbooks/hardware/templates/default/lldp.rb.erb b/cookbooks/hardware/templates/default/lldp.rb.erb
new file mode 100644 (file)
index 0000000..fb8d8cf
--- /dev/null
@@ -0,0 +1,25 @@
+require "json"
+
+Ohai.plugin(:Lldp) do
+  provides "lldp"
+
+  collect_data(:default) do
+    lldp Mash.new
+
+    json = JSON.parse(%x(/usr/sbin/lldpctl -f json))
+
+    interfaces = if json["lldp"]["interface"].is_a?(Array)
+                   json["lldp"]["interface"]
+                 else
+                   [json["lldp"]["interface"]]
+                 end
+
+    interfaces.each do |interface|
+      interface.each do |name, details|
+        lldp[name] = details
+      end
+    end
+
+    lldp
+  end
+end
diff --git a/cookbooks/hardware/templates/default/mcelog-trigger.erb b/cookbooks/hardware/templates/default/mcelog-trigger.erb
deleted file mode 100644 (file)
index 463b390..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-echo "$MESSAGE" | /usr/bin/mail -s "Machine Check Exception for <%= node[:fqdn] %>" admins@openstreetmap.org
diff --git a/cookbooks/hardware/templates/default/modules.erb b/cookbooks/hardware/templates/default/modules.erb
deleted file mode 100644 (file)
index 9ba59d2..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<% node[:hardware][:modules].each do |m| -%>
-<%= m %>
-<% end -%>
diff --git a/cookbooks/hardware/templates/default/munin.hddtemp.erb b/cookbooks/hardware/templates/default/munin.hddtemp.erb
deleted file mode 100644 (file)
index 9d5e495..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[hddtemp_smartctl]
-env.drives <%= @disks.map { |d| d[:hddtemp] }.sort.join(" ") %>
-<% @disks.sort_by { |d| d[:hddtemp] }.each do |disk| -%>
-<% if disk[:smart] -%>
-env.type_<%= disk[:hddtemp] %> <%= disk[:smart] %>
-<% end -%>
-env.dev_<%= disk[:hddtemp] %> <%= disk[:device] %>
-<% end -%>
diff --git a/cookbooks/hardware/templates/default/munin.smart.erb b/cookbooks/hardware/templates/default/munin.smart.erb
deleted file mode 100644 (file)
index 1908f8e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[smart_<%= @disk[:munin] %>]
-<% if @disk[:smart] -%>
-env.smartargs -H -d <%= @disk[:smart] %>
-<% else -%>
-env.smartargs -H
-<% end -%>
-env.ignoreexit 4
index 82194acf29769c5cbd7405c81c4d8107505e5898..1ca3089b78b4ed4a66020b43886e1dc547f1508a 100644 (file)
@@ -155,7 +155,7 @@ Ohai.plugin(:Hardware) do
     find_adaptec_disks(disk) if File.exist?("/usr/sbin/arcconf")
     find_areca_disks(disk) if File.exist?("/opt/areca/x86_64/cli64")
 
-    find_md_arrays(disk)
+    find_md_arrays(disk) if File.exist?("/prod/mdstat")
 
     disk[:disks].each do |disk|
       if disk[:vendor] =~ /^(BTWA|CVPR|PHDV)/ && disk[:model] == "INTEL"
@@ -256,24 +256,44 @@ Ohai.plugin(:Hardware) do
     array = nil
 
     File.new("/proc/mdstat", "r").each do |line|
-      if line =~ /^(md\d+) : active raid(\d+)((?: (?:sd[a-z]|nvme\d+n\d+)\d*\[\d+\](?:\([A-Z]\))*)+)$/
+      if line =~ /^(md\d+) : active raid(\d+)((?: (?:sd[a-z]\d*|nvme\d+n\d+(?:p\d+)?)\[\d+\](?:\([A-Z]\))*)+)$/
         array = {
           :id => devices[:arrays].count,
           :device => "/dev/#{Regexp.last_match(1)}",
+          :status => "optimal",
           :raid_level => Regexp.last_match(2),
           :disks => []
         }
 
-        Regexp.last_match(3).scan(/ (sd[a-z]+|nvme\d+n\d+)\d*\[\d+\](?:\([A-Z]\))*/).flatten.each do |device|
-          if disk = devices[:disks].find { |d| d[:device] == "/dev/#{device}" }
-            disk[:arrays] << array[:id]
-            array[:disks] << disk[:id]
+        Regexp.last_match(3).split(" ").each do |member|
+          if member =~ /^(sd[a-z]+|nvme\d+n\d+).*/
+            device = Regexp.last_match(1)
+
+            if disk = devices[:disks].find { |d| d[:device] == "/dev/#{device}" }
+              if member =~ /\(F\)/
+                disk[:status] = "failed"
+              elsif member =~ /\(S\)/
+                disk[:status] = "hotspare"
+              else
+                disk[:status] = "online"
+              end
+
+              disk[:arrays] << array[:id]
+              array[:disks] << disk[:id]
+            end
           end
         end
 
         devices[:arrays] << array
-      elsif array && line =~ /^\s+(\d+) blocks/
+      elsif array && line =~ /^\s+(\d+) blocks.*(?:\[([U_]+)\])?/
         array[:size] = format_disk_size(Regexp.last_match(1).to_i)
+        array[:status] = "degraded" if Regexp.last_match(2) =~ /_/
+      elsif array && line =~ /^\s+\[.*\]\s+(\S+)\s+=/
+        case Regexp.last_match(1)
+        when "recovery" then array[:status] = "rebuilding"
+        when "resync" then array[:status] = "rebuilding"
+        when "checking" then array[:status] = "checking"
+        end
       end
     end
   end
@@ -287,9 +307,12 @@ Ohai.plugin(:Hardware) do
     disk = nil
 
     IO.popen(%w(ssacli controller all show config detail)).each do |line|
-      if line =~ /^Smart Array (\S+) /
+      next unless line.valid_encoding?
+
+      if line =~ /^Smart (?:Array|HBA) (\S+) /
         controller = {
           :id => devices[:controllers].count,
+          :type => "hp",
           :model => Regexp.last_match(1),
           :arrays => [],
           :disks => []
@@ -303,10 +326,12 @@ Ohai.plugin(:Hardware) do
         disk = nil
       elsif controller && line =~ /^   (\S.*):\s+(.*)$/
         case Regexp.last_match(1)
+        when "Slot" then controller[:slot] = Regexp.last_match(2)
         when "Serial Number" then controller[:serial_number] = Regexp.last_match(2)
         when "Hardware Revision" then controller[:hardware_version] = Regexp.last_match(2)
         when "Firmware Version" then controller[:firmware_version] = Regexp.last_match(2)
         when "PCI Address (Domain:Bus:Device.Function)" then controller[:pci_slot] = Regexp.last_match(2)
+        when "Battery/Capacitor Status" then controller[:battery_status] = Regexp.last_match(2).split.first.downcase
         end
       elsif controller && line =~ /^      Logical Drive: (\d+)$/
         array = {
@@ -320,15 +345,12 @@ Ohai.plugin(:Hardware) do
         controller[:arrays] << array[:id]
 
         disk = nil
-      elsif controller && line =~ /^      physicaldrive (\S+) /
-        disks << Regexp.last_match(1)
       elsif array && line =~ /^      physicaldrive (\S+)$/
         disk = {
           :id => devices[:disks].count,
           :controller => controller[:id],
           :arrays => [array[:id]],
-          :location => Regexp.last_match(1),
-          :smart_device => "cciss,#{disks.find_index(Regexp.last_match(1))}"
+          :location => Regexp.last_match(1)
         }
 
         devices[:disks] << disk
@@ -336,6 +358,8 @@ Ohai.plugin(:Hardware) do
         array[:disks] << disk[:id]
       elsif disk && line =~ /^         (\S[^:]+):\s+(.*\S)\s*$/
         case Regexp.last_match(1)
+        when "Status" then disk[:status] = Regexp.last_match(2)
+        when "Drive Type" then disk[:drive_type] = Regexp.last_match(2)
         when "Interface Type" then disk[:interface] = Regexp.last_match(2)
         when "Size" then disk[:size] = Regexp.last_match(2)
         when "Rotational Speed" then disk[:rpm] = Regexp.last_match(2)
@@ -343,10 +367,17 @@ Ohai.plugin(:Hardware) do
         when "Serial Number" then disk[:serial_number] = Regexp.last_match(2)
         when "Model" then disk[:model] = Regexp.last_match(2)
         end
+      elsif array && line =~ /^         Status:\s+(.*\S)\s*$/
+        case Regexp.last_match(1)
+        when "OK" then array[:status] = "optimal"
+        when "Interim Recovery Mode" then array[:status] = "degraded"
+        else array[:status] = "unknown"
+        end
       elsif array && line =~ /^         (\S[^:]+):\s+(.*\S)\s*$/
         case Regexp.last_match(1)
         when "Size" then array[:size] = Regexp.last_match(2)
         when "Fault Tolerance" then array[:raid_level] = Regexp.last_match(2)
+        when "Status" then array[:status] = Regexp.last_match(2)
         when "Disk Name" then array[:device] = Regexp.last_match(2).strip
         when "Mount Points" then array[:mount_point] = Regexp.last_match(2).split.first
         when "Unique Identifier" then array[:wwn] = Regexp.last_match(2)
@@ -355,6 +386,14 @@ Ohai.plugin(:Hardware) do
     end
 
     controllers.each do |controller|
+      slot = controller[:slot]
+
+      IO.popen(%W(ssacli controller slot=#{slot} pd all show status)).each do |line|
+        if line =~ /^   physicaldrive (\S+) /
+          disks << Regexp.last_match(1)
+        end
+      end
+
       if device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/cciss*").first
         controller[:device] = File.basename(device).sub(/^cciss(\d+)$/, "/dev/cciss/c\\1d0")
       elsif device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target*:3:0/*:3:0:0/scsi_generic/sg*").first
@@ -363,11 +402,36 @@ Ohai.plugin(:Hardware) do
         controller[:device] = "/dev/#{File.basename(device)}"
       end
     end
+
+    devices[:disks].each do |disk|
+      controller = disk[:controller]
+
+      next unless devices[:controllers][controller][:type] == "hp"
+
+      disk[:smart_device] = "cciss,#{disks.find_index(disk[:location])}"
+
+      if disk[:status] == "Failed"
+        disk[:status] = "failed"
+      elsif disk[:status] == "Predictive Failure"
+        disk[:status] = "failed"
+      elsif disk[:status] == "OK" && disk[:drive_type] == "Data Drive"
+        disk[:status] = "online"
+      elsif disk[:status] == "OK" && disk[:drive_type] == "Spare Drive"
+        disk[:status] = "hotspare"
+      elsif disk[:drive_type] == "Unassigned Drive"
+        disk[:status] = "unconfigured"
+      else
+        disk[:status] = "unknown"
+      end
+
+      disk.delete(:drive_type)
+    end
   end
 
   def find_megaraid_disks(devices)
     controllers = []
     arrays = []
+    disks = []
 
     controller = nil
     array = nil
@@ -377,6 +441,7 @@ Ohai.plugin(:Hardware) do
       if line =~ /^PCI information for Controller (\d+)$/
         controller = {
           :id => devices[:controllers].count,
+          :type => "megaraid",
           :arrays => [],
           :disks => []
         }
@@ -384,11 +449,11 @@ Ohai.plugin(:Hardware) do
         devices[:controllers] << controller
 
         controllers << controller
-      elsif line =~ /^Bus Number\s+:\s+(\d+)$/
+      elsif line =~ /^Bus Number\s+:\s+([0-9a-f]+)$/i
         controller[:pci_slot] = format "0000:%02x", Integer("0x#{Regexp.last_match(1)}")
-      elsif line =~ /^Device Number\s+:\s+(\d+)$/
+      elsif line =~ /^Device Number\s+:\s+([0-9a-f]+)$/i
         controller[:pci_slot] = format "%s:%02x", controller[:pci_slot], Integer("0x#{Regexp.last_match(1)}")
-      elsif line =~ /^Function Number\s+:\s+(\d+)$/
+      elsif line =~ /^Function Number\s+:\s+([0-9a-f]+)$/i
         controller[:pci_slot] = format "%s.%01x", controller[:pci_slot], Integer("0x#{Regexp.last_match(1)}")
       end
     end
@@ -437,25 +502,45 @@ Ohai.plugin(:Hardware) do
         devices[:disks] << disk
         controller[:disks] << disk[:id]
         array[:disks] << disk[:id]
-      elsif disk && line =~ /^Firmware state:\s+(.*\S)\s*$/
-        Regexp.last_match(1).split(/,\s*/).each do |state|
-          case state
-          when "Unconfigured(bad)" then disk[:status] = "unconfigured"
-          when "Online" then disk[:status] = "online"
-          when "Hotspare" then disk[:status] = "hotspare"
-          when "Failed" then disk[:status] = "failed"
-          when "Spun Up" then disk[:state] = "spun_up"
-          when "Spun down" then disk[:state] = "spun_down"
-          end
+
+        disks << disk
+      elsif disk && line =~ /^Firmware state:\s+(\S.*)$/
+        status, state = Regexp.last_match(1).split(/,\s*/)
+        case status
+        when "Unconfigured(good)" then disk[:status] = "unconfigured"
+        when "Unconfigured(bad)" then disk[:status] = "unconfigured"
+        when "Hotspare" then disk[:status] = "hotspare"
+        when "Offline" then disk[:status] = "offline"
+        when "Online" then disk[:status] = "online"
+        when "Rebuild" then disk[:status] = "rebuilding"
+        when "Failed" then disk[:status] = "failed"
+        when "Copyback" then disk[:status] = "rebuilding"
+        else disk[:status] = "unknown"
+        end
+        case state
+        when "Spun Up" then disk[:state] = "spun_up"
+        when "Spun down" then disk[:state] = "spun_down"
+        else disk[:state] = "unknown"
         end
       elsif disk && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
-        when "Device Id" then disk[:smart_device] = "megaraid,#{Regexp.last_match(2)}"
+        when "Device Id" then disk[:device_id] = Regexp.last_match(2)
         when "WWN" then disk[:wwn] = Regexp.last_match(2)
         when "PD Type" then disk[:interface] = Regexp.last_match(2)
         when "Raw Size" then disk[:size] = memory_to_disk_size(Regexp.last_match(2).sub(/\s*\[.*\]$/, ""))
         when "Inquiry Data" then disk[:vendor], disk[:model], disk[:serial_number] = Regexp.last_match(2).split
         end
+      elsif array && line =~ /^State\s*:\s+(.*\S)\s*$/
+        case Regexp.last_match(1)
+        when "Partially Degraded" then array[:status] = "degraded"
+        when "Degraded" then array[:status] = "degraded"
+        when "Optimal" then array[:status] = "optimal"
+        when "Consistency Check" then array[:status] = "checking"
+        when "Background Initialization" then array[:status] = "initialising"
+        when "Initialization" then array[:status] = "initialising"
+        when "Reconstruction" then array[:status] = "rebuilding"
+        else array[:status] = "unknown"
+        end
       elsif array && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
         when "RAID Level" then array[:raid_level] = Regexp.last_match(2).scan(/Primary-(\d+)/).first.first
@@ -469,7 +554,8 @@ Ohai.plugin(:Hardware) do
         controller = controllers[Regexp.last_match(1).to_i]
       elsif controller && line =~ /^Enclosure Device ID: \d+$/
         disk = {
-          :controller => controller[:id]
+          :controller => controller[:id],
+          :arrays => []
         }
       elsif disk && line =~ /^WWN:\s+(\S+)$/
         unless devices[:disks].find { |d| d[:wwn] == Regexp.last_match(1) }
@@ -477,21 +563,30 @@ Ohai.plugin(:Hardware) do
           disk[:wwn] = Regexp.last_match(1)
 
           devices[:disks] << disk
+
+          disks << disk
         end
-      elsif disk && line =~ /^Firmware state:\s+(.*\S)\s*$/
-        Regexp.last_match(1).split(/,\s*/).each do |state|
-          case state
-          when "Unconfigured(bad)" then disk[:status] = "unconfigured"
-          when "Online" then disk[:status] = "online"
-          when "Hotspare" then disk[:status] = "hotspare"
-          when "Failed" then disk[:status] = "failed"
-          when "Spun Up" then disk[:state] = "spun_up"
-          when "Spun down" then disk[:state] = "spun_down"
-          end
+      elsif disk && line =~ /^Firmware state:\s+(\S.*)$/
+        status, state = Regexp.last_match(1).split(/,\s*/)
+        case status
+        when "Unconfigured(good)" then disk[:status] = "unconfigured"
+        when "Unconfigured(bad)" then disk[:status] = "unconfigured"
+        when "Hotspare" then disk[:status] = "hotspare"
+        when "Offline" then disk[:status] = "offline"
+        when "Online" then disk[:status] = "online"
+        when "Rebuild" then disk[:status] = "rebuilding"
+        when "Failed" then disk[:status] = "failed"
+        when "Copyback" then disk[:status] = "rebuilding"
+        else disk[:status] = "unknown"
+        end
+        case state
+        when "Spun Up" then disk[:state] = "spun_up"
+        when "Spun down" then disk[:state] = "spun_down"
+        else disk[:state] = "unknown"
         end
       elsif disk && line =~ /^(\S.*\S)\s*:\s+(\S.*)$/
         case Regexp.last_match(1)
-        when "Device Id" then disk[:smart_device] = "megaraid,#{Regexp.last_match(2)}"
+        when "Device Id" then disk[:device_id] = Regexp.last_match(2)
         when "PD Type" then disk[:interface] = Regexp.last_match(2)
         when "Raw Size" then disk[:size] = memory_to_disk_size(Regexp.last_match(2).sub(/\s*\[.*\]$/, ""))
         when "Inquiry Data" then disk[:vendor], disk[:model], disk[:serial_number] = Regexp.last_match(2).split
@@ -504,6 +599,18 @@ Ohai.plugin(:Hardware) do
         controller[:device] = "/dev/#{File.basename(device)}"
       end
     end
+
+    disks.each do |disk|
+      controller = devices[:controllers][disk[:controller]]
+
+      if id = disk.delete(:device_id)
+        if device = Dir.glob("/sys/bus/pci/devices/#{controller[:pci_slot]}/host*/target0:0:#{id}/0:0:#{id}:0/block/sd*").first
+          disk[:device] = "/dev/#{File.basename(device)}"
+        else
+          disk[:smart_device] = "megaraid,#{id}"
+        end
+      end
+    end
   end
 
   def find_mpt1_disks(devices)
@@ -516,6 +623,7 @@ Ohai.plugin(:Hardware) do
       if line =~ /^\/proc\/mpt\/ioc(\d+)\s+LSI Logic\s+(\S+)\s+/
         controller = {
           :id => devices[:controllers].count,
+          :type => "mpt1",
           :model => Regexp.last_match(1),
           :arrays => [],
           :disks => []
@@ -592,6 +700,7 @@ Ohai.plugin(:Hardware) do
       next unless line =~ /^\s+(\d+)\s+(\S+)\s+\h+h\s+\h+h\s+(\S+)\s+\h+h\s+\h+h\s*$/
       controllers[Regexp.last_match(1).to_i] = {
         :id => devices[:controllers].count,
+        :type => "mpt2",
         :model => Regexp.last_match(2),
         :pci_slot => Regexp.last_match(3).sub(/^(\h{2})h:(\h{2})h:(\h{2})h:0(\h)h$/, "00\\1:\\2:\\3.\\4"),
         :arrays => [],
@@ -632,6 +741,23 @@ Ohai.plugin(:Hardware) do
           controller[:disks] << disk[:id]
 
           disks << disk
+        elsif disk && line =~ /^  State\s+:\s+(.*\S)\s*$/
+          Regexp.last_match(1).split(/,\s*/).each do |state|
+            case state
+            when "Online (ONL)" then disk[:status] = "online"
+            when "Hot Spare (HSP)" then disk[:status] = "hotspare"
+            when "Ready (RDY)" then disk[:status] = "unconfigured"
+            when "Available (AVL)" then disk[:status] = "unconfigured"
+            when "Failed (FLD)" then disk[:status] = "failed"
+            when "Missing (MIS)" then disk[:status] = "missing"
+            when "Standby (SBY)" then disk[:status] = "unconfigured"
+            when "Out of Sync (OSY)" then disk[:status] = "degraded"
+            when "Degraded (DGD)" then disk[:status] = "degraded"
+            when "Rebuilding (RBLD)" then disk[:status] = "rebuilding"
+            when "Optimal (OPT)" then disk[:status] = "online"
+            else disk[:status] = "unknown"
+            end
+          end
         elsif disk && line =~ /^  (\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Enclosure #" then disk[:location] = Regexp.last_match(2)
@@ -646,6 +772,18 @@ Ohai.plugin(:Hardware) do
           end
         elsif array && line =~ /^  PHY\[\d+\] Enclosure#\/Slot#\s+:\s+(\d+:\d+)\s*$/
           array[:disks] << Regexp.last_match(1)
+        elsif array && line =~ /^  Status of volume\s+:\s+(.*\S)\s*$/
+          Regexp.last_match(1).split(/,\s*/).each do |state|
+            case state
+            when "Okay (OKY)" then array[:status] = "optimal"
+            when "Degraded (DGD)" then array[:status] = "degraded"
+            when "Failed (FLD)" then array[:status] = "failed"
+            when "Missing (MIS)" then array[:status] = "missing"
+            when "Initializing (INIT)" then array[:status] = "initialising"
+            when "Online (ONL)" then array[:status] = "optimal"
+            else array[:status] = "unknown"
+            end
+          end
         elsif array && line =~ /^  (\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Volume wwid" then array[:device] = find_sas_device(Regexp.last_match(2))
@@ -678,6 +816,7 @@ Ohai.plugin(:Hardware) do
       controller = {
         :id => devices[:controllers].count,
         :number => controller_number,
+        :type => "adaptec",
         :arrays => [],
         :disks => []
       }
@@ -719,6 +858,16 @@ Ohai.plugin(:Hardware) do
         elsif disk && line =~ /^         Reported Channel,Device\(T:L\)\s*:\s+(\d+),(\d+)\(\d+:0\)\s*$/
           disk[:channel_number] = Regexp.last_match(1)
           disk[:device_number] = Regexp.last_match(2)
+        elsif disk && line =~ /^         State\s*:\s+(\S.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "Online" then disk[:status] = "online"
+          when "Online (JBOD)" then disk[:status] = "online"
+          when "Hot Spare" then disk[:status] = "hotspare"
+          when "Ready" then disk[:status] = "unconfigured"
+          when "Global Hot-Spare" then disk[:status] = "hostspare"
+          when "Dedicated Hot-Spare" then disk[:status] = "hotspare"
+          else disk[:status] = "unknown"
+        end
         elsif disk && line =~ /^         (\S.*\S)\s*:\s+(\S.*\S)\s*$/
           case Regexp.last_match(1)
           when "Reported Location" then disk[:location] = Regexp.last_match(2)
@@ -734,6 +883,11 @@ Ohai.plugin(:Hardware) do
           end
         elsif array && line =~ / Present \(.*((?:Connector|Enclosure):\d+,\s*(?:Device|Slot):\d+)\) /
           array[:disks] << Regexp.last_match(1).tr(":", " ").gsub(/,\s*/, ", ")
+        elsif array && line =~ /^   Status of Logical Device\s*:\s+(\S.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "Optimal" then array[:status] = "optimal"
+          else array[:status] = "unknown"
+        end
         elsif array && line =~ /^   (\S.*\S)\s*:\s+(\S.*\S)\s*$/
           case Regexp.last_match(1)
           when "RAID level" then array[:raid_level] = Regexp.last_match(2)
@@ -766,10 +920,11 @@ Ohai.plugin(:Hardware) do
         array[:disks].map! do |location|
           disk = disks.find { |disk| disk[:location] == location }
 
+          controller_number = controller[:number] - 1
           device_number = disk[:device_number]
-          device = Dir.glob("#{host}/device/target*:1:#{device_number}/*:1:#{device_number}:0/scsi_generic/*").first
 
           disk[:device] = "/dev/#{File.basename(device)}"
+          disk[:smart_device] = "aacraid,#{controller_number},0,#{device_number}"
 
           disk[:arrays] << array[:id]
           disk[:id]
@@ -781,6 +936,7 @@ Ohai.plugin(:Hardware) do
   def find_areca_disks(devices)
     controller = {
       :id => devices[:controllers].count,
+      :type => "areca",
       :arrays => [],
       :disks => []
     }
@@ -833,6 +989,11 @@ Ohai.plugin(:Hardware) do
           device = Dir.glob("/sys/bus/pci/devices/#{pci_slot}/host*/target*:0:0/0:#{channel}:#{id}:#{lun}/block/*").first
 
           array[:device] = "/dev/#{File.basename(device)}"
+        elsif line =~ /^Volume State\s+:\s+(.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "Normal" then array[:status] = "optimal"
+          else array[:status] = "unknown"
+          end
         elsif line =~ /^(\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Volume Set Name" then array[:volume_set] = Regexp.last_match(2)
@@ -874,6 +1035,11 @@ Ohai.plugin(:Hardware) do
           disk[:smart_device] = "areca,#{Regexp.last_match(1)}"
         elsif line =~ /^Device Location\s+:\s+Enclosure#(\d+) Slot#?\s*0*(\d+)\s*$/i
           disk[:smart_device] = "areca,#{Regexp.last_match(2)}/#{Regexp.last_match(1)}"
+        elsif line =~ /^Device State\s+:\s+(.*\S)\s*$/
+          case Regexp.last_match(1)
+          when "NORMAL" then disk[:status] = "online"
+          else disk[:status] = "unknown"
+          end
         elsif line =~ /^(\S.*\S)\s+:\s+(.*\S)\s*$/
           case Regexp.last_match(1)
           when "Model Name" then disk[:vendor], disk[:model] = Regexp.last_match(2).split
diff --git a/cookbooks/hardware/templates/default/raid.default.erb b/cookbooks/hardware/templates/default/raid.default.erb
deleted file mode 100644 (file)
index fb9bd31..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-MAILTO="admins@openstreetmap.org"
-REMIND="86400"
-<% unless @devices.empty? -%>
-ID="<%= @devices.sort.uniq.map { |d| "/dev/#{d}" }.join(" ") %>"
-<% end -%>
diff --git a/cookbooks/hardware/templates/default/smart.devices.erb b/cookbooks/hardware/templates/default/smart.devices.erb
new file mode 100644 (file)
index 0000000..8b13ba6
--- /dev/null
@@ -0,0 +1,9 @@
+<% @disks.each do |disk| -%>
+<% if disk[:smart] -%>
+/dev/<%= disk[:device] %>|<%= disk[:smart] %>
+<% elsif disk[:device] =~ /nvme/ -%>
+/dev/<%= disk[:device] %>|nvme
+<% else -%>
+/dev/<%= disk[:device] %>|auto
+<% end -%>
+<% end -%>
diff --git a/cookbooks/hardware/templates/default/update-smart-drivedb.erb b/cookbooks/hardware/templates/default/update-smart-drivedb.erb
new file mode 100644 (file)
index 0000000..5093be8
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+# DO NOT EDIT - This file is being maintained by Chef
+
+set -eu
+
+if [ -x /usr/sbin/update-smart-drivedb ]; then
+  /usr/sbin/update-smart-drivedb -u github > /dev/null
+fi
+
+exit 0
similarity index 61%
rename from cookbooks/munin/templates/default/if.erb
rename to cookbooks/hardware/templates/default/watchdog.conf.erb
index 1f36d5042f877f0fbdf34487ed8b4738bfe353a9..187622f31cb077967c6ebbf73a273d377fe32034 100644 (file)
@@ -1,4 +1,4 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-[if_<%= @ifname %>]
-env.speed 1000
+[Manager]
+RuntimeWatchdogSec=60s
diff --git a/cookbooks/hardware/templates/default/watchdog.erb b/cookbooks/hardware/templates/default/watchdog.erb
deleted file mode 100644 (file)
index afeef44..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Start watchdog at boot time? 0 or 1
-run_watchdog=1
-# Load module before starting watchdog
-watchdog_module="<%= @module %>"
-# Specify additional watchdog options here (see manpage).
index 118521e91159cf98a553da1a4fa233b8eb5bbe3e..9f689b2f766774f5650bf6012c80868748086e8e 100644 (file)
@@ -6,4 +6,4 @@ description       "Configures hot web site"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "apache"
+depends           "podman"
index b4d31692309c5aef2139b7f3d3dc81005894e0eb..8f12dc193badc0d1e8a5e6d86e255fe3d9f66a55 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "apache"
+include_recipe "podman::apache"
 
-ssl_certificate "hot.openstreetmap.org" do
-  domains ["hot.openstreetmap.org", "hot.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "hot.openstreetmap.org" do
-  template "apache.erb"
+podman_site "hot.openstreetmap.org" do
+  image "ghcr.io/openstreetmap/hot.openstreetmap.org-website:latest"
+  aliases ["hot.osm.org"]
 end
diff --git a/cookbooks/hot/templates/default/apache.erb b/cookbooks/hot/templates/default/apache.erb
deleted file mode 100644 (file)
index 71682aa..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:80>
-   ServerName hot.openstreetmap.org
-   ServerAlias hot.osm.org
-   ServerAdmin webmaster@openstreetmap.org
-
-   CustomLog /var/log/apache2/hot.openstreetmap.org-access.log combined
-   ErrorLog /var/log/apache2/hot.openstreetmap.org-error.log
-
-   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-   RedirectPermanent / https://www.hotosm.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-   ServerName hot.openstreetmap.org
-   ServerAlias hot.osm.org
-   ServerAdmin webmaster@openstreetmap.org
-
-   CustomLog /var/log/apache2/hot.openstreetmap.org-access.log combined
-   ErrorLog /var/log/apache2/hot.openstreetmap.org-error.log
-
-   SSLEngine on
-   SSLCertificateFile /etc/ssl/certs/hot.openstreetmap.org.pem
-   SSLCertificateKeyFile /etc/ssl/private/hot.openstreetmap.org.key
-
-   RedirectPermanent / https://www.hotosm.org/
-</VirtualHost>
similarity index 62%
rename from cookbooks/incron/metadata.rb
rename to cookbooks/ideditor/metadata.rb
index b2ab67863a94e98440dac26c6ac3e58a2942b0e1..dc3b802110ba9ca11201a90b399f302e79998991 100644 (file)
@@ -1,8 +1,9 @@
-name              "incron"
+name              "ideditor"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Configures incron"
+description       "Configures ideditor.com web site"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "podman"
diff --git a/cookbooks/ideditor/recipes/default.rb b/cookbooks/ideditor/recipes/default.rb
new file mode 100644 (file)
index 0000000..753ac12
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# Cookbook:: ideditor
+# Recipe:: default
+#
+# Copyright:: 2022, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "podman::apache"
+
+podman_site "preview.ideditor.com" do
+  image "ghcr.io/openstreetmap/preview.ideditor.com-website:latest"
+end
diff --git a/cookbooks/imagery/files/default/os-openmap-local-palette.txt b/cookbooks/imagery/files/default/os-openmap-local-palette.txt
new file mode 100644 (file)
index 0000000..deb8359
--- /dev/null
@@ -0,0 +1,256 @@
+0,0,0
+8,7,7
+24,24,24
+40,40,40
+52,52,52
+85,15,45
+49,83,63
+73,66,53
+61,61,72
+89,88,72
+80,80,80
+87,87,87
+112,83,88
+108,105,87
+87,88,104
+84,111,108
+100,100,100
+105,104,104
+120,120,118
+215,18,54
+148,105,35
+157,113,51
+216,120,19
+136,24,72
+189,38,104
+212,28,64
+216,47,79
+145,120,84
+142,96,102
+138,122,104
+138,120,120
+165,111,122
+217,69,74
+227,85,116
+63,143,54
+8,166,34
+0,166,41
+9,179,51
+55,148,82
+43,179,82
+76,132,88
+76,153,84
+97,170,90
+95,139,107
+121,159,121
+106,160,110
+124,184,117
+55,195,91
+54,200,88
+82,199,111
+152,152,8
+214,133,34
+225,151,59
+200,201,8
+243,243,0
+248,248,8
+174,140,87
+144,157,102
+136,136,120
+153,136,120
+136,158,120
+152,152,120
+162,136,104
+183,151,106
+187,184,104
+240,162,67
+201,155,102
+221,165,123
+226,173,102
+233,184,127
+146,204,109
+255,192,115
+248,200,120
+73,81,199
+255,60,140
+192,115,130
+235,101,128
+229,111,139
+0,159,184
+40,152,172
+69,135,144
+127,154,155
+92,167,180
+25,194,164
+120,214,142
+9,151,200
+0,154,207
+0,169,202
+14,170,200
+6,177,202
+24,161,216
+24,184,217
+45,168,210
+50,185,213
+0,191,230
+41,184,232
+75,184,213
+39,200,232
+81,201,215
+109,199,214
+115,216,212
+80,213,232
+85,216,248
+113,214,236
+117,232,248
+136,136,136
+153,136,136
+133,153,136
+152,152,136
+128,136,153
+152,136,152
+154,154,144
+152,152,152
+168,152,136
+185,150,136
+168,136,152
+185,135,153
+168,152,152
+184,152,152
+151,168,150
+157,191,153
+168,168,136
+184,168,136
+184,184,136
+168,168,152
+184,168,152
+184,184,152
+151,152,170
+171,152,171
+145,172,172
+167,167,167
+184,168,168
+168,188,168
+178,184,173
+184,184,168
+168,168,184
+185,167,184
+166,185,185
+183,184,183
+210,141,149
+255,135,158
+247,136,152
+200,168,132
+200,185,136
+216,191,128
+200,168,152
+199,184,152
+217,184,152
+210,145,169
+248,137,168
+232,154,167
+208,184,168
+242,166,184
+248,185,184
+141,193,137
+164,217,148
+189,220,165
+188,219,184
+158,225,175
+208,204,152
+242,200,145
+246,233,151
+200,200,168
+215,199,168
+216,216,168
+200,200,184
+216,200,184
+216,216,184
+232,200,168
+248,195,168
+232,216,168
+248,216,165
+232,200,184
+231,215,183
+248,216,184
+208,235,184
+232,232,168
+248,232,168
+228,248,168
+248,248,168
+232,232,184
+250,223,191
+252,225,189
+248,232,184
+232,248,184
+255,243,181
+247,247,184
+184,184,200
+248,182,201
+143,214,209
+181,207,204
+149,232,214
+179,232,204
+142,216,234
+169,216,226
+146,232,247
+176,232,242
+199,199,199
+216,200,200
+200,216,200
+216,216,200
+200,200,216
+217,200,216
+200,216,216
+216,216,216
+243,212,207
+200,232,200
+216,232,200
+200,248,200
+208,239,207
+209,241,205
+216,248,200
+200,232,216
+216,232,216
+200,248,216
+215,247,222
+216,247,216
+232,232,200
+251,232,201
+232,248,200
+248,248,200
+232,232,216
+248,232,216
+252,235,217
+232,248,216
+248,248,216
+216,216,232
+232,216,232
+247,215,229
+200,232,232
+216,232,232
+199,248,232
+216,248,232
+194,229,240
+200,232,248
+216,232,248
+199,248,248
+213,244,248
+212,244,250
+216,247,247
+230,235,228
+229,231,231
+232,232,232
+234,234,234
+248,232,232
+231,247,231
+247,247,232
+232,232,248
+248,232,248
+231,247,247
+252,252,252
+249,249,247
+254,254,254
+252,252,254
+255,255,255
+255,255,255
index 9b091a89ec45820010b2572405b716612b443376..85dbc657c664365f3dcc24d88f2cd3cda46056ef 100644 (file)
@@ -6,7 +6,9 @@ description       "Installs and configures imagery"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "nginx"
+depends           "accounts"
 depends           "git"
-depends           "systemd"
+depends           "nginx"
+depends           "podman"
 depends           "ssl"
+depends           "systemd"
index 13a7f915b8e62d08c2fba5e7f0544beec879af5d..9cf0692f2a6244acd9f6c86bd9bc4adb7b846395 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "nginx"
 include_recipe "git"
 
-# Imagery gdal Requirements
+# Imagery gdal and proj requirements
 package %w[
   gdal-bin
-  python-gdal
+  python3-gdal
+  proj-bin
 ]
 
-# Imagery MapServer + Mapcache Requirements
+# Imagery MapServer + Mapcache requirements
 package %w[
   cgi-mapserver
   mapcache-cgi
   mapcache-tools
 ]
 
-# Mapserver via Nginx requires as fastcgi spawner
+# Mapserver via nginx requires as fastcgi spawner
 package %w[
   spawn-fcgi
   multiwatch
@@ -51,45 +53,32 @@ package %w[
 directory "/srv/imagery/mapserver" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   recursive true
 end
 
 directory "/srv/imagery/common" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   recursive true
 end
 
-directory "/srv/imagery/common/ostn02-ntv2-data" do
-  owner "root"
-  group "root"
-  mode 0o755
-end
-
-remote_file "#{Chef::Config[:file_cache_path]}/ostn02-ntv2-data.zip" do
-  source "https://www.ordnancesurvey.co.uk/docs/gps/ostn02-ntv2-data.zip"
-  not_if { File.exist?("/srv/imagery/common/ostn02-ntv2-data/OSTN02_NTv2.gsb") }
+# Pre-download uk_os_OSTN15_NTv2_OSGBtoETRS.tif used for EPSG:27700 conversions
+execute "uk_os_OSTN15_NTv2_OSGBtoETRS.tif" do
+  command "projsync --file uk_os_OSTN15_NTv2_OSGBtoETRS.tif --system-directory"
+  not_if { ::File.exist?("/usr/share/proj/uk_os_OSTN15_NTv2_OSGBtoETRS.tif") }
 end
 
-execute "unzip-ostn02-ntv2-data" do
-  command "unzip -q #{Chef::Config[:file_cache_path]}/ostn02-ntv2-data.zip"
-  cwd "/srv/imagery/common/ostn02-ntv2-data"
-  user "root"
-  group "root"
-  not_if { File.exist?("/srv/imagery/common/ostn02-ntv2-data/OSTN02_NTv2.gsb") }
-end
-
-nginx_site "default" do
-  template "nginx_default.conf.erb"
-  directory "/srv/imagery/default"
-  restart_nginx false
-end
+# nginx_site "default" do
+#   template "nginx_default.conf.erb"
+#   directory "/srv/imagery/default"
+# end
 
 systemd_tmpfile "/run/mapserver-fastcgi" do
   type "d"
   owner "imagery"
   group "imagery"
   mode "0755"
+  not_if { kitchen? }
 end
index bdcb34f593c10ab49850fe89f20b51174c66cc31..b1570c9de1b813364ff3c6f9dfd6968ef15aa601 100644 (file)
@@ -17,6 +17,8 @@
 # limitations under the License.
 #
 
+include_recipe "imagery"
+
 imagery_site "ea.openstreetmap.org.uk" do
   title "OpenStreetMap - Environment Agency OpenData"
   bbox [[51.35, -2.2], [52.65, 0.10]]
index 878ee0fe01ab59a9bd473597af9a29b2dc6d8a4c..4771e81a64f5fef168f34634746a15d39faaafc4 100644 (file)
@@ -26,6 +26,13 @@ cookbook_file "/srv/imagery/common/ossv-palette.txt" do
   mode "0644"
 end
 
+cookbook_file "/srv/imagery/common/os-openmap-local-palette.txt" do
+  source "os-openmap-local-palette.txt"
+  owner "root"
+  group "root"
+  mode "0644"
+end
+
 cookbook_file "/srv/imagery/common/osstvw_process" do
   source "osstvw_process"
   owner "root"
@@ -181,7 +188,6 @@ end
 imagery_layer "gb_os_sv_2016_04" do
   site "os.openstreetmap.org"
   title "April 2016"
-  default_layer true
   projection "EPSG:27700"
   source "/data/imagery/gb/os-sv/ossv-2016-04-combined.vrt"
   copyright "Contains Ordnance Survey data &copy; Crown copyright and database right 2016"
@@ -1049,3 +1055,146 @@ imagery_layer "gb_os_sv_diff_2015_11_2016_04" do
   url_aliases ["/sv-diff-2015-11-2016-04"]
   overlay true
 end
+
+imagery_layer "gb_os_om_local_2016_10" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - October 2016"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2016-10/os-openmap-local-2016-10.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2016"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2017_04" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - April 2017"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2017-04/os-openmap-local-2017-04.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2017"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2017_10" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - October 2017"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2017-10/os-openmap-local-2017-10.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2017"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2018_04" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - April 2018"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2018-04/os-openmap-local-2018-04.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2018"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2018_05" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - May 2018"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2018-05/os-openmap-local-2018-05.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2018"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2019_04" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - April 2019"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2019-04/os-openmap-local-2019-04.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2019"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2020_04" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - April 2020"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2020-04/os-openmap-local-2020-04-combined-sea-average-zstd22.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2020"
+  revision 2
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2020_10" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - October 2020"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2020-10/os-openmap-local-2020-10.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2020"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2021_04" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - April 2021"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2021-04/os-openmap-local-2021-04.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2021"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2021_10" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - October 2021"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2021-10/os-openmap-local-2021-10.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2021"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2022_04" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - April 2022"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2022-04/os-openmap-local-2022-04.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2022"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2022_10" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - October 2022"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2022-10/os-openmap-local-2022-10.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2022"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2023_04" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - April 2023"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2023-04/os-openmap-local-2023-04.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2023"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+end
+
+imagery_layer "gb_os_om_local_2023_10" do
+  site "os.openstreetmap.org"
+  title "OS OpenMap Local - October 2023"
+  projection "EPSG:27700"
+  source "/data/imagery/gb/openmap-local/2023-10/os-openmap-local-2023-10.vrt"
+  copyright "Contains OS data &copy; Crown copyright and database right 2023"
+  background_colour "213 244 248" # OS OpenMap Local Water Blue
+  extension "os_om_local_png"
+  url_aliases ["/om-local-2023-10", "/om-local"]
+  default_layer true
+end
diff --git a/cookbooks/imagery/recipes/lu_lidar_hillshade.rb b/cookbooks/imagery/recipes/lu_lidar_hillshade.rb
new file mode 100644 (file)
index 0000000..a6a277b
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# Cookbook:: imagery
+# Recipe:: lu_lidar_hillshade
+#
+# Copyright:: 2016, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "imagery"
+
+imagery_site "lidar-hillshade-2019.openstreetmap.lu" do
+  title "OpenStreetMap - Lidar Hillshade 2019"
+  bbox [[49.38, 5.64], [50.2, 6.64]]
+end
+
+# Delete borken layers like this
+
+imagery_layer "classy_mappers_delight_lidar_hillshade_2019" do
+  site "lidar-hillshade-2019.openstreetmap.lu"
+  action :delete
+end
+
+imagery_layer "mappers_delight_lidar_dem_2019" do
+  site "lidar-hillshade-2019.openstreetmap.lu"
+  action :delete
+end
+
+imagery_layer "mappers_delight_lidar_hillshade_2019_reprojected" do
+  site "lidar-hillshade-2019.openstreetmap.lu"
+  default_layer true
+  projection "EPSG:3857"
+  source "/data/imagery/lu/lidar-hillshade/lu_hillshade_2019-3857.tif"
+  max_zoom 20
+  title "OpenStreetMap.lu Mapper's Delight 2019 Lidar Hillshading"
+  copyright 'Lidar data 2019 <a href="https://data.public.lu/fr/datasets/lidar-2019-releve-3d-du-territoire-luxembourgeois">Administration du Cadastre et de la Topographie Luxembourg</a>, DEM and hillshading <a href="https://twitter.com/grischard">Guillaume Rischard</a>, CC0'
+end
+
+imagery_layer "mappers_delight_lidar_hillshade_2019_withunclassified" do
+  site "lidar-hillshade-2019.openstreetmap.lu"
+  projection "EPSG:3857"
+  source "/data/imagery/lu/lidar-hillshade/classy-hillshade.tif"
+  max_zoom 20
+  title "OpenStreetMap.lu Mapper's Delight 2019 Lidar Hillshading with unclassified points"
+  copyright 'Lidar data 2019 <a href="https://data.public.lu/fr/datasets/lidar-2019-releve-3d-du-territoire-luxembourgeois">Administration du Cadastre et de la Topographie Luxembourg</a>, DEM and hillshading <a href="https://twitter.com/grischard">Guillaume Rischard</a>, CC0'
+end
diff --git a/cookbooks/imagery/recipes/lu_ngl_dtm.rb b/cookbooks/imagery/recipes/lu_ngl_dtm.rb
new file mode 100644 (file)
index 0000000..e3133bf
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# Cookbook:: imagery
+# Recipe:: lu_ngl_dtm
+#
+# Copyright:: 2016, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "imagery"
+
+imagery_site "ana-dtm-2017.openstreetmap.lu" do
+  title "OpenStreetMap - ANA DTM 2017"
+  bbox [[49.38, 5.64], [50.2, 6.64]]
+end
+
+imagery_layer "ana_dtm_2017" do
+  site "ana-dtm-2017.openstreetmap.lu"
+  action :delete
+end
+
+imagery_layer "ana_dtm_2017_hillshading" do
+  site "ana-dtm-2017.openstreetmap.lu"
+  action :delete
+end
+
+imagery_layer "ana_dtm_2017_hillshading_multi" do
+  site "ana-dtm-2017.openstreetmap.lu"
+  default_layer true
+  projection "EPSG:3857"
+  source "/data/imagery/lu/LUREF_NGL/ANA_LUREF_NGL_DTM_hillshade_multi_epsg3857.tif"
+  max_zoom 21
+  title "DTM Hillshading (multidirectional)"
+  copyright 'DEM 2017 <a href="https://data.public.lu/fr/datasets/digital-terrain-model-high-dem-resolution/">Administration de la Navigation A&eacute;rienne Luxembourg</a>, hillshading <a href="https://twitter.com/dmoraisferreira">David Morais Ferreira</a> &amp; <a href="https://twitter.com/grischard">Guillaume Rischard</a> CC0'
+end
diff --git a/cookbooks/imagery/recipes/tiler.rb b/cookbooks/imagery/recipes/tiler.rb
new file mode 100644 (file)
index 0000000..7358089
--- /dev/null
@@ -0,0 +1,87 @@
+#
+# Cookbook:: imagery
+# Recipe:: tiler
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "imagery"
+include_recipe "podman"
+
+directory "/store/imagery" do
+  owner "root"
+  group "root"
+  mode "755"
+  recursive true
+end
+
+# FIXME: until upstream supports arm64 images: https://github.com/developmentseed/titiler/pull/740
+container_image = if arm?
+                    "ghcr.io/firefishy/titiler:latest"
+                  else
+                    "ghcr.io/developmentseed/titiler:latest"
+                  end
+
+podman_service "titiler" do
+  description "Container service for titiler"
+  image container_image
+  ports 8080 => 8080
+  volume "/store/imagery" => "/store/imagery"
+  environment :PORT                                => 8080,
+              :WORKERS_PER_CORE                    => 1,
+              :GDAL_CACHEMAX                       => 200,
+              :GDAL_DISABLE_READDIR_ON_OPEN        => "EMPTY_DIR",
+              :GDAL_INGESTED_BYTES_AT_OPEN         => 32768,
+              :GDAL_HTTP_MERGE_CONSECUTIVE_RANGES  => "YES",
+              :GDAL_HTTP_MULTIPLEX                 => "YES",
+              :GDAL_HTTP_VERSION                   => 2,
+              :VSI_CACHE                           => "TRUE",
+              :VSI_CACHE_SIZE                      => 5000000,
+              :TITILER_API_ROOT_PATH               => "/api/v1/titiler",
+              :FORWARDED_ALLOW_IPS                 => "*" # https://docs.gunicorn.org/en/latest/settings.html#forwarded-allow-ips
+end
+
+systemd_service "titiler-restart" do
+  type "simple"
+  user "root"
+  exec_start "/bin/systemctl try-restart titiler.service"
+  sandbox true
+  restrict_address_families "AF_UNIX"
+end
+
+systemd_timer "titiler-restart" do
+  on_boot_sec "6h"
+  on_unit_inactive_sec "12h"
+end
+
+service "titiler-restart.timer" do
+  action [:enable, :start]
+end
+
+directory "/var/cache/nginx-cache" do
+  owner "www-data"
+  group "www-data"
+  mode "755"
+end
+
+ssl_certificate "tiler.openstreetmap.org" do
+  domains "tiler.openstreetmap.org"
+  notifies :reload, "service[nginx]"
+end
+
+nginx_site "tiler.openstreetmap.org" do
+  template "nginx_titiler.conf.erb"
+  variables :aliases => ["tiler.osm.org"]
+end
diff --git a/cookbooks/imagery/recipes/za_ngi_aerial.rb b/cookbooks/imagery/recipes/za_ngi_aerial.rb
new file mode 100644 (file)
index 0000000..36123dc
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Cookbook:: imagery
+# Recipe:: za_ngi_aerial
+#
+# Copyright:: 2024, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "imagery::tiler"
+
+imagery_site "aerial.openstreetmap.org.za" do
+  title "OpenStreetMap - NGI - Aerial Imagery"
+  aliases ["aerial.osm.org.za"]
+  bbox [[-35.12, 16.23], [-22.1, 33.18]]
+  uses_tiler true
+end
+
+imagery_layer "ngi-aerial" do
+  site "aerial.openstreetmap.org.za"
+  uses_tiler true
+  title "NGI Aerial 25cm/50cm"
+  source "file:///store/imagery/za/za-25cm/mosaic-tiler-file.json"
+  copyright 'State Copyright &copy; 2024 <a href="https://ngi.dalrrd.gov.za/">Chief Directorate: National Geo-spatial Information</a>'
+  max_zoom 20
+  extension "jpg"
+  default_layer true
+  url_aliases ["/ngi-aerial"]
+end
index 22cd752faaedd10427db9252fd812e5cdab10e5b..46d0a8bc0c398e583fddc70dae723b414a1f097b 100644 (file)
@@ -30,7 +30,7 @@ imagery_layer "za_ngi_topo_250k" do
   title "NGI Topo 250k"
   projection "EPSG:3857"
   source "/data/imagery/za/ngi-topo-250k/ngi-topo-250k-combined.vrt"
-  copyright 'State Copyright &copy; 1996&ndash;2010 <a href="http://www.ngi.gov.za/">Chief Directorate: National Geo-spatial Information</a>'
+  copyright 'State Copyright &copy; 1996&ndash;2010 <a href="https://ngi.dalrrd.gov.za/">Chief Directorate: National Geo-spatial Information</a>'
   default_layer true
 end
 
@@ -39,5 +39,5 @@ imagery_layer "za_ngi_topo_50k" do
   title "NGI Topo 50k"
   projection "EPSG:3857"
   source "/data/imagery/za/ngi-topo-50k/ngi-topo-50k-combined.vrt"
-  copyright 'State Copyright &copy; 1996&ndash;2013 <a href="http://www.ngi.gov.za/">Chief Directorate: National Geo-spatial Information</a>'
+  copyright 'State Copyright &copy; 1996&ndash;2013 <a href="https://ngi.dalrrd.gov.za/">Chief Directorate: National Geo-spatial Information</a>'
 end
index cddd9584760186c7629004ac3fc1dcc8d0178959..4575991a809dbdfb2463c3e9bff09f30ea215f93 100644 (file)
 
 require "yaml"
 
+unified_mode true
+
 default_action :create
 
 property :layer, String, :name_property => true
 property :site, String, :required => true
-property :source, String, :required => true
-property :root_layer, [TrueClass, FalseClass], :default => false
+property :source, String, :required => [:create]
+property :root_layer, [true, false], :default => false
 property :title, String
 property :copyright, String, :default => "Copyright"
 property :projection, String, :default => "EPSG:3857"
@@ -37,17 +39,18 @@ property :extension, String, :default => "png"
 property :max_zoom, Integer, :default => 18
 property :url_aliases, [String, Array], :default => []
 property :revision, Integer, :default => 0
-property :overlay, [TrueClass, FalseClass], :default => false
-property :default_layer, [TrueClass, FalseClass], :default => false
+property :overlay, [true, false], :default => false
+property :default_layer, [true, false], :default => false
+property :uses_tiler, [true, false], :default => false
 
 action :create do
   file "/srv/imagery/layers/#{new_resource.site}/#{new_resource.layer}.yml" do
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     content YAML.dump(:name => new_resource.layer,
                       :title => new_resource.title || new_resource.layer,
-                      :url => "//{s}.#{new_resource.site}/layer/#{new_resource.layer}/{z}/{x}/{y}.png",
+                      :url => "//#{new_resource.site}/layer/#{new_resource.layer}/{z}/{x}/{y}.#{new_resource.extension}".gsub(/\.(os_sv_png|os_sv_diff_png|os_om_local_png)$/, ".png"),
                       :attribution => new_resource.copyright,
                       :default => new_resource.default_layer,
                       :maxZoom => new_resource.max_zoom,
@@ -59,24 +62,15 @@ action :create do
     source "mapserver.map.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables new_resource.to_hash
-  end
-
-  # Disable legacy service
-  service "mapserv-fcgi-#{new_resource.layer}" do
-    action [:stop, :disable]
-  end
-
-  # Remove legacy service
-  systemd_service "mapserv-fcgi-#{new_resource.layer}" do
-    action :delete
+    not_if { new_resource.uses_tiler }
   end
 
   directory "/srv/imagery/nginx/#{new_resource.site}" do
     owner "root"
     group "root"
-    mode 0o755
+    mode "755"
     recursive true
   end
 
@@ -85,7 +79,7 @@ action :create do
     source "nginx_imagery_layer_fragment.conf.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables new_resource.to_hash
   end
 end
@@ -95,18 +89,10 @@ action :delete do
     action :delete
   end
 
-  service "mapserv-fcgi-layer-#{new_resource.layer}" do
-    action [:stop, :disable]
-  end
-
   file "/srv/imagery/mapserver/layer-#{new_resource.layer}.map" do
     action :delete
   end
 
-  systemd_service "mapserv-fcgi-#{new_resource.layer}" do
-    action :delete
-  end
-
   file "/srv/imagery/nginx/#{new_resource.site}/layer-#{new_resource.layer}.conf" do
     action :delete
   end
@@ -114,6 +100,5 @@ end
 
 def after_created
   notifies :create, "imagery_site[#{site}]"
-  notifies :reload, "service[nginx]"
-  # notifies :restart, "service[mapserv-fcgi-#{site}]"
+  notifies :restart, "service[nginx]"
 end
index d483803840e267a536e7526de694972b4c59aa0c..a91f9794c4eab06b7a51e46eabd8201a0fe25149 100644 (file)
 
 require "yaml"
 
+unified_mode true
+
 default_action :create
 
 property :site, String, :name_property => true
-property :title, String, :required => true
+property :title, String, :required => [:create]
 property :aliases, [String, Array], :default => []
-property :bbox, Array, :required => true
+property :bbox, Array, :required => [:create]
+property :uses_tiler, [true, false], :default => false
 
 action :create do
   directory "/srv/#{new_resource.site}" do
     user "root"
     group "root"
-    mode 0o755
+    mode "755"
   end
 
   directory "/srv/imagery/layers/#{new_resource.site}" do
     user "root"
     group "root"
-    mode 0o755
+    mode "755"
     recursive true
   end
 
   directory "/srv/imagery/overlays/#{new_resource.site}" do
     user "root"
     group "root"
-    mode 0o755
+    mode "755"
     recursive true
   end
 
@@ -51,7 +54,7 @@ action :create do
     source "index.html.erb"
     user "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables :title => new_resource.title
   end
 
@@ -59,75 +62,86 @@ action :create do
     source "robots.txt"
     user "root"
     group "root"
-    mode 0o644
+    mode "644"
   end
 
   cookbook_file "/srv/#{new_resource.site}/imagery.css" do
     source "imagery.css"
     user "root"
     group "root"
-    mode 0o644
+    mode "644"
   end
 
   cookbook_file "/srv/#{new_resource.site}/clientaccesspolicy.xml" do
     source "clientaccesspolicy.xml"
     user "root"
     group "root"
-    mode 0o644
+    mode "644"
   end
 
   cookbook_file "/srv/#{new_resource.site}/crossdomain.xml" do
     source "crossdomain.xml"
     user "root"
     group "root"
-    mode 0o644
+    mode "644"
   end
 
   layers = Dir.glob("/srv/imagery/layers/#{new_resource.site}/*.yml").collect do |path|
-    YAML.safe_load(::File.read(path), [Symbol])
+    YAML.safe_load(::File.read(path), :permitted_classes => [Symbol])
   end
 
   declare_resource :template, "/srv/#{new_resource.site}/imagery.js" do
     source "imagery.js.erb"
     user "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables :bbox => new_resource.bbox, :layers => layers
   end
 
   base_domains = [new_resource.site] + Array(new_resource.aliases)
   tile_domains = base_domains.flat_map { |d| [d, "a.#{d}", "b.#{d}", "c.#{d}"] }
 
-  %w[0 1 2 3 4 5 6 7].each do |index|
-    systemd_service "mapserv-fcgi-#{new_resource.site}-#{index}" do
-      description "Map server for #{new_resource.site} layer"
-      environment "MS_MAP_PATTERN" => "^/srv/imagery/mapserver/",
-                  "MS_DEBUGLEVEL" => "0",
-                  "MS_ERRORFILE" => "stderr",
-                  "GDAL_CACHEMAX" => "512"
-      limit_nofile 16384
-      limit_cpu 60
-      memory_max "4G"
-      user "imagery"
-      group "imagery"
-      exec_start_pre "/bin/rm -f /run/mapserver-fastcgi/layer-#{new_resource.site}-#{index}.socket"
-      exec_start "/usr/bin/spawn-fcgi -n -b 8192 -s /run/mapserver-fastcgi/layer-#{new_resource.site}-#{index}.socket -M 0666 -P /run/mapserver-fastcgi/layer-#{new_resource.site}-#{index}.pid -- /usr/lib/cgi-bin/mapserv"
-      private_tmp true
-      private_devices true
-      private_network true
-      protect_system "full"
-      protect_home true
-      no_new_privileges true
-      restart "always"
-      pid_file "/run/mapserver-fastcgi/layer-#{new_resource.site}-#{index}.pid"
-    end
-
-    service "mapserv-fcgi-#{new_resource.site}-#{index}" do
-      provider Chef::Provider::Service::Systemd
-      action [:enable, :start]
-      supports :status => true, :restart => true, :reload => false
-      subscribes :restart, "systemd_service[mapserv-fcgi-#{new_resource.site}-#{index}]"
-    end
+  systemd_service "mapserv-fcgi-#{new_resource.site}" do
+    description "Map server for #{new_resource.site} layer"
+    environment "MS_MAP_PATTERN" => "^/srv/imagery/mapserver/",
+                "MS_DEBUGLEVEL" => "0",
+                "MS_ERRORFILE" => "stderr",
+                "GDAL_CACHEMAX" => "512"
+    limit_nofile 16384
+    memory_high "1G"
+    memory_max "4G"
+    user "imagery"
+    group "imagery"
+    exec_start "/usr/bin/multiwatch -f 8 --signal=TERM -- /usr/lib/cgi-bin/mapserv"
+    standard_input "socket"
+    sandbox true
+    restrict_address_families "AF_UNIX"
+    # Terminate service after 30mins. Service is socket activated
+    runtime_max_sec 1800
+    not_if { new_resource.uses_tiler }
+  end
+
+  systemd_socket "mapserv-fcgi-#{new_resource.site}" do
+    description "Map server for #{new_resource.site} layer socket"
+    socket_user "imagery"
+    socket_group "imagery"
+    listen_stream "/run/mapserver-fastcgi/layer-#{new_resource.site}.socket"
+    not_if { new_resource.uses_tiler }
+  end
+
+  # Ensure service is stopped because otherwise the socket cannot reload
+  service "mapserv-fcgi-#{new_resource.site}" do
+    provider Chef::Provider::Service::Systemd
+    action :nothing
+    subscribes :stop, "systemd_service[mapserv-fcgi-#{new_resource.site}]"
+    subscribes :stop, "systemd_socket[mapserv-fcgi-#{new_resource.site}]"
+    not_if { new_resource.uses_tiler }
+  end
+
+  systemd_unit "mapserv-fcgi-#{new_resource.site}.socket" do
+    action [:enable, :start]
+    subscribes :restart, "systemd_socket[mapserv-fcgi-#{new_resource.site}]"
+    not_if { new_resource.uses_tiler }
   end
 
   ssl_certificate new_resource.site do
@@ -137,7 +151,6 @@ action :create do
   nginx_site new_resource.site do
     template "nginx_imagery.conf.erb"
     directory "/srv/imagery/#{new_resource.site}"
-    restart_nginx false
     variables new_resource.to_hash
   end
 end
@@ -146,10 +159,12 @@ action :delete do
   service "mapserv-fcgi-#{new_resource.site}" do
     provider Chef::Provider::Service::Systemd
     action [:stop, :disable]
+    not_if { new_resource.uses_tiler }
   end
 
   systemd_service "mapserv-fcgi-#{new_resource.site}" do
     action :delete
+    not_if { new_resource.uses_tiler }
   end
 
   nginx_site new_resource.site do
index 0f277444b45b0c9f23d16be14bb8718dfd22d394..e5c289cfdd66c367a877368968e07fd6a499b511 100644 (file)
@@ -1,38 +1,45 @@
+<% require 'uri' %>
 function createMap(divName) {
   // Create a map
-  var map = L.map(divName).fitBounds(<%= @bbox.to_json %>);
+  var map = L.map(divName, {
+    worldCopyJump: true
+  }).fitBounds(<%= @bbox.to_json %>);
 
   // Create a layer switcher
   var layers = L.control.layers(null, null, {collapsed:false}).addTo(map);
 
   // Add OpenStreetMap layer
-  layers.addBaseLayer(L.tileLayer("//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
+  layers.addBaseLayer(L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
     attribution: "© <a target=\"_parent\" href=\"https://www.openstreetmap.org\">OpenStreetMap</a> and contributors, under an <a target=\"_parent\" href=\"https://www.openstreetmap.org/copyright\">open license</a>",
     maxZoom: 19
   }), "OpenStreetMap");
   <% @layers.sort_by { |layer| layer[:name] }.each do |layer| -%>
 
   // Create <%= layer[:name] %> layer
-  var <%= layer[:name] %> = L.tileLayer(<%= layer[:url].to_json %>, {
+  var <%= layer[:name].gsub("-", "_") %> = L.tileLayer(<%= layer[:url].to_json %>, {
     attribution: <%= layer[:attribution].to_json %>,
     maxZoom: <%= layer[:maxZoom].to_json %>
   });
 
   // Add <%= layer[:name] %> to layer switcher
   <% if layer[:overlay] -%>
-  layers.addOverlay(<%= layer[:name] %>, <%= layer[:title].to_json %>);
+  layers.addOverlay(<%= layer[:name].gsub("-", "_") %>, <%= layer[:title].to_json %>);
   <% else %>
-  layers.addBaseLayer(<%= layer[:name] %>, <%= layer[:title].to_json %>);
+  layers.addBaseLayer(<%= layer[:name].gsub("-", "_") %>, <%= layer[:title].to_json %>);
   <% end -%>
 
   <% if layer[:default] -%>
   // Add <%= layer[:name] %> to map
-  <%= layer[:name] %>.addTo(map);
+  <%= layer[:name].gsub("-", "_") %>.addTo(map);
   <% end -%>
   <% end -%>
 
   // Add the permalink control
   map.addControl(new L.Control.Permalink());
 
+  var lc = L.control.locate({
+    position: 'topright'
+  }).addTo(map);
+
   return map;
 }
index 148543937426bc23543260f73e24e481a738ffdd..c21d95e0425c973226bfe99ae10a3ddb1a59161e 100644 (file)
@@ -4,11 +4,17 @@
     <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
     <title><%= @title %></title>
     <link rel="stylesheet" href="imagery.css" type="text/css" media="all" />
-    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="anonymous"/>
-    <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js" integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og==" crossorigin="anonymous"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-plugins/3.1.0/control/Permalink.min.js" integrity="sha256-gz/xcf8U9RgwWUhQK8SgCuS024ACmdXf+eWrglT2KDE=" crossorigin="anonymous"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-plugins/3.1.0/control/Permalink.Layer.min.js" integrity="sha256-IR3dLMDgW61PPbrjYPe8eD7ou3RBAaVyoD4CNcq+8tw=" crossorigin="anonymous"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-plugins/3.1.0/control/Permalink.Overlay.min.js" integrity="sha256-xoP/txAKIYDr3MjZh1f2qtNn8lEa6zmhhkPxoejGgQM=" crossorigin="anonymous"></script>
+
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.8.0/leaflet.min.css" integrity="sha512-oIQ0EBio8LJupRpgmDsIsvm0Fsr6c3XNHLB7at5xb+Cf6eQuCX9xuX8XXGRIcokNgdqL1ms7nqbQ6ryXMGxXpg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.8.0/leaflet.min.js" integrity="sha512-TL+GX2RsOUlTndpkgHVnSQ9r6zldqHzfyECrdabkpucdFroZ3/HAhMmP2WYaPjsJCoot+0McmdPOLjmmicG9qg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-plugins/3.4.0/control/Permalink.min.js" integrity="sha512-wEr+4N2qhQn/6/YACFWVAaKzS2vLeZCWyUJ14MfXGTfHG718QBvOqv9t5xhex+Fnd3VZVd0EWcn9nzRbTLL9bg==" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-plugins/3.4.0/control/Permalink.Layer.min.js" integrity="sha512-m7ds5hujMwIiJ9yPLnJDR4C3bFeURlrFeHnW+QpsDweqYs8hu0/cYdJFBYtRkWGFpvmF6HkOWSGy7vYP1Rg+BA==" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-plugins/3.4.0/control/Permalink.Overlay.min.js" integrity="sha512-dIzyCLt0Sg0QpDfLXJZfgwmkbjl5s+ND7uFGW6A7itxuKA241Fzp6fKmCnPLhadqqmjz5i9/1W6aCFPLNSIIXA==" crossorigin="anonymous"></script>
+
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet.locatecontrol@0.76.1/dist/L.Control.Locate.min.css" integrity="sha256-9ouZwdHZxE1t+iXfxZD90z8xHQrynHnPJk1UgEPXolI="  crossorigin="anonymous" referrerpolicy="no-referrer" />
+    <script src="https://cdn.jsdelivr.net/npm/leaflet.locatecontrol@0.76.1/dist/L.Control.Locate.min.js" charset="utf-8" integrity="sha256-PJ29AcM0ZkANjcOdpF1jAwZ/eq324NP2cQ05f2wABE0=" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+
     <script type="text/javascript" src="imagery.js"></script>
     <style type="text/css">
     @media print {
index 4bec1334f2a8dd9830f24aabbd6a1ae63647266b..c918ca9f1f6b2c99a52f50fb99ff1c9e71d5efa4 100644 (file)
@@ -7,7 +7,7 @@ MAP
     MIMETYPE "image/png"
     IMAGEMODE RGB
     EXTENSION "png"
-    FORMATOPTION "COMPRESSION=9"
+    FORMATOPTION "COMPRESSION=6"
     FORMATOPTION "PALETTE_FORCE=on"
     FORMATOPTION "PALETTE=/srv/imagery/common/ossv-palette.txt"
   END
@@ -19,7 +19,19 @@ MAP
     MIMETYPE "image/png"
     IMAGEMODE RGBA
     EXTENSION "png"
-    FORMATOPTION "COMPRESSION=9"
+    FORMATOPTION "COMPRESSION=6"
+  END
+<% end -%>
+<% if @extension == "os_om_local_png" -%>
+  OUTPUTFORMAT
+    NAME "os_om_local_png"
+    DRIVER AGG/PNG
+    MIMETYPE "image/png"
+    IMAGEMODE RGB
+    EXTENSION "png"
+    FORMATOPTION "COMPRESSION=6"
+    FORMATOPTION "PALETTE_FORCE=on"
+    FORMATOPTION "PALETTE=/srv/imagery/common/os-openmap-local-palette.txt"
   END
 <% end -%>
 
@@ -32,10 +44,7 @@ MAP
   <% end -%>
   IMAGETYPE <%= @extension %>
     PROJECTION
-    <% if @projection == "EPSG:27700" -%>
-      <%# Override EPSG:27700 to use accurate nadgrid %>
-      "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs +nadgrids=/srv/imagery/common/ostn02-ntv2-data/OSTN02_NTv2.gsb"
-    <% elsif @projection == "namibia_aerial" -%>
+    <% if @projection == "namibia_aerial" -%>
       "+proj=tmerc +lat_0=0 +lon_0=17 +k=1 +x_0=600000 +y_0=10000000 +ellps=WGS84 +units=m +no_defs"
     <% else -%>
       "init=<%= @projection.downcase %>"
@@ -46,10 +55,7 @@ MAP
     NAME "<%= @layer %>"
     DATA "<%= @source %>"
     PROJECTION
-    <% if @projection == "EPSG:27700" -%>
-      <%# Override EPSG:27700 to use accurate nadgrid %>
-      "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs +nadgrids=/srv/imagery/common/ostn02-ntv2-data/OSTN02_NTv2.gsb"
-    <% elsif @projection == "namibia_aerial" -%>
+    <% if @projection == "namibia_aerial" -%>
       "+proj=tmerc +lat_0=0 +lon_0=17 +k=1 +x_0=600000 +y_0=10000000 +ellps=WGS84 +units=m +no_defs"
     <% else -%>
       "init=<%= @projection.downcase %>"
index 3d9a5bf5cde9cbbc1613222df9b56dc6a82937d8..cb629d59bda5f5e09d3ecbd2e7b81860aa575f5f 100644 (file)
@@ -1,6 +1,8 @@
 server {
-    listen 80 deferred backlog=16384 reuseport fastopen=2048 default_server;
-    listen 443 ssl deferred backlog=16384 reuseport fastopen=2048 http2; # No default_server here unless certificate specified here too.
+    listen 80 deferred backlog=16384 reuseport default_server;
+    listen 443 ssl deferred backlog=16384 reuseport http2; # No default_server here unless certificate specified here too.
+    listen [::]:80 deferred backlog=16384 reuseport default_server;
+    listen [::]:443 ssl deferred backlog=16384 reuseport http2; # No default_server here unless certificate specified here too.
 
     server_name  _;
     default_type text/html;
index dcdc2872961f2cbe6c0e4832dc8941aebb0be049..019b0a91b66d0168aa4c5b3229db23adb92c3b01 100644 (file)
@@ -1,29 +1,35 @@
 server {
     listen 80;
+    listen [::]:80;
     server_name <%= @name %> a.<%= @name %> b.<%= @name %> c.<%= @name %><% @aliases.each do |alias_name| %> <%= alias_name %> a.<%= alias_name %> b.<%= alias_name %> c.<%= alias_name %><%- end -%>;
 
     rewrite ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 permanent;
     return 301 https://$host$request_uri;
 }
 
+<% if @uses_tiler -%>
+upstream tiler_backend {
+    server 127.0.0.1:8080 max_fails=0;
+
+    keepalive 32;
+}
+<% else -%>
 upstream <%= @name %>_fastcgi {
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-0.socket" max_fails=0;
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-1.socket" max_fails=0;
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-2.socket" max_fails=0;
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-3.socket" max_fails=0;
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-4.socket" max_fails=0;
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-5.socket" max_fails=0;
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-6.socket" max_fails=0;
-    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>-7.socket" max_fails=0;
+    server "unix:/var/run/mapserver-fastcgi/layer-<%= @name %>.socket" max_fails=0;
 
     # Use default round-robin to distribute requests, rather than pick "fast" but maybe faulty.
     # Do not use keepalive
 }
+<% end -%>
 
 server {
-    listen 443 ssl;
+    listen 443 ssl http2;
+    listen [::]:443 ssl http2;
     server_name <%= @name %> a.<%= @name %> b.<%= @name %> c.<%= @name %><% @aliases.each do |alias_name| %> <%= alias_name %> a.<%= alias_name %> b.<%= alias_name %> c.<%= alias_name %><%- end -%>;
 
+    http2_max_concurrent_streams 512;
+    keepalive_timeout 30s;
+
     ssl_certificate /etc/ssl/certs/<%= @name %>.pem;
     ssl_certificate_key /etc/ssl/private/<%= @name %>.key;
 <% if node[:ssl][:strict_transport_security] -%>
@@ -45,9 +51,6 @@ server {
     gzip_comp_level 9;
     gzip_vary on;
 
-    sendfile   on;
-    tcp_nopush on;
-
     # Include site imagery layers
     include /srv/imagery/nginx/<%= @name %>/layer-*.conf;
 }
index 856ec6765f07a4fd89a1e3f5a5b293673b3d0e45..e72a6d7e9c4049052027cd24235e11380eee3a87 100644 (file)
@@ -1,9 +1,36 @@
+<% require 'uri' %>
 # DO NOT EDIT - This file is being maintained by Chef
 location ~* "^/layer/<%= @layer %>/(\d+)/(\d+)/(\d+)\.(png|jpg|jpeg)$" {
+<% if @uses_tiler -%>
+  set $args "";
+  rewrite ^/layer/<%= @layer %>/(\d+)/(\d+)/(\d+)\.jpg /mosaicjson/tiles/WebMercatorQuad/$1/$2/$3@1x?url=<%= URI.encode_www_form_component(@source) %>&pixel_selection=first&tile_format=jpeg break;
+  rewrite ^/layer/<%= @layer %>/(\d+)/(\d+)/(\d+)\.jpeg /mosaicjson/tiles/WebMercatorQuad/$1/$2/$3@1x?url=<%= URI.encode_www_form_component(@source) %>&pixel_selection=first&tile_format=jpeg break;
+  rewrite ^/layer/<%= @layer %>/(\d+)/(\d+)/(\d+)\.png /mosaicjson/tiles/WebMercatorQuad/$1/$2/$3@1x?url=<%= URI.encode_www_form_component(@source) %>&pixel_selection=first&tile_format=png break;
+  proxy_pass http://tiler_backend;
+  proxy_set_header Host $host;
+  proxy_set_header Referer $http_referer;
+  proxy_set_header X-Forwarded-For $remote_addr;
+  proxy_set_header X-Forwarded-Proto https;
+  proxy_set_header X-Forwarded-SSL on;
+  proxy_http_version 1.1;
+  proxy_set_header Connection "";
+  proxy_set_header Cache-Control "";
+  proxy_set_header Pragma "";
+  proxy_redirect off;
+  proxy_cache_key "<%= @layer %><%= @revision %> $request_method $1 $2 $3";
+  proxy_cache proxy_cache_zone;
+  proxy_cache_valid 200 204 180d;
+  proxy_cache_use_stale error timeout updating http_502 http_503 http_504;
+  proxy_cache_background_update on;
+  proxy_next_upstream error timeout invalid_header http_500 http_503;
+  proxy_next_upstream_tries 3;
+  proxy_intercept_errors on;
+  proxy_next_upstream_timeout 30s;
+
+<% else -%>
   # Override QUERY_STRING to force mapserver query parameters
   fastcgi_param QUERY_STRING "map=/srv/imagery/mapserver/layer-<%= @layer %>.map&mode=tile&layers=<%= @layer %>&tilemode=gmap&tile=$2+$3+$1";
   fastcgi_pass "<%= @site %>_fastcgi";
-  fastcgi_buffers 8 64k;
   include fastcgi_params;
   fastcgi_param REQUEST_METHOD "GET";
   fastcgi_param HTTP_PROXY "";
@@ -16,24 +43,30 @@ location ~* "^/layer/<%= @layer %>/(\d+)/(\d+)/(\d+)\.(png|jpg|jpeg)$" {
   # Free connection to socket for other requests
   fastcgi_keep_conn off;
 
-  fastcgi_cache_lock on;
-  fastcgi_cache_lock_timeout 30s;
   fastcgi_cache_valid 200 21d;
+
+  # Serve stale cache on errors or if updating
   fastcgi_cache_use_stale error timeout updating http_500 http_503;
+  # If in cache as stale, serve stale and update in background
+  fastcgi_cache_background_update on;
+  # Enable revalidation using If-Modified-Since and If-None-Match for stale items
+  fastcgi_cache_revalidate on;
 
-  # Ignore client abort as it causes issues with the pipeline
-  fastcgi_ignore_client_abort on;
+  keepalive_requests 0;
 
   fastcgi_catch_stderr "Image handling error";
 
   fastcgi_next_upstream error timeout invalid_header http_500 http_503;
   fastcgi_next_upstream_tries 8;
+<% end -%>
 
   # Do not GZIP tiles
   gzip off;
 
   # Add HTTP Cache-Control + Expires Headers
   expires 7d;
+  add_header Cache-Control "stale-while-revalidate=604800, stale-if-error=604800";
+  add_header x-cache-status $upstream_cache_status;
 
   # Allow CORS requests
   add_header 'Access-Control-Allow-Origin' '*';
diff --git a/cookbooks/imagery/templates/default/nginx_titiler.conf.erb b/cookbooks/imagery/templates/default/nginx_titiler.conf.erb
new file mode 100644 (file)
index 0000000..d3595ac
--- /dev/null
@@ -0,0 +1,64 @@
+server {
+    listen 80;
+    listen [::]:80;
+    server_name <%= @name %> <% @aliases.each do |alias_name| %> <%= alias_name %><%- end -%>;
+
+    rewrite ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 permanent;
+
+    location / {
+      return 301 https://$host$request_uri;
+    }
+
+    location /za-25cm {
+      root "/store/imagery/za";
+      expires max;
+    }
+}
+
+server {
+    listen 443 ssl http2;
+    listen [::]:443 ssl http2;
+    server_name <%= @name %> <% @aliases.each do |alias_name| %> <%= alias_name %><%- end -%>;
+
+    http2_max_concurrent_streams 512;
+    keepalive_timeout 30s;
+
+    ssl_certificate /etc/ssl/certs/<%= @name %>.pem;
+    ssl_certificate_key /etc/ssl/private/<%= @name %>.key;
+<% if node[:ssl][:strict_transport_security] -%>
+
+    add_header Strict-Transport-Security "<%= node[:ssl][:strict_transport_security] %>" always;
+<% end -%>
+
+    # Requests sent within early data are subject to replay attacks.
+    # See: http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
+    ssl_early_data on;
+
+    # root "/srv/<%= @name %>";
+
+    gzip on;
+    gzip_types text/plain text/css application/json application/javascript application/x-javascript text/javascript text/xml application/xml application/rss+xml application/atom+xml application/rdf+xml image/svg+xml; # text/html is implicit
+    gzip_min_length 512;
+    gzip_http_version 1.0;
+    gzip_proxied any;
+    gzip_comp_level 9;
+    gzip_vary on;
+
+    location /za-25cm {
+      root "/store/imagery/za";
+      expires max;
+    }
+
+    location /api/v1/titiler {
+      rewrite ^/api/v1/titiler(.*)$ $1 break;
+      proxy_pass http://localhost:8080;
+      proxy_set_header Host $host;
+      proxy_set_header Referer $http_referer;
+      proxy_set_header X-Forwarded-For $remote_addr;
+      proxy_set_header X-Forwarded-Proto https;
+      proxy_set_header X-Forwarded-SSL on;
+      proxy_http_version 1.1;
+      proxy_set_header Connection "";
+      proxy_redirect off;
+    }
+}
diff --git a/cookbooks/incron/README.md b/cookbooks/incron/README.md
deleted file mode 100644 (file)
index 095b006..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# incron Cookbook
-
-This cookbook installs incron, an inotify-based cron.
diff --git a/cookbooks/incron/attributes/default.rb b/cookbooks/incron/attributes/default.rb
deleted file mode 100644 (file)
index 4d2ce58..0000000
+++ /dev/null
@@ -1 +0,0 @@
-default[:incron] = {}
diff --git a/cookbooks/incron/recipes/default.rb b/cookbooks/incron/recipes/default.rb
deleted file mode 100644 (file)
index f7d44a4..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Cookbook:: incron
-# Recipe:: default
-#
-# Copyright:: 2014, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-package "incron"
-
-service "incron" do
-  action [:enable, :start]
-  supports :status => true, :reload => true, :restart => true
-end
-
-incrontabs = {}
-
-node[:incron].each_value do |details|
-  user = details[:user]
-  path = details[:path]
-  mask = details[:events].join(",")
-  command = details[:command]
-
-  incrontabs[user] ||= []
-
-  incrontabs[user].push("#{path} #{mask} #{command}")
-end
-
-incrontabs.each do |user, lines|
-  file "/var/spool/incron/#{user}" do
-    owner user
-    group "incron"
-    mode 0o600
-    content lines.join("\n")
-  end
-end
-
-file "/etc/incron.allow" do
-  owner "root"
-  group "incron"
-  mode "0640"
-  content incrontabs.keys.sort.join("\n")
-end
diff --git a/cookbooks/irc/README.md b/cookbooks/irc/README.md
new file mode 100644 (file)
index 0000000..051982f
--- /dev/null
@@ -0,0 +1,3 @@
+# Irc Cookbook
+
+This cookbook installs and configures the irc.openstreetmap.org web site.
similarity index 63%
rename from cookbooks/openvpn/metadata.rb
rename to cookbooks/irc/metadata.rb
index 15bee3b880aebfa37e01bb8cf1da30ff5c9dc338..80523f6b426b27b4c174833852961d074a7dea33 100644 (file)
@@ -1,8 +1,9 @@
-name              "openvpn"
+name              "irc"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures OpenVPN"
+description       "Configures irc.openstreetmap.org"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "podman"
similarity index 50%
rename from cookbooks/cgiirc/recipes/default.rb
rename to cookbooks/irc/recipes/default.rb
index 4e8a9c1cc934da05de1dacbcd7a35cb81075257f..138912e8a1e5cbe75b7d79edd913655a7b38a915 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Cookbook:: cgiirc
+# Cookbook:: irc
 # Recipe:: default
 #
 # Copyright:: 2011, OpenStreetMap Foundation
 # limitations under the License.
 #
 
-include_recipe "apache"
+include_recipe "podman::apache"
 
-blocks = data_bag_item("cgiirc", "blocks")
-
-package "cgiirc"
-
-template "/etc/cgiirc/cgiirc.config" do
-  source "cgiirc.config.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
-template "/etc/cgiirc/ipaccess" do
-  source "ipaccess.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :blocks => blocks["addresses"]
-end
-
-ssl_certificate "irc.openstreetmap.org" do
-  domains ["irc.openstreetmap.org", "irc.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "irc.openstreetmap.org" do
-  template "apache.erb"
-  variables :aliases => ["irc.osm.org"]
+podman_site "irc.openstreetmap.org" do
+  image "ghcr.io/openstreetmap/irc-website:latest"
+  aliases ["irc.osm.org"]
 end
index 46dda49ceb4c3410bde5960a0a915dc1fa162617..bb431975a25e25f1a51828f22779b874cec4dcf6 100644 (file)
@@ -1,2 +1,4 @@
 default[:kibana][:version] = "4.1.1"
 default[:kibana][:sites] = {}
+
+default[:accounts][:users][:kibana][:status] = :role
index 83c575e9bc058893ad6393eb95193ecf5f810e7b..ec3e6f4c60b80e857e15a8223ea04edfbd6eb743 100644 (file)
@@ -6,5 +6,6 @@ description       "Installs and configures a kibana server"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
 depends           "systemd"
index c2e2693b37948e9b614fad9af8c83ce2479044a7..2f2fc6f28a4f7495c4b47c551ae15aea66029d8b 100644 (file)
@@ -19,6 +19,7 @@
 
 require "yaml"
 
+include_recipe "accounts"
 include_recipe "apache"
 
 apache_module "proxy_http"
@@ -26,40 +27,41 @@ apache_module "proxy_http"
 version = node[:kibana][:version]
 
 remote_file "#{Chef::Config[:file_cache_path]}/kibana-#{version}.tar.gz" do
-  source "https://download.elastic.co/kibana/kibana/kibana-4.1.1-linux-x64.tar.gz"
-  not_if { File.exist?("/opt/kibana-#{version}/bin/kibana") }
+  source "https://download.elastic.co/kibana/kibana/kibana-#{version}-linux-x64.tar.gz"
+  not_if { ::File.exist?("/opt/kibana-#{version}/bin/kibana") }
 end
 
 directory "/opt/kibana-#{version}" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
-execute "unzip-kibana-#{version}" do
-  command "tar --gunzip --extract --strip-components=1 --file=#{Chef::Config[:file_cache_path]}/kibana-#{version}.tar.gz"
-  cwd "/opt/kibana-#{version}"
-  user "root"
+archive_file "#{Chef::Config[:file_cache_path]}/kibana-#{version}.tar.gz" do
+  destination "/opt/kibana-#{version}"
+  overwrite true
+  strip_components 1
+  owner "root"
   group "root"
-  not_if { File.exist?("/opt/kibana-#{version}/bin/kibana") }
+  not_if { ::File.exist?("/opt/kibana-#{version}/bin/kibana") }
 end
 
 directory "/etc/kibana" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/run/kibana" do
   owner "kibana"
   group "kibana"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/log/kibana" do
   owner "kibana"
   group "kibana"
-  mode 0o755
+  mode "755"
 end
 
 systemd_service "kibana@" do
@@ -86,7 +88,7 @@ node[:kibana][:sites].each do |name, details|
                       ))
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     notifies :restart, "service[kibana@#{name}]"
   end
 
index 0691d8a315cfdc13ef1ac9984e4512a8159dfc6b..2121eeda206fed599ae7e6fcc84bd65127f3b76f 100644 (file)
@@ -4,7 +4,7 @@
    ServerName <%= @site %>
    ServerAdmin webmaster@openstreetmap.org
 
-   CustomLog /var/log/apache2/<%= @site %>-access.log combined
+   CustomLog /var/log/apache2/<%= @site %>-access.log combined_extended
    ErrorLog /var/log/apache2/<%= @site %>-error.log
 
    RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -15,7 +15,7 @@
    ServerName <%= @site %>
    ServerAdmin webmaster@openstreetmap.org
 
-   CustomLog /var/log/apache2/<%= @site %>-access.log combined
+   CustomLog /var/log/apache2/<%= @site %>-access.log combined_extended
    ErrorLog /var/log/apache2/<%= @site %>-error.log
 
    SSLEngine on
diff --git a/cookbooks/letsencrypt/attributes/default.rb b/cookbooks/letsencrypt/attributes/default.rb
new file mode 100644 (file)
index 0000000..21b32a8
--- /dev/null
@@ -0,0 +1 @@
+default[:accounts][:users][:letsencrypt][:status] = :role
index 73bd8a658c1731a2f15b835ddb2f9ef4e4b1050b..f24681589e13687c2c16e0fc79804ec9e7aa6391 100755 (executable)
@@ -2,6 +2,7 @@
 
 require "socket"
 require "openssl"
+require "net/http"
 
 host = ARGV.shift
 address = ARGV.shift
@@ -23,6 +24,8 @@ end
 
 if ssl
   certificate = ssl.peer_cert
+  chain = ssl.peer_cert_chain.drop(1)
+  issuer = chain.first
 
   if Time.now < certificate.not_before
     puts "Certificate #{domains.first} on #{host} not valid until #{certificate.not_before}"
@@ -30,6 +33,43 @@ if ssl
     puts "Certificate #{domains.first} on #{host} expires at #{certificate.not_after}"
   end
 
+  digest = OpenSSL::Digest::SHA1.new
+  certificate_id = OpenSSL::OCSP::CertificateId.new(certificate, issuer, digest)
+  ocsp_request = OpenSSL::OCSP::Request.new.add_certid(certificate_id)
+
+  authority_info_access = certificate.extensions.find { |ext| ext.oid == "authorityInfoAccess" }
+  ocsp = authority_info_access.value.split("\n").find { |desc| desc.start_with?("OCSP") }
+  ocsp_uri = URI(ocsp.sub(/^.* URI:/, ""))
+
+  http_response = Net::HTTP.start(ocsp_uri.hostname, ocsp_uri.port) do |http|
+    path = ocsp_uri.path
+    path = "/" if path.empty?
+    http.post(path, ocsp_request.to_der, "Content-Type" => "application/ocsp-request")
+  end
+
+  basic_response = OpenSSL::OCSP::Response.new(http_response.body).basic
+
+  store = OpenSSL::X509::Store.new
+  store.set_default_paths
+
+  unless basic_response.verify(chain, store)
+    raise "OCSP response is not signed by a trusted certificate"
+  end
+
+  single_response = basic_response.find_response(certificate_id)
+
+  unless single_response
+    raise "OCSP response does not have the status for the certificate"
+  end
+
+  unless single_response.check_validity
+    raise "OCSP response is not valid"
+  end
+
+  if single_response.cert_status == OpenSSL::OCSP::V_CERTSTATUS_REVOKED
+    puts "Certificate #{domains.first} on #{host} has been revoked"
+  end
+
   subject_alt_name = certificate.extensions.find { |ext| ext.oid == "subjectAltName" }
 
   if subject_alt_name.nil?
index b7c7af196aebf442ba701868a5cc1b2146b33065..13ad5fdc025e09b02fbaf4ab697c1d7b8b9c247b 100755 (executable)
@@ -1,7 +1,5 @@
 #!/bin/bash
 
-domains=($RENEWED_DOMAINS)
-
 exec 2>&1
 
-exec /srv/acme.openstreetmap.org/bin/upload "${domains[0]}" "$RENEWED_LINEAGE"
+exec /srv/acme.openstreetmap.org/bin/upload "$(basename $RENEWED_LINEAGE)" "$RENEWED_LINEAGE"
index 56da6294c85dc13af95a75d9f390b45bf32c09db..a52f30257aea8764afbaae94012be5933a6bf19a 100755 (executable)
@@ -17,4 +17,4 @@ file = Tempfile.new(["letsencrypt", ".json"])
 file.puts JSON.generate(bag)
 file.close
 
-system("/usr/bin/knife", "data", "bag", "from", "file", "letsencrypt", file.path)
+system("/opt/chef/embedded/bin/knife", "data", "bag", "from", "file", "letsencrypt", file.path)
index 3af7bdd2e99fc3815a355dbe31cd1367afb885a2..52ef99f7ccb172343eefaa2df3b938e049557bf3 100644 (file)
@@ -6,4 +6,6 @@ description       "Support for letsencrypt certificates"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
+depends           "chef"
index 42d1e4678c859faf609ecc0682f725797c2baa5e..382a0a58cfb01b25a097f1fa3af639086dd05005 100644 (file)
@@ -17,7 +17,9 @@
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "apache"
+include_recipe "chef::knife"
 
 keys = data_bag_item("chef", "keys")
 
@@ -29,31 +31,31 @@ package %w[
 directory "/etc/letsencrypt" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/lib/letsencrypt" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/log/letsencrypt" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o700
+  mode "700"
 end
 
 directory "/srv/acme.openstreetmap.org" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o755
+  mode "755"
 end
 
 directory "/srv/acme.openstreetmap.org/html" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o755
+  mode "755"
 end
 
 ssl_certificate "acme.openstreetmap.org" do
@@ -69,55 +71,55 @@ end
 directory "/srv/acme.openstreetmap.org/config" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o755
+  mode "755"
 end
 
 directory "/srv/acme.openstreetmap.org/work" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o755
+  mode "755"
 end
 
 directory "/srv/acme.openstreetmap.org/logs" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o700
+  mode "700"
 end
 
 directory "/srv/acme.openstreetmap.org/.chef" do
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o2775
+  mode "2775"
 end
 
 file "/srv/acme.openstreetmap.org/.chef/client.pem" do
   content keys["letsencrypt"].join("\n")
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o660
+  mode "660"
 end
 
 cookbook_file "/srv/acme.openstreetmap.org/.chef/knife.rb" do
   source "knife.rb"
   owner "letsencrypt"
   group "letsencrypt"
-  mode 0o660
+  mode "660"
 end
 
 remote_directory "/srv/acme.openstreetmap.org/bin" do
   source "bin"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o755
+  files_mode "755"
 end
 
 directory "/srv/acme.openstreetmap.org/requests" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 certificates = search(:node, "letsencrypt:certificates").each_with_object({}) do |n, c|
@@ -136,7 +138,7 @@ certificates.each do |name, details|
     source "request.erb"
     owner "root"
     group "letsencrypt"
-    mode 0o754
+    mode "754"
     variables details
   end
 
@@ -147,10 +149,11 @@ certificates.each do |name, details|
     user "letsencrypt"
     group "letsencrypt"
     subscribes :run, "template[/srv/acme.openstreetmap.org/requests/#{name}]"
+    not_if { kitchen? }
   end
 end
 
-Dir.each_child("/srv/acme.openstreetmap.org/requests") do |name|
+Dir.glob("*", :base => "/srv/acme.openstreetmap.org/requests") do |name|
   next if certificates.include?(name)
 
   file "/srv/acme.openstreetmap.org/requests/#{name}" do
@@ -169,13 +172,53 @@ template "/srv/acme.openstreetmap.org/bin/check-certificates" do
   source "check-certificates.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   variables :certificates => certificates
 end
 
-template "/etc/cron.d/letsencrypt" do
-  source "cron.erb"
+systemd_service "letsencrypt-renew" do
+  description "Renew letsencrypt certificates"
+  exec_start "/srv/acme.openstreetmap.org/bin/renew"
+  user "letsencrypt"
+  sandbox :enable_network => true
+  read_write_paths [
+    "/srv/acme.openstreetmap.org/config",
+    "/srv/acme.openstreetmap.org/html",
+    "/srv/acme.openstreetmap.org/logs",
+    "/srv/acme.openstreetmap.org/work"
+  ]
+end
+
+systemd_timer "letsencrypt-renew" do
+  description "Renew letsencrypt certificates"
+  on_boot_sec "1h"
+  on_unit_inactive_sec "12h"
+end
+
+service "letsencrypt-renew.timer" do
+  action [:enable, :start]
+end
+
+systemd_service "letsencrypt-check" do
+  description "Check letsencrypt certificates"
+  exec_start "/srv/acme.openstreetmap.org/bin/check-certificates"
+  user "letsencrypt"
+  sandbox :enable_network => true
+end
+
+systemd_timer "letsencrypt-check" do
+  description "Check letsencrypt certificates"
+  on_boot_sec "2h"
+  on_unit_inactive_sec "12h"
+end
+
+service "letsencrypt-check.timer" do
+  action [:enable, :start]
+end
+
+template "/etc/logrotate.d/letsencrypt" do
+  source "logrotate.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
index c49079daed731ddf0ae128af1d2213a007e667ef..37d1df5283de05c1d0b72d280cd975e7bc6d77b6 100644 (file)
@@ -5,7 +5,7 @@
         ServerAlias acme.osm.org
         ServerAdmin webmaster@openstreetmap.org
 
-        CustomLog /var/log/apache2/acme.openstreetmap.org-access.log combined
+        CustomLog /var/log/apache2/acme.openstreetmap.org-access.log combined_extended
         ErrorLog /var/log/apache2/acme.openstreetmap.org-error.log
 
         DocumentRoot /srv/acme.openstreetmap.org/html
@@ -16,7 +16,7 @@
         ServerAlias acme.osm.org
         ServerAdmin webmaster@openstreetmap.org
 
-        CustomLog /var/log/apache2/acme.openstreetmap.org-access.log combined
+        CustomLog /var/log/apache2/acme.openstreetmap.org-access.log combined_extended
         ErrorLog /var/log/apache2/acme.openstreetmap.org-error.log
 
         SSLEngine on
diff --git a/cookbooks/letsencrypt/templates/default/cron.erb b/cookbooks/letsencrypt/templates/default/cron.erb
deleted file mode 100644 (file)
index 74a8ee0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-MAILTO=admins@openstreetmap.org
-
-00 */12 * * * letsencrypt /srv/acme.openstreetmap.org/bin/renew
-30 */12 * * * letsencrypt /srv/acme.openstreetmap.org/bin/check-certificates
diff --git a/cookbooks/letsencrypt/templates/default/logrotate.erb b/cookbooks/letsencrypt/templates/default/logrotate.erb
new file mode 100644 (file)
index 0000000..57fe6d6
--- /dev/null
@@ -0,0 +1,6 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+/srv/acme.openstreetmap.org/logs/*.log {
+    missingok
+    compress
+}
index 4014b7207bc99a5e8e53f917901b44b3ffe5befa..1b97ce33558f09c8f393f3f25c54a6b0db8f1d56 100644 (file)
@@ -1,4 +1,6 @@
 default[:logstash][:forwarder]["output.logstash"]["hosts"] = ["logstash.openstreetmap.org:5044"]
 default[:logstash][:forwarder]["output.logstash"]["ssl.certificate_authorities"] = "/etc/filebeat/filebeat.crt"
 default[:logstash][:forwarder]["output.logstash"]["ssl.verification_mode"] = "none"
-default[:logstash][:forwarder]["filebeat.prospectors"] = []
+default[:logstash][:forwarder]["filebeat.inputs"] = []
+
+default[:elasticsearch][:cluster][:name] = "logstash"
index e13ece1b0ebca6e6ccbfbbc8f8f2d5dcb3ee97e5..a1a7d387bc4385f451f2f29c107816480fc25608 100644 (file)
@@ -6,4 +6,6 @@ description       "Installs and configures a elasticsearch server"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "apt"
+depends           "elasticsearch"
 depends           "networking"
index babff56df277c1532a6249251a4fad18b68d59aa..bbe8450214f4168e0a770c47188987e6dbda7c1f 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "elasticsearch"
 include_recipe "networking"
 
 keys = data_bag_item("logstash", "keys")
 
 package %w[
-  openjdk-8-jre-headless
+  openjdk-11-jre-headless
   logstash
 ]
 
@@ -30,7 +31,7 @@ cookbook_file "/var/lib/logstash/beats.crt" do
   source "beats.crt"
   user "root"
   group "logstash"
-  mode 0o644
+  mode "644"
   notifies :restart, "service[logstash]"
 end
 
@@ -38,7 +39,7 @@ file "/var/lib/logstash/beats.key" do
   content keys["beats"].join("\n")
   user "root"
   group "logstash"
-  mode 0o640
+  mode "640"
   notifies :restart, "service[logstash]"
 end
 
@@ -46,82 +47,49 @@ template "/etc/logstash/conf.d/chef.conf" do
   source "logstash.conf.erb"
   user "root"
   group "root"
-  mode 0o644
-  notifies :reload, "service[logstash]"
+  mode "644"
+  notifies :start, "service[logstash]"
 end
 
 file "/etc/logrotate.d/logstash" do
-  mode 0o644
+  mode "644"
 end
 
 template "/etc/default/logstash" do
   source "logstash.default.erb"
   user "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :restart, "service[logstash]"
 end
 
 service "logstash" do
   action [:enable, :start]
-  supports :status => true, :restart => true, :reload => true
 end
 
 template "/etc/cron.daily/expire-logstash" do
   source "expire.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
-forwarders = search(:node, "recipes:logstash\\:\\:forwarder")
+forwarders = []
 
-forwarders.sort_by { |n| n[:fqdn] }.each do |forwarder|
-  forwarder.interfaces(:role => :external) do |interface|
-    firewall_rule "accept-lumberjack-#{forwarder}" do
-      action :accept
-      family interface[:family]
-      source "#{interface[:zone]}:#{interface[:address]}"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports "5043"
-      source_ports "1024:"
-    end
-
-    firewall_rule "accept-beats-#{forwarder}" do
-      action :accept
-      family interface[:family]
-      source "#{interface[:zone]}:#{interface[:address]}"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports "5044"
-      source_ports "1024:"
-    end
-  end
+search(:node, "recipes:logstash\\:\\:forwarder").each do |forwarder|
+  forwarders.append(forwarder.ipaddresses(:role => :external))
 end
 
-gateways = search(:node, "roles:gateway")
-
-gateways.sort_by { |n| n[:fqdn] }.each do |gateway|
-  gateway.interfaces(:role => :external) do |interface|
-    firewall_rule "accept-lumberjack-#{gateway}" do
-      action :accept
-      family interface[:family]
-      source "#{interface[:zone]}:#{interface[:address]}"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports "5043"
-      source_ports "1024:"
-    end
+search(:node, "roles:gateway").each do |forwarder|
+  forwarders.append(forwarder.ipaddresses(:role => :external))
+end
 
-    firewall_rule "accept-beats-#{gateway}" do
-      action :accept
-      family interface[:family]
-      source "#{interface[:zone]}:#{interface[:address]}"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports "5044"
-      source_ports "1024:"
-    end
-  end
+firewall_rule "accept-logstash" do
+  action :accept
+  context :incoming
+  protocol :tcp
+  source forwarders
+  dest_ports %w[5043 5044]
+  source_ports "1024-65535"
+  not_if { forwarders.empty? }
 end
index 14866558b3fc40e27d33d1b11d2aba7ab8eeacb2..2184da04864d2b093c5ab252c67690b75a782b94 100644 (file)
 
 require "yaml"
 
+include_recipe "apt::elasticsearch8"
+
 package "filebeat"
 
 cookbook_file "/etc/filebeat/filebeat.crt" do
   source "beats.crt"
   user "root"
   group "root"
-  mode 0o600
+  mode "600"
   notifies :restart, "service[filebeat]"
 end
 
@@ -33,7 +35,7 @@ file "/etc/filebeat/filebeat.yml" do
   content YAML.dump(node[:logstash][:forwarder].to_hash)
   user "root"
   group "root"
-  mode 0o600
+  mode "600"
   notifies :restart, "service[filebeat]"
 end
 
index dc12f2ffa69916d0b540cb7cd955dd2d8fd874c6..3ee45fbdbddcfabd6517ea30ca5518508a510527 100644 (file)
@@ -7,3 +7,5 @@ description       "Installs and configures mailman"
 version           "1.0.0"
 supports          "ubuntu"
 depends           "apache"
+depends           "chef"
+depends           "prometheus"
index 6e53ee8e531a17fb080a287d65fc716944600477..f7deccaddb03f102f9b775b32b35bb9ec0fa89f5 100644 (file)
 require "securerandom"
 
 include_recipe "apache"
+include_recipe "prometheus"
 
-package "mailman"
+package %w[
+  locales-all
+  mailman
+  ruby-webrick
+]
 
-node.normal_unless[:mailman][:subscribe_form_secret] = SecureRandom.base64(48)
+subscribe_form_secret = persistent_token("mailman", "subscribe_form_secret")
 
 template "/etc/mailman/mm_cfg.py" do
   source "mm_cfg.py.erb"
   user "root"
   group "root"
-  mode 0o644
+  mode "644"
+  variables :subscribe_form_secret => subscribe_form_secret
   notifies :restart, "service[mailman]"
 end
 
+execute "newlist" do
+  command "newlist -q mailman mailman@example.com mailman"
+  user "root"
+  group "root"
+  not_if { ::File.exist?("/var/lib/mailman/lists/mailman/") }
+end
+
 service "mailman" do
   action [:enable, :start]
   supports :restart => true, :reload => true
@@ -56,5 +69,10 @@ template "/etc/cron.daily/lists-backup" do
   source "backup.cron.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
+end
+
+prometheus_exporter "mailman" do
+  port 8083
+  user "list"
 end
index d2c0aab91a71b8093c341a8137d3feaa8c970d3d..42cdf2092cd911799b4587a6a777666d01c04bbd 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
   ServerAdmin postmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -26,7 +26,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent / https://<%= @name %>/
@@ -42,7 +42,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
   LogLevel warn
 
@@ -58,6 +58,9 @@
   RedirectMatch ^/$ /listinfo
   RedirectMatch ^/cgi-bin/mailman/(.*)$ /$1
 
+  # Redact list archive entries per request of talk moderators
+  RedirectMatch 451 ^/pipermail/talk/2022-July/(087645|087647)\.html$
+
   <Directory /var/lib/mailman/archives/>
          Options Indexes FollowSymLinks
     AllowOverride None
@@ -81,7 +84,8 @@
   ScriptAlias /subscribe /usr/lib/cgi-bin/mailman/subscribe
   ScriptAlias /mailman/ /usr/lib/cgi-bin/mailman/
 
-  <Location ~ "/pipermail/([^/]+)/(2004|2005|2006|2007|2008|2009|2010|2011|2012|2013|2014|2015|2016|2017|2018)">
+  <% last_year = year = Time.now.year - 1  %>
+  <Location ~ "/pipermail/([^/]+)/(<%= (2004..last_year).to_a.join('|') %>)">
     ExpiresActive On
     ExpiresDefault "access plus 180 days"
   </Location>
index 12a550c03a36695ef18482fb13f9a3fbd334d464..8d72d9d6000edad0f04b567cad8c8296024b9a30 100644 (file)
@@ -9,10 +9,9 @@ B=lists-$D.tar.gz
 mkdir $T/lists-$D
 ln -s /var/lib/mailman $T/lists-$D/mailman
 
-export GZIP="--rsyncable -9"
 export RSYNC_RSH="ssh -ax"
 
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B lists-$D
+nice tar --create --dereference --warning=no-file-changed --warning=no-file-removed --directory=$T lists-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
index 5252157f27e4e952eefaf9a8a8662b7a8d1f16bd..53b4990d45caf2914e66f5b2acb0d560467b2d3f 100644 (file)
@@ -109,7 +109,7 @@ POSTFIX_STYLE_VIRTUAL_DOMAINS = ['openstreetmap.org']
 
 #-------------------------------------------------------------
 # Secret for web forms to protect against XSRF attacks
-SUBSCRIBE_FORM_SECRET='<%= node[:mailman][:subscribe_form_secret] %>'
+SUBSCRIBE_FORM_SECRET='<%= @subscribe_form_secret %>'
 
 # Note - if you're looking for something that is imported from mm_cfg, but you
 # didn't find it above, it's probably in /usr/lib/mailman/Mailman/Defaults.py.
diff --git a/cookbooks/matomo/README.md b/cookbooks/matomo/README.md
new file mode 100644 (file)
index 0000000..6cb8ee4
--- /dev/null
@@ -0,0 +1,4 @@
+# Matomo Cookbook
+
+This cookbook installs and configures the Matomo server-side software used for
+analytics on openstreetmap.org
diff --git a/cookbooks/matomo/attributes/default.rb b/cookbooks/matomo/attributes/default.rb
new file mode 100644 (file)
index 0000000..82d41f5
--- /dev/null
@@ -0,0 +1,70 @@
+default[:matomo][:version] = "5.0.1"
+default[:matomo][:plugins] = {
+  "Actions" => nil,
+  "Annotations" => nil,
+  "API" => nil,
+  "BulkTracking" => nil,
+  "Contents" => nil,
+  "CoreAdminHome" => nil,
+  "CoreConsole" => nil,
+  "CoreHome" => nil,
+  "CorePluginsAdmin" => nil,
+  "CoreUpdater" => nil,
+  "CoreVisualizations" => nil,
+  "CoreVue" => nil,
+  "CustomJsTracker" => nil,
+  "Dashboard" => nil,
+  "DBStats" => nil,
+  "DeviceFeatureWebGL" => "5.0.0",
+  "DevicePlugins" => nil,
+  "DevicesDetection" => nil,
+  "Diagnostics" => nil,
+  "Ecommerce" => nil,
+  "Events" => nil,
+  "Feedback" => nil,
+  "GeoIp2" => nil,
+  "Goals" => nil,
+  "Heartbeat" => nil,
+  "ImageGraph" => nil,
+  "Insights" => nil,
+  "Installation" => nil,
+  "Intl" => nil,
+  "IntranetMeasurable" => nil,
+  "LanguagesManager" => nil,
+  "Live" => nil,
+  "Login" => nil,
+  "Marketplace" => nil,
+  "MobileAppMeasurable" => nil,
+  "MobileMessaging" => nil,
+  "Monolog" => nil,
+  "Morpheus" => nil,
+  "MultiSites" => nil,
+  "Overlay" => nil,
+  "PagePerformance" => nil,
+  "PrivacyManager" => nil,
+  "ProfessionalServices" => nil,
+  "Proxy" => nil,
+  "Referrers" => nil,
+  "Resolution" => nil,
+  "RssWidget" => nil,
+  "ScheduledReports" => nil,
+  "SegmentEditor" => nil,
+  "SEO" => nil,
+  "SitesManager" => nil,
+  "Tour" => nil,
+  "Transitions" => nil,
+  "TwoFactorAuth" => nil,
+  "UserCountry" => nil,
+  "UserCountryMap" => nil,
+  "UserId" => nil,
+  "UserLanguage" => nil,
+  "UsersManager" => nil,
+  "VisitFrequency" => nil,
+  "VisitorInterest" => nil,
+  "VisitsSummary" => nil,
+  "VisitTime" => nil,
+  "WebsiteMeasurable" => nil,
+  "Widgetize" => nil,
+}
+
+default[:mysql][:settings][:mysqld][:secure_file_priv] = "/opt/matomo-#{node[:matomo][:version]}/matomo/tmp/assets"
similarity index 58%
rename from cookbooks/donate/metadata.rb
rename to cookbooks/matomo/metadata.rb
index 0882bddf8cc9522c60ae639218b558ca0598f181..380cbbe430ac65face8029ebf8b5af4fb1ee7d46 100644 (file)
@@ -1,11 +1,13 @@
-name              "donate"
+name              "matomo"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures Donate Site"
+description       "Installs and configures Matomo"
 
 version           "1.0.0"
 supports          "ubuntu"
 depends           "apache"
+depends           "geoipupdate"
 depends           "mysql"
-depends           "git"
+depends           "php"
+depends           "systemd"
diff --git a/cookbooks/matomo/recipes/default.rb b/cookbooks/matomo/recipes/default.rb
new file mode 100644 (file)
index 0000000..5557d78
--- /dev/null
@@ -0,0 +1,223 @@
+#
+# Cookbook:: matomo
+# Recipe:: default
+#
+# Copyright:: 2011, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apache"
+include_recipe "geoipupdate"
+include_recipe "mysql"
+include_recipe "php::fpm"
+
+passwords = data_bag_item("matomo", "passwords")
+
+package %w[
+  brotli
+  gzip
+  php-cli
+  php-curl
+  php-mbstring
+  php-mysql
+  php-gd
+  php-xml
+  php-apcu
+]
+
+apache_module "expires"
+apache_module "proxy"
+apache_module "proxy_fcgi"
+apache_module "rewrite"
+
+version = node[:matomo][:version]
+
+geoip_directory = node[:geoipupdate][:directory]
+
+remote_file "#{Chef::Config[:file_cache_path]}/matomo-#{version}.zip" do
+  source "https://builds.matomo.org/matomo-#{version}.zip"
+end
+
+archive_file "#{Chef::Config[:file_cache_path]}/matomo-#{version}.zip" do
+  destination "/opt/matomo-#{version}"
+  notifies :run, "notify_group[matomo-updated]"
+end
+
+node[:matomo][:plugins].each do |plugin_name, plugin_version|
+  next if plugin_version.nil?
+
+  remote_file "#{Chef::Config[:file_cache_path]}/matomo-#{plugin_name}-#{plugin_version}.zip" do
+    source "https://plugins.matomo.org/api/2.0/plugins/#{plugin_name}/download/#{plugin_version}"
+  end
+
+  archive_file "#{Chef::Config[:file_cache_path]}/matomo-#{plugin_name}-#{plugin_version}.zip" do
+    destination "/opt/matomo-#{plugin_name}-#{plugin_version}"
+  end
+
+  link "/opt/matomo-#{version}/matomo/plugins/#{plugin_name}" do
+    to "/opt/matomo-#{plugin_name}-#{plugin_version}/#{plugin_name}"
+    notifies :run, "notify_group[matomo-updated]"
+  end
+end
+
+directory "/opt/matomo-#{version}/matomo/config" do
+  owner "www-data"
+  group "www-data"
+  mode "0755"
+end
+
+template "/opt/matomo-#{version}/matomo/config/config.ini.php" do
+  source "config.erb"
+  owner "root"
+  group "root"
+  mode "0644"
+  variables :passwords => passwords,
+            :directory => "/opt/matomo-#{version}/matomo",
+            :plugins => node[:matomo][:plugins].keys.sort
+  notifies :run, "notify_group[matomo-updated]"
+end
+
+directory "/opt/matomo-#{version}/matomo/tmp" do
+  owner "www-data"
+  group "www-data"
+  mode "0755"
+end
+
+directory "/opt/matomo-#{version}/matomo/tmp/assets" do
+  owner "www-data"
+  group "mysql"
+  mode "0750"
+end
+
+directory "/opt/matomo-#{version}/matomo/tmp/cache" do
+  owner "www-data"
+  group "www-data"
+  mode "0750"
+end
+
+link "/opt/matomo-#{version}/matomo/misc/GeoLite2-ASN.mmdb" do
+  to "#{geoip_directory}/GeoLite2-ASN.mmdb"
+end
+
+link "/opt/matomo-#{version}/matomo/misc/GeoLite2-City.mmdb" do
+  to "#{geoip_directory}/GeoLite2-City.mmdb"
+end
+
+link "/opt/matomo-#{version}/matomo/misc/GeoLite2-Country.mmdb" do
+  to "#{geoip_directory}/GeoLite2-Country.mmdb"
+end
+
+mysql_user "piwik@localhost" do
+  password passwords["database"]
+end
+
+mysql_database "piwik" do
+  permissions "piwik@localhost" => :all
+end
+
+notify_group "matomo-updated"
+
+if File.symlink?("/srv/matomo.openstreetmap.org")
+  execute "core:update" do
+    action :nothing
+    command "/opt/matomo-#{version}/matomo/console core:update --yes"
+    user "www-data"
+    group "www-data"
+    subscribes :run, "notify_group[matomo-updated]"
+  end
+
+  execute "custom-matomo-js:update" do
+    action :nothing
+    command "/opt/matomo-#{version}/matomo/console custom-matomo-js:update"
+    user "root"
+    group "root"
+    subscribes :run, "execute[core:update]"
+  end
+
+  execute "/opt/matomo-#{version}/matomo/matomo.br" do
+    action :nothing
+    command "brotli --keep --force --best /opt/matomo-#{version}/matomo/matomo.js"
+    cwd "/opt/matomo-#{version}"
+    user "root"
+    group "root"
+    subscribes :run, "execute[custom-matomo-js:update]"
+  end
+
+  execute "/opt/matomo-#{version}/matomo/matomo.js" do
+    action :nothing
+    command "gzip --keep --force --best /opt/matomo-#{version}/matomo/matomo.js"
+    cwd "/opt/matomo-#{version}"
+    user "root"
+    group "root"
+    subscribes :run, "execute[custom-matomo-js:update]"
+  end
+
+  execute "/opt/matomo-#{version}/matomo/piwik.br" do
+    action :nothing
+    command "brotli --keep --force --best /opt/matomo-#{version}/matomo/piwik.js"
+    cwd "/opt/matomo-#{version}"
+    user "root"
+    group "root"
+    subscribes :run, "execute[custom-matomo-js:update]"
+  end
+
+  execute "/opt/matomo-#{version}/matomo/piwik.js" do
+    action :nothing
+    command "gzip --keep --force --best /opt/matomo-#{version}/matomo/piwik.js"
+    cwd "/opt/matomo-#{version}"
+    user "root"
+    group "root"
+    subscribes :run, "execute[custom-matomo-js:update]"
+  end
+end
+
+link "/srv/matomo.openstreetmap.org" do
+  to "/opt/matomo-#{version}/matomo"
+  notifies :restart, "service[php#{node[:php][:version]}-fpm]"
+end
+
+ssl_certificate "matomo.openstreetmap.org" do
+  domains ["matomo.openstreetmap.org", "matomo.osm.org",
+           "piwik.openstreetmap.org", "piwik.osm.org"]
+  notifies :reload, "service[apache2]"
+end
+
+php_fpm "matomo.openstreetmap.org" do
+  prometheus_port 9253
+end
+
+apache_site "matomo.openstreetmap.org" do
+  template "apache.erb"
+end
+
+systemd_service "matomo-archive" do
+  description "Matomo report archiving"
+  exec_start "/usr/bin/php /srv/matomo.openstreetmap.org/console core:archive --url=https://matomo.openstreetmap.org/"
+  user "www-data"
+  sandbox true
+  proc_subset "all"
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/opt/matomo-#{version}/matomo/tmp"
+end
+
+systemd_timer "matomo-archive" do
+  description "Matomo report archiving"
+  on_boot_sec "30m"
+  on_unit_inactive_sec "30m"
+end
+
+service "matomo-archive.timer" do
+  action [:enable, :start]
+end
diff --git a/cookbooks/matomo/templates/default/apache.erb b/cookbooks/matomo/templates/default/apache.erb
new file mode 100644 (file)
index 0000000..525d1fb
--- /dev/null
@@ -0,0 +1,88 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<VirtualHost *:443>
+       ServerName matomo.openstreetmap.org
+       ServerAdmin webmaster@openstreetmap.org
+
+       SSLEngine on
+       SSLCertificateFile /etc/ssl/certs/matomo.openstreetmap.org.pem
+       SSLCertificateKeyFile /etc/ssl/private/matomo.openstreetmap.org.key
+
+       CustomLog /var/log/apache2/matomo.openstreetmap.org-access.log combined_extended
+       ErrorLog /var/log/apache2/matomo.openstreetmap.org-error.log
+
+       Options -Indexes
+
+       DocumentRoot /srv/matomo.openstreetmap.org
+
+       Redirect 403 /core/
+       Redirect 403 /config/
+       Redirect 403 /lang/
+       Redirect 403 /tmp/
+</VirtualHost>
+
+<VirtualHost *:443>
+       ServerName matomo.osm.org
+       ServerAlias piwik.openstreetmap.org
+       ServerAlias piwik.osm.org
+       ServerAdmin webmaster@openstreetmap.org
+
+       SSLEngine on
+       SSLCertificateFile /etc/ssl/certs/matomo.openstreetmap.org.pem
+       SSLCertificateKeyFile /etc/ssl/private/matomo.openstreetmap.org.key
+
+       CustomLog /var/log/apache2/matomo.openstreetmap.org-access.log combined_extended
+       ErrorLog /var/log/apache2/matomo.openstreetmap.org-error.log
+
+       RedirectPermanent / https://matomo.openstreetmap.org/
+</VirtualHost>
+
+<VirtualHost *:80>
+       ServerName matomo.openstreetmap.org
+       ServerAlias matomo.osm.org
+       ServerAlias piwik.openstreetmap.org
+       ServerAlias piwik.osm.org
+       ServerAdmin webmaster@openstreetmap.org
+
+       CustomLog /var/log/apache2/matomo.openstreetmap.org-access.log combined_extended
+       ErrorLog /var/log/apache2/matomo.openstreetmap.org-error.log
+
+       RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
+       RedirectPermanent / https://matomo.openstreetmap.org/
+</VirtualHost>
+
+<Directory /srv/matomo.openstreetmap.org>
+       Require all granted
+
+       ExpiresActive On
+       RewriteEngine on
+
+       RewriteCond "%{HTTP:Accept-Encoding}" "br"
+       RewriteCond "%{REQUEST_FILENAME}\.br" -s
+       RewriteRule "^(.*)\.js" "$1\.js\.br" [QSA]
+
+       RewriteCond "%{HTTP:Accept-Encoding}" "gzip"
+       RewriteCond "%{REQUEST_FILENAME}\.gz" -s
+       RewriteRule "^(.*)\.js" "$1\.js\.gz" [QSA]
+
+       RewriteRule "\.js\.(br|gz)$"  "-" [T=text/javascript,E=no-gzip:1,E=no-brotli:1]
+
+       <FilesMatch "\.js\.br$">
+               Header append Content-Encoding br
+               Header append Vary Accept-Encoding
+       </FilesMatch>
+
+       <FilesMatch "\.js\.gz$">
+               Header append Content-Encoding gzip
+               Header append Vary Accept-Encoding
+       </FilesMatch>
+
+       <FilesMatch "(\.js|\.js\.gz|\.js\.br)$">
+               ExpiresDefault "access plus 1 week"
+               Header set Cache-Control "max-age=604800"
+       </FilesMatch>
+
+        <FilesMatch ".+\.ph(ar|p|tml)$">
+                SetHandler "proxy:unix:/run/php/php-matomo.openstreetmap.org-fpm.sock|fcgi://127.0.0.1"
+        </FilesMatch>
+</Directory>
similarity index 72%
rename from cookbooks/piwik/templates/default/config.erb
rename to cookbooks/matomo/templates/default/config.erb
index 3e4b940b81c6ce3d9957923ff906edfe0331e246..457badc839c343f5545c06e437f7da0cbfd81eba 100644 (file)
@@ -1,20 +1,25 @@
 ; <?php exit; ?> DO NOT REMOVE THIS LINE
-; file automatically generated or modified by Piwik; you can manually override the default values in global.ini.php by redefining them in this file.
+; file automatically generated or modified by Matomo; you can manually override the default values in global.ini.php by redefining them in this file.
 [database]
 host = "localhost"
 username = "piwik"
 password = "<%= @passwords['database'] %>"
 dbname = "piwik"
 tables_prefix = "piwik_"
-charset = "utf8"
+charset = "utf8mb4"
 
 [General]
 force_ssl = 1
 force_ssl_login = 1
+login_allowlist_apply_to_reporting_api_requests = "0"
 proxy_client_headers[] = "HTTP_X_FORWARDED_FOR"
+trusted_hosts[] = "matomo.openstreetmap.org"
 trusted_hosts[] = "piwik.openstreetmap.org"
 salt = "<%= @passwords['salt'] %>"
 
+[Tracker]
+ignore_visits_cookie_name = "matomo_ignore"
+
 [Plugins]
 <% @plugins.each do |plugin| -%>
 Plugins[] = "<%= plugin %>"
@@ -28,7 +33,6 @@ PluginsInstalled[] = "<%= plugin %>"
 [Plugins_Tracker]
 Plugins_Tracker[] = "Provider"
 Plugins_Tracker[] = "Goals"
-Plugins_Tracker[] = "DoNotTrack"
 Plugins_Tracker[] = "UserCountry"
 Plugins_Tracker[] = "DevicesDetection"
 Plugins_Tracker[] = "UsersManager"
index 59838f9206df8dbd529d19798c47816d977ce825..7a043d5592285dd5e88d601ef6962b8138b0a0d9 100644 (file)
@@ -1,12 +1,6 @@
-# Add the mediawiki APT source
-default[:apt][:sources] = node[:apt][:sources] | ["mediawiki"]
-
 # Default to enabling the "wiki" role
 default[:accounts][:users][:wiki][:status] = :role
 
-# Use prefork as PHP is to dumb for anything else
-default[:apache][:mpm] = "prefork"
-
 # Set mediawiki defaults
 default[:mediawiki][:user] = "wiki"
 default[:mediawiki][:group] = "wiki"
index 9df8048079287980de97d44bb3500bac0428839e..e3a159c8062ed3562a04784d5c610d495a1dd3c6 100644 (file)
@@ -6,7 +6,12 @@ description       "Installs and configures mediawiki"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "memcached"
+depends           "accounts"
 depends           "apache"
-depends           "mysql"
+depends           "apt"
+depends           "chef"
 depends           "git"
+depends           "memcached"
+depends           "mysql"
+depends           "php"
+depends           "systemd"
index 27c7cb48fe1b228a4b076345c67b78774fbb2c5a..c7249e8facfebb58845bbcacd24f9eb1c2a82242 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "memcached"
+include_recipe "accounts"
 include_recipe "apache"
-include_recipe "mysql"
+include_recipe "apt"
 include_recipe "git"
+include_recipe "memcached"
+include_recipe "mysql"
+include_recipe "php::fpm"
 
 # Mediawiki Base Requirements
 package %w[
-  php
+  php-apcu
   php-cli
   php-curl
   php-gd
+  php-igbinary
   php-intl
+  php-memcache
   php-mbstring
   php-mysql
   php-xml
   php-zip
   composer
+  unzip
+  ffmpeg
 ]
 
 # Mediawiki enhanced difference engine
@@ -60,34 +67,99 @@ package %w[
 # Mediawiki packages for VisualEditor support
 package %w[
   curl
-  parsoid
 ]
 
 # Mediawiki packages for SyntaxHighight support
-package "python-pygments"
+package "python3-pygments"
 
-file "/etc/mediawiki/parsoid/settings.js" do
-  action :delete
+link "/etc/php/#{node[:php][:version]}/fpm/conf.d/20-wikidiff2.ini" do
+  to "../../mods-available/wikidiff2.ini"
 end
 
-template "/etc/mediawiki/parsoid/config.yaml" do
-  source "parsoid-config.yaml.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+apache_module "proxy"
+apache_module "proxy_fcgi"
+apache_module "rewrite"
+
+systemd_service "mediawiki-sitemap@" do
+  description "Generate sitemap.xml for %i"
+  exec_start "/usr/bin/php -d memory_limit=2048M -d error_reporting=22517 /srv/%i/w/maintenance/generateSitemap.php --server=https://%i --urlpath=https://%i/ --fspath=/srv/%i --quiet --skip-redirects"
+  user node[:mediawiki][:user]
+  nice 10
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/srv/%i"
 end
 
-service "parsoid" do
-  action [:enable]
-  supports :status => false, :restart => true, :reload => false
-  subscribes :restart, "file[/etc/mediawiki/parsoid/settings.js]"
-  subscribes :restart, "template[/etc/mediawiki/parsoid/config.yaml]"
+systemd_timer "mediawiki-sitemap@" do
+  description "Generate sitemap.xml for %i"
+  on_calendar "00:30"
 end
 
-apache_module "php7.2"
+systemd_service "mediawiki-jobs@" do
+  description "Run mediawiki jobs for %i"
+  exec_start "/usr/bin/php -d memory_limit=2048M -d error_reporting=22517 /srv/%i/w/maintenance/runJobs.php --server=https://%i --maxtime=175 --memory-limit=2048M --procs=8"
+  user node[:mediawiki][:user]
+  nice 10
+  runtime_max_sec 3600
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/srv/%i"
+end
 
-link "/etc/php/7.2/apache2/conf.d/20-wikidiff2.ini" do
-  to "../../mods-available/wikidiff2.ini"
+systemd_timer "mediawiki-jobs@" do
+  description "Run mediawiki jobs for %i"
+  on_boot_sec "3m"
+  on_unit_inactive_sec "3m"
 end
 
-apache_module "rewrite"
+systemd_service "mediawiki-email-jobs@" do
+  description "Run mediawiki email jobs for %i"
+  exec_start "/usr/bin/php -d memory_limit=2048M -d error_reporting=22517 /srv/%i/w/maintenance/runJobs.php --server=https://%i --maxtime=55 --type=enotifNotify --memory-limit=2048M --procs=4"
+  user node[:mediawiki][:user]
+  nice 10
+  runtime_max_sec 3600
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/srv/%i"
+end
+
+systemd_timer "mediawiki-email-jobs@" do
+  description "Run mediawiki email jobs for %i"
+  on_boot_sec "1m"
+  on_unit_inactive_sec "1m"
+end
+
+systemd_service "mediawiki-cleanup-gs" do
+  description "Clean up imagemagick gs_* files"
+  exec_start "/usr/bin/find /tmp -maxdepth 1 -type f -user www-data -mmin +90 -name 'gs_*' -delete"
+  user node[:mediawiki][:user]
+  sandbox true
+end
+
+systemd_timer "mediawiki-cleanup-gs" do
+  description "Clean up imagemagick gs_* files"
+  on_calendar "02:10"
+end
+
+service "mediawiki-cleanup-gs.timer" do
+  action [:enable, :start]
+end
+
+systemd_service "mediawiki-cleanup-magick" do
+  description "Clean up imagemagick magick-* files"
+  exec_start "/usr/bin/find /tmp -maxdepth 1 -type f -user www-data -mmin +90 -name 'magick-*' -delete"
+  user node[:mediawiki][:user]
+  sandbox true
+end
+
+systemd_timer "mediawiki-cleanup-magick" do
+  description "Clean up imagemagick magick-* files"
+  on_calendar "02:20"
+end
+
+service "mediawiki-cleanup-magick.timer" do
+  action [:enable, :start]
+end
index 1fe4faea5ec657c3a3ae46765e369d4bdf6dba2b..6240f6e87d008c1624d5497c6f2da6595499af61 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :extension, :kind_of => String, :name_attribute => true
+property :extension, :kind_of => String, :name_property => true
 property :site, :kind_of => String, :required => true
 property :source, :kind_of => String
 property :template, :kind_of => String
@@ -38,10 +40,10 @@ action :create do
       source new_resource.source
       owner node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      mode 0o755
+      mode "755"
       files_owner node[:mediawiki][:user]
       files_group node[:mediawiki][:group]
-      files_mode 0o755
+      files_mode "755"
     end
   else
     extension_repository = new_resource.repository || default_repository
@@ -57,10 +59,11 @@ action :create do
       action :sync
       repository extension_repository
       reference extension_reference
+      depth 1
       enable_submodules true
       user node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      ignore_failure extension_repository.start_with?("git://github.com/wikimedia/mediawiki-extensions")
+      ignore_failure extension_repository.start_with?("https://github.com/wikimedia/mediawiki-extensions")
     end
   end
 
@@ -70,7 +73,7 @@ action :create do
       source new_resource.template
       user node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      mode 0o664
+      mode "664"
       variables new_resource.variables
     end
   else
@@ -78,19 +81,9 @@ action :create do
       content "<?php wfLoadExtension( '#{new_resource.extension}' );\n"
       user node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      mode 0o664
+      mode "664"
     end
   end
-
-  execute "#{extension_directory}/composer.json" do
-    action :nothing
-    command "composer update --no-dev"
-    cwd mediawiki_directory
-    user node[:mediawiki][:user]
-    group node[:mediawiki][:group]
-    only_if { ::File.exist?("#{extension_directory}/composer.json") }
-    subscribes :run, "git[#{extension_directory}]"
-  end
 end
 
 action :delete do
@@ -122,17 +115,10 @@ action_class do
   end
 
   def default_repository
-    "git://github.com/wikimedia/mediawiki-extensions-#{new_resource.extension}.git"
+    "https://github.com/wikimedia/mediawiki-extensions-#{new_resource.extension}.git"
   end
 end
 
 def after_created
-  if update_site
-    notifies :update, "mediawiki_site[#{site}]"
-  else
-    site_directory = node[:mediawiki][:sites][site][:directory]
-
-    notifies :create, "template[#{site_directory}/w/LocalSettings.php]"
-    notifies :run, "execute[#{site_directory}/w/maintenance/update.php]"
-  end
+  notifies :update, "mediawiki_site[#{site}]" if update_site
 end
index a3862ca521c8c50810e4e6b16f57887c42818a2f..0bbddfe8174e2e3c869450f775afe99f28e768df 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :site, :kind_of => String, :name_attribute => true
+property :site, :kind_of => String, :name_property => true
 property :aliases, :kind_of => [String, Array]
-property :directory, :kind_of => String
-property :version, :kind_of => String, :default => "1.33"
+property :version, :kind_of => String, :default => "1.39"
 property :database_name, :kind_of => String, :required => true
-property :database_user, :kind_of => String, :required => true
-property :database_password, :kind_of => String, :required => true
+property :database_user, :kind_of => String, :required => [:create, :update]
+property :database_password, :kind_of => String, :required => [:create, :update]
 property :sitename, :kind_of => String, :default => "OpenStreetMap Wiki"
 property :metanamespace, :kind_of => String, :default => "OpenStreetMap"
 property :logo, :kind_of => String, :default => "$wgStylePath/common/images/wiki.png"
@@ -37,24 +38,29 @@ property :skin, :kind_of => String, :default => "vector"
 property :site_notice, :kind_of => [String, TrueClass, FalseClass], :default => false
 property :site_readonly, :kind_of => [String, TrueClass, FalseClass], :default => false
 property :admin_user, :kind_of => String, :default => "Admin"
-property :admin_password, :kind_of => String, :required => true
+property :admin_password, :kind_of => String, :required => [:create]
 property :private_accounts, :kind_of => [TrueClass, FalseClass], :default => false
 property :private_site, :kind_of => [TrueClass, FalseClass], :default => false
-property :recaptcha_public_key, :kind_of => String
-property :recaptcha_private_key, :kind_of => String
+property :hcaptcha_public_key, :kind_of => String, :default => ""
+property :hcaptcha_private_key, :kind_of => String, :default => ""
 property :extra_file_extensions, :kind_of => [String, Array], :default => []
+property :fpm_max_children, :kind_of => Integer, :default => 5
+property :fpm_start_servers, :kind_of => Integer, :default => 2
+property :fpm_min_spare_servers, :kind_of => Integer, :default => 1
+property :fpm_max_spare_servers, :kind_of => Integer, :default => 3
+property :fpm_request_terminate_timeout, :kind_of => Integer, :default => 300
+property :fpm_prometheus_port, :kind_of => Integer
 property :reload_apache, :kind_of => [TrueClass, FalseClass], :default => true
 
 action :create do
-  node.normal_unless[:mediawiki][:sites][new_resource.site] = {}
-
-  node.normal[:mediawiki][:sites][new_resource.site][:directory] = site_directory
-  node.normal[:mediawiki][:sites][new_resource.site][:version] = new_resource.version
-
-  node.normal_unless[:mediawiki][:sites][new_resource.site][:wgSecretKey] = SecureRandom.base64(48)
+  node.default[:mediawiki][:sites][new_resource.site] = {
+    :directory => site_directory,
+    :version => new_resource.version
+  }
 
   mysql_user "#{new_resource.database_user}@localhost" do
     password new_resource.database_password
+    reload true
   end
 
   mysql_database new_resource.database_name do
@@ -63,102 +69,69 @@ action :create do
 
   mediawiki_directory = "#{site_directory}/w"
 
-  ruby_block "rename-installer-localsettings" do
-    action :nothing
-    block do
-      ::File.rename("#{mediawiki_directory}/LocalSettings.php", "#{mediawiki_directory}/LocalSettings-install.php")
-    end
-  end
-
-  execute "#{mediawiki_directory}/maintenance/install.php" do
-    action :nothing
-    # Use metanamespace as Site Name to ensure correct set namespace
-    command "php maintenance/install.php --server '#{name}' --dbtype 'mysql' --dbname '#{new_resource.database_name}' --dbuser '#{new_resource.database_user}' --dbpass '#{new_resource.database_password}' --dbserver 'localhost' --scriptpath /w --pass '#{new_resource.admin_password}' '#{new_resource.metanamespace}' '#{new_resource.admin_user}'"
-    cwd mediawiki_directory
-    user node[:mediawiki][:user]
-    group node[:mediawiki][:group]
-    not_if do
-      ::File.exist?("#{mediawiki_directory}/LocalSettings-install.php")
-    end
-    notifies :run, "ruby_block[rename-installer-localsettings]", :immediately
-  end
-
-  execute "#{mediawiki_directory}/maintenance/update.php" do
-    action :nothing
-    command "php maintenance/update.php --quick"
-    cwd mediawiki_directory
-    user node[:mediawiki][:user]
-    group node[:mediawiki][:group]
-  end
-
   declare_resource :directory, site_directory do
     owner node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o775
+    mode "775"
   end
 
   declare_resource :directory, mediawiki_directory do
     owner node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o775
+    mode "775"
   end
 
-  mediawiki_reference = "REL#{new_resource.version}".tr(".", "_")
-
   git mediawiki_directory do
     action :sync
-    repository "https://gerrit.wikimedia.org/r/p/mediawiki/core.git"
+    repository "https://gerrit.wikimedia.org/r/mediawiki/core.git"
     revision mediawiki_reference
+    depth 1
     user node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    notifies :run, "execute[#{mediawiki_directory}/composer.json]", :immediately
-    notifies :run, "execute[#{mediawiki_directory}/maintenance/install.php]", :immediately
-    notifies :run, "execute[#{mediawiki_directory}/maintenance/update.php]"
+  end
+
+  template "#{mediawiki_directory}/composer.local.json" do
+    cookbook "mediawiki"
+    source "composer.local.json.erb"
+    owner node[:mediawiki][:user]
+    group node[:mediawiki][:group]
+    mode "664"
   end
 
   execute "#{mediawiki_directory}/composer.json" do
-    action :nothing
     command "composer update --no-dev"
     cwd mediawiki_directory
     user node[:mediawiki][:user]
     group node[:mediawiki][:group]
+    environment "COMPOSER_HOME" => site_directory
+    not_if { ::File.exist?("#{mediawiki_directory}/composer.lock") }
   end
 
-  template "#{mediawiki_directory}/composer.local.json" do
-    cookbook "mediawiki"
-    source "composer.local.json.erb"
-    owner node[:mediawiki][:user]
+  execute "#{mediawiki_directory}/maintenance/install.php" do
+    # Use metanamespace as Site Name to ensure correct set namespace
+    command "php maintenance/install.php --server '#{name}' --dbtype 'mysql' --dbname '#{new_resource.database_name}' --dbuser '#{new_resource.database_user}' --dbpass '#{new_resource.database_password}' --dbserver 'localhost' --scriptpath /w --pass '#{new_resource.admin_password}' '#{new_resource.metanamespace}' '#{new_resource.admin_user}'"
+    cwd mediawiki_directory
+    user node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o664
-  end
-
-  # Safety catch if git doesn't update but install.php hasn't run
-  ruby_block "catch-installer-localsettings-run" do
-    action :run
-    block do
-    end
-    not_if do
-      ::File.exist?("#{mediawiki_directory}/LocalSettings-install.php")
-    end
-    notifies :run, "execute[#{mediawiki_directory}/maintenance/install.php]", :immediately
+    not_if { ::File.exist?("#{mediawiki_directory}/LocalSettings.php") }
   end
 
   declare_resource :directory, "#{mediawiki_directory}/images" do
     owner "www-data"
     group node[:mediawiki][:group]
-    mode 0o775
+    mode "775"
   end
 
   declare_resource :directory, "#{mediawiki_directory}/cache" do
     owner "www-data"
     group node[:mediawiki][:group]
-    mode 0o775
+    mode "775"
   end
 
   declare_resource :directory, "#{mediawiki_directory}/LocalSettings.d" do
     user node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o775
+    mode "775"
   end
 
   template "#{mediawiki_directory}/LocalSettings.php" do
@@ -166,22 +139,27 @@ action :create do
     source "LocalSettings.php.erb"
     owner node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o664
+    mode "664"
     variables :name => new_resource.site,
               :directory => mediawiki_directory,
               :database_params => database_params,
-              :mediawiki => mediawiki_params
-    notifies :run, "execute[#{mediawiki_directory}/maintenance/update.php]"
+              :mediawiki => mediawiki_params,
+              :secret_key => secret_key
   end
 
-  template "/etc/cron.d/mediawiki-#{cron_name}" do
-    cookbook "mediawiki"
-    source "mediawiki.cron.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    variables :name => new_resource.site, :directory => site_directory,
-              :user => node[:mediawiki][:user]
+  service "mediawiki-sitemap@#{new_resource.site}.timer" do
+    action [:enable, :start]
+    only_if { ::File.exist?("#{mediawiki_directory}/LocalSettings.php") }
+  end
+
+  service "mediawiki-jobs@#{new_resource.site}.timer" do
+    action [:enable, :start]
+    only_if { ::File.exist?("#{mediawiki_directory}/LocalSettings.php") }
+  end
+
+  service "mediawiki-email-jobs@#{new_resource.site}.timer" do
+    action [:enable, :start]
+    only_if { ::File.exist?("#{mediawiki_directory}/LocalSettings.php") }
   end
 
   template "/etc/cron.daily/mediawiki-#{cron_name}-backup" do
@@ -189,16 +167,18 @@ action :create do
     source "mediawiki-backup.cron.erb"
     owner "root"
     group "root"
-    mode 0o700
+    mode "700"
     variables :name => new_resource.site,
               :directory => site_directory,
               :database_params => database_params
+    only_if { ::File.exist?("#{mediawiki_directory}/LocalSettings.php") }
   end
 
   # MobileFrontend extension is required by MinervaNeue skin
   mediawiki_extension "MobileFrontend" do
     site new_resource.site
     template "mw-ext-MobileFrontend.inc.php.erb"
+    update_site false
   end
 
   # MobileFrontend extension is required by MinervaNeue skin
@@ -252,8 +232,8 @@ action :create do
     mediawiki_extension "ConfirmEdit" do
       site new_resource.site
       template "mw-ext-ConfirmEdit.inc.php.erb"
-      variables :public_key => new_resource.recaptcha_public_key,
-                :private_key => new_resource.recaptcha_private_key
+      variables :public_key => new_resource.hcaptcha_public_key,
+                :private_key => new_resource.hcaptcha_private_key
       update_site false
     end
   end
@@ -341,6 +321,11 @@ action :create do
     update_site false
   end
 
+  mediawiki_extension "CategoryTree" do
+    site new_resource.site
+    update_site false
+  end
+
   mediawiki_extension "cldr" do
     site new_resource.site
     template "mw-ext-cldr.inc.php.erb"
@@ -353,22 +338,12 @@ action :create do
     update_site false
   end
 
+  # Extension has been archived: https://www.mediawiki.org/wiki/Extension:LocalisationUpdate
   mediawiki_extension "LocalisationUpdate" do
     site new_resource.site
-    template "mw-ext-LocalisationUpdate.inc.php.erb"
-    update_site false
+    action :delete
   end
 
-  # LocalisationUpdate Update Cron
-  # template "/etc/cron.d/mediawiki-#{name}-LocalisationUpdate" do
-  #   cookbook "mediawiki"
-  #   source "mediawiki-LocalisationUpdate.cron.erb"
-  #   owner "root"
-  #   group "root"
-  #   mode 0755
-  #   variables :name => name, :directory => site_directory, :user => node[:mediawiki][:user]
-  # end
-
   # mediawiki_extension "Translate" do
   #   site new_resource.site
   #   template "mw-ext-Translate.inc.php.erb"
@@ -417,34 +392,18 @@ action :create do
 
   mediawiki_extension "osmtaginfo" do
     site new_resource.site
-    template "mw-ext-osmtaginfo.inc.php.erb"
-    repository "git://github.com/Firefishy/osmtaginfo.git"
-    tag "live"
-    update_site false
-  end
-
-  mediawiki_extension "SimpleMap" do
-    site new_resource.site
-    template "mw-ext-SimpleMap.inc.php.erb"
-    repository "git://github.com/Firefishy/SimpleMap.git"
+    repository "https://github.com/openstreetmap/osmtaginfo.git"
     tag "live"
     update_site false
   end
 
-  mediawiki_extension "SlippyMap" do
+  mediawiki_extension "OSMCALWikiWidget" do
     site new_resource.site
-    template "mw-ext-SlippyMap.inc.php.erb"
-    repository "git://github.com/Firefishy/SlippyMap.git"
+    repository "https://github.com/thomersch/OSMCALWikiWidget.git"
     tag "live"
     update_site false
   end
 
-  mediawiki_extension "Mantle" do
-    site new_resource.site
-    update_site false
-    action :delete
-  end
-
   mediawiki_extension "DisableAccount" do
     site new_resource.site
     template "mw-ext-DisableAccount.inc.php.erb"
@@ -454,6 +413,7 @@ action :create do
   mediawiki_extension "VisualEditor" do
     site new_resource.site
     template "mw-ext-VisualEditor.inc.php.erb"
+    variables :version => new_resource.version
     update_site false
   end
 
@@ -462,11 +422,24 @@ action :create do
     update_site false
   end
 
+  if new_resource.commons
+    mediawiki_extension "QuickInstantCommons" do
+      site new_resource.site
+      update_site false
+    end
+  else
+    mediawiki_extension "QuickInstantCommons" do
+      site new_resource.site
+      update_site false
+      action :delete
+    end
+  end
+
   cookbook_file "#{site_directory}/cc-wiki.png" do
     cookbook "mediawiki"
     owner node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o644
+    mode "644"
     backup false
   end
 
@@ -474,7 +447,7 @@ action :create do
     cookbook "mediawiki"
     owner node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o644
+    mode "644"
     backup false
   end
 
@@ -482,7 +455,7 @@ action :create do
     cookbook "mediawiki"
     owner node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o644
+    mode "644"
     backup false
   end
 
@@ -490,6 +463,20 @@ action :create do
     domains [new_resource.site] + Array(new_resource.aliases)
   end
 
+  php_fpm new_resource.site do
+    pm_max_children new_resource.fpm_max_children
+    pm_start_servers new_resource.fpm_start_servers
+    pm_min_spare_servers new_resource.fpm_min_spare_servers
+    pm_max_spare_servers new_resource.fpm_max_spare_servers
+    request_terminate_timeout new_resource.fpm_request_terminate_timeout
+    php_admin_values "open_basedir" => "#{site_directory}/:/usr/share/php/:/dev/null:/tmp/"
+    php_values "memory_limit" => "500M",
+               "max_execution_time" => "240",
+               "upload_max_filesize" => "70M",
+               "post_max_size" => "100M"
+    prometheus_port new_resource.fpm_prometheus_port
+  end
+
   apache_site new_resource.site do
     cookbook "mediawiki"
     template "apache.erb"
@@ -512,17 +499,25 @@ end
 action :update do
   mediawiki_directory = "#{site_directory}/w"
 
+  execute "#{mediawiki_directory}/composer.json" do
+    command "composer update --no-dev"
+    cwd mediawiki_directory
+    user node[:mediawiki][:user]
+    group node[:mediawiki][:group]
+    environment "COMPOSER_HOME" => site_directory
+  end
+
   template "#{mediawiki_directory}/LocalSettings.php" do
     cookbook "mediawiki"
     source "LocalSettings.php.erb"
     owner node[:mediawiki][:user]
     group node[:mediawiki][:group]
-    mode 0o664
+    mode "664"
     variables :name => new_resource.site,
               :directory => mediawiki_directory,
               :database_params => database_params,
-              :mediawiki => mediawiki_params
-    notifies :run, "execute[#{mediawiki_directory}/maintenance/update.php]"
+              :mediawiki => mediawiki_params,
+              :secret_key => secret_key
   end
 
   execute "#{mediawiki_directory}/maintenance/update.php" do
@@ -531,6 +526,7 @@ action :update do
     cwd mediawiki_directory
     user node[:mediawiki][:user]
     group node[:mediawiki][:group]
+    timeout 86400
   end
 end
 
@@ -555,8 +551,21 @@ action :delete do
 end
 
 action_class do
+  include OpenStreetMap::Mixin::PersistentToken
+
   def site_directory
-    new_resource.directory || "/srv/#{new_resource.site}"
+    "/srv/#{new_resource.site}"
+  end
+
+  def mediawiki_reference
+    shell_out!("git", "ls-remote", "--refs", "--sort=-version:refname",
+               "https://gerrit.wikimedia.org/r/mediawiki/core.git",
+               "refs/tags/#{new_resource.version}.*")
+      .stdout
+      .split("\n")
+      .first
+      .split("/")
+      .last
   end
 
   def cron_name
@@ -589,8 +598,13 @@ action_class do
       :private_site => new_resource.private_site
     }
   end
+
+  def secret_key
+    persistent_token("mediawiki", new_resource.site, "wgSecretKey")
+  end
 end
 
 def after_created
+  notifies :update, "mediawiki_site[#{site}]"
   notifies :reload, "service[apache2]" if reload_apache
 end
index adcc2ae87accb3b668be37fc5b35c63b85667e26..15ab639464f815380fe87e69be06e4e848d4bfea 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :skin, :kind_of => String, :name_attribute => true
+property :skin, :kind_of => String, :name_property => true
 property :site, :kind_of => String, :required => true
 property :source, :kind_of => String
 property :template, :kind_of => String
@@ -37,10 +39,10 @@ action :create do
       source new_resource.source
       owner node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      mode 0o755
+      mode "755"
       files_owner node[:mediawiki][:user]
       files_group node[:mediawiki][:group]
-      files_mode 0o755
+      files_mode "755"
     end
   else
     skin_repository = new_resource.repository || default_repository
@@ -53,7 +55,7 @@ action :create do
       enable_submodules true
       user node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      ignore_failure skin_repository.start_with?("git://github.com/wikimedia/mediawiki-skins")
+      ignore_failure skin_repository.start_with?("https://github.com/wikimedia/mediawiki-skins")
     end
   end
 
@@ -63,7 +65,7 @@ action :create do
       source new_resource.template
       user node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      mode 0o664
+      mode "664"
       variables new_resource.variables
     end
   else
@@ -79,7 +81,7 @@ action :create do
       content file_content
       user node[:mediawiki][:user]
       group node[:mediawiki][:group]
-      mode 0o664
+      mode "664"
       only_if { ::File.exist?(skin_file) }
     end
   end
@@ -114,17 +116,10 @@ action_class do
   end
 
   def default_repository
-    "git://github.com/wikimedia/mediawiki-skins-#{new_resource.skin}.git"
+    "https://github.com/wikimedia/mediawiki-skins-#{new_resource.skin}.git"
   end
 end
 
 def after_created
-  if update_site
-    notifies :update, "mediawiki_site[#{site}]"
-  else
-    site_directory = node[:mediawiki][:sites][site][:directory]
-
-    notifies :create, "template[#{site_directory}/w/LocalSettings.php]"
-    notifies :run, "execute[#{site_directory}/w/maintenance/update.php]"
-  end
+  notifies :update, "mediawiki_site[#{site}]" if update_site
 end
index 1cceb2ab886fb59cbd9c0dc86dc9b1fb9f635a90..9070c0ee8620b4a88010b2836cec58875c69dbde 100644 (file)
@@ -46,6 +46,7 @@ $wgEnableUserEmail  = true; # UPO
 $wgEmergencyContact = "<%= @mediawiki[:email_contact] %>";
 $wgPasswordSender   = "<%= @mediawiki[:email_sender] %>";
 $wgPasswordSenderName = "<%= @mediawiki[:email_sender_name] %>"; //Replaced by MediaWiki:Emailsender in v1.23.0
+$wgNoReplyAddress = "<%= @mediawiki[:email_sender] %>";
 
 $wgEnotifUserTalk      = true; # UPO
 $wgEnotifWatchlist     = true; # UPO
@@ -53,6 +54,15 @@ $wgEmailAuthentication = true;
 
 $wgEnotifUseJobQ       = true;
 
+$wgSMTP = [
+  "host" => "localhost",
+  "socket_options" => [
+    "ssl" => [
+      "verify_peer_name" => false
+    ]
+  ]
+];
+
 ## Database settings
 $wgDBtype           = "mysql";
 $wgDBserver         = "<%= @database_params[:host] %>";
@@ -71,6 +81,9 @@ $wgDBmysql5 = false;
 
 ## Shared memory settings
 $wgMainCacheType    = CACHE_MEMCACHED;
+$wgParserCacheType  = CACHE_MEMCACHED;
+$wgMessageCacheType = CACHE_MEMCACHED;
+$wgSessionCacheType = CACHE_MEMCACHED;
 $wgMemCachedServers = array('127.0.0.1:11211');
 $wgSessionsInObjectCache = TRUE;
 
@@ -88,13 +101,13 @@ $wgMaxShellTime = 360;
 $wgMaxShellWallClockTime = 360;
 
 # Allow some more upload extensions
-$wgFileExtensions[] = 'doc';
 $wgFileExtensions[] = 'pdf';
 $wgFileExtensions[] = 'odt';
 $wgFileExtensions[] = 'odp';
 $wgFileExtensions[] = 'ods';
 $wgFileExtensions[] = 'svg';
 $wgFileExtensions[] = 'osm';
+$wgFileExtensions[] = 'odg';
 <% @mediawiki[:extra_file_extensions].each do |mw_extra_file_extension| -%>
        $wgFileExtensions[] = '<%= mw_extra_file_extension %>';
 <% end -%>
@@ -111,13 +124,6 @@ $wgSVGConverters = array( 'rsvg' => '/usr/bin/rsvg-convert -w $width -h $height
 $wgSVGConverter = 'rsvg';
 $wgSVGMaxSize = 2000;
 
-# InstantCommons allows wiki to use images from https://commons.wikimedia.org
-<% if @mediawiki[:commons] -%>
-$wgUseInstantCommons  = true;
-<% else -%>
-$wgUseInstantCommons  = false;
-<% end -%>
-
 ## If you use ImageMagick (or any other shell command) on a
 ## Linux server, this will need to be set to the name of an
 ## available UTF-8 locale
@@ -132,7 +138,7 @@ $wgShellLocale = "en_US.utf8";
 ## Set $wgCacheDirectory to a writable directory on the web server
 ## to make your wiki go slightly faster. The directory should not
 ## be publically accessible from the web.
-#$wgCacheDirectory = "$IP/cache";
+$wgCacheDirectory = "$IP/cache";
 
 # Site language code, should be one of the list in ./languages/Names.php
 $wgLanguageCode = "en";
@@ -141,7 +147,7 @@ $wgLanguageCode = "en";
 $wgPageLanguageUseDB = true;
 $wgGroupPermissions['user']['pagelang'] = true;
 
-$wgSecretKey = '<%= @node[:mediawiki][:sites][@name][:wgSecretKey] %>';
+$wgSecretKey = '<%= @secret_key %>';
 
 # Site upgrade key. Must be set to a string (default provided) to turn on the
 # web installer while LocalSettings.php is in place
@@ -176,16 +182,6 @@ $wgResourceLoaderMaxQueryLength = -1;
 # Only Allow Signed-in users to edit
 $wgGroupPermissions['*']['edit'] = false;
 
-# Only allow autoconfirmed for a few actions
-$wgGroupPermissions['user']['move'] = false;
-$wgGroupPermissions['user']['movefile'] = false;
-$wgGroupPermissions['user']['move-categorypages'] = false;
-$wgGroupPermissions['user']['upload'] = false;
-$wgGroupPermissions['autoconfirmed']['move'] = true;
-$wgGroupPermissions['autoconfirmed']['movefile'] = true;
-$wgGroupPermissions['autoconfirmed']['move-categorypages'] = true;
-$wgGroupPermissions['autoconfirmed']['upload'] = true;
-
 # Allow bureaucrat group access to oversight options
 $wgGroupPermissions['bureaucrat']['hideuser'] = true;
 $wgGroupPermissions['bureaucrat']['deletelogentry'] = true;
@@ -214,8 +210,8 @@ $wgGroupPermissions['sysop']['gadgets-definition-edit'] = true;
 $wgGroupPermissions['*']['createaccount'] = false;
 $wgGroupPermissions['user']['createaccount'] = true;
 <% end -%>
-<% if @mediawiki[:private_site] -%>
 
+<% if @mediawiki[:private_site] -%>
 # Disable reading by anonymous users
 $wgGroupPermissions['*']['read'] = false;
 
@@ -234,7 +230,12 @@ $wgNamespacesWithSubpages[NS_MAIN] = true;
 
 # DNS Blacklists to use
 $wgEnableDnsBlacklist = true;
-$wgDnsBlacklistUrls = array( 'proxies.dnsbl.sorbs.net.', 'opm.tornevall.org.', 'xbl.spamhaus.org.', 'dnsbl-3.uceprotect.net.' );
+$wgDnsBlacklistUrls = [
+  'proxies.dnsbl.sorbs.net.',
+  'opm.tornevall.org.',
+  'xbl.spamhaus.org.',
+  'dnsbl-2.uceprotect.net.'
+];
 
 # Require validated email to edit
 $wgEmailConfirmToEdit = true;
@@ -242,37 +243,62 @@ $wgEmailConfirmToEdit = true;
 # Extend autoblock period
 $wgAutoblockExpiry = 7776000; // 90 days
 
-# Spam filter regex
-$wgSpamRegex = '/\b(gmail|dell|asus|eps(o|0)n|br(o|0)ther|can(o|0)n|hp|k(o|0)dak|lexmark|mcafee|bitdefender|n(o|0)rt(o|0)n( 360)?|avira|kaspersky|avg|avast|micr(o|0)s(o|0)ft|(o|0)utl(o|0)(o|0)k|printer|netgear( r(o|0)uter)?|quickb(o|0)(o|0)ks( payr(o|0)ll)?)( antivirus)?( helpline| cust(o|0)mer|( technical| tech)| cust(o|0)mer service)? (supp(o|0)rt number|ph(o|0)ne number|supp(o|0)rt ph(o|0)ne number|care number|helpdesk number)\b/i';
-
-# Autopromote users to autoconfirmed
-$wgAutoConfirmAge = 345600; // 4 days
-$wgAutoConfirmCount = 10;
-
 # Disable Hit Counter for Performance
 $wgDisableCounters = TRUE;
 # Disable IP in Header to avoid cache issue
 $wgShowIPinHeader = FALSE;
 
-# Job Runs mostly by cron
-$wgJobRunRate = 0.01;
+# Job Runs by cron
+$wgJobRunRate = 0;
 
 # dissolves double redirects automatically
 $wgFixDoubleRedirects = TRUE;
 
 # Allow external images from a few sites
-$wgAllowExternalImagesFrom = array( 'http://tile.openstreetmap.org/', 'https://tile.openstreetmap.org', 'http://josm.openstreetmap.de/', 'http://trac.openstreetmap.org/', 'http://rweait.dev.openstreetmap.org/' );
-
-$wgNoFollowDomainExceptions = array( 'www.openstreetmap.org', 'josm.openstreetmap.de', 'taginfo.openstreetmap.org', 'blog.openstreetmap.org', 'wiki.osmfoundation.org' );
-
-# FIXME - move to specific
-$wgForceUIMsgAsContentMsg = array( 'mainpage-url', 'portal-url', 'mapfeatures-url', 'helppage' );
+$wgAllowExternalImagesFrom = [
+  'http://tile.openstreetmap.org/',
+  'https://tile.openstreetmap.org',
+  'http://josm.openstreetmap.de/'
+];
+
+$wgNoFollowDomainExceptions = [
+  'www.openstreetmap.org',
+  'josm.openstreetmap.de',
+  'taginfo.openstreetmap.org',
+  'blog.openstreetmap.org',
+  'forum.openstreetmap.org',
+  'community.openstreetmap.org',
+  'lists.openstreetmap.org',
+  'help.openstreetmap.org',
+  'switch2osm.org',
+  'wiki.osmfoundation.org',
+  'www.openstreetmap.us',
+  'learnosm.org',
+  'nominatim.org',
+  'openstreetmap.community',
+  'www.openstreetbrowser.org',
+  'openinframap.org',
+  'leafletjs.com'
+];
 
 # FIXME - move to specific
 $wgAllowUserJs = TRUE;
 $wgAllowUserCss = TRUE;
 
-# FIXME - move to specific
+# Raise expensive lua (and other function) call limits to match WP
+# Docs:  https://www.mediawiki.org/wiki/Manual:$wgExpensiveParserFunctionLimit
+# Wikipedia's Config:  https://noc.wikimedia.org/conf/highlight.php?file=CommonSettings.php
+$wgExpensiveParserFunctionLimit = 500;
+
+
+<% if @mediawiki[:site_notice] -%>
+$wgSiteNotice = "<%= @mediawiki[:site_notice] %>";
+<% end -%>
+<% if @mediawiki[:site_readonly] -%>
+$wgReadOnly = "<%= @mediawiki[:site_readonly] %>";
+<% end -%>
+
+<% if @name == "wiki.openstreetmap.org" -%>
 # DE
 define('NS_LANG_DE', 200);
 $wgExtraNamespaces[NS_LANG_DE] = 'DE';
@@ -336,6 +362,17 @@ define('NS_LANG_JA_TALK', 213);
 $wgExtraNamespaces[NS_LANG_JA_TALK] = 'JA_talk';
 $wgNamespacesWithSubpages[NS_LANG_JA_TALK] = TRUE;
 
+# Proposal
+# namespace features a specific search weight defined at
+# cookbooks/mediawiki/templates/default/mw-ext-CirrusSearch.inc.php.erb
+define('NS_PROPOSAL', 3000);
+$wgExtraNamespaces[NS_PROPOSAL] = 'Proposal';
+$wgNamespacesWithSubpages[NS_PROPOSAL] = TRUE;
+$wgContentNamespaces[] = NS_PROPOSAL;
+define('NS_PROPOSAL_TALK', 3001);
+$wgExtraNamespaces[NS_PROPOSAL_TALK] = 'Proposal_talk';
+$wgNamespacesWithSubpages[NS_PROPOSAL_TALK] = TRUE;
+
 $wgNamespacesToBeSearchedDefault[NS_LANG_DE] = TRUE;
 $wgNamespacesToBeSearchedDefault[NS_LANG_FR] = TRUE;
 $wgNamespacesToBeSearchedDefault[NS_LANG_ES] = TRUE;
@@ -343,21 +380,57 @@ $wgNamespacesToBeSearchedDefault[NS_LANG_IT] = TRUE;
 $wgNamespacesToBeSearchedDefault[NS_LANG_NL] = TRUE;
 $wgNamespacesToBeSearchedDefault[NS_LANG_RU] = TRUE;
 $wgNamespacesToBeSearchedDefault[NS_LANG_JA] = TRUE;
+$wgNamespacesToBeSearchedDefault[NS_PROPOSAL] = TRUE;
 
+# defines which links of the sidebar are translatable
+$wgForceUIMsgAsContentMsg = array( 'mainpage-url', 'mapfeatures-url', 'contributors-url', 'helppage', 'blogs-url', 'shop-url', 'sitesupport-url' );
+<% end -%>
 
-# Raise expensive lua (and other function) call limits to match WP
-# Docs:  https://www.mediawiki.org/wiki/Manual:$wgExpensiveParserFunctionLimit
-# Wikipedia's Config:  https://noc.wikimedia.org/conf/highlight.php?file=CommonSettings.php
-$wgExpensiveParserFunctionLimit = 500;
-
+# load extensions
+<% Dir.glob("#{@directory}/LocalSettings.d/*.php") do |file| -%>
+<%= "require_once('#{file}');" %>
+<% end -%>
 
-<% if @mediawiki[:site_notice] -%>
-$wgSiteNotice = "<%= @mediawiki[:site_notice] %>";
+<% if @name == "wiki.openstreetmap.org" -%>
+# wiki.openstreetmap.org specific config loaded after extensions
+$wgRCWatchCategoryMembership = true;
 <% end -%>
-<% if @mediawiki[:site_readonly] -%>
-$wgReadOnly = "<%= @mediawiki[:site_readonly] %>";
+
+<% if not(@mediawiki[:private_accounts]) and not(@mediawiki[:private_site]) -%>
+# require user confirmation for certain actions
+$wgGroupPermissions['user']['move'] = false;
+$wgGroupPermissions['user']['movefile'] = false;
+$wgGroupPermissions['user']['move-categorypages'] = false;
+$wgGroupPermissions['user']['upload'] = false;
+$wgGroupPermissions['autoconfirmed']['move'] = true;
+$wgGroupPermissions['autoconfirmed']['movefile'] = true;
+$wgGroupPermissions['autoconfirmed']['move-categorypages'] = true;
+$wgGroupPermissions['autoconfirmed']['upload'] = true;
+# Autopromote users to autoconfirmed
+$wgAutoConfirmAge = 345600; // 4 days
+$wgAutoConfirmCount = 10;
+
+# user group "confirmed" with identical rights as "autoconfirmed", but assigned manually by sysops
+$wgGroupPermissions['confirmed'] = $wgGroupPermissions['autoconfirmed'];
+$wgAddGroups['sysop'][] = 'confirmed';
+$wgRemoveGroups['sysop'][] = 'confirmed';
 <% end -%>
 
-<% Dir.glob("#{@directory}/LocalSettings.d/*.php") do |file| -%>
-<%= "require_once('#{file}');" %>
+<% if @mediawiki[:private_accounts] or @mediawiki[:private_site] -%>
+# disable automatic confirmation of users, grant all "autoconfirmed" rights to all users
+$wgAutoConfirmAge = 0;
+$wgAutoConfirmCount = 0;
+$wgGroupPermissions['user'] = array_merge( $wgGroupPermissions['user'], $wgGroupPermissions['autoconfirmed'] );
+
+unset( $wgGroupPermissions['autoconfirmed'] );
+unset( $wgRevokePermissions['autoconfirmed'] );
+unset( $wgAddGroups['autoconfirmed'] );
+unset( $wgRemoveGroups['autoconfirmed'] );
+unset( $wgGroupsAddToSelf['autoconfirmed'] );
+unset( $wgGroupsRemoveFromSelf['autoconfirmed'] );
 <% end -%>
+
+# Increase curl timeout to allow parsoid requests to heavy pages like Map Features
+# Mediawiki 1.38 has fix to allow this to be set by $wgVirtualRestConfig
+# https://phabricator.wikimedia.org/T285478
+$wgHTTPTimeout = 240;
index d5485a6204bb46b713cced32ad4b66c18486ad3d..d3d25a3a1c24d921b5fb2bdb08c616754dbc2b53 100644 (file)
@@ -8,7 +8,7 @@
 
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-secure-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-secure-error.log
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   DocumentRoot <%= @directory %>
 
-  php_admin_value open_basedir <%= @directory %>/:/usr/share/php/:/dev/null:/tmp/
-  #php_admin_value disable_functions "exec,shell_exec,system,passthru,popen,proc_open"
-  php_value memory_limit 500M
-  php_value max_execution_time 240
-  php_value upload_max_filesize 70M
-  php_value post_max_size 100M
+  AllowEncodedSlashes NoDecode
+
+  ProxyTimeout 300
 
   RewriteCond %{SERVER_NAME} !=<%= @name %>
   RewriteRule ^/(.*)$ https://<%= @name %>/$1 [R=permanent]
 
-  RedirectMatch 301 ^/$                           /wiki/Main_Page
-
-  #Historical Compatibility Links
+  # Historical Compatibility Links
   RedirectMatch 301 ^/index\.php$                 /w/index.php
   RedirectMatch 301 ^/index\.php/(.*)$            /wiki/$1
   RedirectMatch 301 ^/skins/(.*)$                 /w/skins/$1
@@ -52,7 +47,7 @@
   RedirectMatch 301 ^/api\.php$                   /w/api.php
   RedirectMatch 301 ^/opensearch_desc\.php$       /w/opensearch_desc.php
 
-  #Support Wikidata redirects based on Wikimedia's redirects:
+  # Support Wikidata redirects based on Wikimedia's redirects:
   # https://github.com/wikimedia/puppet/blob/production/modules/mediawiki/files/apache/sites/wikidata-uris.incl
   RedirectMatch 301 ^/entity/statement/([QqPp]\d+).*$        /wiki/Special:EntityData/$1
   RedirectMatch 301 ^/value/(.*)$                            /wiki/Special:ListDatatypes
@@ -74,8 +69,9 @@
 
   Alias /wiki <%= @directory %>/w/index.php
 
-  #Support /pagename -> /wiki/pagename
+  # Support /pagename -> /wiki/pagename
   RewriteEngine on
+  RewriteRule ^/$ /w/index.php?title=Main_Page [L,QSA]
   RewriteCond %{REQUEST_URI} !^/w/
   RewriteCond %{REQUEST_URI} !^/wiki/
   RewriteCond %{REQUEST_URI} !^/index\.php
   RewriteCond %{REQUEST_URI} !^/entity/
   RewriteCond %{REQUEST_URI} !^/value/
   RewriteCond %{REQUEST_URI} !^/reference/
-  RewriteCond %{REQUEST_URI} !^/prop/  
-  RewriteCond %{REQUEST_URI} !^/dump/  
+  RewriteCond %{REQUEST_URI} !^/prop/
+  RewriteCond %{REQUEST_URI} !^/dump/
   RewriteCond %{REQUEST_URI} !^/server-status
+  RewriteCond %{REQUEST_URI} !^/server-info
   RewriteCond %{REQUEST_URI} !^/.well-known/
   RewriteCond %{LA-U:REQUEST_FILENAME} !-f
   RewriteCond %{LA-U:REQUEST_FILENAME} !-d
   <Directory <%= @directory %>>
     Options -Indexes
     Require all granted
+
+    <FilesMatch ".+\.ph(ar|p|tml)$">
+      SetHandler "proxy:unix:/run/php/php-<%= @name %>-fpm.sock|fcgi://127.0.0.1"
+    </FilesMatch>
   </Directory>
 
   <Directory <%= @directory %>/w/images/>
-    # No php execution in the upload area
-    php_admin_flag engine off
     Options -ExecCGI -Includes -Indexes
     AllowOverride None
     AddType text/plain .html .htm .shtml
 <% if @private_site -%>
     Require all denied
 <% end -%>
+    <FilesMatch ".+\.ph(ar|p|tml)$">
+      SetHandler None
+    </FilesMatch>
   </Directory>
 
   <Directory <%= @directory %>/w/images/thumb/>
     Options -ExecCGI -Includes -Indexes
     AllowOverride None
     AddType text/plain .html .htm .shtml
-    php_admin_flag engine off
+    <FilesMatch ".+\.ph(ar|p|tml)$">
+      SetHandler None
+    </FilesMatch>
   </Directory>
 
   <Directory <%= @directory %>/dump/>
index c4b7a053f871a24adf44fdfdfd4587e99b1a34c9..73678e1cc8580e11ae4141028e549bf243e51d52 100644 (file)
@@ -6,5 +6,8 @@
         "skins/*/composer.json"
       ]
     }
+  },
+  "require": {
+    "guzzlehttp/psr7": "2.4.5"
   }
 }
index ff28a185cc184d9e1c76037976b36759ffdbe391..94ebb404ee00feef87ba1992f765de801847bded 100755 (executable)
@@ -7,10 +7,9 @@ mkdir $T/wiki-<%= @name %>-$D
 echo '[mysqldump]' > $T/mysqldump.opts
 echo 'user=<%= @database_params[:username] %>' >> $T/mysqldump.opts
 echo 'password=<%= @database_params[:password] %>' >> $T/mysqldump.opts
-mysqldump --defaults-file=$T/mysqldump.opts --opt --skip-lock-tables --single-transaction "<%= @database_params[:name] %>" | lz4 -9 > $T/wiki-<%= @name %>-$D/wiki.sql.lz4
+mysqldump --defaults-file=$T/mysqldump.opts --opt --skip-lock-tables --single-transaction --no-tablespaces "<%= @database_params[:name] %>" | lz4 -9 > $T/wiki-<%= @name %>-$D/wiki.sql.lz4
 ln -s <%= @directory %>  $T/wiki-<%= @name %>-$D/www
-export GZIP="--rsyncable -9" #make backup rsyncable
-nice tar --create --gzip --dereference --directory=$T --warning=no-file-changed --exclude=wiki-<%= @name %>-$D/www/w/images/thumb --exclude=wiki-<%= @name %>-$D/www/w/.git --exclude=wiki-<%= @name %>-$D/www/w/extensions/*/.git --file=$T/$B wiki-<%= @name %>-$D
+nice tar --create --dereference --directory=$T --warning=no-file-changed --warning=no-file-removed --exclude=wiki-<%= @name %>-$D/www/w/images/thumb --exclude=wiki-<%= @name %>-$D/www/w/.git --exclude=wiki-<%= @name %>-$D/www/w/extensions/*/.git --exclude=wiki-<%= @name %>-$D/www/dump wiki-<%= @name %>-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
diff --git a/cookbooks/mediawiki/templates/default/mediawiki.cron.erb b/cookbooks/mediawiki/templates/default/mediawiki.cron.erb
deleted file mode 100644 (file)
index a6d996b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Generate sitemap.xml daily
-30 0 * * * <%= @user %> /usr/bin/nice /usr/bin/php -d memory_limit=1024M -d error_reporting=22517 <%= @directory %>/w/maintenance/generateSitemap.php --server="https://<%= @name %>" --urlpath="https://<%= @name %>/" --fspath="<%= @directory %>" --quiet --skip-redirects
-# Run mediawiki jobs
-*/3 * * * * <%= @user %> /usr/bin/nice /usr/bin/php -d memory_limit=1024M -d error_reporting=22517 <%= @directory %>/w/maintenance/runJobs.php --server="https://<%= @name %>" --maxtime=160 --memory-limit=1024M --procs=8 --quiet
-# Run mediawiki email jobs
-* * * * * <%= @user %> /usr/bin/nice /usr/bin/php -d memory_limit=1024M -d error_reporting=22517 <%= @directory %>/w/maintenance/runJobs.php --server="https://<%= @name %>" --maxtime=30 --type=enotifNotify --memory-limit=1024M --procs=4 --quiet
-# Run mediawiki refresh links table weekly
-5 0 * * 0 <%= @user %> /usr/bin/nice /usr/bin/php -d memory_limit=1024M -d error_reporting=22517 <%= @directory %>/w/maintenance/refreshLinks.php --server="https://<%= @name %>" --memory-limit=1024M --quiet
-
-# Clean up imagemagic garbage
-10 2 * * * <%= @user %> /usr/bin/find /tmp/ -maxdepth 1 -type f -user www-data -mmin +90 -name 'gs_*' -delete
-20 2 * * * <%= @user %> /usr/bin/find /tmp/ -maxdepth 1 -type f -user www-data -mmin +90 -name 'magick-*' -delete
index 4c9216ac0d9b9cd7a7510734671593ea841f09e6..09f5814b872dab175343bc68045a39a22de4ba3b 100644 (file)
@@ -8,3 +8,8 @@ $wgGroupPermissions['*']['abusefilter-log'] = true;
 $wgGroupPermissions['sysop']['abusefilter-private'] = true;
 $wgGroupPermissions['sysop']['abusefilter-modify-restricted'] = true;
 $wgGroupPermissions['sysop']['abusefilter-revert'] = true;
+
+# Tune AbuseFilter limits
+# https://github.com/openstreetmap/operations/issues/353
+$wgAbuseFilterEmergencyDisableThreshold['default'] = 0.30; # 30%
+$wgAbuseFilterEmergencyDisableCount['default'] = 25;
index 12fe10e5bab7e334ce38e209a1ee0501bdd6c89c..ddb87f166eb3d755f92d597498c95ee347204b6a 100644 (file)
@@ -1,5 +1,5 @@
 <?php
 # DO NOT EDIT - This file is being maintained by Chef
-require_once($IP .'/extensions/CirrusSearch/CirrusSearch.php');
+wfLoadExtension( 'CirrusSearch' );
 $wgDisableSearchUpdate = false;
 $wgSearchType = 'CirrusSearch';
index 50e1d480183ccbb5c2ed0de08f5ee83af1d1617d..2e0af37bab4520d2a46cd754620e7a1de43afd1b 100644 (file)
@@ -1,12 +1,12 @@
 <?php
 # DO NOT EDIT - This file is being maintained by Chef
-wfLoadExtensions( array( 'ConfirmEdit', 'ConfirmEdit/ReCaptchaNoCaptcha' ) );
-$wgCaptchaClass = 'ReCaptchaNoCaptcha';
-$wgReCaptchaSendRemoteIP = true;
-$wgReCaptchaSiteKey = '<%= @public_key %>';
-$wgReCaptchaSecretKey = '<%= @private_key %>';
-
-$wgCaptchaTriggers['addurl'] = true;
-$wgCaptchaTriggers['create'] = true;
+wfLoadExtensions( array( 'ConfirmEdit', 'ConfirmEdit/hCaptcha' ) );
+$wgHCaptchaSendRemoteIP = true;
+$wgHCaptchaSiteKey = '<%= @public_key %>';
+$wgHCaptchaSecretKey = '<%= @private_key %>';
 
 $wgGroupPermissions['autoconfirmed']['skipcaptcha'] = true;
+$wgGroupPermissions['bot'          ]['skipcaptcha'] = true;
+$wgGroupPermissions['sysop'        ]['skipcaptcha'] = true;
+
+$wgRateLimits['badcaptcha']['newbie'] = [ 100, 86400 ];
diff --git a/cookbooks/mediawiki/templates/default/mw-ext-SimpleMap.inc.php.erb b/cookbooks/mediawiki/templates/default/mw-ext-SimpleMap.inc.php.erb
deleted file mode 100644 (file)
index 2984e28..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?php
-# DO NOT EDIT - This file is being maintained by Chef
-require_once($IP .'/extensions/SimpleMap/SimpleMap.php');
diff --git a/cookbooks/mediawiki/templates/default/mw-ext-SlippyMap.inc.php.erb b/cookbooks/mediawiki/templates/default/mw-ext-SlippyMap.inc.php.erb
deleted file mode 100644 (file)
index 00aee9c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?php
-# DO NOT EDIT - This file is being maintained by Chef
-require_once($IP .'/extensions/SlippyMap/SlippyMap.php');
index da2fb70ee721aac969a8a105ebd3c7c0870d0c2c..721ea398e4812c988f0c035ab7bf27a0ec77a2a0 100644 (file)
@@ -5,3 +5,7 @@ wfLoadExtension( 'SpamBlacklist' );
 $wgSpamBlacklistFiles = array(
        'https://meta.wikimedia.org/w/index.php?title=Spam_blacklist&action=raw&sb_ver=1'
 );
+# log hits, but allow only administrators to view them
+$wgLogSpamBlacklistHits = true;
+$wgGroupPermissions['user']['spamblacklistlog'] = false;
+$wgGroupPermissions['sysop']['spamblacklistlog'] = true;
index 7f1dc889409e33ad485e3a02e483c8a20cf39e38..111ff3d2fbefd38c3eb66273e15b5f066963ade6 100644 (file)
@@ -11,3 +11,7 @@ $wgTitleBlacklistSources = array(
     'src'  => 'https://meta.wikimedia.org/w/index.php?title=Title_blacklist&action=raw',
   ),
 );
+# log hits, but allow only administrators to view them
+$wgTitleBlacklistLogHits = true;
+$wgGroupPermissions['user']['titleblacklistlog'] = false;
+$wgGroupPermissions['sysop']['titleblacklistlog'] = true;
index a36e5c25f490530060601f4190370cf14dc969c8..2b7dd90ab7bca5cc0c21aef8e3786c25463c4a50 100644 (file)
@@ -1,13 +1,2 @@
 <?php
-$wgVirtualRestConfig['modules']['parsoid'] = array(
-  'url' => 'http://localhost:8142'
-);
-$wgVirtualRestConfig['modules']['parsoid']['forwardCookies'] = true;
-
-require_once($IP .'/extensions/VisualEditor/VisualEditor.php');
-
-// Enable by default for everybody
-$wgDefaultUserOptions['visualeditor-enable'] = 1;
-
-// Don't allow users to disable it
-// $wgHiddenPrefs[] = 'visualeditor-enable';
+wfLoadExtension( 'VisualEditor' );
diff --git a/cookbooks/mediawiki/templates/default/mw-ext-osmtaginfo.inc.php.erb b/cookbooks/mediawiki/templates/default/mw-ext-osmtaginfo.inc.php.erb
deleted file mode 100644 (file)
index 4c75cb8..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<?php
-# DO NOT EDIT - This file is being maintained by Chef
-require_once($IP .'/extensions/osmtaginfo/osmtaginfo.php');
diff --git a/cookbooks/mediawiki/templates/default/parsoid-config.yaml.erb b/cookbooks/mediawiki/templates/default/parsoid-config.yaml.erb
deleted file mode 100644 (file)
index e0a4e96..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-worker_heartbeat_timeout: 300000
-
-logging:
-    level: info
-
-#metrics:
-#    type: log
-
-services:
-  - module: src/lib/index.js
-    entrypoint: apiServiceWorker
-    conf:
-        # For backwards compatibility, and to continue to support non-static
-        # configs for the time being, optionally provide a path to a
-        # localsettings.js file.  See localsettings.example.js
-        #localsettings: ./localsettings.js
-
-        # Set your own user-agent string
-        # Otherwise, defaults to:
-        #   'Parsoid/<current-version-defined-in-package.json>'
-        #userAgent: 'My-User-Agent-String'
-
-        # Configure Parsoid to point to your MediaWiki instances.
-        mwApis:
-        # - # This is the only required parameter,
-          # the URL of you MediaWiki API endpoint.
-        #  uri: 'http://localhost/w/api.php'
-          # The "domain" is used for communication with Visual Editor
-          # and RESTBase.  It defaults to the hostname portion of
-          # the `uri` property below, but you can manually set it
-          # to an arbitrary string.
-        #  domain: 'localhost'  # optional
-          # To specify a proxy (or proxy headers) specific to this prefix
-          # (which overrides defaultAPIProxyURI). Alternatively, set `proxy`
-          # to `null` to override and force no proxying when a default proxy
-          # has been set.
-          #proxy:
-          #    uri: 'http://my.proxy:1234/'
-          #    headers:  # optional
-          #        'X-Forwarded-Proto': 'https'
-<% node[:mediawiki][:sites].keys.sort.each do |site_url| -%>
-        - # This is the only required parameter,
-          uri: 'https://<%= site_url %>/w/api.php'
-<% end -%>
-
-        # We pre-define wikipedias as 'enwiki', 'dewiki' etc. Similarly
-        # for other projects: 'enwiktionary', 'enwikiquote', 'enwikibooks',
-        # 'enwikivoyage' etc.
-        # The default for this is false. Uncomment the line below if you want
-        # to load WMF's config for wikipedias, etc.
-        #loadWMF: true
-
-        # A default proxy to connect to the API endpoints.
-        # Default: undefined (no proxying).
-        # Overridden by per-wiki proxy config in setMwApi.
-        #defaultAPIProxyURI: 'http://proxy.example.org:8080'
-
-        # Enable debug mode (prints extra debugging messages)
-        #debug: true
-
-        # Use the PHP preprocessor to expand templates via the MW API (default true)
-        #usePHPPreProcessor: false
-
-        # Use selective serialization (default false)
-        useSelser: true
-
-        # Allow cross-domain requests to the API (default '*')
-        # Sets Access-Control-Allow-Origin header
-        # disable:
-        #allowCORS: false
-        # restrict:
-        #allowCORS: 'some.domain.org'
-
-        # Allow override of port/interface:
-        #serverPort: 8000
-        #serverInterface: '127.0.0.1'
-
-        # Enable linting of some wikitext errors to the log
-        #linting: true
-        # Send lint errors to MW API instead of to the log
-        #linterSendAPI: false
-
-        # Require SSL certificates to be valid (default true)
-        # Set to false when using self-signed SSL certificates
-        #strictSSL: false
-
-        # Use a different server for CSS style modules.
-        # Leaving it undefined (the default) will use the same URI as the MW API,
-        # changing api.php for load.php.
-        #modulesLoadURI: 'http://example.org/load.php'
index e9dd85c82b2dfdfaa69b2076403fe2782a54109e..c5cee82b25c52e676e7debf18b9a167b145e2d98 100644 (file)
@@ -6,3 +6,4 @@ description       "Installs and configures memcached"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "prometheus"
index 8c1b427b18806f2b37551cb4e2bc97733785cead..a4a1462d3f9c99f95374a685c6b0e79ae61874c9 100644 (file)
@@ -17,6 +17,8 @@
 # limitations under the License.
 #
 
+include_recipe "prometheus"
+
 package "memcached"
 
 service "memcached" do
@@ -28,16 +30,11 @@ template "/etc/memcached.conf" do
   source "memcached.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :restart, "service[memcached]"
 end
 
-munin_plugin_conf "memcached_multi" do
-  template "munin.erb"
-end
-
-%w[bytes commands conns evictions items memory].each do |stat|
-  munin_plugin "memcached_multi_#{stat}" do
-    target "memcached_multi_"
-  end
+prometheus_exporter "memcached" do
+  port 9150
+  options "--memcached.address=#{node[:memcached][:ip_address]}:#{node[:memcached][:tcp_port]} --memcached.pid-file=/run/memcached/memcached.pid"
 end
index 93ff610840faa678c8b75059b9124692c5425ffd..7b60de4667797752c78b49de7aa3f1c2013655ae 100644 (file)
@@ -6,6 +6,9 @@
 # Run as user memcache
 -u memcache
 
+# Use a pidfile
+-P /run/memcached/memcached.pid
+
 # Log memcached's output to /var/log/memcached
 logfile /var/log/memcached.log
 
diff --git a/cookbooks/memcached/templates/default/munin.erb b/cookbooks/memcached/templates/default/munin.erb
deleted file mode 100644 (file)
index 40d4348..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[memcached_multi_*]
-user nobody
-env.host <%= node[:memcached][:ip_address] %>
-env.port <%= node[:memcached][:tcp_port] %>
diff --git a/cookbooks/munin/README.md b/cookbooks/munin/README.md
deleted file mode 100644 (file)
index 42ea706..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# Munin Cookbook
-
-This cookbook configures munin, which we use for server monitoring at
-[munin.openstreetmap.org](https://munin.openstreetmap.org). The cookbook
-contains two recipes:
-
-* default - installs and configures munin-node on each machine.
-* server - configures the central munin server
-
-Additionally two providers are defined - munin_plugin and munin_plugin_conf, for
-configuring individual munin plugins.
diff --git a/cookbooks/munin/attributes/default.rb b/cookbooks/munin/attributes/default.rb
deleted file mode 100644 (file)
index a1eb792..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-default[:munin][:allow] = []
-default[:munin][:graphs] = {}
-default[:munin][:plugins] = {}
diff --git a/cookbooks/munin/files/default/plugin-conf.d/api b/cookbooks/munin/files/default/plugin-conf.d/api
deleted file mode 100644 (file)
index 614696e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[api_calls_num]
-user root
diff --git a/cookbooks/munin/files/default/plugin-conf.d/chef b/cookbooks/munin/files/default/plugin-conf.d/chef
deleted file mode 100644 (file)
index 33beecc..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[chef_*]
-user chefrepo
diff --git a/cookbooks/munin/files/default/plugin-conf.d/hpasmcli2 b/cookbooks/munin/files/default/plugin-conf.d/hpasmcli2
deleted file mode 100644 (file)
index d7673cd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[hpasmcli2_*]
-user root
diff --git a/cookbooks/munin/files/default/plugins/api_calls_ b/cookbooks/munin/files/default/plugins/api_calls_
deleted file mode 100755 (executable)
index ea95ed1..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/ruby
-
-require "rubygems"
-require "date"
-require "hpricot"
-require "open-uri"
-
-def uris_from_status(server)
-  file = open("http://#{server}/server-status").read
-  doc = Hpricot.parse(file)
-  tables = doc / "table"
-  rows = (tables[1] / "tr")[1..-1]
-  data = rows.collect { |r| (r / "td").collect(&:inner_html) }
-  # filter where the PID is numeric, status is 'W' and host matches the server
-  matching_data = data.select { |r| r[1].to_i.positive? && r[3].match(/W/) && r[11].match(server) }
-  # return only the URI part
-  matching_data.collect { |r| r[12] }
-end
-
-CALL_TYPES = {
-  :map => "Map API calls",
-  :upload => "Changeset diff uploads",
-  :amf => "AMF API calls",
-  :history => "Element history fetches",
-  :full => "Full element fetches",
-  :trkpts => "GPX trackpoints calls",
-  :web => "Web site traffic",
-  :other => "Other API calls"
-}.freeze
-
-def categorise_uri(line)
-  uri = line.split(" ")[1]
-
-  case uri
-  when %r{api/0\.6/map} then :map
-  when %r{api/0\.6/changeset/[0-9]*/upload} then :upload
-  when %r{api/0\.6/amf} then :amf
-  when %r{api/0\.6/(node|way|relation)/[0-9]*/history} then :history
-  when %r{api/0\.6/(node|way|relation)/[0-9]*/full} then :full
-  when %r{api/0\.6/trackpoints} then :trkpts
-  when %r{api/0\.6/} then :other
-  else :web
-  end
-end
-
-server = $PROGRAM_NAME.match("api_calls_(.*)")[1]
-
-if ARGV[0] == "config"
-  puts "graph_title Active requests"
-  puts "graph_vlabel Number of requests"
-  puts "graph_category api"
-  CALL_TYPES.each { |k, v| puts "#{k}.label #{v}" }
-
-else
-  counts = uris_from_status(server)
-           .collect { |x| categorise_uri(x) }
-           .each_with_object({}) do |e, h|
-    if h.key? e
-      h[e] += 1
-    else
-      h[e] = 1
-    end
-  end
-
-  CALL_TYPES.each_key do |type|
-    count = counts[type] || 0
-    puts "#{type}.value #{count}"
-  end
-end
diff --git a/cookbooks/munin/files/default/plugins/api_calls_num b/cookbooks/munin/files/default/plugins/api_calls_num
deleted file mode 100755 (executable)
index e776505..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/ruby
-
-require "json"
-
-CALL_TYPES = {
-  :map => "Map API calls",
-  :upload => "Changeset diff uploads",
-  :amf => "AMF API calls",
-  :history => "Element history fetches",
-  :full => "Full element fetches",
-  :trkpts => "GPX trackpoints calls",
-  :web => "Web site traffic",
-  :other => "Other API calls"
-}.freeze
-
-if ARGV[0] == "config"
-  puts "graph_title Requests processed"
-  puts "graph_args --base 1000"
-  puts "graph_vlabel Number of requests per ${graph_period}"
-  puts "graph_category api"
-
-  CALL_TYPES.each do |type, label|
-    puts "#{type}.label #{label}"
-    puts "#{type}.type DERIVE"
-    puts "#{type}.min 0"
-  end
-else
-  statistics = JSON.parse(File.read("/srv/www.openstreetmap.org/rails/tmp/statistics.json"))
-
-  CALL_TYPES.each_key do |type|
-    count = statistics["uri"][type.to_s] || 0
-    puts "#{type}.value #{count}"
-  end
-end
diff --git a/cookbooks/munin/files/default/plugins/api_calls_status b/cookbooks/munin/files/default/plugins/api_calls_status
deleted file mode 100755 (executable)
index 4a9623f..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/ruby
-
-require "json"
-
-HTTP_STATUSES = {
-  "200" => "OK",
-  "206" => "Partial Content",
-  "301" => "Moved Permanently",
-  "302" => "Found",
-  "303" => "See Other",
-  "304" => "Not Modified",
-  "400" => "Bad Request",
-  "401" => "Unauthorized",
-  "403" => "Forbidden",
-  "404" => "Not Found",
-  "405" => "Method Not Allowed",
-  "408" => "Request Timeout",
-  "409" => "Conflict",
-  "410" => "Gone",
-  "412" => "Precondition Failed",
-  "416" => "Requested Range Not Satisfiable",
-  "422" => "Unprocessable Entity",
-  "500" => "Internal Server Error",
-  "502" => "Bad Gateway",
-  "503" => "Service Unavailable",
-  "509" => "Bandwidth Limit Exceeded"
-}.freeze
-
-if ARGV[0] == "config"
-  puts "graph_title HTTP response codes"
-  puts "graph_args --base 1000"
-  puts "graph_vlabel Number of requests per ${graph_period}"
-  puts "graph_category api"
-
-  HTTP_STATUSES.each do |code, label|
-    puts "http#{code}.label #{code} #{label}"
-    puts "http#{code}.type DERIVE"
-    puts "http#{code}.min 0"
-  end
-else
-  statistics = JSON.parse(File.read("/srv/www.openstreetmap.org/rails/tmp/statistics.json"))
-
-  HTTP_STATUSES.each_key do |code|
-    count = statistics["status"][code] || 0
-    puts "http#{code}.value #{count}"
-  end
-end
diff --git a/cookbooks/munin/files/default/plugins/api_waits_ b/cookbooks/munin/files/default/plugins/api_waits_
deleted file mode 100755 (executable)
index f575dad..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/ruby
-
-require "rubygems"
-require "date"
-require "hpricot"
-require "open-uri"
-
-def uri_and_times_from_status(server)
-  file = open("http://#{server}/server-status").read
-  doc = Hpricot.parse(file)
-  tables = doc / "table"
-  rows = (tables[1] / "tr")[1..-1]
-  data = rows.collect { |r| (r / "td").collect(&:inner_html) }
-  # filter where the PID is numeric, status is 'W' and host matches the server
-  matching_data = data.select { |r| r[1].to_i.positive? && r[3].match(/W/) && r[11].match(server) }
-  # return URI and number of seconds processing for each request
-  matching_data.collect { |r| [r[12], r[5].to_i] }
-end
-
-CALL_TYPES = {
-  :map => "Map API calls",
-  :upload => "Changeset diff uploads",
-  :amf => "AMF API calls",
-  :history => "Element history fetches",
-  :full => "Full element fetches",
-  :trkpts => "GPX trackpoints calls",
-  :web => "Web site traffic",
-  :other => "Other API calls"
-}.freeze
-
-def categorise_uri(line)
-  uri = line.split(" ")[1]
-
-  case uri
-  when %r{api/0\.6/map} then :map
-  when %r{api/0\.6/changeset/[0-9]*/upload/} then :upload
-  when %r{api/0\.6/amf} then :amf
-  when %r{api/0\.6/(node|way|relation)/[0-9]*/history} then :history
-  when %r{api/0\.6/(node|way|relation)/[0-9]*/full} then :full
-  when %r{api/0\.6/trackpoints} then :trkpts
-  when %r{api/0\.6/} then :other
-  else :web
-  end
-end
-
-server = $PROGRAM_NAME.match("api_waits_(.*)")[1]
-
-if ARGV[0] == "config"
-  puts "graph_title Wait times for active requests"
-  puts "graph_vlabel Average time of requests"
-  puts "graph_category api"
-  CALL_TYPES.each { |k, v| puts "#{k}.label #{v}" }
-
-else
-  counts = uri_and_times_from_status(server)
-           .collect { |x, y| [categorise_uri(x), y] }
-           .each_with_object({}) do |e, h|
-    category, time = e
-    if h.key? category
-      h[category] += [time]
-    else
-      h[category] = [time]
-    end
-  end
-
-  CALL_TYPES.each_key do |type|
-    count = counts[type] || [0]
-    avg = count.inject(0) { |acc, elem| acc + elem } / (1.0 * count.length)
-    puts "#{type}.value #{avg}"
-  end
-end
diff --git a/cookbooks/munin/files/default/plugins/chef_status b/cookbooks/munin/files/default/plugins/chef_status
deleted file mode 100755 (executable)
index 9d4c742..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/ruby
-
-require "json"
-
-nodes = JSON.parse(IO.popen(["knife", "status", "-c", "/var/lib/chef/.chef/knife.rb", "-F", "json"]).read).sort_by { |node| node["name"] }
-
-if ARGV[0] == "config"
-  puts "graph_title Chef node status"
-  puts "graph_args --base 1000 --logarithmic"
-  puts "graph_vlabel Time since last checkin"
-  puts "graph_category chef"
-
-  nodes.each do |node|
-    name = node["name"].split(".").first
-
-    puts "#{name}.label #{name}"
-    puts "#{name}.type GAUGE"
-    puts "#{name}.min 0"
-    puts "#{name}.warning 14400"
-    puts "#{name}.critical 43200"
-  end
-else
-  nodes.each do |node|
-    name = node["name"].split(".").first
-    time = Time.now.to_f - node["ohai_time"]
-
-    puts "#{name}.value #{time}"
-  end
-end
diff --git a/cookbooks/munin/files/default/plugins/chrony b/cookbooks/munin/files/default/plugins/chrony
deleted file mode 100755 (executable)
index 314860f..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/bin/sh
-
-: <<=cut
-
-=head1 NAME
-
-parse Chrony Tracking output for timeserver status information
-
-=head1 APPLICABLE SYSTEMS
-
-Any system with a local chronyd service.
-
-=head1 CONFIGURATION
-
-No configuration.
-
-=head1 MAGIC MARKERS
-
-  #%# family=auto
-  #%# capabilities=autoconf
-
-=head1 VERSION
-
-Revision 0.1 2008/08/23 13:06:00 joti
-
-  First version only chronyc tracking, autodetection included.
-
-Revision 0.2 2008/10/11 16:09:00 joti
-
-  Added scaling of other values to match with frequency, added more description to fields
-
-Revision 0.3 2014/02/16 zjttoefs
-
-  reduce forking by using awk
-  do not limit output precision
-  add stratum monitoring
-  detect slow/fast time or freqency and adjust sign of value accordingly
-  remove commented out code
-
-Revision 0.4 2016/11/10 Lars Kruse
-
-  rewrite field handling
-  use "which" for "chronyc" location
-  switch from "bash" to "sh"
-  fix exit code of failing "autoconf"
-
-=head1 AUTHOR
-
-  joti
-  zjttoefs
-  Lars Kruse <devel@sumpfralle.de>
-
-=cut
-
-CHRONYC="$(which chronyc | head -1)"
-
-# Frequency has extremely higher values than other. Therefore they are fitted by scaling via suitable factors.
-# field definitions:
-#   - munin fieldname
-#   - factor for graph visualization (all values are supposed to reach a similar dimension)
-#   - regular expression of the chrony output line (may not contain whitespace, case insensitive)
-#   - label (may include "%d" for including the factor; may contain whitespace)
-fields="stratum                1       ^Stratum                Stratum
-       systime         1000    ^System.time            System Time (x%d)
-       frequency       1       ^Frequency              Frequency (ppm)
-       residualfreq    100     ^Residual.freq          Residual Freq (ppm, x%d)
-       skew            100     ^Skew                   Skew (ppm, x%d)
-       rootdelay       1000    ^Root.delay             Root delay (seconds, x%d)
-       rootdispersion  1000    ^Root.dispersion        Root dispersion (seconds, x%d)"
-
-# chrony example output (v2.4.1):
-#   Reference ID    : 131.188.3.221 (ntp1.rrze.uni-erlangen.de)
-#   Stratum         : 2
-#   Ref time (UTC)  : Thu Nov 10 22:39:50 2016
-#   System time     : 0.000503798 seconds slow of NTP time
-#   Last offset     : +0.000254355 seconds
-#   RMS offset      : 0.002186779 seconds
-#   Frequency       : 17.716 ppm slow
-#   Residual freq   : +0.066 ppm
-#   Skew            : 4.035 ppm
-#   Root delay      : 0.042980 seconds
-#   Root dispersion : 0.005391 seconds
-#   Update interval : 258.4 seconds
-#   Leap status     : Normal
-
-
-if [ "$1" = "autoconf" ]; then
-       if [ -n "$CHRONYC" ] && [ -x "$CHRONYC" ]; then
-               echo yes
-       else
-               echo "no (missing 'chronyc' executable)"
-       fi
-       exit 0
-fi
-
-if [ "$1" = "config" ]; then
-       echo 'graph_title Chrony Tracking Stats'
-       echo 'graph_args --base 1000 -l 0'
-       echo 'graph_vlabel (seconds,ppm)'
-       echo 'graph_category time'
-       echo "$fields" | while read fieldname factor regex label; do
-               # insert the factor, if "%d" is part of the label
-               printf "${fieldname}.label $label\n" "$factor"
-               echo "${fieldname}.type GAUGE"
-       done
-       exit 0
-fi
-
-chrony_status="$("$CHRONYC" tracking)"
-echo "$fields" | while read fieldname factor regex label; do
-       status_line="$(echo "$chrony_status" | grep -i -- "$regex " | cut -d ":" -f 2-)"
-       if [ -z "$status_line" ]; then
-               value="U"
-       else
-               # the keyword "slow" indicates negative values
-               value="$(echo "$status_line" | awk '{ /slow/ ? SIGN=-1 : SIGN=1; print $1 * SIGN * '"$factor"' }')"
-       fi
-       echo "${fieldname}.value $value"
-done
diff --git a/cookbooks/munin/files/default/plugins/fw_conntrack b/cookbooks/munin/files/default/plugins/fw_conntrack
deleted file mode 100755 (executable)
index c575dd8..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/perl -w
-
-=head1 NAME
-
-fw_conntrack - Plugin to monitor the number of tracked connections
-through a Linux 2.4/2.6 firewall
-
-=head1 CONFIGURATION
-
-This plugin must run with root privileges
-
-=head2 CONFIGURATION EXAMPLE
-
-/etc/munin/plugin-conf.d/global or other file in that dir must contain:
-
- [fw_*]
-  user root
-
-=head1 NOTES
-
-ESTABLISHED+FIN_WAIT+TIME_WAIT+SYN_SENT+UDP are the most interesting
-connections.
-
-The total list also includes SYN_RECV, CLOSE, CLOSE_WAIT, LAST_ACK and
-LISTEN, but these were not (often) observed on my firewall.
-
-TOTAL is the total number of tracked connections.
-
-ASSURED and UNREPLIED connections are complimentary subsets of
-ESTABLISHED.
-
-ASSURED is after ACK is seen after SYN_RECV.  Therefore ASSURED is
-plotted but not UNREPLIED.
-
-Note that the plugin depends on the netfilter "conntrack" userspace tool.
-It comes from http://conntrack-tools.netfilter.org/
-
-=head1 AUTHORS
-
-=over
-
-=item 2004.05.05: Initial version by Nicolai Langfeldt, Linpro AS, Oslo, Norway
-
-=item 2004.05.06: Enhanced to count NATed connections after input from Xavier on munin-users list
-
-=item 2011.09.23: Perl version by Alex Tomlins
-
-=back
-
-=head1 LICENSE
-
-GPL
-
-=head1 MAGIC MARKERS
-
- #%# family=auto
- #%# capabilities=autoconf
-
-=cut
-
-use strict;
-use Munin::Plugin;
-
-my $conntrack = '/usr/sbin/conntrack';
-my $nf_conntrack_file = '/proc/net/nf_conntrack';
-my $ip_conntrack_file = '/proc/net/ip_conntrack';
-my @conntrack_max_files = qw(
-        /proc/sys/net/nf_conntrack_max
-        /proc/sys/net/netfilter/nf_conntrack_max
-        /proc/sys/net/ipv4/ip_conntrack_max
-        /proc/sys/net/ipv4/netfilter/ip_conntrack_max
-);
-
-if ( defined($ARGV[0]) and $ARGV[0] eq "autoconf" ) {
-    if ( -x $conntrack or -r $nf_conntrack_file or -r $ip_conntrack_file) {
-        print "yes\n";
-    } else {
-        print "no\n";
-    }
-    exit 0;
-}
-
-if ( defined($ARGV[0]) and $ARGV[0] eq "config" ) {
-    print <<EOF;
-graph_title Connections through firewall
-graph_vlabel Connections
-graph_category network
-graph_args -l 0
-established.label Established
-established.type GAUGE
-established.draw AREA
-fin_wait.label FIN_WAIT
-fin_wait.type GAUGE
-fin_wait.draw STACK
-time_wait.label TIME_WAIT
-time_wait.type GAUGE
-time_wait.draw STACK
-syn_sent.label SYN_SENT
-syn_sent.type GAUGE
-syn_sent.draw STACK
-udp.label UDP connections
-udp.type GAUGE
-udp.draw STACK
-assured.label Assured
-assured.type GAUGE
-assured.draw LINE2
-nated.label NATed
-nated.type GAUGE
-nated.draw LINE1
-total.label Total
-total.type GAUGE
-total.graph no
-EOF
-    my $max;
-    foreach (@conntrack_max_files) {
-        if ( -r $_) {
-            chomp($max = `cat $_`);
-            last;
-        }
-    }
-    if ($max) {
-        print "total.warning ", $max * 8 / 10, "\n";
-        print "total.critical ", $max * 9 / 10, "\n";
-    }
-    exit 0;
-}
-
-my $command;
-if ( -x $conntrack) {
-    $command = "$conntrack -L -o extended -f ipv4 2>/dev/null; $conntrack -L -o extended -f ipv6 2>/dev/null";
-} elsif ( -r $nf_conntrack_file ) {
-    $command = "cat $nf_conntrack_file";
-} else {
-    $command = "cat $ip_conntrack_file";
-}
-
-my %state = (
-    'ESTABLISHED' => 0,
-    'FIN_WAIT' => 0,
-    'TIME_WAIT' => 0,
-    'SYN_SENT' => 0,
-    'UDP' => 0,
-    'ASSURED' => 0,
-    'NATTED' => 0,
-    'TOTAL' => 0
-);
-open CMD, "$command|";
-while (<CMD>) {
-    $state{'TOTAL'} ++;
-    $state{'UDP'} ++ if /udp /;
-    $state{'ASSURED'} ++ if /ASSURED/;
-    if (/tcp \s*\d+\s+\d+\s+(\S+)/) {
-         $state{$1} ++;
-    }
-    if (/src=(\S+)\s+dst=(\S+)\s+sport.*src=(\S+)\s+dst=(\S+)/) {
-        $state{'NATTED'} ++ if $1 ne $4 or $2 ne $3;
-    }
-}
-close CMD;
-
-print "established.value $state{'ESTABLISHED'}\n";
-print "fin_wait.value $state{'FIN_WAIT'}\n";
-print "time_wait.value $state{'TIME_WAIT'}\n";
-print "syn_sent.value $state{'SYN_SENT'}\n";
-print "udp.value $state{'UDP'}\n";
-print "assured.value $state{'ASSURED'}\n";
-print "nated.value $state{'NATTED'}\n";
-print "total.value $state{'TOTAL'}\n";
diff --git a/cookbooks/munin/files/default/plugins/fw_forwarded_local b/cookbooks/munin/files/default/plugins/fw_forwarded_local
deleted file mode 100755 (executable)
index f081d36..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/perl -w
-
-=head1 NAME
-
-fw_forwarded_local - Plugin to monitor network connections.
-
-=head1 CONFIGURATION
-
-This plugin must run with root privileges
-
-=head2 CONFIGURATION EXAMPLE
-
-/etc/munin/plugin-conf.d/global or other file in that dir must contain:
-
- [fw_*]
-  user root
-
-=head1 NOTES
-
-=over
-
-=item * forward: number of connections forwarded
-
-=item * local: number of connections for the host itself
-
-=back
-
-=head1 AUTHORS
-
-2011.09.23: Perl version by Alex Tomlins
-
-=head1 MAGIC MARKERS
-
- #%# family=auto
- #%# capabilities=autoconf
-
-=cut
-
-use strict;
-use Munin::Plugin;
-
-my $conntrack = '/usr/sbin/conntrack';
-my $nf_conntrack_file = '/proc/net/nf_conntrack';
-my $ip_conntrack_file = '/proc/net/ip_conntrack';
-
-if ( defined($ARGV[0]) and $ARGV[0] eq "autoconf" ) {
-    if ( -x $conntrack or -r $nf_conntrack_file or -r $ip_conntrack_file) {
-        print "yes\n";
-    } else {
-        print "no\n";
-    }
-    exit 0;
-}
-
-if ( defined($ARGV[0]) and $ARGV[0] eq "config" ) {
-    print "graph_title ipconntrack\n";
-    print "graph_args -l 0 --base 1000\n";
-    print "graph_vlabel established connections\n";
-    print "graph_category network\n";
-    print "forward.label forward\n";
-    print "forward.type GAUGE\n";
-    print "local.label local\n";
-    print "local.type GAUGE\n";
-    exit 0;
-}
-
-my $command;
-if ( -x $conntrack) {
-    $command = "$conntrack -L -o extended 2>/dev/null";
-} elsif ( -r $nf_conntrack_file ) {
-    $command = "cat $nf_conntrack_file";
-} elsif (-r $ip_conntrack_file ) {
-    $command = "cat $ip_conntrack_file";
-} else {
-    die "Can't find conntrack information\n";
-}
-
-my $local = 0;
-my $forward = 0;
-open CMD, "$command|";
-while (<CMD>) {
-    if (/ESTABLISHED\s+src=(\S+)\s+dst=(\S+)\s+sport.*src=(\S+)\s+dst=(\S+)/) {
-        if ($1 eq $4) {
-            $local++;
-        } else {
-            $forward++;
-        }
-    }
-}
-close CMD;
-
-print "forward.value $forward\n";
-print "local.value $local\n"
diff --git a/cookbooks/munin/files/default/plugins/hpasmcli2_ b/cookbooks/munin/files/default/plugins/hpasmcli2_
deleted file mode 100755 (executable)
index 2169998..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/env perl
-#
-# Plugin to monitor Proliant server health status using hpasmcli.
-#
-# Config variables:
-#   user root       -- requrired by hpasmcli
-#   env.hpasmcli    -- path to hpasmcli executable (optional)
-#   env.degree      -- Unit of temperatures (C or F / default value is C)
-#
-#
-# Author: Tsuyoshi Wada <mail@tuyo.jp>
-#
-# v1.0  2007/12/08 - First version
-#
-# Copyright (c) 2007 Tsuyoshi Wada
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Magic markers
-#%# family=contrib
-#%# capabilities=autoconf suggest
-
-use strict;
-
-my $hpasmcli = exists $ENV{hpasmcli} ? $ENV{hpasmcli} : undef;
-$hpasmcli = `which hpasmcli` unless $hpasmcli;
-chomp $hpasmcli;
-$hpasmcli = undef unless -x $hpasmcli;
-my @dirs = qw(/usr/bin /usr/sbin /usr/local/bin /usr/local/sbin);
-until ($hpasmcli or @dirs == 0) {
-    my $dir = shift @dirs;
-    my $path = $dir.'/hpasmcli';
-    $hpasmcli = $path if -x $path;
-}
-my $degree = exists $ENV{degree} ? $ENV{degree} : 'C';
-my $deg_name = $degree eq 'C' ? "Celsius": "Fahrenheit";
-
-if (defined($ARGV[0])) {
-    if ($ARGV[0] eq 'autoconf') {
-        if ($hpasmcli and -x $hpasmcli) {
-            my @chk_result = `$hpasmcli -s \"help\"`;
-            if ($? eq "0") {
-                print "yes\n";
-                exit 0;
-            } else {
-                my $reason = 'Unknown error';
-                foreach my $line (@chk_result) {
-                    if ($line =~ /^ERROR/i) {
-                        chomp($line);
-                        $reason = $line;
-                        last;
-                    }
-                }
-                print "no ($reason)\n";
-                exit 1;
-            }
-        } else {
-            print "no (hpasmcli not found)\n";
-            exit 1;
-        }
-    } elsif ($ARGV[0] eq 'suggest') {
-        print "temp\nfans\n";
-        exit 0;
-    }
-}
-
-$0 =~ /hpasmcli2_(.+)*$/;
-my $show_target = $1;
-my @show_result = `$hpasmcli -s \"show $show_target\"`;
-my %output;
-
-if (defined($show_target) and $show_target eq 'temp') {
-    foreach my $line (@show_result) {
-        if ($line =~ /^#/) {
-            $line =~ s/\s+/ /g;
-            $line =~ s/^\s//g;
-            my ($sensor, $loc, $temp, $threshold) = split(/\s/, $line);
-            next if ($temp eq "-");
-            $loc =~ s/\/|#//g;
-            $temp = $degree eq 'C' ? (split(/\//, $temp))[0] : (split(/\//, $temp))[1];
-            $temp =~ s/C|F//g;
-            $threshold = $degree eq 'C' ? (split(/\//, $threshold))[0] : (split(/\//, $threshold))[1];
-            $threshold =~ s/C|F//g;
-            $sensor =~s/#//g;
-            $output{$sensor} = {
-                'location'  => lc($loc),
-                'temp'      => $temp,
-                'threshold' => $threshold
-            };
-        }
-    }
-    if (defined($ARGV[0]) and $ARGV[0] eq 'config') {
-        print "graph_title hpasm: Temperature\n";
-        print "graph_args --base 1000 -l 0\n";
-        print "graph_vlabel Degrees in $deg_name\n";
-        print "graph_category sensors\n";
-        print "graph_info This graph shows the temperatures as reported by hpasmcli.\n";
-        foreach my $key (sort keys %output) {
-            print "temp$key.label $output{$key}->{'location'}\n";
-            print "temp$key.warning " . ($output{$key}->{'threshold'} * 0.85) . "\n";
-            print "temp$key.critical $output{$key}->{'threshold'}\n";
-        }
-    } else {
-        foreach my $key (sort keys %output) {
-            print "temp$key.value $output{$key}->{'temp'}\n";
-        }
-    }
-} elsif (defined($show_target) and $show_target eq 'fans') {
-    foreach my $line (@show_result) {
-        if ($line =~ /^#/) {
-            $line =~ s/\s+/ /g;
-            $line =~ s/^\s//g;
-            my ($fan, $loc, $present, $speed, $rate, $redundant, $partner, $pluggable) = split(/\s/, $line);
-            next if ($present ne "Yes");
-            $loc =~ s/\/|#//g;
-            $rate =~ s/\%//g;
-            my $threshold = '100';
-            $fan =~s/#//g;
-            $output{$fan} = {
-                'location'  => lc($loc),
-                'rate'      => $rate,
-                'threshold' => $threshold
-            };
-        }
-    }
-    if (defined($ARGV[0]) and $ARGV[0] eq 'config') {
-        print "graph_title hpasm: Fans\n";
-        print "graph_args --base 1000 -l 0\n";
-        print "graph_vlabel of max (%)\n";
-        print "graph_category sensors\n";
-        print "graph_info This graph shows the info of fans as reported by hpasmcli.\n";
-        foreach my $key (sort keys %output) {
-            print "fan$key.label FAN$key $output{$key}->{'location'}\n";
-            print "fan$key.warning " . ($output{$key}->{'threshold'} * 0.75) . "\n";
-            print "fan$key.critical $output{$key}->{'threshold'}\n";
-        }
-    } else {
-        foreach my $key (sort keys %output) {
-            print "fan$key.value $output{$key}->{'rate'}\n";
-        }
-    }
-} else {
-    die "Unknown target specified ($show_target)\n";
-}
-
-exit 0;
diff --git a/cookbooks/munin/files/default/plugins/memcached_ b/cookbooks/munin/files/default/plugins/memcached_
deleted file mode 100755 (executable)
index 5838cda..0000000
+++ /dev/null
@@ -1,486 +0,0 @@
-#!/usr/bin/perl
-#
-
-=head1 MEMCACHED
-
-Memcached - A Plugin to monitor Memcached Servers
-
-=head1 MUNIN CONFIGURATION
-
-[memcached_*]
- env.host 127.0.0.1     *default*
- env.port 11211         *default*
-
-=head2 MUNIN ENVIRONMENT CONFIGURATION EXPLANATION
-
- host = host we are going to monitor
- port = port we are connecting to, in order to gather stats
-
-=head1 NODE CONFIGURATION
-
-Please make sure you can telnet to your memcache servers and issue the
- following commands: stats
-
-Available Graphs contained in this Plugin
-
-bytes => This graphs the current network traffic in and out
-
-commands => This graphs the current commands being issued to the memcache machine.
-
-conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec is derived from total_conns / uptime.
-
-evictions => This graphs the current evictions on the node.
-
-items => This graphs the current items and total items in the memcached node.
-
-memory => This graphs the current and max memory allocation.
-
-The following example holds true for all graphing options in this plugin.
- Example: ln -s /usr/share/munin/plugins/memcached_ /etc/munin/plugins/memcached_bytes
-
-=head1 ACKNOWLEDGEMENTS
-
-Thanks to dormando for putting up with me ;)
-
-=head1 AUTHOR
-
-Matt West < https://github.com/mhwest13/Memcached-Munin-Plugin >
-
-=head1 LICENSE
-
-GPLv2
-
-=head1 MAGIC MARKERS
-
-#%# family=auto
-#%# capabilities=autoconf suggest
-
-=cut
-
-use strict;
-use IO::Socket;
-
-my $host = $ENV{host} || "127.0.0.1";
-my $port = $ENV{port} || 11211;
-my $connection;
-
-my %stats;
-
-# This hash contains the information contained in two memcache commands
-# stats and stats settings.
-
-# So I was trying to figure out how to build this up, and looking at some good examples
-# I decided to use the format, or for the most part, the format from the mysql_ munin plugin
-# for Innodb by Kjell-Magne Ãierud, it just spoke ease of flexibility especially with multigraphs
-# thanks btw ;)
-#
-# %graphs   is a container for all of the graph definition information. In here is where you'll
-#           find the configuration information for munin's graphing procedure.
-#   Format:
-#
-#   $graph{graph_name} => {
-#       config => {
-#           # You'll find keys and values stored here for graph manipulation
-#       },
-#       datasrc => [
-#           # Name: name given to data value
-#           # Attr: Attribute for given value
-#           { name => 'Name', (Attr) },
-#           { ... },
-#       ],
-#   }
-my %graphs;
-
-$graphs{items} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Items in Memcached',
-        category => 'memcached',
-        title    => 'Items',
-        info     => 'This graph shows the number of items in use by memcached',
-    },
-    datasrc => [
-        { name => 'curr_items', label => 'Current Items', min => '0' },
-        {
-            name  => 'total_items',
-            label => 'New Items',
-            min   => '0',
-            type  => 'DERIVE'
-        },
-    ],
-};
-
-$graphs{memory} = {
-    config => {
-        args     => '--base 1024 --lower-limit 0',
-        vlabel   => 'Bytes Used',
-        category => 'memcached',
-        title    => 'Memory Usage',
-        info     => 'This graph shows the memory consumption of memcached',
-    },
-    datasrc => [
-        {
-            name  => 'limit_maxbytes',
-            draw  => 'AREA',
-            label => 'Maximum Bytes Allocated',
-            min   => '0'
-        },
-        {
-            name  => 'bytes',
-            draw  => 'AREA',
-            label => 'Current Bytes Used',
-            min   => '0'
-        },
-    ],
-};
-
-$graphs{bytes} = {
-    config => {
-        args     => '--base 1000',
-        vlabel   => 'bits in (-) / out (+)',
-        title    => 'Network Traffic',
-        category => 'memcached',
-        info =>
-'This graph shows the network traffic in (-) / out (+) of the machine',
-        order => 'bytes_read bytes_written',
-    },
-    datasrc => [
-        {
-            name  => 'bytes_read',
-            type  => 'DERIVE',
-            label => 'Network Traffic coming in (-)',
-            graph => 'no',
-            cdef  => 'bytes_read,8,*',
-            min   => '0'
-        },
-        {
-            name     => 'bytes_written',
-            type     => 'DERIVE',
-            label    => 'Traffic in (-) / out (+)',
-            negative => 'bytes_read',
-            cdef     => 'bytes_written,8,*',
-            min      => '0'
-        },
-    ],
-};
-
-$graphs{conns} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Connections per ${graph_period}',
-        category => 'memcached',
-        title    => 'Connections',
-        info =>
-'This graph shows the number of connections being handled by memcached',
-        order => 'curr_conns avg_conns',
-    },
-    datasrc => [
-        { name => 'curr_conns', label => 'Current Connections', min => '0' },
-        { name => 'avg_conns',  label => 'Avg Connections',     min => '0' },
-    ],
-};
-
-$graphs{commands} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Commands per ${graph_period}',
-        category => 'memcached',
-        title    => 'Commands',
-        info =>
-          'This graph shows the number of commands being handled by memcached',
-    },
-    datasrc => [
-        {
-            name  => 'cmd_get',
-            type  => 'DERIVE',
-            label => 'Gets',
-            info  => 'Cumulative number of retrieval reqs',
-            min   => '0'
-        },
-        {
-            name  => 'cmd_set',
-            type  => 'DERIVE',
-            label => 'Sets',
-            info  => 'Cumulative number of storage reqs',
-            min   => '0'
-        },
-        {
-            name  => 'get_hits',
-            type  => 'DERIVE',
-            label => 'Get Hits',
-            info  => 'Number of keys that were requested and found',
-            min   => '0'
-        },
-        {
-            name  => 'get_misses',
-            type  => 'DERIVE',
-            label => 'Get Misses',
-            info  => 'Number of keys there were requested and not found',
-            min   => '0'
-        },
-    ],
-};
-
-$graphs{evictions} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Evictions per ${graph_period}',
-        category => 'memcached',
-        title    => 'Evictions',
-        info     => 'This graph shows the number of evictions per second',
-    },
-    datasrc => [
-        {
-            name  => 'evictions',
-            label => 'Evictions',
-            info  => 'Cumulative Evictions Across All Slabs',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-    ],
-};
-
-##
-#### Config Check ####
-##
-
-if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) {
-
-    $0 =~ /(?:([^\/]+)_)?memcached_(.+)$/;
-    my $prefix = $1 ? $1 : '';
-    my $plugin = $2;
-
-    die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
-      unless $graphs{$plugin};
-
-# We need to fetch the stats before we do any config, cause its needed for multigraph
-    fetch_stats();
-
-    # Now lets go ahead and print out our config.
-    do_config( $prefix, $plugin );
-    exit 0;
-}
-
-##
-#### Autoconf Check ####
-##
-
-if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) {
-
-    # Lets attempt to connect to memcached
-    my $s = get_conn();
-
-    # Lets check that we did connect to memcached
-    if ( defined($s) ) {
-        print "yes\n";
-        exit 0;
-    }
-    else {
-        print "no (unable to connect to $connection)\n";
-        exit 0;
-    }
-}
-
-##
-#### Suggest Check ####
-##
-
-if ( defined $ARGV[0] && $ARGV[0] eq 'suggest' ) {
-
-    # Lets attempt to connect to memcached
-    my $s = get_conn();
-
-    # Lets check that we did connect to memcached
-    if ( defined($s) ) {
-        my @rootplugins =
-          ( 'bytes', 'conns', 'commands', 'evictions', 'items', 'memory' );
-        foreach my $plugin (@rootplugins) {
-            print "$plugin\n";
-        }
-        exit 0;
-    }
-    else {
-        print "no (unable to connect to $connection)\n";
-        exit 0;
-    }
-}
-
-##
-#### Well We aren't running (auto)config/suggest so lets print some stats ####
-##
-
-fetch_output();
-
-##
-#### Subroutines for printing info gathered from memcached ####
-##
-
-##
-#### This subroutine performs the bulk processing for printing statistics.
-##
-
-sub fetch_output {
-
-    $0 =~ /(?:([^\/]+)_)?memcached_(.+)$/;
-    my $prefix = $1 ? $1 : '';
-    my $plugin = $2;
-
-    die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
-      unless $graphs{$plugin};
-
-    # Well we need to actually fetch the stats before we do anything to them.
-    fetch_stats();
-
-    # Now lets go ahead and print out our output.
-    print_root_output($plugin);
-
-    return;
-}
-
-##
-#### This subroutine is for the root non-multigraph graphs which render on the main node page ####
-##
-
-sub print_root_output {
-    my ($plugin) = (@_);
-
-    my $graph = $graphs{$plugin};
-
-    #print "graph memcached_$plugin\n";
-
-    if ( $plugin ne 'conns' ) {
-        foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-            my %datasrc = %$dsrc;
-            while ( my ( $key, $value ) = each(%datasrc) ) {
-                next if ( $key ne 'name' );
-                my $output = $stats{$value};
-                print "$dsrc->{name}.value $output\n";
-            }
-        }
-    }
-    else {
-        my $output;
-        foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-            my %datasrc = %$dsrc;
-            while ( my ( $key, $value ) = each(%datasrc) ) {
-                if ( $value eq 'curr_conns' ) {
-                    $output = $stats{curr_connections};
-                }
-                elsif ( $value eq 'avg_conns' ) {
-                    $output = sprintf( "%02d",
-                        $stats{total_connections} / $stats{uptime} );
-                }
-                else {
-                    next;
-                }
-                print "$dsrc->{name}.value $output\n";
-            }
-        }
-    }
-
-    return;
-}
-
-##
-#### Subroutines for printing out config information for graphs ####
-##
-
-##
-#### This subroutine does the bulk printing the config info per graph ####
-##
-
-sub do_config {
-    my ( $prefix, $plugin ) = (@_);
-    print_root_config( $prefix, $plugin );
-
-    return;
-}
-
-##
-#### This subroutine is for the config info for non multigraph graphs which render on the main node page ####
-##
-
-sub print_root_config {
-    my ( $prefix, $plugin ) = (@_);
-
-    die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
-      unless $graphs{$plugin};
-
-    my $graph = $graphs{$plugin};
-
-    my %graphconf = %{ $graph->{config} };
-
-    #print "graph memcached_$plugin\n";
-
-    while ( my ( $key, $value ) = each(%graphconf) ) {
-        if ( $key eq 'title' ) {
-            if ($prefix) {
-                print "graph_$key " . ucfirst($prefix) . " $value\n";
-            }
-            else {
-                print "graph_$key $value\n";
-            }
-        }
-        else {
-            print "graph_$key $value\n";
-        }
-    }
-
-    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-        my %datasrc = %$dsrc;
-        while ( my ( $key, $value ) = each(%datasrc) ) {
-            next if ( $key eq 'name' );
-            print "$dsrc->{name}.$key $value\n";
-        }
-    }
-
-    return;
-}
-
-##
-#### This subroutine returns a socket connection ####
-##
-
-sub get_conn {
-    my $s = undef;
-
-    # check if we want to use sockets instead of tcp
-    my ($sock) = ( $host =~ /unix:\/\/(.+)$/ );
-
-    if ($sock) {
-        $connection = "unix:\/\/$sock";
-        $s = IO::Socket::UNIX->new( Peer => $sock );
-    }
-    else {
-        $connection = "$host:$port";
-        $s          = IO::Socket::INET->new(
-            Proto    => "tcp",
-            PeerAddr => $host,
-            PeerPort => $port,
-            Timeout  => 10,
-        );
-    }
-
-    return $s;
-}
-
-##
-#### This subroutine actually performs the data fetch for us ####
-#### These commands do not lock up Memcache at all ####
-##
-
-sub fetch_stats {
-    my $s = get_conn();
-
-    die "Error: Unable to Connect to $connection\n" unless $s;
-
-    print $s "stats\r\n";
-
-    while ( my $line = <$s> ) {
-        if ( $line =~ /STAT\s(.+?)\s(\d+)/ ) {
-            my ( $skey, $svalue ) = ( $1, $2 );
-            $stats{$skey} = $svalue;
-        }
-        last if $line =~ /^END/;
-    }
-}
diff --git a/cookbooks/munin/files/default/plugins/memcached_multi_ b/cookbooks/munin/files/default/plugins/memcached_multi_
deleted file mode 100755 (executable)
index 1202726..0000000
+++ /dev/null
@@ -1,1631 +0,0 @@
-#!/usr/bin/perl
-#
-
-=head1 MEMCACHED MULTI
-
-Memcached Multi - A Plugin to monitor Memcached Servers (Multigraph)
-
- The common difference between this memcached Munin plugin and others that exists, is that
- others don't expose slab information from memcached, so you can better tune your memcached
- interaction / stability / etc. With this plugin we leverage multigraph capabilities in
- Munin to "hide" the slab information underneath of their parent graphs.
-
-=head1 MUNIN NODE CONFIGURATION
-
-The following configuration information can be overridden by placing environment definitions
- like shown here, in a file located in /etc/munin/plugin-conf.d
-
-[memcached_multi_*]
- env.host 127.0.0.1                             *default*
- env.port 11211                                 *default*
- env.timescale 3                                *default*
- env.cmds get set delete incr decr touch        *default*
- env.leitime -1                                 *default*
-
-=head2 MUNIN NODE ENVIRONMENT CONFIGURATION EXPLANATION
-
- host = host we are going to monitor, this can be used to specify a unix socket.
- port = port we are connecting to, in order to gather stats
- timescale = what time frame do we want to format our graphs too
- cmds = cmd types to display on cmd graph, remove cmds you don't want displayed from list.
- leitime = setting this to 1 will re-enable slab eviction time graphs, see note below.
-
-=head2 BASIC TROUBLESHOOTING
-
-Please make sure you can telnet to your memcache servers and issue the
- following commands: stats, stats settings, stats items and stats slabs.
-
-=head2 PLUGIN INFORMATION
-
-Available Graphs contained in this Plugin
-
-bytes => This graphs the current network traffic in and out
-
-commands => I<MULTIGRAPH> This graphs the current commands being issued to the memcache machine.
-                                B<Multigraph breaks this down to per slab.>
-
-conns => This graphs the current, max connections as well as avg conns per sec avg conns per sec
-            and is derived from total_conns / uptime.
-
-evictions => I<MULTIGRAPH> This graphs the current evictions on the node.
-                                B<Multigraph breaks this down to per slab.>
-
-items => I<MULTIGRAPH> This graphs the current items and total items in the memcached node.
-                                B<Multigraph breaks this down to per slab.>
-
-memory => I<MULTIGRAPH> This graphs the current and max memory allocation.
-                                B<Multigraph breaks this down to per slab.>
-
-unfetched => I<MULTIGRAPH> This graphs the number of items that were never touched by a
-                get/incr/append/etc before being evicted or expiring from the cache.
-                                B<Multigraph breaks this down to per slab.>
-
-=head1 ADDITIONAL INFORMATION
-
-B<NOTE:> The slab plugin for LEI has been disabled since I believe the counters to be inaccurate,
-    or perhaps not being updated as often I thought they would be. They can be re-enabled by
-    setting an environment variable, see munin configuration section at the top.
-
-You will find that some of the graphs have LEI on them. This was done in order to save room
-on space for text and stands for B<Last Evicted Item>.
-
-The B<Timescale> variable formats certain graphs based on the following guidelines.
- 1 => Seconds
- 2 => Minutes
- 3 => Hours  B<*Default*>
- 4 => Days
-
-=head1 ACKNOWLEDGEMENTS
-
-Thanks to dormando for putting up with me ;)
-
-=head1 AUTHOR
-
-Matt West < https://github.com/mhwest13/Memcached-Munin-Plugin >
-
-=head1 LICENSE
-
-GPLv2
-
-=head1 MAGIC MARKERS
-
-#%# family=auto
-#%# capabilities=autoconf suggest
-
-=cut
-
-use strict;
-use warnings;
-use IO::Socket;
-use Munin::Plugin;
-use File::Basename;
-
-if ( basename($0) !~ /(?:([^\/]+)_)?memcached_multi_/ ) {
-    print
-"This script needs to be named (prefix_)?memcached_multi_ to run properly.\n";
-    exit 1;
-}
-
-# tell munin about our multigraph capabilities
-need_multigraph();
-
-=head1 Variable Declarations
-
-    This section of code is to declare the variables used throughout the plugin
-    Some of them are imported as environment variables from munin plugin conf.d
-    file, others are hashes used for storing information that comes from the
-    stats commands issued to memcached.
-
-=cut
-
-# lets import environment variables for the plugin or use the default
-my $host = $ENV{host} || "127.0.0.1";
-my $port = $ENV{port} || 11211;
-my $connection;
-
-# This gives us the ability to control the timescale our graphs are displaying.
-# The default it set to divide by hours, if you want to get seconds set it to 1.
-# Options: 1 = seconds, 2 = minutes, 3 = hours, 4 = days
-my $timescale = $ENV{timescale} || 3;
-
-# This gives us the ability to turn the Last Evicted Item time slab graph on.
-# It was removed because I believe the counter / response to be broken but
-# perhaps this was useful to someone.
-my $leitime = $ENV{leitime} || -1;
-
-# This gives us the ability to specify which commands we want to display on the
-# command graph. Allowing finer control since some environments don't leverage
-# every command possible in memcached.
-# Options: get set delete incr decr cas touch flush
-my $commands = $ENV{cmds} || "get set delete incr decr touch";
-
-# This hash contains the information contained in two memcache commands
-# stats and stats settings.
-my %stats;
-
-# This gives us eviction rates and other hit stats per slab
-# We track this so we can see if something was evicted earlier than necessary
-my %items;
-
-# This gives us the memory size and usage per slab
-# We track this so we can see what slab is being used the most and has no free chunks
-# so we can re-tune memcached to allocate more pages for the specified chunk size
-my %chnks;
-
-# Variable for setting up a quick access map for plugin configurations / version adherence
-my $globalmap;
-
-=head2 Graph Declarations
-
-    This block of code builds up all of the graph info for all root / subgraphs.
-
-    %graphs: is a container for all of the graph definition information. In here is where you'll
-             find the configuration information for munin's graphing procedure.
-    Format:
-
-    $graph{graph_name} => {
-        config => {
-            You'll find the main graph config stored here
-            { key => value },
-            { ... },
-        },
-        datasrc => [
-            Name: name given to data value
-            Attr: Attribute and value, attribute must be valid plugin argument
-            { name => 'Name', info => 'info about graph', ... },
-            { ... },
-        ],
-    }
-
-=cut
-
-my %graphs;
-
-# main graph for memcached item count
-$graphs{items} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Items in Memcached',
-        category => 'memcached global items',
-        title    => 'Items',
-        info     => 'Number of items in use by memcached',
-    },
-    datasrc => [
-        { name => 'curr_items', label => 'Current Items', min => '0' },
-        {
-            name  => 'total_items',
-            label => 'New Items',
-            min   => '0',
-            type  => 'DERIVE'
-        },
-    ],
-};
-
-# main graph for memcached memory usage
-$graphs{memory} = {
-    config => {
-        args     => '--base 1024 --lower-limit 0',
-        vlabel   => 'Bytes Used',
-        category => 'memcached global memory',
-        title    => 'Memory Usage',
-        info     => 'Memory consumption of memcached',
-    },
-    datasrc => [
-        {
-            name  => 'limit_maxbytes',
-            draw  => 'AREA',
-            label => 'Maximum Bytes Allocated',
-            min   => '0'
-        },
-        {
-            name  => 'bytes',
-            draw  => 'AREA',
-            label => 'Current Bytes Used',
-            min   => '0'
-        },
-    ],
-};
-
-# main graph for memcached network usage
-$graphs{bytes} = {
-    config => {
-        args     => '--base 1000',
-        vlabel   => 'bits in (-) / out (+)',
-        title    => 'Network Traffic',
-        category => 'memcached',
-        info     => 'Network traffic in (-) / out (+) of the machine',
-        order    => 'bytes_read bytes_written',
-    },
-    datasrc => [
-        {
-            name  => 'bytes_read',
-            type  => 'DERIVE',
-            label => 'Network Traffic coming in (-)',
-            graph => 'no',
-            cdef  => 'bytes_read,8,*',
-            min   => '0'
-        },
-        {
-            name     => 'bytes_written',
-            type     => 'DERIVE',
-            label    => 'Traffic in (-) / out (+)',
-            negative => 'bytes_read',
-            cdef     => 'bytes_written,8,*',
-            min      => '0'
-        },
-    ],
-};
-
-# graph for memcached connections
-$graphs{conns} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Connections per ${graph_period}',
-        category => 'memcached',
-        title    => 'Connections',
-        info     => 'Number of connections being handled by memcached',
-        order    => 'max_conns curr_conns avg_conns',
-    },
-    datasrc => [
-        { name => 'curr_conns', label => 'Current Connections', min => '0' },
-        { name => 'max_conns',  label => 'Max Connections',     min => '0' },
-        { name => 'avg_conns',  label => 'Avg Connections',     min => '0' },
-    ],
-};
-
-# main graph for memcached commands issued
-$graphs{commands} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Commands per ${graph_period}',
-        category => 'memcached global commands',
-        title    => 'Commands',
-        info     => 'Number of commands being handled by memcached',
-    },
-    datasrc => [
-        {
-            name  => 'cmd_get',
-            type  => 'DERIVE',
-            label => 'Gets',
-            info  => 'Cumulative number of retrieval reqs',
-            min   => '0'
-        },
-        {
-            name  => 'cmd_set',
-            type  => 'DERIVE',
-            label => 'Sets',
-            info  => 'Cumulative number of storage reqs',
-            min   => '0'
-        },
-        {
-            name  => 'cmd_flush',
-            type  => 'DERIVE',
-            label => 'Flushes',
-            info  => 'Cumulative number of flush reqs',
-            min   => '0'
-        },
-        {
-            name  => 'cmd_touch',
-            type  => 'DERIVE',
-            label => 'Touches',
-            info  => 'Cumulative number of touch reqs',
-            min   => '0'
-        },
-        {
-            name  => 'get_hits',
-            type  => 'DERIVE',
-            label => 'Get Hits',
-            info  => 'Number of keys that were requested and found',
-            min   => '0'
-        },
-        {
-            name  => 'get_misses',
-            type  => 'DERIVE',
-            label => 'Get Misses',
-            info  => 'Number of keys there were requested and not found',
-            min   => '0'
-        },
-        {
-            name  => 'delete_hits',
-            type  => 'DERIVE',
-            label => 'Delete Hits',
-            info =>
-              'Number of delete requests that resulted in a deletion of a key',
-            min => '0'
-        },
-        {
-            name  => 'delete_misses',
-            type  => 'DERIVE',
-            label => 'Delete Misses',
-            info  => 'Number of delete requests for missing key',
-            min   => '0'
-        },
-        {
-            name  => 'incr_hits',
-            type  => 'DERIVE',
-            label => 'Increment Hits',
-            info  => 'Number of successful increment requests',
-            min   => '0'
-        },
-        {
-            name  => 'incr_misses',
-            type  => 'DERIVE',
-            label => 'Increment Misses',
-            info  => 'Number of unsuccessful increment requests',
-            min   => '0'
-        },
-        {
-            name  => 'decr_hits',
-            type  => 'DERIVE',
-            label => 'Decrement Hits',
-            info  => 'Number of successful decrement requests',
-            min   => '0'
-        },
-        {
-            name  => 'decr_misses',
-            type  => 'DERIVE',
-            label => 'Decrement Misses',
-            info  => 'Number of unsuccessful decrement requests',
-            min   => '0'
-        },
-        {
-            name  => 'cas_misses',
-            type  => 'DERIVE',
-            label => 'CAS Misses',
-            info  => 'Number of Compare and Swap requests against missing keys',
-            min   => '0'
-        },
-        {
-            name  => 'cas_hits',
-            type  => 'DERIVE',
-            label => 'CAS Hits',
-            info  => 'Number of successful Compare and Swap requests',
-            min   => '0'
-        },
-        {
-            name  => 'cas_badval',
-            type  => 'DERIVE',
-            label => 'CAS Badval',
-            info  => 'Number of unsuccessful Compare and Swap requests',
-            min   => '0'
-        },
-        {
-            name  => 'touch_hits',
-            type  => 'DERIVE',
-            label => 'Touch Hits',
-            info  => 'Number of successfully touched keys',
-            min   => '0'
-        },
-        {
-            name  => 'touch_misses',
-            type  => 'DERIVE',
-            label => 'Touch Misses',
-            info  => 'Number of unsuccessful touch keys',
-            min   => '0'
-        },
-    ],
-};
-
-# main graph for memcached eviction rates
-$graphs{evictions} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Evictions per ${graph_period}',
-        category => 'memcached global evictions',
-        title    => 'Evictions',
-        info     => 'Number of evictions per second',
-    },
-    datasrc => [
-        {
-            name  => 'evictions',
-            type  => 'DERIVE',
-            label => 'Evictions',
-            info  => 'Cumulative Evictions Across All Slabs',
-            min   => '0'
-        },
-        {
-            name  => 'evicted_nonzero',
-            type  => 'DERIVE',
-            label => 'Evictions prior to Expire',
-            info => 'Cumulative Evictions forced to expire prior to expiration',
-            min  => '0'
-        },
-        {
-            name  => 'reclaimed',
-            type  => 'DERIVE',
-            label => 'Reclaimed Items',
-            info  => 'Cumulative Reclaimed Item Entries Across All Slabs',
-            min   => '0'
-        },
-    ],
-};
-
-# main graph for memcached eviction rates
-$graphs{unfetched} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Unfetched Items per ${graph_period}',
-        category => 'memcached global unfetched',
-        title    => 'Unfetched Items',
-        info =>
-'Number of items that were never touched get/incr/append/etc before X occured',
-    },
-    datasrc => [
-        {
-            name  => 'expired_unfetched',
-            type  => 'DERIVE',
-            label => 'Expired Unfetched',
-            min   => '0',
-            info =>
-'Number of items that expired and never had get/incr/append/etc performed'
-        },
-        {
-            name  => 'evicted_unfetched',
-            type  => 'DERIVE',
-            label => 'Evictioned Unfetched',
-            min   => '0',
-            info =>
-'Number of items that evicted and never had get/incr/append/etc performed'
-        },
-    ],
-};
-
-# subgraph for breaking memory info down by slab ( subgraph of memory )
-$graphs{slabchnks} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Available Chunks for this Slab',
-        category => 'memcached slab chunk usage',
-        title    => 'Chunk Usage for Slab: ',
-        info => 'This graph shows you the chunk usage for this memory slab.',
-    },
-    datasrc => [
-        {
-            name  => 'total_chunks',
-            label => 'Total Chunks Available',
-            min   => '0'
-        },
-        { name => 'used_chunks', label => 'Total Chunks in Use', min => '0' },
-        {
-            name  => 'free_chunks',
-            label => 'Total Chunks Not in Use (Free)',
-            min   => '0'
-        },
-    ],
-};
-
-# subgraph for breaking commands down by slab ( subgraph of commands )
-$graphs{slabhits} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Hits per Slab per ${graph_period}',
-        category => 'memcached slab commands',
-        title    => 'Hits for Slab: ',
-        info =>
-          'This graph shows you the successful hit rate for this memory slab.',
-    },
-    datasrc => [
-        {
-            name  => 'get_hits',
-            label => 'Get Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-        {
-            name  => 'cmd_set',
-            label => 'Set Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-        {
-            name  => 'delete_hits',
-            label => 'Delete Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-        {
-            name  => 'incr_hits',
-            label => 'Increment Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-        {
-            name  => 'decr_hits',
-            label => 'Decrement Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-        {
-            name  => 'cas_hits',
-            label => 'Sucessful CAS Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-        {
-            name  => 'cas_badval',
-            label => 'UnSucessful CAS Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-        {
-            name  => 'touch_hits',
-            label => 'Touch Requests',
-            type  => 'DERIVE',
-            min   => '0'
-        },
-    ],
-};
-
-# subgraph for breaking evictions down by slab ( subgraph of evictions )
-$graphs{slabevics} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Evictions per Slab per ${graph_period}',
-        category => 'memcached slab evictions',
-        title    => 'Evictions for Slab: ',
-        info => 'This graph shows you the eviction rate for this memory slab.',
-    },
-    datasrc => [
-        {
-            name  => 'evicted',
-            label => 'Total Evictions',
-            type  => 'DERIVE',
-            min   => '0',
-            info  => 'Items evicted from memory slab'
-        },
-        {
-            name  => 'evicted_nonzero',
-            type  => 'DERIVE',
-            label => 'Evictions from LRU Prior to Expire',
-            info  => 'Items evicted from memory slab before ttl expiration',
-            min   => '0'
-        },
-        {
-            name  => 'reclaimed',
-            type  => 'DERIVE',
-            label => 'Reclaimed Expired Items',
-            info =>
-              'Number of times an item was stored in expired memory slab space',
-            min => '0'
-        },
-    ],
-};
-
-# subgraph for showing the time between an item was last evicted and requested ( subgraph of evictions )
-$graphs{slabevictime} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => ' since Request for LEI',
-        category => 'memcached slab eviction time',
-        title    => 'Eviction Request Time for Slab: ',
-        info =>
-'This graph shows you the time since we requested the last evicted item',
-    },
-    datasrc => [
-        {
-            name  => 'evicted_time',
-            label => 'Eviction Time (LEI)',
-            info  => 'Time Since Request for Last Evicted Item',
-            min   => '0'
-        },
-    ],
-};
-
-# subgraph for breaking items down by slab ( subgraph of items )
-$graphs{slabitems} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Items per Slab',
-        category => 'memcached slab item count',
-        title    => 'Items in Slab: ',
-        info =>
-'This graph shows you the number of items and reclaimed items per slab.',
-    },
-    datasrc => [
-        {
-            name  => 'number',
-            label => 'Items',
-            draw  => 'AREA',
-            info  => 'This is the amount of items stored in this slab',
-            min   => '0'
-        },
-    ],
-};
-
-# subgraph for showing the age of the eldest item stored in a slab ( subgraph of items )
-$graphs{slabitemtime} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => ' since item was stored',
-        category => 'memcached slab item age',
-        title    => 'Age of Eldest Item in Slab: ',
-        info => 'This graph shows you the time of the eldest item in this slab',
-    },
-    datasrc =>
-      [ { name => 'age', label => 'Eldest Item\'s Age', min => '0' }, ],
-};
-
-# main graph for memcached eviction rates
-$graphs{slabunfetched} = {
-    config => {
-        args     => '--base 1000 --lower-limit 0',
-        vlabel   => 'Unfetched Items per ${graph_period}',
-        category => 'memcached slab unfetched',
-        title    => 'Unfetched Items in Slab: ',
-        info =>
-'Number of items that were never touched get/incr/append/etc before X occured',
-    },
-    datasrc => [
-        {
-            name  => 'expired_unfetched',
-            type  => 'DERIVE',
-            label => 'Expired Unfetched',
-            min   => '0',
-            info =>
-'Number of items that expired and never had get/incr/append/etc performed'
-        },
-        {
-            name  => 'evicted_unfetched',
-            type  => 'DERIVE',
-            label => 'Evictioned Unfetched',
-            min   => '0',
-            info =>
-'Number of items that evicted and never had get/incr/append/etc performed'
-        },
-    ],
-};
-
-=head1 Munin Checks
-
-    These checks look for config / autoconf / suggest params
-
-=head2 Config Check
-
-    This block of code looks at the argument that is possibly supplied,
-    should it be config, it then checks to make sure the plugin 
-    specified exists, assuming it does, it will run the do_config 
-    subroutine for the plugin specified, otherwise it dies complaining
-    about an unknown plugin.
-
-=cut
-
-if ( defined $ARGV[0] && $ARGV[0] eq 'config' ) {
-
-# Lets get our plugin from the symlink being called up, we'll also verify its a valid
-# plugin that we have graph information for
-    $0 =~ /(?:([^\/]+)_)?memcached_multi_(.+)$/;
-    my $prefix = $1 ? $1 : '';
-    my $plugin = $2;
-    die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
-      unless $graphs{$plugin};
-
-# We need to fetch the stats before we do any config, cause its needed for multigraph
-# subgraphs which use slab information for title / info per slab
-    fetch_stats();
-    $globalmap = buildglobalmap();
-
-    # Now lets go ahead and print out our config.
-    do_config( $prefix, $plugin );
-    exit 0;
-}
-
-=head2 Autoconf Check
-
-    This block of code looks at the argument that is possibly supplied,
-    should it be autoconf, we will attempt to connect to the memcached
-    service specified on the host:port, upon successful connection it
-    prints yes, otherwise it prints no.
-
-=cut
-
-if ( defined $ARGV[0] && $ARGV[0] eq 'autoconf' ) {
-
-    # Lets attempt to connect to memcached
-    my $s = get_conn();
-
-    # Lets verify that we did connect to memcached
-    if ( defined($s) ) {
-        print "yes\n";
-        exit 0;
-    }
-    else {
-        print "no (unable to connect to $connection)\n";
-        exit 0;
-    }
-}
-
-=head2 Suggest Check
-
-    This block of code looks at the argument that is possibly supplied,
-    should it be suggest, we are going to print the possible plugins
-    which can be specified. Note we only specify the root graphs for the
-    multigraphs, since the rest of the subgraphs will appear "behind" the
-    root graphs. It also attempts to connect to the memcached service to
-    verify it is infact running.
-
-=cut
-
-if ( defined $ARGV[0] && $ARGV[0] eq 'suggest' ) {
-
-    # Lets attempt to connect to memcached
-    my $s = get_conn();
-
-    # Lets check that we did connect to memcached
-    if ( defined($s) ) {
-        fetch_stats();
-        my @rootplugins =
-          ( 'bytes', 'conns', 'commands', 'evictions', 'items', 'memory' );
-        if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
-            push( @rootplugins, 'unfetched' );
-        }
-        foreach my $plugin (@rootplugins) {
-            print "$plugin\n";
-        }
-        exit 0;
-    }
-    else {
-        print "no (unable to connect to $connection)\n";
-        exit 0;
-    }
-}
-
-=head1 Output Subroutines
-
-    Output Subroutine calls to output data values
-
-=head2 fetch_output
-
-    This subroutine is the main call for printing data for the plugin.
-    No parameters are taken as this is the default call if no arguments
-    are supplied from the command line.
-
-=cut
-
-# Well, no arguments were supplied that we know about, so lets print some data
-$0 =~ /(?:([^\/]+)_)?memcached_multi_(.+)$/;
-my $prefix = $1 ? $1 : '';
-my $plugin = $2;
-die 'Unknown Plugin Specified: ' . ( $plugin ? $plugin : '' )
-  unless $graphs{$plugin};
-fetch_stats();
-$globalmap = buildglobalmap();
-fetch_output( $prefix, $plugin );
-
-sub fetch_output {
-    my ( $prefix, $plugin ) = (@_);
-
-    # Now lets go ahead and print out our output.
-    my @subgraphs;
-    if ( $plugin eq 'memory' ) {
-        @subgraphs = ('slabchnks');
-        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
-            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_output( $prefix, $plugin );
-        print_rootmulti_output( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'commands' ) {
-        @subgraphs = ('slabhits');
-        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
-            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_output( $prefix, $plugin );
-        print_rootmulti_output( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'evictions' ) {
-        @subgraphs = ('slabevics');
-        if ( $leitime == 1 ) { push( @subgraphs, 'slabevictime' ); }
-        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_output( $prefix, $plugin );
-        print_rootmulti_output( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'items' ) {
-        @subgraphs = ( 'slabitems', 'slabitemtime' );
-        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_output( $prefix, $plugin );
-        print_rootmulti_output( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'unfetched' ) {
-        @subgraphs = ('slabunfetched');
-        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-            print_submulti_output( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_output( $prefix, $plugin );
-        print_rootmulti_output( $prefix, $plugin );
-    }
-    else {
-        print_root_output($plugin);
-    }
-
-    return;
-}
-
-=head2 print_root_output
-
-    This subroutine prints out the return values for our non-multigraph root graphs.
-    It takes one parameter $plugin and returns when completed.
-
-        $plugin;    graph we are calling up to print data values for 
-
-    Example: print_root_output($plugin);
-
-=cut
-
-sub print_root_output {
-
-    # Lets get our plugin, set our graph reference and print out info for Munin
-    my ($plugin) = (@_);
-    my $graph = $graphs{$plugin};
-
-    # The conns plugin has some specific needs, looking for plugin type
-    if ( $plugin ne 'conns' ) {
-        foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-            my %datasrc = %$dsrc;
-            while ( my ( $key, $value ) = each(%datasrc) ) {
-                next if ( $key ne 'name' );
-                my $output = $stats{$value};
-                print "$dsrc->{name}.value $output\n";
-            }
-        }
-    }
-    else {
-        my $output;
-        foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-            my %datasrc = %$dsrc;
-            while ( my ( $key, $value ) = each(%datasrc) ) {
-                if ( $value eq 'max_conns' ) {
-                    $output = $stats{maxconns};
-                }
-                elsif ( $value eq 'curr_conns' ) {
-                    $output = $stats{curr_connections};
-                }
-                elsif ( $value eq 'avg_conns' ) {
-                    $output = sprintf( "%02d",
-                        $stats{total_connections} / $stats{uptime} );
-                }
-                else {
-                    next;
-                }
-                print "$dsrc->{name}.value $output\n";
-            }
-        }
-    }
-    return;
-}
-
-=head2 print_rootmulti_output
-
-    This subroutine prints out the return values for our multigraph root graphs.
-    It takes one parameter $plugin and returns when completed.
-
-        $plugin;    root graph we are calling up to print data values for
-
-    Example: print_rootmulti_output($plugin);
-
-=cut
-
-sub print_rootmulti_output {
-
-    # Lets get our plugin, set our graph reference and print out info for Munin
-    my ( $prefix, $plugin ) = (@_);
-    my $graph = $graphs{$plugin};
-    if ($prefix) {
-        print "multigraph $prefix\_memcached_multi_$plugin\n";
-    }
-    else {
-        print "multigraph memcached_multi_$plugin\n";
-    }
-
-    # Lets print our data values with their appropriate name
-    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-        my $output  = 0;
-        my %datasrc = %$dsrc;
-        while ( my ( $key, $value ) = each(%datasrc) ) {
-            next if ( $key ne 'name' );
-            next
-              if ( ( $plugin eq 'evictions' )
-                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
-              );
-            next
-              if ( ( $plugin eq 'commands' )
-                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
-            if ( ( $plugin eq 'evictions' ) && ( $value eq 'evicted_nonzero' ) )
-            {
-                foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-                    $output += $items{$slabid}->{evicted_nonzero};
-                }
-            }
-            else {
-                $output = $stats{$value};
-            }
-            print "$dsrc->{name}.value $output\n";
-        }
-    }
-    return;
-}
-
-=head2 print_subrootmulti_output
-
-    This subroutine prints out the return values for our multigraph root graphs, only this set of
-    data will display on the subpage made by the multigraph capabilities of munin and the plugin.
-    It takes one parameter $plugin and returns when completed.
-
-        $plugin;    root graph we are calling up to print data values for
-
-    Example: print_rootmulti_output($plugin);
-
-=cut
-
-sub print_subrootmulti_output {
-
-    # Lets get our plugin, set our graph reference and print out info for Munin
-    my ( $prefix, $plugin ) = (@_);
-    my $graph = $graphs{$plugin};
-    if ($prefix) {
-        if ( $plugin eq 'evictions' ) {
-            print "multigraph $prefix\_memcached_multi_$plugin.global$plugin\n";
-        }
-        else {
-            print "multigraph $prefix\_memcached_multi_$plugin.$plugin\n";
-        }
-    }
-    else {
-        if ( $plugin eq 'evictions' ) {
-            print "multigraph memcached_multi_$plugin.global$plugin\n";
-        }
-        else {
-            print "multigraph memcached_multi_$plugin.$plugin\n";
-        }
-    }
-
-    # Lets print our data values with their appropriate name
-    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-        my $output  = 0;
-        my %datasrc = %$dsrc;
-        while ( my ( $key, $value ) = each(%datasrc) ) {
-            next if ( $key ne 'name' );
-            next
-              if ( ( $plugin eq 'evictions' )
-                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
-              );
-            next
-              if ( ( $plugin eq 'commands' )
-                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
-            if ( ( $plugin eq 'evictions' ) && ( $value eq 'evicted_nonzero' ) )
-            {
-                foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-                    $output += $items{$slabid}->{evicted_nonzero};
-                }
-            }
-            else {
-                $output = $stats{$value};
-            }
-            print "$dsrc->{name}.value $output\n";
-        }
-    }
-    return;
-}
-
-=head2 print_submulti_output
-
-    This subroutine prints out the return values for our multigraph subgraphs. It takes
-    three parameters $slabid, $plugin, @subgraphs and then rReturns when completed.
-
-        $slabid;    slab id that we will use to grab info from and print out
-        $plugin;    root graph being called, used for multigraph output and slab id
-        @subgraphs; graphs we are actually trying to print data values for
-
-    Example: print_submulti_output($slabid,$plugin,@subgraphs);
-
-=cut
-
-sub print_submulti_output {
-
-    # Lets get our slabid, plugin, and subgraphs
-    my ( $prefix, $slabid, $plugin, @subgraphs ) = (@_);
-    my $currslab = undef;
-
-    # Time to loop over our subgraphs array
-    foreach my $sgraph (@subgraphs) {
-
- # Lets set our graph reference for quick calling, and print some info for munin
-        my $graph = $graphs{$sgraph};
-        if ($prefix) {
-            print
-              "multigraph $prefix\_memcached_multi_$plugin.$sgraph\_$slabid\n";
-        }
-        else {
-            print "multigraph memcached_multi_$plugin.$sgraph\_$slabid\n";
-        }
-
-        # Lets figure out what slab info we are trying to call up
-        if (   ( $plugin eq 'evictions' )
-            || ( $plugin eq 'items' )
-            || ( $plugin eq 'unfetched' ) )
-        {
-            $currslab = $items{$slabid};
-        }
-        elsif ( ( $plugin eq 'memory' ) || ( $plugin eq 'commands' ) ) {
-            $currslab = $chnks{$slabid};
-        }
-        else {
-            return;
-        }
-
-        # Lets print our data values with their appropriate name
-        foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-            my %datasrc = %$dsrc;
-            while ( my ( $key, $value ) = each(%datasrc) ) {
-                next if ( $key ne 'name' );
-                next
-                  if ( ( $sgraph eq 'slabevics' )
-                    && ( !exists( $globalmap->{slabevics}->{ $dsrc->{name} } ) )
-                  );
-                next
-                  if ( ( $plugin eq 'commands' )
-                    && ( !exists( $globalmap->{slabcmds}->{ $dsrc->{name} } ) )
-                  );
-                my $output = $currslab->{$value};
-                if (   ( $sgraph eq 'slabevictime' )
-                    || ( $sgraph eq 'slabitemtime' ) )
-                {
-                    $output = time_scale( 'data', $output );
-                }
-                print "$dsrc->{name}.value $output\n";
-            }
-        }
-    }
-    return;
-}
-
-=head1 Config Subroutines
-
-    These subroutines handle the config portion of munin calls.
-
-=head2 do_config
-
-    This is the main call issued assuming we call up config and plugin specified exists
-    The subroutine takes one parameter $plugin, and returns when completed.
-
-        $plugin; root graph being called
-
-    Example: do_config($prefix, $plugin);
-
-=cut
-
-sub do_config {
-    my ( $prefix, $plugin ) = (@_);
-    my @subgraphs;
-    if ( $plugin eq 'memory' ) {
-        @subgraphs = ('slabchnks');
-        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
-            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_config( $prefix, $plugin );
-        print_rootmulti_config( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'commands' ) {
-        @subgraphs = ('slabhits');
-        foreach my $slabid ( sort { $a <=> $b } keys %chnks ) {
-            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_config( $prefix, $plugin );
-        print_rootmulti_config( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'evictions' ) {
-        @subgraphs = ('slabevics');
-        if ( $leitime == 1 ) { push( @subgraphs, 'slabevictime' ); }
-        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_config( $prefix, $plugin );
-        print_rootmulti_config( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'items' ) {
-        @subgraphs = ( 'slabitems', 'slabitemtime' );
-        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_config( $prefix, $plugin );
-        print_rootmulti_config( $prefix, $plugin );
-    }
-    elsif ( $plugin eq 'unfetched' ) {
-        @subgraphs = ('slabunfetched');
-        foreach my $slabid ( sort { $a <=> $b } keys %items ) {
-            print_submulti_config( $prefix, $slabid, $plugin, @subgraphs );
-        }
-        print_subrootmulti_config( $prefix, $plugin );
-        print_rootmulti_config( $prefix, $plugin );
-    }
-    else {
-        print_root_config( $prefix, $plugin );
-    }
-
-    return;
-}
-
-=head2 print_root_config
-
-    This subroutine prints out the config information for all of the non-multigraph root graphs.
-    It takes one parameter, $plugin, returns when completed.
-
-        $prefix;    possible prefix used to allow multiple plugins per machine
-        $plugin;    root graph used for multigraph call
-
-    Example:  print_root_config($prefix,$plugin);
-
-=cut
-
-sub print_root_config {
-
-    # Lets get our plugin, set our graph reference and our graph config info
-    my ( $prefix, $plugin ) = (@_);
-    my $graph     = $graphs{$plugin};
-    my %graphconf = %{ $graph->{config} };
-
-  # Lets tell munin about the graph we are referencing and print the main config
-    while ( my ( $key, $value ) = each(%graphconf) ) {
-        if ( $key eq 'title' ) {
-            if ($prefix) {
-                print "graph_$key " . ucfirst($prefix) . " $value\n";
-            }
-            else {
-                print "graph_$key $value\n";
-            }
-        }
-        else {
-            print "graph_$key $value\n";
-        }
-    }
-
-    # Lets tell munin about our data values and how to treat them
-    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-        my %datasrc = %$dsrc;
-        while ( my ( $key, $value ) = each(%datasrc) ) {
-            next if ( $key eq 'name' );
-            print "$dsrc->{name}.$key $value\n";
-        }
-    }
-    return;
-}
-
-=head2 print_rootmulti_config
-
-    This subroutine prints out the config information for all of the multigraph root graphs.
-    It takes one parameter, $plugin, returns when completed.
-
-        $prefix;    possible prefix used to allow multiple plugins per machine
-        $plugin;    root graph used for multigraph call
-
-    Example:  print_rootmulti_config($prefix,$plugin);
-
-=cut
-
-sub print_rootmulti_config {
-
-    # Lets get out plugin, set our graph reference and our graph config info
-    my ( $prefix, $plugin ) = (@_);
-    my $graph     = $graphs{$plugin};
-    my %graphconf = %{ $graph->{config} };
-
-  # Lets tell munin about the graph we are referencing and print the main config
-    if ($prefix) {
-        print "multigraph $prefix\_memcached_multi_$plugin\n";
-    }
-    else {
-        print "multigraph memcached_multi_$plugin\n";
-    }
-    while ( my ( $key, $value ) = each(%graphconf) ) {
-        if ( $key eq 'category' ) {
-            print "graph_$key memcached\n";
-        }
-        elsif ( $key eq 'title' ) {
-            if ($prefix) {
-                print "graph_$key " . ucfirst($prefix) . " $value\n";
-            }
-            else {
-                print "graph_$key $value\n";
-            }
-        }
-        else {
-            print "graph_$key $value\n";
-        }
-    }
-
-    # Lets tell munin about our data values and how to treat them
-    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-        my %datasrc = %$dsrc;
-        while ( my ( $key, $value ) = each(%datasrc) ) {
-            next if ( $key eq 'name' );
-            next
-              if ( ( $plugin eq 'evictions' )
-                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
-              );
-            next
-              if ( ( $plugin eq 'commands' )
-                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
-            print "$dsrc->{name}.$key $value\n";
-        }
-    }
-    return;
-}
-
-=head2 print_subrootmulti_config
-
-    This subroutine prints out the config information for all of the multigraph root graph, only this
-    graph of the data will display on the subpage made by the multigraph capabilities of munin and
-    the plugin. It takes one parameter, $plugin, returns when completed.
-
-        $prefix;    possible prefix used to allow multiple plugins per machine
-        $plugin;    root graph used for multigraph call
-
-    Example:  print_rootmulti_config($prefix,$plugin);
-
-=cut
-
-sub print_subrootmulti_config {
-
-    # Lets get out plugin, set our graph reference and our graph config info
-    my ( $prefix, $plugin ) = (@_);
-    my $graph     = $graphs{$plugin};
-    my %graphconf = %{ $graph->{config} };
-    if ($prefix) {
-        if ( $plugin eq 'evictions' ) {
-            print "multigraph $prefix\_memcached_multi_$plugin.global$plugin\n";
-        }
-        else {
-            print "multigraph $prefix\_memcached_multi_$plugin.$plugin\n";
-        }
-    }
-    else {
-        if ( $plugin eq 'evictions' ) {
-            print "multigraph memcached_multi_$plugin.global$plugin\n";
-        }
-        else {
-            print "multigraph memcached_multi_$plugin.$plugin\n";
-        }
-    }
-
-    while ( my ( $key, $value ) = each(%graphconf) ) {
-        if ( $key eq 'title' ) {
-            if ($prefix) {
-                print "graph_$key " . ucfirst($prefix) . " $value\n";
-            }
-            else {
-                print "graph_$key $value\n";
-            }
-        }
-        else {
-            print "graph_$key $value\n";
-        }
-    }
-
-    # Lets tell munin about our data values and how to treat them
-    foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-        my %datasrc = %$dsrc;
-        while ( my ( $key, $value ) = each(%datasrc) ) {
-            next if ( $key eq 'name' );
-            next
-              if ( ( $plugin eq 'evictions' )
-                && ( !exists( $globalmap->{globalevics}->{ $dsrc->{name} } ) )
-              );
-            next
-              if ( ( $plugin eq 'commands' )
-                && ( !exists( $globalmap->{globalcmds}->{ $dsrc->{name} } ) ) );
-            print "$dsrc->{name}.$key $value\n";
-        }
-    }
-    return;
-}
-
-=head2 print_submulti_config
-
-    This subroutine prints out the config information for all of the multigraph subgraphs.
-    It takes three parameters, $slabid, $plugin and @subgraphs, returns when completed.
-
-        $prefix;    possible prefix used to allow multiple plugins per machine
-        $slabid;    slab id that we will use to grab info from and print out
-        $plugin;    root graph being called, used for multigraph output and slab id
-        @subgraphs; graphs we are actually trying to print data values for
-
-    Example:  print_submulti_config($prefix,$slabid,$plugin,@subgraphs);
-
-=cut
-
-sub print_submulti_config {
-
-    # Lets get our slabid, plugin, and subgraphs
-    my ( $prefix, $slabid, $plugin, @subgraphs ) = (@_);
-    my ( $slabitems, $slabchnks ) = undef;
-
-    # Time to loop over our subgraphs array
-    foreach my $sgraph (@subgraphs) {
-
-        # Lets set our graph reference, and main graph config for easy handling
-        my $graph     = $graphs{$sgraph};
-        my %graphconf = %{ $graph->{config} };
-
-# Lets tell munin which graph we are graphing, and what our main graph config info is
-        if ($prefix) {
-            print
-              "multigraph $prefix\_memcached_multi_$plugin.$sgraph\_$slabid\n";
-        }
-        else {
-            print "multigraph memcached_multi_$plugin.$sgraph\_$slabid\n";
-        }
-        while ( my ( $key, $value ) = each(%graphconf) ) {
-            if ( $key eq 'title' ) {
-                if ($prefix) {
-                    print "graph_$key "
-                      . ucfirst($prefix)
-                      . " $value"
-                      . "$slabid"
-                      . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
-                }
-                else {
-                    print "graph_$key $value"
-                      . "$slabid"
-                      . " ($chnks{$slabid}->{chunk_size} Bytes)\n";
-                }
-            }
-            elsif (
-                ( $key eq 'vlabel' )
-                && (   ( $sgraph eq 'slabevictime' )
-                    || ( $sgraph eq 'slabitemtime' ) )
-              )
-            {
-                $value = time_scale( 'config', $value );
-                print "graph_$key $value\n";
-            }
-            else {
-                print "graph_$key $value\n";
-            }
-        }
-
-        # Lets tell munin about our data values and how to treat them
-        foreach my $dsrc ( @{ $graph->{datasrc} } ) {
-            my %datasrc = %$dsrc;
-            while ( my ( $key, $value ) = each(%datasrc) ) {
-                next if ( $key eq 'name' );
-                next
-                  if ( ( $sgraph eq 'slabevics' )
-                    && ( !exists( $globalmap->{slabevics}->{ $dsrc->{name} } ) )
-                  );
-                next
-                  if ( ( $plugin eq 'commands' )
-                    && ( !exists( $globalmap->{slabcmds}->{ $dsrc->{name} } ) )
-                  );
-                print "$dsrc->{name}.$key $value\n";
-            }
-        }
-    }
-    return;
-}
-
-=head1 Misc Subroutines
-
-    These subroutines are misc ones, and are referenced inside of the code. They
-    should never be called up by Munin.
-
-=head2 get_conn
-
-    This subroutine returns a socket connection
-
-=cut
-
-sub get_conn {
-    my $s = undef;
-
-    # check if we want to use sockets instead of tcp
-    my ($sock) = ( $host =~ /unix:\/\/(.+)*$/ );
-
-    if ($sock) {
-        $connection = "unix:\/\/$sock";
-        $s = IO::Socket::UNIX->new( Peer => $sock );
-    }
-    else {
-        $connection = "$host:$port";
-        $s          = IO::Socket::INET->new(
-            Proto    => "tcp",
-            PeerAddr => $host,
-            PeerPort => $port,
-            Timeout  => 10,
-        );
-    }
-    return $s;
-}
-
-=head2 fetch_stats
-
-    This subroutine fetches the information from memcached and stores it into our
-    hashes for later referencing throughout the graph. Returns when completed
-
-=cut
-
-sub fetch_stats {
-
-    # Lets try and connect to memcached
-    my $s = get_conn();
-
-    # Die if we can't establish a connection to memcached
-    die "Error: Unable to Connect to $connection\n" unless $s;
-
-    # Lets print the stats command and store the info from the output
-    print $s "stats\r\n";
-    while ( my $line = <$s> ) {
-        if ( $line =~ /STAT\s(.+?)\s((\w|\d|\S)+)/ ) {
-            my ( $skey, $svalue ) = ( $1, $2 );
-            $stats{$skey} = $svalue;
-        }
-        last if $line =~ /^END/;
-    }
-
-    # Lets print the stats settings command and store the info from the output
-    print $s "stats settings\r\n";
-    while ( my $line = <$s> ) {
-        if ( $line =~ /STAT\s(.+?)\s((\w|\d|\S)+)/ ) {
-            my ( $skey, $svalue ) = ( $1, $2 );
-            if ( $skey eq 'evictions' ) {
-                $skey = 'evictions_active';
-            }
-            $stats{$skey} = $svalue;
-        }
-        last if $line =~ /^END/;
-    }
-
-    # Lets print the stats slabs command and store the info from the output
-    print $s "stats slabs\r\n";
-    while ( my $line = <$s> ) {
-        if ( $line =~ /STAT\s(\d+):(.+)\s(\d+)/ ) {
-            my ( $slabid, $slabkey, $slabvalue ) = ( $1, $2, $3 );
-            $chnks{$slabid}->{$slabkey} = $slabvalue;
-        }
-        last if $line =~ /^END/;
-    }
-
-    # Lets print the stats items command and store the info from the output
-    print $s "stats items\r\n";
-    while ( my $line = <$s> ) {
-        if ( $line =~ /STAT\sitems:(\d+):(.+?)\s(\d+)/ ) {
-            my ( $itemid, $itemkey, $itemvalue ) = ( $1, $2, $3 );
-            $items{$itemid}->{$itemkey} = $itemvalue;
-        }
-        last if $line =~ /^END/;
-    }
-}
-
-=head2 time_scale
-
-    This subroutine is here for me to adjust the timescale of the time graphs
-    for last evicted item and age of eldest item in cache.
-
-        Please note, after long usage I have noticed these counters may not
-        be accurate, I believe the developers are aware and have submitted
-        a patch upstream.
-
-=cut
-
-sub time_scale {
-
-    # Lets get our config option and value to adjust
-    my ( $configopt, $origvalue ) = (@_);
-    my $value;
-
-    # If config is defined, it returns the config info for time scale
-    # If data is defined, it returns the original value after its been adjusted
-    if ( $configopt eq 'config' ) {
-        if ( $timescale == 1 ) {
-            $value = "Seconds" . $origvalue;
-        }
-        elsif ( $timescale == 2 ) {
-            $value = "Minutes" . $origvalue;
-        }
-        elsif (( $timescale == 3 )
-            || ( $timescale > 4 )
-            || ( !defined($timescale) ) )
-        {
-            $value = "Hours" . $origvalue;
-        }
-        elsif ( $timescale == 4 ) {
-            $value = "Days" . $origvalue;
-        }
-    }
-    elsif ( $configopt eq 'data' ) {
-        if ( $timescale == 1 ) {
-            $value = sprintf( "%02.2f", $origvalue / 1 );
-        }
-        elsif ( $timescale == 2 ) {
-            $value = sprintf( "%02.2f", $origvalue / 60 );
-        }
-        elsif (( $timescale == 3 )
-            || ( $timescale > 4 )
-            || ( !defined($timescale) ) )
-        {
-            $value = sprintf( "%02.2f", $origvalue / 3600 );
-        }
-        elsif ( $timescale == 4 ) {
-            $value = sprintf( "%02.2f", $origvalue / 86400 );
-        }
-    }
-    else {
-        die "Unknown time_scale option given: either [config/data]\n";
-    }
-    return $value;
-}
-
-=head2 buildglobalmap
-
-    This subroutine looks at the specified commands inputted, and generates
-    a hashref containing two arrays, one for global command keys and one for
-    slab command keys.
-
-=cut
-
-sub buildglobalmap {
-    my $results;
-    my @cmds = split( ' ', $commands );
-    foreach my $cmd (@cmds) {
-        if ( $cmd eq "get" ) {
-            $results->{globalcmds}->{cmd_get}    = 1;
-            $results->{globalcmds}->{get_hits}   = 1;
-            $results->{globalcmds}->{get_misses} = 1;
-            $results->{slabcmds}->{get_hits}     = 1;
-        }
-        elsif ( $cmd eq "set" ) {
-            $results->{globalcmds}->{cmd_set} = 1;
-            $results->{slabcmds}->{cmd_set}   = 1;
-        }
-        elsif ( $cmd eq "delete" ) {
-            $results->{globalcmds}->{delete_hits}   = 1;
-            $results->{globalcmds}->{delete_misses} = 1;
-            $results->{slabcmds}->{delete_hits}     = 1;
-        }
-        elsif ( $cmd eq "incr" ) {
-            $results->{globalcmds}->{incr_hits}   = 1;
-            $results->{globalcmds}->{incr_misses} = 1;
-            $results->{slabcmds}->{incr_hits}     = 1;
-        }
-        elsif ( $cmd eq "decr" ) {
-            $results->{globalcmds}->{decr_hits}   = 1;
-            $results->{globalcmds}->{decr_misses} = 1;
-            $results->{slabcmds}->{decr_hits}     = 1;
-        }
-        elsif ( $cmd eq "cas" ) {
-            $results->{globalcmds}->{cas_hits}   = 1;
-            $results->{globalcmds}->{cas_misses} = 1;
-            $results->{globalcmds}->{cas_badval} = 1;
-            $results->{slabcmds}->{cas_hits}     = 1;
-            $results->{slabcmds}->{cas_badval}   = 1;
-        }
-        elsif ( $cmd eq "touch" ) {
-            if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
-                $results->{globalcmds}->{cmd_touch}    = 1;
-                $results->{globalcmds}->{touch_hits}   = 1;
-                $results->{globalcmds}->{touch_misses} = 1;
-                $results->{slabcmds}->{touch_hits}     = 1;
-            }
-        }
-        elsif ( $cmd eq "flush" ) {
-            if ( $stats{version} !~ /^1\.4\.[0-7]$/ ) {
-                $results->{globalcmds}->{cmd_flush} = 1;
-            }
-        }
-        else {
-
-            # Do absolutely nothing...
-        }
-    }
-    $results->{globalevics}->{evictions}       = 1;
-    $results->{globalevics}->{evicted_nonzero} = 1;
-    $results->{slabevics}->{evicted}           = 1;
-    $results->{slabevics}->{evicted_nonzero}   = 1;
-    if ( $stats{version} !~ /^1\.4\.[0-2]$/ ) {
-        $results->{globalevics}->{reclaimed} = 1;
-        $results->{slabevics}->{reclaimed}   = 1;
-    }
-    return $results;
-}
diff --git a/cookbooks/munin/files/default/plugins/munin_rrdcached b/cookbooks/munin/files/default/plugins/munin_rrdcached
deleted file mode 100644 (file)
index 9f9cb6d..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/perl -w
-# -*- cperl -*-
-
-use strict;
-use warnings;
-
-use IO::Socket::UNIX;
-
-$| = 1;
-
-my $arg = shift;
-if ($arg && $arg eq "config") {
-       print "graph_title Munin rrdcached statistics\n";
-       print "graph_category munin\n";
-       print "QueueLength.label Queue length\n";
-       print "UpdatesReceived.label UpdatesReceived\n";
-       print "UpdatesReceived.type DERIVE\n";
-       print "FlushesReceived.label FlushesReceived\n";
-       print "FlushesReceived.type DERIVE\n";
-       print "UpdatesWritten.label UpdatesWritten\n";
-       print "UpdatesWritten.type DERIVE\n";
-       print "DataSetsWritten.label DataSetsWritten\n";
-       print "DataSetsWritten.type DERIVE\n";
-       print "TreeNodesNumber.label TreeNodesNumber\n";
-       print "TreeDepth.label TreeDepth\n";
-       print "JournalBytes.label JournalBytes\n";
-       print "JournalBytes.type DERIVE\n";
-       print "JournalRotate.label JournalRotate\n";
-       print "JournalRotate.type DERIVE\n";
-       exit 0;
-}
-
-my $sock = new IO::Socket::UNIX(
-       Type => SOCK_STREAM,
-       Peer => "/var/run/rrdcached.sock",
-) or die "Cannot open socket : $!";
-
-print $sock "STATS\n";
-print $sock "QUIT\n";
-
-# skip first line
-<$sock>;
-print map { s/: /.value /; $_; } <$sock>;
-
-exit 0;
diff --git a/cookbooks/munin/files/default/plugins/mysql_ b/cookbooks/munin/files/default/plugins/mysql_
deleted file mode 100644 (file)
index 80c561e..0000000
+++ /dev/null
@@ -1,2514 +0,0 @@
-#!/usr/bin/perl
-
-=encoding utf8
-
-=head1 NAME
-
-mysql_ - Munin plugin to display misc MySQL server status
-
-=head1 APPLICABLE SYSTEMS
-
-Any MySQL platform, tested by the authors on:
-* MySQL 5.6.12
-* MySQL 5.5.32, 5.5.37
-* MySQL 5.1.29,
-* MySQL 5.0.51
-* MariaDB 5.5.39
-* MariaDB-5.5.39(galera).
-
-Plugins:
-* MariaDB-10 Query Response Time: https://mariadb.com/kb/en/mariadb/query_response_time-plugin/
-
-Information Schema tables:
-* User statistics - MariaDB-5.2+, OurDelta, Percona Server - https://mariadb.com/kb/en/mariadb/user-statistics
-
-=head1 CONFIGURATION
-
-This script is used to generate data for several graphs. To generate
-data for one specific graph, you need to create a symbolic link with a
-name like mysql_<GRAPH> to this script.
-
-If you need to run against multiple MySQL instances on the same host,
-create your symlinks with names like mysql<N>_<GRAPH> where N is any
-non-negative integer. You must also set the env.cachenamespace variable
-to a unique value for each group of symlinks.
-
-To get a list of symlinks that can be created, run:
-
-  ./mysql_ suggest
-
-In addition you might need to specify connection parameters in the
-plugin configuration to override the defaults. These are the defaults:
-
-  [mysql_*]
-    env.mysqlconnection DBI:mysql:information_schema
-    env.mysqluser root
-
-Non-default example:
-
-  [mysql_*]
-    env.mysqlconnection DBI:mysql:information_schema;host=127.0.0.1;port=3306
-    env.mysqluser munin
-    env.mysqlpassword geheim
-    env.cachenamespace munin_mysql_pri
-  [mysql2_*]
-    env.mysqlconnection DBI:mysql:information_schema;host=127.0.0.1;port=13306
-    env.mysqluser munin;
-    env.mysqlpassword ryuWyawEv
-    env.cachenamespace munin_mysql_alt
-  [mysql10_*]
-    user munin
-    env.mysqluser munin
-    env.mysqlconnection DBI:mysql:information_schema;mysql_read_default_file=/etc/munin/.my-10.cnf
-    env.cachenamespace munin_mysql_10
-    # here the [client] section of /etc/munin/.my-10.cnf is read. socket= can
-    # be specified here.
-
-Creating a munin user:
-
-  CREATE USER 'munin'@'localhost' IDENTIFIED BY 'ryuWyawEv';
-
-or with a unix_socket plugin (INSTALL PLUGIN unix_socket SONAME 'auth_socket')
-
-  CREATE USER 'munin'@'localhost' IDENTIFIED WITH unix_socket;
-
-Note: requires 'user munin' in the configuration.
-
-The minimum required priviledges of the munin database user is:
-
-  GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'munin'@'localhost';
-
-
-Warning and critical values can be set via the environment in the usual way.
-For example:
-
-  [mysql_replication]
-    env.slave_io_running_warning 0.5
-    env.slave_sql_running_warning 0.5
-    env.seconds_behind_master_warning 300
-    env.seconds_behind_master_critical 600
-
-=head1 DEPENDENCIES
-
-=over
-
-=item Cache::Cache
-
-The plugin uses shared memory to cache the statistics gathered from
-MySQL. This ensures minimal inpact on the MySQL server.
-
-=item DBD::mysql
-
-=back
-
-=head1 INTERPRETATION
-
-=head2 InnoDB
-
-The statistics from innodb are mainly collected from the command
-
-  SHOW ENGINE INNODB STATUS
-
-A nice walk through is found at
-L<http://www.mysqlperformanceblog.com/2006/07/17/show-innodb-status-walk-through/>
-
-Undo logs:
-L<http://blog.jcole.us/2014/04/16/the-basics-of-the-innodb-undo-logging-and-history-system/>
-
-=head2 The graphs
-
-FIX point to relevant sections in the MySQL manual and other www
-resources for each graph
-
-=over
-
-=item mysql_replication
-
-slave_io_running and slave_sql_running both translate the "Yes" values to 0 and
-anything else to 1 for their respective fields in the "SHOW SLAVE STATUS" output.
-This can be used to warn on slave failure if the warning and critical values
-are set as seen in a previous section.
-
-=item wsrep_cluster_status
-
-"Primary" is translated 0 and "non-Primary" to 1.
-
-=back
-
-=head1 LICENSE
-
-Copyright (C) 2008,2009 Kjell-Magne Øierud, 2014 Open Query
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; version 2 dated June, 1991.
-
-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, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-=head1 VERSION
-
-git-master + a few munin modifications
-
-This plugin was downloaded from L<http://github.com/kjellm/munin-mysql/>
-
-=head1 MAGICK MARKERS
-
-  #%# family=auto
-  #%# capabilities=suggest autoconf
-
-=cut
-
-use warnings;
-use strict;
-use utf8;
-
-use DBI;
-use File::Basename;
-use Math::BigInt; # Used to append "=> lib 'GMP'" here, but GMP caused
-                 # segfault on some occasions. Removed as I don't
-                 # think the tiny performance boost is worth the
-                 # debugging effort.
-use Storable qw(nfreeze thaw);
-
-use Munin::Plugin;
-
-my $has_cache;
-
-BEGIN {
-    eval 'require Cache::SharedMemoryCache';
-    $has_cache = $@ ? 0 : 1;
-}
-
-
-#---------------------------------------------------------------------
-#  C O N F I G
-#---------------------------------------------------------------------
-
-my %config = (
-    'dsn'        => $ENV{'mysqlconnection'} || 'DBI:mysql:information_schema',
-    'user'       => $ENV{'mysqluser'}       || 'root',
-    'password'   => $ENV{'mysqlpassword'}   || '',
-    'cache_namespace' => $ENV{'cachenamespace'} || 'munin_mysql',
-);
-
-
-#---------------------------------------------------------------------
-#  C A C H E
-#---------------------------------------------------------------------
-
-my %cache_options = (
-    'namespace'          => $config{cache_namespace},
-    'default_expires_in' => 60,
-);
-
-my $shared_memory_cache ;
-if ($has_cache)
-{
-  $shared_memory_cache = Cache::SharedMemoryCache->new(\%cache_options)
-    or die("Couldn't instantiate SharedMemoryCache");
-}
-
-#---------------------------------------------------------------------
-#  G R A P H   D E F I N I T I O N S
-#---------------------------------------------------------------------
-
-# These are defaults to save typing in the graph definitions
-my %defaults = (
-    global_attrs => {
-       args   => '--base 1000',
-    },
-    data_source_attrs => {
-       min   => '0',
-       type  => 'DERIVE',
-       draw  => 'AREASTACK',
-    },
-);
-
-# %graphs contains the graph definitions, it is indexed on the graph
-# name. The information stored for each graph is used for both showing
-# data source values and for printing the graph configuration. Each
-# graph follows the followingformat:
-#
-# $graph{NAME} => {
-#     config => {
-#         # The global attributes for this graph
-#         global_attrs => {}
-#         # Attributes common to all data sources in this graph
-#         data_source_attrs => {}
-#     },
-#     data_sources => [
-#         # NAME - The name of the data source (e.g. variable names
-#         #        from SHOW STATUS)
-#         # DATA_SOURCE_ATTRS - key-value pairs with data source
-#         #                     attributes
-#         {name => 'NAME', (DATA_SOURCE_ATTRS)},
-#         {...},
-#     ],
-my %graphs = ();
-
-#---------------------------------------------------------------------
-
-
-$graphs{wsrep_cluster_status} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera Status',
-                vlabel => 'PRIMARY',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-                   min   => '0',
-                   max   => '1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_cluster_status', label => '0-Primary, 1-Non-Primary',
-                                           info  => 'If the host is primary',
-                                           type  => 'GAUGE',
-                                           critical => '1'},
-        ],
-};
-
-$graphs{wsrep_cluster_size} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera cluster size',
-                vlabel => 'Hosts',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_cluster_size', label => 'Cluster size',
-                                           info  => 'The number of hosts in the cluster.',
-                                           type  => 'GAUGE'},
-        ],
-};
-
-
-# http://www.codership.com/wiki/doku.php?id=galera_node_fsm
-$graphs{wsrep_local_state} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera node state',
-                vlabel => 'State (galera_node_fsm)',
-                args   => '--lower-limit 0 --upper-limit 6',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-                   min   => '0',
-                   max   => '6',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_local_state', label => '1-Joining, 2-Donor, 3-Joined, 4-Synced, 5-Donor, 6-Join after Donor ',
-                                          info  => 'The state of the node in the cluster.',
-                                          type  => 'GAUGE',
-                                          warning => '3.5:4.5'},
-        ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{wsrep_transactions} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera transactions',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_last_committed', label => 'Committed transactions',
-                                             info  => '# of committed transactions.',
-                                             type  => 'COUNTER',
-                                             min   => 0},
-            {name => 'wsrep_local_commits',  label => 'Locally Committed transactions',
-                                             info  => '# of locally committed transactions.',
-                                             type  => 'COUNTER',
-                                             min   => 0},
-        ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{wsrep_writesets} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera writesets',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_replicated', label => 'Writesets sent',
-                                         info  => '# of writesets sent to other nodes',
-                                         type  => 'COUNTER',
-                                         min   => '0',
-                                         graph => 'no'},
-            {name => 'wsrep_received',   label => 'Writesets received',
-                                         info  => '# of writesets received from other nodes',
-                                         type  => 'COUNTER',
-                                         min   => '0',
-                                         negative => 'wsrep_replicated'},
-        ],
-};
-
-#-------------------------
-
-
-$graphs{wsrep_writesetbytes} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera writesets bytes/sec',
-            },
-            data_source_attrs => {
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_received_bytes',   label => 'Writesets bytes received',
-                                               info  => '# of bytes in writesets received from other nodes',
-                                               type  => 'DERIVE',
-                                               min   => 0,
-                                               graph => 'no'},
-            {name => 'wsrep_replicated_bytes', label => 'Writesets bytes sent',
-                                               info  => '# of bytes in writesets sent to other nodes',
-                                               type  => 'DERIVE',
-                                               draw  => 'LINE1',
-                                               min   => 0,
-                                               negative => 'wsrep_received_bytes'},
-            {name => 'wsrep_repl_keys_bytes', label => 'Writeset key size sent',
-                                               info  => '# of bytes in writesets of keys sent to other nodes',
-                                               type  => 'DERIVE',
-                                               min   => 0},
-            {name => 'wsrep_repl_data_bytes', label => 'Writeset data size sent',
-                                               info  => '# of bytes in writesets of data sent to other nodes',
-                                               type  => 'DERIVE',
-                                               min   => 0},
-            {name => 'wsrep_repl_other_bytes', label => 'Writeset other size sent',
-                                               info  => '# of bytes in writesets of other data sent to other nodes',
-                                               type  => 'DERIVE',
-                                               min   => 0},
-        ],
-};
-
-
-#-------------------------
-
-$graphs{wsrep_errors} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera transaction problems'
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_local_cert_failures', label => 'Certification failures',
-                                                  type  => 'DERIVE',
-                                                  min   => 0},
-            {name => 'wsrep_local_bf_aborts',     label => 'Aborted local transactions',
-                                                  type  => 'DERIVE',
-                                                  min   => 0},
-            {name => 'wsrep_local_replays',       label => 'Replays',
-                                                  type  => 'DERIVE',
-                                                  min   => 0},
-        ],
-};
-
-#-------------------------
-
-$graphs{wsrep_queue} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera queues',
-                     vlabel => 'queue length received (-) / sent (+) per ${graph_period}',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_local_recv_queue',     label => 'Receive queue length',
-                                                   type  => 'GAUGE',
-                                                   graph => 'no'},
-            {name => 'wsrep_local_recv_queue_min', label => 'Receive queue length min',
-                                                   type  => 'GAUGE',
-                                                   graph => 'no'},
-            {name => 'wsrep_local_recv_queue_avg', label => 'Average receive queue length',
-                                                   type  => 'GAUGE',
-                                                   graph => 'no'},
-            {name => 'wsrep_local_recv_queue_max', label => 'Receive queue length max',
-                                                   type  => 'GAUGE',
-                                                   graph => 'no'},
-            {name => 'wsrep_local_send_queue',     label => 'Send queue length',
-                                                   type  => 'GAUGE',
-                                                   negative => 'wsrep_local_recv_queue'},
-            {name => 'wsrep_local_send_queue_min', label => 'Send queue length min',
-                                                   type  => 'GAUGE',
-                                                   negative => 'wsrep_local_recv_queue_min'},
-            {name => 'wsrep_local_send_queue_avg', label => 'Average send queue length',
-                                                   type  => 'GAUGE',
-                                                   negative => 'wsrep_local_recv_queue_avg'},
-            {name => 'wsrep_local_send_queue_max', label => 'Send queue length max',
-                                                   type  => 'GAUGE',
-                                                   negative => 'wsrep_local_recv_queue_max'},
-        ],
-};
-
-#-------------------------
-
-$graphs{wsrep_concurrency} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera Performance - Apply to Commit',
-                vlabel => 'commit + / apply - '
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-                type  => 'GAUGE',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_apply_window',         label => 'apply window',
-                                                   graph => 'no'},
-            {name => 'wsrep_apply_oooe',           label => 'apply out of order',
-                                                   graph => 'no'},
-            {name => 'wsrep_apply_oool',           label => 'apply out of order (slowness)',
-                                                   graph => 'no'},
-            {name => 'wsrep_commit_window',        label => 'commit window',
-                                                   negative => 'wsrep_apply_window'},
-            {name => 'wsrep_commit_oooe',          label => 'commit out of order',
-                                                   negative => 'wsrep_apply_oooe'},
-            {name => 'wsrep_commit_oool',          label => 'commit out of order (slowness)',
-                                                   negative => 'wsrep_apply_oool'},
-        ],
-};
-
-#-------------------------
-
-$graphs{wsrep_flow} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera flow control',
-                     vlabel => 'events received (-) / sent (+) per ${graph_period}',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_flow_control_recv',      label => 'Pause events received',
-                                                     type  => 'DERIVE',
-                                                     min   => 0,
-                                                     graph => 'no'},
-            {name => 'wsrep_flow_control_sent',      label => 'Pause events sent',
-                                                     type  => 'DERIVE',
-                                                     min   => 0,
-                                                     negative => 'wsrep_flow_control_recv'},
-        ],
-  };
-
-
-
-#-------------------------
-
-$graphs{wsrep_flow_paused} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera flow control paused ratio',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_flow_control_paused',    label => 'Ratio flow control was paused',
-                                                     type  => 'GAUGE',
-                                                     min   => '0',
-                                                     max   => '1',
-                                                     warning => 0.1,
-                                                     critical => 0.9},
-        ],
-   };
-
-#-------------------------
-
-$graphs{wsrep_flow_paused_ns} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera flow control paused time',
-                vlabel => 'nanoseconds',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_flow_control_paused_ns',    label => 'Time flow control was paused (ns)',
-                                                     min   => '0',
-                                                     warning => 20000,
-                                                     critical => 1000000},
-        ],
-   };
-
-#-------------------------
-
-$graphs{wsrep_distance} = {
-        config => {
-            global_attrs => {
-                title  => 'Galera distance',
-            },
-            data_source_attrs => {
-                draw  => 'LINE1',
-            },
-        },
-        data_sources => [
-            {name => 'wsrep_cert_deps_distance',    label => 'cert_deps_distance',
-                                                    type  => 'GAUGE'},
-            {name => 'wsrep_cert_index_size',       label => 'wsrep_cert_index_size',
-                                                    type  => 'GAUGE'},
-            {name => 'wsrep_slave_threads',        label => 'wsrep_slave_threads',
-                                                    type  => 'GAUGE'},
-            {name => 'wsrep_commit_window',         label => 'commit_window',
-                                                    type  => 'GAUGE'},
-        ],
-};
-
-#-------------------------
-$graphs{bin_relay_log} = {
-    config => {
-       global_attrs => {
-           title  => 'Binary/Relay Logs',
-           vlabel => 'Log activity',
-       },
-       data_source_attrs => {
-           draw  => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'Binlog_cache_disk_use', label => 'Binlog Cache Disk Use'},
-       {name => 'Binlog_cache_use',      label => 'Binlog Cache Use'},
-       {name => 'Binlog_stmt_cache_disk_use', label => 'Binlog Statement Cache Disk Use'},
-       {name => 'Binlog_stmt_cache_use',      label => 'Binlog Statement Cache Use'},
-       {name => 'ma_binlog_size',        label => 'Binary Log Space'},
-       {name => 'relay_log_space',       label => 'Relay Log Space'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{commands} = {
-    config => {
-       global_attrs => {
-           title  => 'Command Counters',
-           vlabel => 'Commands per ${graph_period}',
-           total  => 'Questions',
-       },
-       data_source_attrs => {},
-    },
-    data_sources => [
-       {name => 'Com_delete',         label => 'Delete'},
-       {name => 'Com_insert',         label => 'Insert'},
-       {name => 'Com_insert_select',  label => 'Insert select'},
-       {name => 'Com_load',           label => 'Load Data'},
-       {name => 'Com_replace',        label => 'Replace'},
-       {name => 'Com_replace_select', label => 'Replace select'},
-       {name => 'Com_select',         label => 'Select'},
-       {name => 'Com_update',         label => 'Update'},
-       {name => 'Com_update_multi',   label => 'Update multi'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{connections} = {
-    config => {
-       global_attrs => {
-           title  => 'Connections',
-           vlabel => 'Connections per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'max_connections',      label  => 'Max connections',
-                                        type   => 'GAUGE',
-                                        draw   => 'AREA',
-                                        colour => 'cdcfc4'},
-       {name => 'Max_used_connections', label  => 'Max used',
-                                        type   => 'GAUGE',
-                                        draw   => 'AREA',
-                                        colour => 'ffd660'},
-       {name => 'Aborted_clients',      label => 'Aborted clients'},
-       {name => 'Aborted_connects',     label => 'Aborted connects'},
-       {name => 'Threads_connected',    label => 'Threads connected',
-                                        type  => 'GAUGE'},
-       {name => 'Threads_running',      label => 'Threads running',
-                                        type  => 'GAUGE'},
-       {name => 'Connections',          label => 'New connections'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{files} = {
-    config => {
-       global_attrs => {
-           title  => 'Files',
-       },
-       data_source_attrs => {
-           type  => 'GAUGE',
-           draw  => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'open_files_limit', label  => 'File Limit',
-                                    draw   => 'AREA',
-                                    colour => 'cdcfc4'},
-       {name => 'Open_files',       label => 'Open files',
-                                    type  => 'DERIVE',
-                  min   => 0},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{tables} = {
-    config => {
-       global_attrs => {
-           title  => 'Tables',
-       },
-       data_source_attrs => {
-           type  => 'GAUGE',
-           draw  => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'table_open_cache',   label  => 'Table cache',
-                                    draw   => 'AREA',
-                                    colour => 'cdcfc4'},
-       {name => 'innodb_open_files',  label => 'Innodb Table Cache Limit',
-                                    draw   => 'AREA',
-                                    colour => 'ffd660'},
-       {name => 'Open_tables',        label => 'Open tables'},
-       {name => 'Slave_open_temp_tables',  label => 'Open Slave Temp Tables'},
-       {name => 'Opened_tables',      label => 'Opened tables',
-                                    type  => 'DERIVE',
-                  min   => 0},
-       {name => 'Opened_views',       label => 'Opened Views',
-                                    type  => 'DERIVE',
-                  min   => 0},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{table_definitions} = {
-    config => {
-       global_attrs => {
-           title  => 'Tables Definitions',
-       },
-       data_source_attrs => {
-           type  => 'GAUGE',
-           draw  => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'table_definition_cache',  label => 'Cache Limit',
-                                    draw   => 'AREA',
-                                    colour => 'cdcfc4'},
-       {name => 'Open_table_definitions',  label => 'Open'},
-       {name => 'Opened_table_definitions',  label => 'Opened',
-                                    type  => 'DERIVE',
-                  min   => 0},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_bpool} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Buffer Pool',
-           vlabel => 'Pages',
-           args   => '--base 1024',
-       },
-       data_source_attrs => {
-           draw => 'LINE2',
-           type => 'GAUGE',
-       },
-    },
-    data_sources => [
-       {name => 'ib_bpool_size',     label  => 'Buffer pool size',
-                                     draw   => 'AREA',
-                                     colour => 'ffd660'},
-       {name => 'ib_bpool_dbpages',  label  => 'Database pages',
-                                     draw   => 'AREA',
-                                     colour => 'cdcfc4'},
-       {name => 'ib_bpool_free',     label => 'Free pages'},
-       {name => 'ib_bpool_modpages', label => 'Modified pages'},
-       {name => 'ib_bpool_oldpages', label => 'Old pages'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_bpool_act} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Buffer Pool Activity',
-           vlabel => 'Pages per ${graph_period}',
-           total  => 'Total',
-       },
-       data_source_attrs => {
-           draw => 'LINE2',
-       },
-    },
-    data_sources => [
-       {name => 'ib_bpool_read',           label => 'Read'},
-       {name => 'ib_bpool_created',        label => 'Created'},
-       {name => 'ib_bpool_written',        label => 'Written'},
-       {name => 'ib_bpool_made_young',     label => 'Made young'},
-       {name => 'ib_bpool_made_not_young', label => 'Made not young'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_bpool_internal_breakdown} = {
-    config => {
-        global_attrs => {
-            title  => 'InnoDB Buffer Pool Internal breakdown',
-            args   => '--base 1024 --lower-limit 0',
-            vlabel => 'bytes',
-        },
-        data_source_attrs => {
-            min  => '0',
-            draw => 'AREASTACK',
-            type => 'GAUGE',
-        },
-    },
-    data_sources => [
-        {name => 'ib_bpool_internal_adaptive_hash_size_const',    label => 'Adaptive Hash const'},
-        {name => 'ib_bpool_internal_adaptive_hash_size_var',      label => 'Adaptive Hash var'},
-        {name => 'ib_bpool_internal_page_hash_size_total',        label => 'Page Hash'},
-        {name => 'ib_bpool_internal_dictionary_cache_size_const', label => 'Dictionary const'},
-        {name => 'ib_bpool_internal_dictionary_cache_size_var',   label => 'Dictionary var'},
-        {name => 'ib_bpool_internal_file_system_size_const',      label => 'Filesystem const'},
-        {name => 'ib_bpool_internal_file_system_size_var',        label => 'Filesystem var'},
-        {name => 'ib_bpool_internal_lock_system_size_const',      label => 'Lock system const'},
-        {name => 'ib_bpool_internal_lock_system_size_var',        label => 'Lock system var'},
-        {name => 'ib_bpool_internal_recovery_system_size_const',  label => 'Recovery system const'},
-        {name => 'ib_bpool_internal_recovery_system_size_var',    label => 'Recovery system var'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_insert_buf} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Insert Buffer',
-           vlabel => 'Activity per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw => 'LINE1',
-       },
-    },
-    data_sources => [
-      {name => 'ib_ibuf_inserts',    label => 'Merge Inserts'},
-      {name => 'ib_ibuf_delete',     label => 'Merge Deletes'},
-      {name => 'ib_ibuf_merged_rec', label => 'Merged Records'},
-      {name => 'ib_ibuf_merges',     label => 'Merges'},
-      {name => 'ib_ibuf_discard_inserts', label => 'Discard Inserts'},
-      {name => 'ib_ibuf_discard_delete',  label => 'Discard Deletes'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_adaptive_hash} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Adaptive Hash Optimiser',
-       },
-       data_source_attrs => {
-           draw => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'Innodb_adaptive_hash_hash_searches',    label => 'Hash Searches'},
-       {name => 'Innodb_adaptive_hash_non_hash_searches', label => 'Nonhash Searches'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_io} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB IO',
-           vlabel => 'IO operations per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'ib_io_read',  label => 'File reads'},
-       {name => 'ib_io_write', label => 'File writes'},
-       {name => 'ib_io_log',   label => 'Log writes'},
-       {name => 'ib_io_fsync', label => 'File syncs'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_io_pend} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB IO Pending',
-           vlabel => 'Pending operations',
-       },
-       data_source_attrs => {
-           draw => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'ib_iop_log',         label => 'AIO Log'},
-       {name => 'ib_iop_sync',        label => 'AIO Sync'},
-       {name => 'ib_iop_flush_bpool', label => 'Buf Pool Flush'},
-       {name => 'ib_iop_flush_log',   label => 'Log Flushes'},
-       {name => 'ib_iop_ibuf_aio',    label => 'Insert Buf AIO Read'},
-       {name => 'ib_iop_aioread',     label => 'Normal AIO Reads'},
-       {name => 'ib_iop_aiowrite',    label => 'Normal AIO Writes'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_log} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Log',
-           vlabel => 'Log activity per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'innodb_log_buffer_size', label  => 'Buffer Size',
-                                          type   => 'GAUGE',
-                                          draw   => 'AREA',
-                                          colour => 'fafd9e'},
-       {name => 'ib_log_flush',           label => 'KB Flushed'},
-       {name => 'ib_log_written',         label => 'KB Written'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_rows} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Row Operations',
-           vlabel => 'Operations per ${graph_period}',
-           total  => 'Total',
-       },
-       data_source_attrs => {},
-    },
-    data_sources => [
-       {name => 'Innodb_rows_deleted',  label => 'Deletes'},
-       {name => 'Innodb_rows_inserted', label => 'Inserts'},
-       {name => 'Innodb_rows_read',     label => 'Reads'},
-       {name => 'Innodb_rows_updated',  label => 'Updates'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_semaphores} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Semaphores',
-           vlabel => 'Semaphores per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'AREASTACK',
-       },
-    },
-    data_sources => [
-       {name => 'ib_spin_rounds', label => 'Spin Rounds'},
-       {name => 'ib_spin_waits',  label => 'Spin Waits'},
-       {name => 'ib_os_waits',    label => 'OS Waits'},
-  {name => 'ib_rw_shared_rounds', label => 'RW/S Rounds'},
-  {name => 'ib_rw_shared_waits',  label => 'RW/S Waits'},
-  {name => 'ib_rw_shared_os_waits',    label => 'RW/S OS Waits'},
-  {name => 'ib_rw_excl_rounds', label => 'RW/X Rounds'},
-  {name => 'ib_rw_excl_waits',  label => 'RW/X Waits'},
-  {name => 'ib_rw_excl_os_waits',    label => 'RW/X OS Waits'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_tnx} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Transactions',
-           vlabel => 'Transactions per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'ib_tnx', label => 'Transactions created'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_history_list_length} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB History List Length',
-           vlabel => 'Undo log units',
-       },
-       data_source_attrs => {
-           draw  => 'LINE1',
-      type  => 'GAUGE',
-       },
-    },
-    data_sources => [
-       {name => 'ib_tnx_hist', label => 'History List Length'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_srv_master_thread} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Master Thread',
-       },
-       data_source_attrs => {
-           type  => 'DERIVE',
-           draw  => 'AREASTACK',
-       },
-    },
-    data_sources => [
-       {name => 'ib_srv_main_flush_loops', label => 'Flush Loop'},
-       {name => 'ib_srv_main_background_loops', label => 'Background Loop'},
-       {name => 'ib_srv_main_flushs_writes', label => 'Flushes/Writes', draw  => 'LINE1'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_queries} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Engine Queries and Transactions',
-           args   => '--lower-limit 0',
-       },
-       data_source_attrs => {
-           type  => 'GAUGE',
-       },
-    },
-    data_sources => [
-       {name => 'ib_innodb_queries', label => 'Active'},
-       {name => 'ib_innodb_transactions_active', label => 'Transactions'},
-       {name => 'ib_innodb_query_queue_len', label => 'Queued'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_read_views} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Read Views',
-           args   => '--lower-limit 0',
-       },
-       data_source_attrs => {
-           type  => 'GAUGE',
-       },
-    },
-    data_sources => [
-       {name => 'ib_innodb_read_views', label => 'Views'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{innodb_descriptors} = {
-    config => {
-       global_attrs => {
-           title  => 'InnoDB Descriptors',
-           args   => '--lower-limit 0',
-       },
-       data_source_attrs => {
-           type  => 'GAUGE',
-       },
-    },
-    data_sources => [
-       {name => 'ib_innodb_descriptors', label => 'Descriptors'},
-       {name => 'ib_innodb_descriptors_max', label => 'Max', draw => 'AREA', colour => 'ffd660'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{performance} = {
-    config => {
-       global_attrs => {
-           title  => 'Performance Schema Losses',
-       },
-       data_source_attrs => {
-           draw  => 'LINE1',
-       },
-    },
-    data_sources => [
-  {name => 'Performance_schema_cond_classes_lost',     label => 'Condition classes'},
-  {name => 'Performance_schema_cond_instances_lost',   label => 'Condition instances'},
-  {name => 'Performance_schema_file_classes_lost',     label => 'File classes'},
-  {name => 'Performance_schema_file_handles_lost',     label => 'File handles'},
-  {name => 'Performance_schema_file_instances_lost',   label => 'File instances'},
-  {name => 'Performance_schema_locker_lost',           label => 'Locker'},
-  {name => 'Performance_schema_mutex_classes_lost',    label => 'Mutex classes'},
-  {name => 'Performance_schema_mutex_instances_lost',  label => 'Mutex instances'},
-  {name => 'Performance_schema_rwlock_classes_lost',   label => 'Read/Write lock classes'},
-  {name => 'Performance_schema_rwlock_instances_lost', label => 'Read/Write lock instances'},
-  {name => 'Performance_schema_table_handles_lost',    label => 'Table handles'},
-  {name => 'Performance_schema_table_instances_lost',  label => 'Table instances'},
-  {name => 'Performance_schema_thread_classes_lost',   label => 'Thread classes'},
-  {name => 'Performance_schema_thread_instances_lost', label => 'Thread instances'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{myisam_indexes} = {
-    config => {
-       global_attrs => {
-           title  => 'MyISAM Indexes',
-           vlabel => 'Requests per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-       },
-    },
-    data_sources => [
-       {name => 'Key_read_requests',  label => 'Key read requests'},
-       {name => 'Key_reads',          label => 'Key reads'},
-       {name => 'Key_write_requests', label => 'Key write requests'},
-       {name => 'Key_writes',         label => 'Key writes'},
-   ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{network_traffic} = {
-    config => {
-       global_attrs => {
-           title  => 'Network Traffic',
-           args   => '--base 1024',
-           vlabel => 'Bytes received (-) / sent (+) per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-       },
-    },
-    data_sources => [
-       {name => 'Bytes_received', label => 'Bytes transferred',
-                                  graph => 'no'},
-       {name => 'Bytes_sent',     label    => 'Bytes transferred',
-                                  negative => 'Bytes_received'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{qcache} = {
-    config => {
-       global_attrs => {
-           title  => 'Query Cache',
-           vlabel => 'Commands per ${graph_period}',
-       },
-       data_source_attrs => {
-            draw => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'Qcache_queries_in_cache', label => 'Queries in cache', type  => 'GAUGE'},
-       {name => 'Qcache_hits',             label => 'Cache hits'},
-       {name => 'Subquery_cache_hit',      label => 'Subquery Cache hits'},
-       {name => 'Subquery_cache_miss',     label => 'Subquery Cache misses'},
-       {name => 'Qcache_inserts',          label => 'Inserts'},
-       {name => 'Qcache_not_cached',       label => 'Not cached'},
-       {name => 'Qcache_lowmem_prunes',    label => 'Low-memory prunes'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{qcache_mem} = {
-    config => {
-       global_attrs => {
-           title  => 'Query Cache Memory',
-           vlabel => 'Bytes',
-           args   => '--base 1024 --lower-limit 0',
-       },
-       data_source_attrs => {
-           draw => 'AREA',
-           type => 'GAUGE',
-       },
-    },
-    data_sources => [
-       {name => 'query_cache_size',    label => 'Cache size'},
-       {name => 'Qcache_free_memory',  label => 'Free mem'},
-    ],
-};
-
-
-#---------------------------------------------------------------------
-
-$graphs{max_mem} = {
-    config => {
-       global_attrs => {
-           title  => 'Maximum memory that Mysql could use',
-           vlabel => 'Bytes',
-           args   => '--base 1024 --lower-limit 0',
-       },
-       data_source_attrs => {
-           draw => 'AREASTACK',
-           type => 'GAUGE',
-       },
-    },
-    data_sources => [
-       {name => 'mysql_connection_memory',    label => 'Connection Memory'},
-       {name => 'mysql_base_memory',  label => 'Base MYSQL Memory'},
-    ],
-};
-
-
-#---------------------------------------------------------------------
-
-$graphs{replication} = {
-    config => {
-       global_attrs => {
-           title  => 'Replication',
-           vlabel => 'Activity',
-       },
-       data_source_attrs => {
-           draw => 'LINE1',
-       },
-    },
-    data_sources => [
-       {name => 'slave_io_running',           label => 'Slave IO Running',
-                                              type  => 'GAUGE',
-                                              draw  => 'AREA'},
-       {name => 'slave_sql_running',          label => 'Slave SQL Running',
-                                              type  => 'GAUGE',
-                                              draw  => 'AREA'},
-       {name => 'Slave_retried_transactions', label => 'Retried Transactions'},
-       {name => 'Slave_open_temp_tables',     label => 'Open Temp Tables'},
-       {name => 'seconds_behind_master',      label => 'Secs Behind Master',
-                                              type  => 'GAUGE'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{select_types} = {
-    config => {
-       global_attrs => {
-           title  => 'Select types',
-           vlabel => 'Commands per ${graph_period}',
-           total  => 'Total',
-       },
-       data_source_attrs => {},
-    },
-    data_sources => [
-       {name => 'Select_full_join',       label => 'Full join'},
-       {name => 'Select_full_range_join', label => 'Full range'},
-       {name => 'Select_range',           label => 'Range'},
-       {name => 'Select_range_check',     label => 'Range check'},
-       {name => 'Select_scan',            label => 'Scan'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{slow} = {
-    config => {
-       global_attrs => {
-           title  => 'Slow Queries',
-           vlabel => 'Slow queries per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-       },
-    },
-    data_sources => [
-       {name => 'Slow_queries', label => 'Slow queries'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{sorts} = {
-    config => {
-       global_attrs => {
-           title  => 'Sorts',
-           vlabel => 'Sorts / ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-       },
-    },
-    data_sources => [
-       {name => 'Sort_rows',         label => 'Rows sorted'},
-       {name => 'Sort_range',        label => 'Range'},
-       {name => 'Sort_merge_passes', label => 'Merge passes'},
-       {name => 'Sort_scan',         label => 'Scan'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{table_locks} = {
-    config => {
-       global_attrs => {
-           title  => 'Table locks',
-           vlabel => 'locks per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-       },
-    },
-    data_sources => [
-       {name => 'Table_locks_immediate', label => 'Table locks immed'},
-       {name => 'Table_locks_waited',    label => 'Table locks waited'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{tmp_tables} = {
-    config => {
-       global_attrs => {
-           title  => 'Temporary objects',
-           vlabel => 'Objects per ${graph_period}',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-       },
-    },
-    data_sources => [
-       {name => 'Created_tmp_disk_tables', label => 'Temp disk tables'},
-       {name => 'Created_tmp_tables',      label => 'Temp tables'},
-       {name => 'Created_tmp_files',       label => 'Temp files'},
-    ],
-};
-
-
-#---------------------------------------------------------------------
-
-$graphs{rows} = {
-    config => {
-  global_attrs => {
-      title  => 'Rows',
-  },
-  data_source_attrs => {
-      draw  => 'LINE2',
-      type => 'DERIVE',
-  },
-    },
-    data_sources => [
-  {name => 'Rows_read',     label => 'Read'},
-  {name => 'Rows_sent',     label => 'Sent'},
-  {name => 'Rows_tmp_read', label => 'Temp Read'},
-    ],
-  };
-
-#---------------------------------------------------------------------
-
-$graphs{handler_read} = {
-    config => {
-  global_attrs => {
-      title  => 'Read Handler',
-  },
-  data_source_attrs => {
-      draw  => 'AREASTACK',
-      type => 'DERIVE',
-  },
-    },
-    data_sources => [
-  {name => 'Handler_read_first',       label => 'Key First'},
-  {name => 'Handler_read_key',         label => 'Key Read'},
-  {name => 'Handler_read_last',        label => 'Key Last'},
-  {name => 'Handler_read_prev',        label => 'Key Prev'},
-  {name => 'Handler_read_rnd',         label => 'Row position'},
-  {name => 'Handler_read_rnd_deleted', label => 'Row position delete'},
-  {name => 'Handler_read_rnd_next',    label => 'Row position next'},
-    ],
-  };
-
-#---------------------------------------------------------------------
-
-$graphs{handler_transaction} = {
-    config => {
-  global_attrs => {
-      title  => 'Transactions Handler',
-  },
-  data_source_attrs => {
-      draw  => 'AREASTACK',
-      type => 'DERIVE',
-  },
-    },
-    data_sources => [
-  {name => 'Handler_commit',             label => 'Commit'},
-  {name => 'Handler_rollback',           label => 'Rollback'},
-  {name => 'Handler_savepoint',          label => 'Savepoint'},
-  {name => 'Handler_savepoint_rollback', label => 'Savepoint Rollback'},
-    ],
-  };
-
-#---------------------------------------------------------------------
-
-$graphs{handler_write} = {
-    config => {
-  global_attrs => {
-      title  => 'Write/Update Handler',
-  },
-  data_source_attrs => {
-      draw => 'LINE2',
-      type => 'DERIVE',
-  },
-    },
-    data_sources => [
-  {name => 'Handler_write',  label => 'Writes'},
-  {name => 'Handler_update', label => 'Updates'},
-    ],
-  };
-
-#---------------------------------------------------------------------
-
-$graphs{handler_tmp} = {
-    config => {
-  global_attrs => {
-      title  => 'Temporary Write/Update Handler',
-  },
-  data_source_attrs => {
-      draw => 'LINE2',
-      type => 'DERIVE',
-  },
-    },
-    data_sources => [
-  {name => 'Handler_tmp_write',  label => 'Writes'},
-  {name => 'Handler_tmp_update', label => 'Updates'},
-    ],
-  };
-
-#---------------------------------------------------------------------
-
-$graphs{execution} = {
-    config => {
-  global_attrs => {
-      title  => 'Execution Events',
-  },
-  data_source_attrs => {
-      draw => 'LINE2',
-      type => 'DERIVE',
-  },
-    },
-    data_sources => [
-  {name => 'Executed_events',   label => 'Events'},
-  {name => 'Executed_triggers', label => 'Triggers'},
-    ],
-  };
-
-#---------------------------------------------------------------------
-
-$graphs{icp} = {
-    config => {
-       global_attrs => {
-           title  => 'Index Condition Pushdown',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-           type => 'DERIVE',
-       },
-    },
-    data_sources => [
-       {name => 'Handler_icp_attempts', label => 'Attempts'},
-       {name => 'Handler_icp_match',    label => 'Matches'},
-    ],
-};
-
-#---------------------------------------------------------------------
-
-$graphs{mrr} = {
-    config => {
-       global_attrs => {
-           title  => 'Multi Range Read optimizations',
-       },
-       data_source_attrs => {
-           draw  => 'LINE2',
-           type => 'DERIVE',
-       },
-    },
-    data_sources => [
-       {name => 'Handler_mrr_init', label => 'Uses'},
-       {name => 'Handler_mrr_key_refills',  label => 'Key refills'},
-       {name => 'Handler_mrr_rowid_refills',  label => 'Row refills'},
-    ],
-};
-
-#---------------------------------------------------------------------
-#  Plugin Graphs
-#  These are mysql plugins of type INFORMATION SCHEMA
-#
-#  These will be added to $graphs if available
-#---------------------------------------------------------------------
-
-my %graph_plugins = ();
-
-$graph_plugins{query_response_time} = {
-    count => {
-        config => {
-            global_attrs => {
-                title  => 'Query Response Time Count',
-                vlabel  => 'queries per ${graph_period}',
-            },
-            data_source_attrs => {
-                draw  => 'LINE2',
-                type => 'DERIVE',
-            },
-        },
-        # data_sources are populated by sub plugin_query_response_time
-        data_sources => [
-        ],
-   },
-   total => {
-        config => {
-            global_attrs => {
-                title  => 'Query Response Time Total',
-                vlabel  => 'query time (microseconds) per ${graph_period}',
-            },
-            data_source_attrs => {
-                draw  => 'LINE2',
-                type => 'DERIVE',
-            },
-        },
-        # data_sources are populated by sub plugin_query_response_time
-        data_sources => [
-        ],
-   }
-};
-
-$graph_plugins{user_statistics} = {
-    connections => {
-        config => {
-            global_attrs => {
-                title  => 'User Connections',
-                vlabel  => 'connections per ${graph_period}',
-            },
-            data_source_attrs => {
-                draw  => 'LINE2',
-                type => 'DERIVE',
-            },
-        },
-        cols => { 'total_connections' => {}, 'concurrent_connections' => {}, 'denied_connections' => {}, 'lost_connections'  => {}},
-        data_sources => [
-        ],
-   },
-   usertime => {
-        config => {
-            global_attrs => {
-                title  => 'User Time',
-                vlabel  => 'seconds',
-            },
-            data_source_attrs => {
-                draw  => 'LINE2',
-                type => 'DERIVE',
-            },
-        },
-        cols => { 'connected_time' => {}, 'busy_time' => {}, 'cpu_time' => {} },
-        data_sources => [
-        ],
-   },
-   bytes => {
-        config => {
-            global_attrs => {
-                title  => 'User Bytes',
-                vlabel  => 'bytes',
-            },
-            data_source_attrs => {
-                draw  => 'LINE2',
-                type => 'DERIVE',
-            },
-        },
-        cols => { 'bytes_received' => {}, 'bytes_sent' => {}, 'binlog_bytes_written' => {} },
-        data_sources => [
-        ],
-   },
-   rows => {
-        config => {
-            global_attrs => {
-                title  => 'User Rows',
-                vlabel  => 'rows',
-            },
-            data_source_attrs => {
-                draw  => 'LINE2',
-                type => 'DERIVE',
-            },
-        },
-        cols => { 'rows_read' => {}, 'rows_sent' => {}, 'rows_deleted' => {}, 'rows_inserted' => {}, 'rows_updated' => {} },
-        data_sources => [
-        ],
-   },
-   commands => {
-        config => {
-            global_attrs => {
-                title  => 'Command breakdown by user',
-                vlabel  => 'commands',
-            },
-            data_source_attrs => {
-                draw  => 'LINE2',
-                type => 'DERIVE',
-            },
-        },
-        cols => { 'select_commands' => {}, 'update_commands' => {}, 'other_commands' => {}, 'commit_transactions' => {}, 'rollback_transactions' => {} },
-        data_sources => [
-        ],
-   }
-
-};
-#---------------------------------------------------------------------
-#  M A I N
-#---------------------------------------------------------------------
-
-
-#
-# Global hash holding the data collected from mysql.
-#
-our $data; # Was 'my'. Changed to 'our' to facilitate testing.
-
-
-sub main {
-    my $graph = basename($0);
-    $graph =~ s/^mysql[0-9]*_//g; # allow multiple instances
-    my $command = $ARGV[0] || 'show';
-
-    my %command_map = (
-       'autoconf' => \&autoconf,
-       'config'   => \&config,
-       'show'     => \&show,
-       'suggest'  => \&suggest,
-    );
-
-    die "Unknown command: $command"
-       unless exists $command_map{$command};
-
-    die "Missing dependency Cache::Cache"
-       unless $has_cache || $command eq 'autoconf';
-
-    return $command_map{$command}->($graph);
-}
-
-
-#---------------------------------------------------------------------
-#  C O M M A N D   H A N D L E R S
-#---------------------------------------------------------------------
-
-# Each command handler should return an appropriate exit code
-
-
-# http://munin-monitoring.org/wiki/ConcisePlugins#autoconf
-sub autoconf {
-    unless ($has_cache) {
-       print "no (Missing dependency Cache::Cache)\n";
-       return 0;
-    }
-
-    eval {
-       db_connect();
-    };
-    if ($@) {
-       my $err = $@;
-       $err =~ s{\s at \s \S+ \s line .*}{}xms;
-       print "no ($err)\n";
-       return 0;
-    }
-    print "yes\n";
-    return 0;
-}
-
-
-# http://munin-monitoring.org/wiki/ConcisePlugins#suggest
-sub suggest {
-
-    # What is the best way to decide which graphs is applicable to a
-    # given system?
-    # Answer:
-    # Use lack of variables to indicate that the capability doesn't exist
-    # Use variable values to indicate some graph isn't currently used.
-    # update_data() now does this.
-
-    update_data();
-
-
-    foreach my $graph (sort keys(%graphs)) {
-        next if $graph =~ /innodb_/ && $data->{_innodb_disabled};
-        next if $graph =~ /wsrep_/ && $data->{_galera_disabled};
-        print "$graph\n";
-    }
-
-    return 0;
-}
-
-
-sub config {
-    my $graph_name = shift;
-
-    # In MySQL 5.1 (and probably erlier versions as well) status
-    # variables are unique when looking at the last 19 characters.
-    #
-    #   SELECT RIGHT(variable_name, 19), COUNT(*)
-    #     FROM information_schema.global_status
-    #    GROUP BY RIGHT(variable_name, 19)
-    #   HAVING COUNT(*) > 1;
-    #
-    #   Empty set (0.06 sec)
-    #
-    # There is one duplicate when looking at server variables
-    #
-    #   SELECT RIGHT(variable_name, 19), COUNT(*)
-    #     FROM information_schema.global_variables
-    #    GROUP BY RIGHT(variable_name, 19)
-    #   HAVING COUNT(*) > 1;
-    #
-    #   +--------------------------+----------+
-    #   | RIGHT(variable_name, 19) | COUNT(*) |
-    #   +--------------------------+----------+
-    #   | OW_PRIORITY_UPDATES      |        2 |
-    #   +--------------------------+----------+
-    #   1 row in set (0.05 sec)
-    #
-    #   show global variables like '%OW_PRIORITY_UPDATES';
-    #
-    #   +--------------------------+-------+
-    #   | Variable_name            | Value |
-    #   +--------------------------+-------+
-    #   | low_priority_updates     | OFF   |
-    #   | sql_low_priority_updates | OFF   |
-    #   +--------------------------+-------+
-    #   2 rows in set (0.00 sec)
-    #
-    # Not a problem since we don't graph these
-
-    update_data();
-
-    die 'Unknown graph ' . ($graph_name ? $graph_name : '')
-       unless $graphs{$graph_name};
-
-    my $graph = $graphs{$graph_name};
-
-    my %conf = (%{$defaults{global_attrs}}, %{$graph->{config}{global_attrs}});
-    while (my ($k, $v) = each %conf) {
-       print "graph_$k $v\n";
-    }
-    if ($graph_name =~ /wsrep_/) {
-      print "graph_category galera\n";
-    } else {
-      print "graph_category mysql\n";
-    }
-
-    my $i = 0;
-    for my $ds (@{$graph->{data_sources}}) {
-       my %ds_spec = (
-           %{$defaults{data_source_attrs}},
-           %{$graph->{config}{data_source_attrs}},
-           %$ds,
-       );
-       while (my ($k, $v) = each %ds_spec) {
-           # 'name' is only used internally in this script, not
-           # understood by munin.
-           next if ($k eq 'name');
-
-           # AREASTACK is part of munin as of version 1.3.3 (not
-           # released yet). Until then ...
-           if ($k eq 'draw' && $v eq 'AREASTACK') {
-               printf("%s.%s %s\n",
-                      clean_fieldname($ds->{name}), $k, ($i ? 'STACK' : 'AREA'));
-           }
-           else {
-               printf("%s.%s %s\n", clean_fieldname($ds->{name}), $k, $v);
-           }
-           $i++;
-       }
-       print_thresholds(clean_fieldname($ds->{name}));
-    }
-
-    return 0;
-}
-
-sub show {
-    my $graph_name = shift;
-
-    update_data();
-
-    die 'Unknown graph ' . ($graph_name ? $graph_name : '')
-       unless $graphs{$graph_name};
-
-    my $graph = $graphs{$graph_name};
-
-    die "Can't show data for '$graph_name' because InnoDB is disabled."
-       if $graph_name =~ /innodb_/ && $data->{_innodb_disabled};
-
-    die "Can't show data for '$graph_name' because not a Galera mysql version."
-       if $graph_name =~ /wsrep_/ && $data->{_galera_disabled};
-
-    for my $ds (@{$graph->{data_sources}}) {
-       printf "%s.value %s\n",
-           clean_fieldname($ds->{name}),
-           defined $data->{$ds->{name}} ? $data->{$ds->{name}} : 'U';
-    }
-
-    return 0;
-}
-
-
-
-#---------------------------------------------------------------------
-#  U T I L I T Y   S U B S
-#---------------------------------------------------------------------
-
-
-sub db_connect {
-    my $dsn = "$config{dsn};mysql_connect_timeout=5";
-
-    return DBI->connect($dsn, $config{user}, $config{password}, {
-       RaiseError       => 1,
-       PrintError       => 0,
-       FetchHashKeyName => 'NAME_lc',
-    });
-}
-
-
-sub update_data {
-    $data = $shared_memory_cache->get('data');
-    my $graphs_stored = $shared_memory_cache->get('graphs');
-    %graphs = %{thaw($graphs_stored)} if $graphs_stored;
-    return if $data;
-
-    $data = {};
-
-    my $dbh = db_connect();
-
-    update_variables($dbh);
-    update_plugins($dbh);
-    update_innodb($dbh);
-    update_master($dbh);
-    delete $graphs{replication} if update_slave($dbh)==1;
-
-    delete $graphs{bin_relay_log} if not defined $data->{relay_log_space}
-        && not defined $data->{ma_binlog_size};
-
-    delete $graphs{execution} if not defined $data->{Executed_events}
-        && not defined $data->{Executed_triggers};
-
-    delete $graphs{icp} if not defined $data->{Handler_icp_attempts}
-        && not defined $data->{Handler_icp_matches};
-
-    delete $graphs{innodb_adaptive_hash}
-        if not defined $data->{Innodb_adaptive_hash_hash_searches}
-        && not defined $data->{Innodb_adaptive_hash_non_hash_searches};
-
-    delete $graphs{innodb_bpool_internal_breakdown}
-        if not defined $data->{ib_bpool_internal_adaptive_hash_size_const};
-
-    delete $graphs{innodb_descriptors}
-        if not defined $data->{ib_innodb_descriptors};
-
-    delete $graphs{mrr} if not defined $data->{Handler_mrr_init};
-
-    delete $graphs{rows} if not defined $data->{Rows_sent};
-
-    delete $graphs{handler_temp} if not defined $data->{Handler_tmp_write};
-
-    $shared_memory_cache->set('data', $data);
-    $shared_memory_cache->set('graphs', nfreeze(\%graphs));
-}
-
-
-sub update_plugins {
-    my ($dbh) = @_;
-
-    my %plugin_map = (
-       'query_response_time'         => \&plugin_query_response_time,
-    );
-
-    sub add_graphs {
-      my ($f, $sec, $dbh, %g) = @_;
-      if ($f->($dbh) == 0) {
-        while (my ($k, $v) = each %g) {
-          $graphs{$sec . '_' . $k} = $v;
-        }
-      }
-    }
-
-    my $sth = $dbh->prepare("SHOW PLUGINS");
-    $sth->execute();
-    while (my $row = $sth->fetchrow_hashref()) {
-        next if $row->{'type'} ne 'INFORMATION SCHEMA';
-        my $sec = lc $row->{'name'};
-        next if not exists $plugin_map{$sec};
-        add_graphs($plugin_map{$sec}, $sec, $dbh, %{$graph_plugins{$sec}});
-    }
-    $sth->finish();
-
-    my %is_map = (
-       'user_statistics'         => \&is_user_statistics,
-    );
-
-    $sth = $dbh->prepare("SHOW TABLES IN INFORMATION_SCHEMA");
-    $sth->execute();
-    while (my $row = $sth->fetchrow_hashref()) {
-        my $sec = lc $row->{'tables_in_information_schema'};
-        next if not exists $is_map{$sec};
-        add_graphs($is_map{$sec}, $sec, $dbh, %{$graph_plugins{$sec}});
-    }
-    $sth->finish();
-}
-
-sub update_variables {
-    my ($dbh) = @_;
-    my @queries = (
-       'SHOW GLOBAL STATUS',
-       'SHOW GLOBAL VARIABLES',
-    );
-
-    my %variable_name_map = (
-       table_cache => 'table_open_cache', # table_open_cache was
-                                          # previously known as
-                                          # table_cache in MySQL
-                                          # 5.1.2 and earlier.
-    );
-    my %wsrep_cluster_status_map = (
-        'Primary' =>  0,
-        'non-Primary' => 1,
-    );
-
-    for my $query (@queries) {
-       $data->{$query} = {};
-
-       my $sth = $dbh->prepare($query);
-       $sth->execute();
-       while (my $row = $sth->fetch) {
-           my $var = $variable_name_map{$row->[0]} || $row->[0];
-           $data->{$var} = $row->[1];
-       }
-       $sth->finish();
-    }
-
-    $data->{'mysql_base_memory'} = $data->{'key_buffer_size'} 
-                                         + $data->{'query_cache_size'}
-                                         + $data->{'innodb_buffer_pool_size'}
-                                         + ( $data->{'innodb_additional_mem_pool_size'} || 0 )
-                                         + $data->{'innodb_log_buffer_size'}
-                                         + ( $data->{'tokudb_cache_size'} || 0 );
-
-    my $tmp_table_size = $data->{'tmp_table_size'};
-    my $max_heap_table_size = $data->{'max_heap_table_size'};
-    $data->{'mysql_connection_memory'} = $data->{'read_buffer_size'}
-                                   + $data->{'read_rnd_buffer_size'}
-                                   + $data->{'sort_buffer_size'}
-                                   + $data->{'join_buffer_size'}
-                                   + $data->{'binlog_cache_size'}
-                                   + $data->{'thread_stack'}
-                                   + ( $tmp_table_size >= $max_heap_table_size ? $tmp_table_size : $max_heap_table_size )
-                                   + ( $data->{'tokudb_read_buf_size'} || 0 );
-
-   # wsrep_thread_count was separated from max_connections for mariadb-5.5.38 https://mariadb.atlassian.net/browse/MDEV-6206
-   $data->{'mysql_connection_memory'} *= $data->{'max_connections'} + ( $data->{'wsrep_thread_count'} || 0 );
-
-    if ($data->{wsrep_cluster_status}) {
-      my $var = $wsrep_cluster_status_map{$data->{wsrep_cluster_status}};
-      $data->{wsrep_cluster_status} = $var;
-    }
-    $data->{_galera_disabled} = 1 unless ($data->{wsrep_provider_name});
-}
-
-
-sub update_innodb {
-    my ($dbh) = @_;
-
-    my $sth = $dbh->prepare('SHOW /*!50000 ENGINE*/ INNODB STATUS');
-    eval {
-       $sth->execute();
-    };
-    if ($@) {
-       if ($@ =~ /Unknown (storage|table) engine 'INNODB'|Cannot call SHOW INNODB STATUS because skip-innodb is defined/i) {
-           $data->{_innodb_disabled} = 1;
-           return;
-       }
-       die $@;
-    }
-    my $row = $sth->fetchrow_hashref();
-    my $status = $row->{'status'};
-    $sth->finish();
-
-    parse_innodb_status($status);
-}
-
-
-sub update_master {
-    my ($dbh) = @_;
-
-    my $sth = $dbh->prepare('SHOW MASTER LOGS');
-    eval {
-       $sth->execute();
-    };
-    if ($@) {
-       # SHOW MASTER LOGS failed because binlog is not enabled
-       return if $@ =~ /You are not using binary logging/;
-       die $@;
-    }
-
-    while (my $row = $sth->fetch) {
-       $data->{ma_binlog_size} += $row->[1];
-    }
-
-    $sth->finish();
-}
-
-
-sub update_slave {
-    my ($dbh) = @_;
-
-    my $sth = $dbh->prepare('SHOW SLAVE STATUS');
-    $sth->execute();
-    my $row = $sth->fetchrow_hashref();
-    return 1 unless $row;
-    while (my ($k, $v) = each %$row) {
-       $data->{$k} = $v;
-    }
-    $sth->finish();
-
-    # We choose master_host here as a stopped slave
-    # may not indicate that we have reset all slave capability
-    # however the minimium requirement is a master_host
-    return 1 if not defined $data->{master_host};
-
-    # undef when slave is stopped, or when MySQL fails to calculate
-    # the lag (which happens depresingly often). (mk-heartbeat fixes
-    # this problem.)
-    $data->{seconds_behind_master} ||= 0;
-
-    # Track these two fields so we can trigger warnings if the slave stops
-    # running
-    $data->{slave_sql_running} = ($data->{slave_sql_running} eq 'Yes')
-           ? 0 : 1;
-    $data->{slave_io_running} = ($data->{slave_io_running} eq 'Yes')
-           ? 0 : 1;
-    return 0;
-}
-
-
-#---------------------------------------------------------------------
-#  Information SCHEMA tables represent data to be processed
-#---------------------------------------------------------------------
-
-
-sub plugin_query_response_time {
-    my ($dbh) = @_;
-
-    return 1 if not defined $data->{query_response_time_stats};
-    return 1 if $data->{query_response_time_stats} eq 'OFF';
-
-    my $sth = $dbh->prepare("SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME");
-    $sth->execute();
-    while (my $row = $sth->fetchrow_hashref()) {
-        my $time = $row->{'time'};
-        $data->{'query_response_time_count_' . $time} = $row->{'count'};
-        push @{$graph_plugins{query_response_time}->{count}->{data_sources}}, {name => 'query_response_time_count_' . $time, label => $time };
-        next if $row->{'total'} eq 'TOO LONG';
-        $data->{'query_response_time_total_' . $time} = $row->{'total'} * 1e6;
-        push @{$graph_plugins{query_response_time}->{total}->{data_sources}}, {name => 'query_response_time_total_' . $time, label => $time };
-    }
-    $sth->finish();
-
-    return 0;
-}
-
-sub is_user_statistics {
-    my ($dbh) = @_;
-
-    return 1 if not defined $data->{userstat};
-    return 1 if $data->{userstat} eq 'OFF';
-
-    my $sth = $dbh->prepare("SELECT * FROM INFORMATION_SCHEMA.USER_STATISTICS");
-    $sth->execute();
-    while (my $row = $sth->fetchrow_hashref()) {
-        my $user = $row->{'user'};
-        my $var;
-        while (my ($g, $v) = each %{$graph_plugins{user_statistics}}) {
-          while (my ($userstat,$conf) = each %{$v->{cols}}) {
-            $var = 'user_stats_' . $user . '_' . $userstat;
-            $data->{$var} = int $row->{$userstat};
-            my $ds = { %$conf };
-            $ds->{name} = $var;
-            $ds->{label} = $user . ' ' . $userstat;
-            push @{$graph_plugins{user_statistics}->{$g}->{data_sources}}, $ds;
-          }
-        }
-    }
-    $sth->finish();
-    return 0;
-}
-
-#
-# In 'SHOW ENGINE INNODB STATUS' 64 bit integers are not formated as
-# plain integers. They are either:
-#
-#   - split in two and needs to be shifted together,
-#   - or hexadecimal
-#
-sub innodb_bigint {
-    my ($x, $y) = @_;
-
-    return defined $y
-       ? Math::BigInt->new($x)->blsft(32) + $y
-       : Math::BigInt->new("0x$x");
-}
-
-#---------------------------------------------------------------------
-#  P A R S E   'SHOW ENGINE INNODB STATUS'   O U T P U T
-#---------------------------------------------------------------------
-
-
-# A nice walk through
-# http://www.mysqlperformanceblog.com/2006/07/17/show-innodb-status-walk-through/
-
-# The parsing is split in one subrutine per section. Each subroutine
-# should parse a block with the following structure
-#
-# block body ...
-# more lines ....
-# ----------
-
-sub parse_innodb_status {
-    local $_ = shift;
-
-    # Add a dummy section to the end in case the innodb status output
-    # has been truncated (Happens for status > 64K characters)
-    $_ .= "\n----------\nDUMMY\n----------\n";
-
-    my %section_map = (
-
-       'BUFFER POOL AND MEMORY'      => \&parse_buffer_pool_and_memory,
-       'INDIVIDUAL BUFFER POOL INFO' => \&parse_individual_buffer_pool,
-       'FILE I/O'                    => \&parse_file_io,
-       'INSERT BUFFER AND ADAPTIVE HASH INDEX'
-           => \&parse_insert_buffer_and_adaptive_hash_index,
-       'LATEST DETECTED DEADLOCK'    => \&skip,
-       'LATEST FOREIGN KEY ERROR'    => \&skip,
-       'LOG'                         => \&parse_log,
-       'ROW OPERATIONS'              => \&parse_row_operations,
-       'SEMAPHORES'                  => \&parse_semaphores,
-       'TRANSACTIONS'                => \&parse_transactions,
-       'BACKGROUND THREAD'           => \&parse_background_thread,
-    );
-
-    skip_heading();
-    parse_header_seconds();
-    for (;;) {
-       m/\G(.*)\n/gc;
-       my $sec = $1;
-
-       last if $sec eq 'END OF INNODB MONITOR OUTPUT';
-       if ($sec eq 'DUMMY') {
-           handle_incomplete_innodb_status();
-           last;
-       }
-
-       if (exists $section_map{$sec}) {
-      $section_map{$sec}->();
-       } else {
-      #warn "Unknown section: $1";
-      skip();
-       }
-    }
-}
-
-
-# This regular expression handles the different formating of 64-bit
-# integers in different versions of the innodb engine. Either two
-# decimal 32-bit integers separated by a space, or a single
-# hexadecimal 64-bit integer.
-my $innodb_bigint_rx = qr{([[a-fA-F\d]+)(?: (\d+))?};
-
-
-sub match_new_section {
-   return m/\G
-            -+\n                 # ---------------------------
-            (?= [A-Z\/ ]+\n      # SECTION NAME
-                [=-]+\n)/gcx;    # --------------------------- ('=' on end of output)
-}
-
-
-sub skip_line    { return m/\G.*\n/gc; }
-
-
-sub skip_heading {
-    # Heading is 3 lines
-    for my $foo (1...3) {
-       skip_line or die('Parse error');
-    }
-}
-
-
-sub parse_section {
-    my ($parser) = @_;
-
-    #warn substr($_, pos(), 10);
-    for (;;) {
-       return if match_new_section;
-       next if $parser->();
-       skip_line();
-    }
-}
-
-
-sub skip { parse_section(sub {}); }
-
-
-sub parse_header_seconds {
-    parse_section(
-       sub {
-           m/\GPer second averages calculated from the last (\d+) seconds\n/gc && do {
-               $data->{innodb_engine_status_seconds}  = $1;
-               return 1;
-           };
-       }
-    );
-}
-
-
-sub parse_background_thread {
-    parse_section(
-       sub {
-           m/\Gsrv_master_thread loops: \d+ 1_second, \d+ sleeps, \d+ 10_second, (\d+) background, (\d+) flush\n/gc && do {
-               $data->{ib_srv_main_flush_loops} = $1;
-               $data->{ib_srv_main_background_loops} = $2;
-               return 1;
-           };
-           m/\Gsrv_master_thread log flush and writes: (\d+)\n/gc && do {
-               $data->{ib_srv_main_flushs_writes}  = $1;
-               return 1;
-           };
-       }
-    );
-}
-
-sub parse_row_operations {
-    parse_section(
-        sub {
-            m/\G(\d+) queries inside InnoDB, (\d+) queries in queue\n/gc && do {
-                $data->{ib_innodb_queries}  = $1;
-                $data->{ib_innodb_query_queue_len} = $2;
-                return 1;
-            };
-            m/\G(\d+) read views open inside InnoDB\n/gc && do {
-                $data->{ib_innodb_read_views}  = $1;
-                return 1;
-            };
-            m/\G(\d+) transactions active inside InnoDB\n/gc && do {
-                $data->{ib_innodb_transactions_active}  = $1;
-                return 1;
-            };
-            m/\G(\d+) out of (\d+) descriptors used\n/gc && do {
-                $data->{ib_innodb_descriptors}  = $1;
-                $data->{ib_innodb_descriptors_max} = $2;
-                return 1;
-            };
-            # no need for this - its exposed as status variables
-            # m/\GNumber of rows inserted (\d+), updated (\d+), deleted (\d+), read (\d+)\n/gc && do {
-            #     $data->{ib_innodb_rows_inserted} = $1;
-            #     $data->{ib_innodb_rows_updated}  = $2;
-            #     $data->{ib_innodb_rows_deleted}  = $3;
-            #     $data->{ib_innodb_rows_read}     = $4;
-            #     return 1;
-            # };
-        }
-   );
-}
-
-sub parse_semaphores {
-    parse_section(
-       sub {
-           m/\GMutex spin waits (\d+), rounds (\d+), OS waits (\d+)\n/gc && do {
-               $data->{ib_spin_waits}  = $1;
-               $data->{ib_spin_rounds} = $2;
-               $data->{ib_os_waits}    = $3;
-               return 1;
-           };
-           m/\GRW-shared spins (\d+), rounds (\d+), OS waits (\d+)\n/gc && do {
-               $data->{ib_rw_shared_waits}  = $1;
-               $data->{ib_rw_shared_rounds} = $2;
-               $data->{ib_rw_shared_os_waits}    = $3;
-               return 1;
-           };
-           m/\GRW-excl spins (\d+), rounds (\d+), OS waits (\d+)\n/gc && do {
-               $data->{ib_rw_excl_waits}  = $1;
-               $data->{ib_rw_excl_rounds} = $2;
-               $data->{ib_rw_excl_os_waits}    = $3;
-               return 1;
-           };
-       }
-    );
-}
-
-
-sub parse_transactions {
-    parse_section(
-       sub {
-           m/\GTrx id counter $innodb_bigint_rx\n/gc && do {
-               $data->{ib_tnx} = innodb_bigint($1, $2);
-               return 1;
-           };
-           m/\GPurge done for trx's n:o < $innodb_bigint_rx undo n:o < $innodb_bigint_rx\n/gc && do {
-               if (defined $3) {
-                   # old format
-                   $data->{ib_tnx_prg} = innodb_bigint($1, $2);
-                   # FIX add to data? innodb_bigint($3, $4);
-               }
-               else {
-                   # new format
-                   $data->{ib_tnx_prg} = innodb_bigint($1);
-                   # FIX add to data? innodb_bigint($2);
-               }
-               return 1;
-           };
-           m/\GHistory list length (\d+)\n/gc && do {
-               $data->{ib_tnx_hist} = $1;
-               return 1;
-           };
-       }
-    );
-
-}
-
-
-sub parse_file_io {
-    parse_section(
-       sub {
-           m/\GPending normal aio reads: (\d+)(?: \[(?:\d+, )*\d+\] )?, aio writes: (\d+)(?: \[(?:\d+, )*\d+\] )?,\n\s*ibuf aio reads: (\d+), log i\/o's: (\d+), sync i\/o's: (\d+)\n/gc && do {
-               $data->{ib_iop_aioread}  = $1;
-               $data->{ib_iop_aiowrite} = $2;
-               $data->{ib_iop_ibuf_aio} = $3;
-               $data->{ib_iop_log}      = $4;
-               $data->{ib_iop_sync}     = $5;
-               return 1;
-           };
-           m/\GPending flushes \(fsync\) log: (\d+); buffer pool: (\d+)\n/gc && do {
-               $data->{ib_iop_flush_log}   = $1;
-               $data->{ib_iop_flush_bpool} = $2;
-               return 1;
-           };
-           m/\G(\d+) OS file reads, (\d+) OS file writes, (\d+) OS fsyncs\n/gc && do {
-               $data->{ib_io_read}  = $1;
-               $data->{ib_io_write} = $2;
-               $data->{ib_io_fsync} = $3;
-               return 1;
-           };
-       }
-    );
-}
-
-
-sub parse_insert_buffer_and_adaptive_hash_index {
-    parse_section(
-       sub {
-      # MySQL < 5.5
-      m/\G(\d+) inserts, (\d+) merged recs, (\d+) merges\n/gc && do {
-        $data->{ib_ibuf_inserts}    = $1;
-        $data->{ib_ibuf_merged_rec} = $2;
-        $data->{ib_ibuf_merges}     = $3;
-        return 1;
-      };
-      # MySQL >= 5.5
-      m/\Gmerged operations:\n insert (\d+), delete mark (\d+), delete (\d+)\ndiscarded operations:\n insert (\d+), delete mark (\d+), delete (\d+)\n/gc && do {
-        $data->{ib_ibuf_inserts} = $1;
-        $data->{ib_ibuf_delete_mark} = $2;
-        $data->{ib_ibuf_delete} = $3;
-        $data->{ib_ibuf_discard_inserts} = $4;
-        $data->{ib_ibuf_discard_delete_mark} = $5;
-        $data->{ib_ibuf_discard_delete} = $6;
-        $data->{ib_ibuf_merged_rec} = $data->{ib_ibuf_inserts} +  $data->{ib_ibuf_discard_inserts};
-        return 1;
-      };
-
-      m/\GIbuf: size (\d+), free list len (\d+), seg size (\d+),(?: (\d+) merges)?\n/gc && do {
-    $data->{ib_ibuf_size}     = $1;
-    $data->{ib_ibuf_free_len} = $2;
-    $data->{ib_ibuf_seg_size} = $3;
-    $data->{ib_ibuf_merges}   = $4 if defined $4; # MySQL >= 5.5
-               return 1;
-           };
-       }
-    );
-}
-
-
-sub parse_log {
-    parse_section(
-       sub {
-           m/\GLog sequence number $innodb_bigint_rx\n/gc && do {
-               $data->{ib_log_written} = innodb_bigint($1, $2);
-               return 1;
-           };
-           m/\GLog flushed up to\s+$innodb_bigint_rx\n/gc && do {
-               $data->{ib_log_flush} = innodb_bigint($1, $2);
-               return 1;
-           };
-           m/\G(\d+) log i\/o's done.*\n/gc && do {
-               $data->{ib_io_log} = $1;
-               return 1;
-           };
-       }
-    );
-}
-
-
-sub parse_buffer_pool_and_memory {
-    parse_section(
-       sub {
-           m/\GBuffer pool size\s+(\d+)\n/gc && do {
-               $data->{ib_bpool_size} = $1;
-               return 1;
-           };
-      m/\GBuffer pool size, bytes\s+(\d+)\n/gc && do {
-    $data->{ib_bpool_size_bytes} = $1;
-               return 1;
-      };
-           m/\GFree buffers\s+(\d+)\n/gc && do {
-               $data->{ib_bpool_free} = $1;
-               return 1;
-           };
-           m/\GDatabase pages\s+(\d+)\n/gc && do {
-               $data->{ib_bpool_dbpages} = $1;
-               return 1;
-           };
-           m/\GModified db pages\s+(\d+)\n/gc && do {
-               $data->{ib_bpool_modpages} = $1;
-               return 1;
-           };
-           m/\GOld database pages\s+(\d+)\n/gc && do {
-               $data->{ib_bpool_oldpages} = $1;
-               return 1;
-           };
-      m/\GPages made young (\d+), not young (\d+)\n/gc && do {
-    $data->{ib_bpool_made_young}     = $1;
-    $data->{ib_bpool_made_not_young} = $2;
-               return 1;
-    };
-           m/\GPages read (\d+), created (\d+), written (\d+)\n/gc && do {
-               $data->{ib_bpool_read}    = $1;
-               $data->{ib_bpool_created} = $2;
-               $data->{ib_bpool_written} = $3;
-               return 1;
-           };
-      # mariadb-5.5
-      m/\GInternal hash tables \(constant factor \+ variable factor\)\n\s*Adaptive hash index\s*(\d+)\s*\((\d+) \+ (\d+)\) *\n\s+Page hash +(\d+) +\(buffer pool \d+ only\) *\n\s+Dictionary cache\s*(\d+)\s+\((\d+) \+ (\d+)\) *\n\s+File system\s+(\d+)\s+\((\d+) \+ (\d+)\) *\n\s+Lock system\s+(\d+)\s+\((\d+) \+ (\d+)\) *\n\s+Recovery system\s*(\d+)\s+\((\d+) \+ (\d+)\) *\n/gc  
-          && do {
-          $data->{ib_bpool_internal_adaptive_hash_size_total}  = $1;
-          $data->{ib_bpool_internal_adaptive_hash_size_const}  = $2;
-          $data->{ib_bpool_internal_adaptive_hash_size_var}    = $3;
-          $data->{ib_bpool_internal_page_hash_size_total}  = $4;
-          $data->{ib_bpool_internal_dictionary_cache_size_total}  = $5;
-          $data->{ib_bpool_internal_dictionary_cache_size_const}  = $6;
-          $data->{ib_bpool_internal_dictionary_cache_size_var}    = $7;
-          $data->{ib_bpool_internal_file_system_size_total}  = $8;
-          $data->{ib_bpool_internal_file_system_size_const}  = $9;
-          $data->{ib_bpool_internal_file_system_size_var}    = $10;
-          $data->{ib_bpool_internal_lock_system_size_total}  = $11;
-          $data->{ib_bpool_internal_lock_system_size_const}  = $12;
-          $data->{ib_bpool_internal_lock_system_size_var}    = $13;
-          $data->{ib_bpool_internal_recovery_system_size_total}  = $14;
-          $data->{ib_bpool_internal_recovery_system_size_const}  = $15;
-          $data->{ib_bpool_internal_recovery_system_size_var}    = $16;
-          return 1;
-      };
-
-       }
-    );
-}
-
-sub parse_individual_buffer_pool {
-    parse_section(
-  sub {
-    m/\G---BUFFER POOL (\d+)\n/gc && do {
-      my $pool = $1;
-      $data->{ib_bpool_individual_pool_count} = $pool + 1;
-      m/\GBuffer pool size\s+(\d+)\n/gc && do {
-        $data->{"ib_bpool_individual_pool_${pool}_size"} = $1;
-      };
-      m/\GBuffer pool size, bytes\s+(\d+)\n/gc && do {
-        $data->{"ib_bpool_individual_pool_${pool}_size_bytes"} = $1;
-      };
-      m/\GFree buffers\s+(\d+)\nDatabase pages\s+(\d+)\nOld database pages\s+(\d+)\nModified db pages\s+(\d+)\nPending reads\s+(\d+)\nPending writes: LRU\s+(\d+), flush list\s+(\d+), single page\s+(\d+)\n/gc && do {
-        $data->{"ib_bpool_individual_pool_${pool}_free"} = $1;
-        $data->{"ib_bpool_individual_pool_${pool}_dbpages"} = $2;
-        $data->{"ib_bpool_individual_pool_${pool}_oldpages"} = $3;
-        $data->{"ib_bpool_individual_pool_${pool}_modpages"} = $4;
-        $data->{"ib_bpool_individual_pool_${pool}_pending_reads"} = $5;
-        $data->{"ib_bpool_individual_pool_${pool}_pending_writes_lru"} = $6;
-        $data->{"ib_bpool_individual_pool_${pool}_pending_writes_flush"} = $7;
-        $data->{"ib_bpool_individual_pool_${pool}_pending_writes_single"} = $8;
-      };
-      skip_line();
-      m/\GPages read (\d+), created (\d+), written (\d+)\n/gc && do {
-        $data->{"ib_bpool_individual_pool_${pool}_read"}    = $1;
-        $data->{"ib_bpool_individual_pool_${pool}_created"} = $2;
-        $data->{"ib_bpool_individual_pool_${pool}_written"} = $3;
-      };
-      return 1;
-    };
-        }
-  );
-}
-
-sub handle_incomplete_innodb_status {
-
-    warn "Output from SHOW ENGINE INNODB STATUS was truncated. "
-       . "This happens if the output of STATUS exceeds 64KB. "
-       . "Several of the InnoDB graphs might be affected by this.";
-
-    # FIX Is it possible to find some of the missing values from SHOW
-    # STATUS?
-}
-
-
-exit main() unless caller;
-
-
-1;
diff --git a/cookbooks/munin/files/default/plugins/passenger_memory b/cookbooks/munin/files/default/plugins/passenger_memory
deleted file mode 100755 (executable)
index dd0f663..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env ruby
-# put in /etc/munin/plugins and restart munin-node
-# by Dan Manges, http://www.dcmanges.com/blog/rails-application-visualization-with-munin
-# NOTE: you might need to add munin to allow passwordless sudo for passenger-memory-stats
-
-require "English"
-
-def output_config
-  puts <<~CONFIG
-    graph_args --base 1024 -l 0 --vertical-label bytes --upper-limit 4056231936
-    graph_category passenger
-    graph_title Passenger memory
-
-    memory.label memory
-  CONFIG
-  exit 0
-end
-
-def output_values
-  status = `/usr/sbin/passenger-memory-stats | tail -1`
-  unless $CHILD_STATUS.success?
-    warn "failed executing passenger-memory-stats"
-    exit 1
-  end
-  status =~ /(\d+\.\d+)/
-  puts "memory.value #{(Regexp.last_match[1].to_f * 1024 * 1024).round}"
-end
-
-if ARGV[0] == "config"
-  output_config
-else
-  output_values
-end
diff --git a/cookbooks/munin/files/default/plugins/passenger_processes b/cookbooks/munin/files/default/plugins/passenger_processes
deleted file mode 100755 (executable)
index 863ff86..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env ruby
-
-require "English"
-require "rexml/document"
-
-def passenger_status
-  @passenger_status ||= REXML::Document.new(`/usr/sbin/passenger-status --show=xml`)
-end
-
-def output_config
-  puts <<~CONFIG
-    graph_args --lower-limit 0
-    graph_category passenger
-    graph_title Passenger processes
-    graph_order active inactive
-    graph_vlabel processes
-    graph_total total
-
-    active.label busy servers
-    active.draw AREA
-    inactive.label idle servers
-    inactive.draw STACK
-  CONFIG
-  exit 0
-end
-
-def output_values
-  active = 0
-  inactive = 0
-
-  passenger_status.get_elements("//process").each do |process|
-    if process.text("sessions").to_i.positive?
-      active += 1
-    else
-      inactive += 1
-    end
-  end
-
-  puts "active.value #{active}"
-  puts "inactive.value #{inactive}"
-end
-
-if ARGV[0] == "config"
-  output_config
-else
-  output_values
-end
diff --git a/cookbooks/munin/files/default/plugins/passenger_queues b/cookbooks/munin/files/default/plugins/passenger_queues
deleted file mode 100755 (executable)
index a546766..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env ruby
-
-require "English"
-require "rexml/document"
-
-def passenger_status
-  @passenger_status ||= REXML::Document.new(`/usr/sbin/passenger-status --show=xml`)
-end
-
-def output_config
-  puts <<~CONFIG
-    graph_args --lower-limit 0
-    graph_category passenger
-    graph_title Passenger queues
-    graph_vlabel count
-
-    global.label global
-    global.draw AREA
-  CONFIG
-
-  groups = passenger_status.get_elements("//supergroup").map do |supergroup|
-    supergroup.text("name")
-  end
-
-  groups.sort.each do |name|
-    puts "#{name}.label #{name}"
-    puts "#{name}.draw STACK"
-  end
-end
-
-def output_values
-  global = passenger_status.text("/item/get_wait_list").to_i
-
-  puts "global.value #{global}"
-
-  passenger_status.get_elements("//supergroup").each do |supergroup|
-    name = supergroup.text("name")
-    queue = supergroup.text("get_wait_list").to_i
-
-    puts "#{name}.value #{queue}"
-  end
-end
-
-if ARGV[0] == "config"
-  output_config
-else
-  output_values
-end
diff --git a/cookbooks/munin/files/default/plugins/passenger_requests b/cookbooks/munin/files/default/plugins/passenger_requests
deleted file mode 100755 (executable)
index 67dc343..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env ruby
-
-require "English"
-require "rexml/document"
-
-def passenger_status
-  @passenger_status ||= REXML::Document.new(`/usr/sbin/passenger-status --show=xml`)
-end
-
-def output_config
-  puts <<~CONFIG
-    graph_args --base 1000 --lower-limit 0
-    graph_category passenger
-    graph_title Passenger requests
-    graph_vlabel requests / ${graph_period}
-
-    total.label total
-    total.type DERIVE
-    total.max 1000000
-    total.min 0
-  CONFIG
-
-  groups = passenger_status.get_elements("//supergroup").map do |supergroup|
-    supergroup.text("name")
-  end
-
-  groups.sort.each do |name|
-    puts "#{name}.label #{name}"
-    puts "#{name}.type DERIVE"
-    puts "#{name}.max 1000000"
-    puts "#{name}.min 0"
-  end
-end
-
-def output_values
-  total_requests = 0
-
-  passenger_status.get_elements("//supergroup").map do |supergroup|
-    name = supergroup.text("name")
-    requests = 0
-
-    supergroup.get_elements("group/processes/process").each do |process|
-      requests += process.text("processed").to_i
-    end
-
-    total_requests += requests
-
-    puts "#{name}.value #{requests}"
-  end
-
-  puts "total.value #{total_requests}"
-end
-
-if ARGV[0] == "config"
-  output_config
-else
-  output_values
-end
diff --git a/cookbooks/munin/files/default/plugins/planet_age b/cookbooks/munin/files/default/plugins/planet_age
deleted file mode 100755 (executable)
index 220c7c5..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/ruby
-
-files = [
-  {
-    :label => "planet",
-    :name => "/store/planet/planet/planet-latest.osm.bz2",
-    :title => "Planet Dump",
-    :frequency => 7 * 24 * 60 * 60,
-    :warning => 1.05,
-    :critical => 1.1
-  },
-  {
-    :label => "day",
-    :name => "/store/planet/replication/day/state.txt",
-    :title => "Daily Replication",
-    :frequency => 24 * 60 * 60,
-    :warning => 1.05,
-    :critical => 1.1
-  },
-  {
-    :label => "hour",
-    :name => "/store/planet/replication/hour/state.txt",
-    :title => "Hourly Replication",
-    :frequency => 60 * 60,
-    :warning => 1.05,
-    :critical => 1.1
-  },
-  {
-    :label => "minute",
-    :name => "/store/planet/replication/minute/state.txt",
-    :title => "Minutely Replication",
-    :frequency => 60,
-    :warning => 5,
-    :critical => 10
-  }
-]
-
-if ARGV[0] == "config"
-  puts "graph_title Planet Age"
-  puts "graph_args --base 1000 --lower-limit 0"
-  puts "graph_scale no"
-  puts "graph_vlabel fraction of expected max age"
-  puts "graph_category planet"
-
-  files.each do |file|
-    puts "#{file[:label]}.label #{file[:title]}"
-    puts "#{file[:label]}.type GAUGE"
-    puts "#{file[:label]}.warning 0:#{file[:warning]}"
-    puts "#{file[:label]}.critical 0:#{file[:critical]}"
-  end
-else
-
-  files.each do |file|
-    value = (Time.now - File.mtime(file[:name])) / file[:frequency]
-
-    puts "#{file[:label]}.value #{value}"
-  end
-end
diff --git a/cookbooks/munin/files/default/plugins/postgres_replication b/cookbooks/munin/files/default/plugins/postgres_replication
deleted file mode 100755 (executable)
index 56ee163..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-use Munin::Plugin::Pgsql;
-
-my $pg = Munin::Plugin::Pgsql->new(
-    title     => 'PostgreSQL replication delay',
-    info      => 'Replication delay',
-    vlabel    => 'Seconds',
-    basequery => "SELECT (extract(epoch FROM now()) - extract(epoch FROM pg_last_xact_replay_timestamp()))::int AS delay",
-    pivotquery => 1,
-    configquery => "VALUES ('delay','Replication delay')",
-    extraconfig => "delay.warning 300\ndelay.critical 3600",
-    graphmin  => 0
-);
-
-$pg->Process();
diff --git a/cookbooks/munin/files/default/plugins/replication_delay b/cookbooks/munin/files/default/plugins/replication_delay
deleted file mode 100755 (executable)
index 27dd108..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-#
-# Plugin to monitor the age of the imported data in the rendering db
-#
-# Parameters:
-#
-#       config   (required)
-#       autoconf (optional - used by munin-config)
-#
-
-if [ "$1" = "config" ]; then
-
-        echo 'graph_title Data import lag'
-        echo 'graph_args --base 1000 -l 0'
-        echo 'graph_vlabel minutes'
-        echo 'graph_category renderd'
-        echo 'age.label DB import age'
-        echo 'age.type GAUGE'
-        echo 'age.cdef age,60,/'
-        echo 'age.warning :600'
-        echo 'age.critical :3600'
-        exit 0
-fi
-
-tstamp=$(osmium fileinfo --extended --get=data.timestamp.last /var/lib/replicate/changes-latest.osc.gz)
-tstampsec=$(date --date=${tstamp} +%s)
-nowsec=$(date +%s)
-
-echo "age.value " `expr $nowsec - $tstampsec`
diff --git a/cookbooks/munin/files/default/plugins/rrdcached b/cookbooks/munin/files/default/plugins/rrdcached
deleted file mode 100644 (file)
index ff18a9a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/perl
-# -*- cperl -*-
-
-use strict;
-use warnings;
-
-use IO::Socket::UNIX;
-
-$| = 1;
-
-my $arg = shift;
-if ($arg && $arg eq "config") {
-       print "graph_title rrdcached stats\n";
-       print "QueueLength.label Queue length\n";
-       print "UpdatesReceived.label UpdatesReceived\n";
-       print "UpdatesReceived.type DERIVE\n";
-       print "FlushesReceived.label FlushesReceived\n";
-       print "FlushesReceived.type DERIVE\n";
-       print "UpdatesWritten.label UpdatesWritten\n";
-       print "UpdatesWritten.type DERIVE\n";
-       print "DataSetsWritten.label DataSetsWritten\n";
-       print "DataSetsWritten.type DERIVE\n";
-       print "TreeNodesNumber.label TreeNodesNumber\n";
-       print "TreeDepth.label TreeDepth\n";
-       print "JournalBytes.label JournalBytes\n";
-       print "JournalBytes.type DERIVE\n";
-       print "JournalRotate.label JournalRotate\n";
-       print "JournalRotate.type DERIVE\n";
-       exit 0;
-}
-
-my $sock = new IO::Socket::UNIX(
-       Type => SOCK_STREAM,
-       Peer => "/var/run/rrdcached.sock",
-) or die "Cannot open socket : $!";
-
-print $sock "STATS\n";
-print $sock "QUIT\n";
-
-# skip first line
-<$sock>;
-print map { s/: /.value /; $_; } <$sock>;
-
-exit 0;
diff --git a/cookbooks/munin/files/default/plugins/snmp__apcpdu_current b/cookbooks/munin/files/default/plugins/snmp__apcpdu_current
deleted file mode 100755 (executable)
index d2f8b26..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/perl
-
-=head1 MAGIC MARKERS
-
-  #%# family=snmpauto
-  #%# capabilities=snmpconf
-
-=cut
-
-use strict;
-use warnings;
-use Munin::Plugin::SNMP;
-
-my $session = Munin::Plugin::SNMP->session;
-
-if (defined $ARGV[0] and $ARGV[0] eq "config") {
-    my $host = $session->hostname;
-    my $warning = $session->get_single(".1.3.6.1.4.1.318.1.1.26.6.1.1.6.1");
-    my $critical = $session->get_single(".1.3.6.1.4.1.318.1.1.26.6.1.1.7.1");
-
-    print "host_name $host\n" unless $host eq "localhost";
-    print "graph_title Load\n";
-    print "graph_args --base 1000 -l 0\n";
-    print "graph_vlabel Amps\n";
-    print "graph_category power\n";
-    print "graph_info This graph shows the total throughput the PDU.\n";
-
-    print "current.label Current\n";
-    print "current.type GAUGE\n";
-    print "current.info Current load in amps.\n";
-    print "current.draw LINE2\n";
-    print "current.warning ${warning}\n";
-    print "current.critical ${critical}\n";
-} else {
-    my $current = $session->get_single(".1.3.6.1.4.1.318.1.1.26.6.3.1.5.1");
-
-    $current = $current / 10 unless $current eq "U";
-
-    print "current.value ${current}\n";
-}
diff --git a/cookbooks/munin/files/default/plugins/snmp__apcpdu_humidity b/cookbooks/munin/files/default/plugins/snmp__apcpdu_humidity
deleted file mode 100755 (executable)
index 5900689..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/perl
-
-=head1 MAGIC MARKERS
-
-  #%# family=snmpauto
-  #%# capabilities=snmpconf
-
-=cut
-
-use strict;
-use warnings;
-use Munin::Plugin::SNMP;
-
-my $session = Munin::Plugin::SNMP->session;
-
-if (defined $ARGV[0] and $ARGV[0] eq "config") {
-    my $host = $session->hostname;
-    my $warning = $session->get_single(".1.3.6.1.4.1.318.1.1.26.10.2.1.1.13.1");
-    my $critical = $session->get_single(".1.3.6.1.4.1.318.1.1.26.10.2.1.1.14.1");
-
-    print "host_name $host\n" unless $host eq "localhost";
-    print "graph_title Humidity\n";
-    print "graph_args -l 0\n";
-    print "graph_vlabel %\n";
-    print "graph_category sensors\n";
-    print "graph_info This graph shows the humidity from the PDUs environmental sensor.\n";
-
-    print "humidity.label Humidity\n";
-    print "humidity.type GAUGE\n";
-    print "humidity.info Relative humidity.\n";
-    print "humidity.draw LINE2\n";
-    print "humidity.warning ${warning}:\n";
-    print "humidity.critical ${critical}:\n";
-} else {
-    my $humidity = $session->get_single(".1.3.6.1.4.1.318.1.1.26.10.2.2.1.10.1");
-    
-    print "humidity.value ${humidity}\n";
-}
diff --git a/cookbooks/munin/files/default/plugins/snmp__apcpdu_power b/cookbooks/munin/files/default/plugins/snmp__apcpdu_power
deleted file mode 100755 (executable)
index cfb6a81..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/perl
-
-=head1 MAGIC MARKERS
-
-  #%# family=snmpauto
-  #%# capabilities=snmpconf
-
-=cut
-
-use strict;
-use warnings;
-use Munin::Plugin::SNMP;
-
-my $session = Munin::Plugin::SNMP->session;
-
-if (defined $ARGV[0] and $ARGV[0] eq "config") {
-    my $host = $session->hostname;
-
-    print "host_name $host\n" unless $host eq "localhost";
-    print "graph_title Power\n";
-    print "graph_args --base 1000 -l 0\n";
-    print "graph_vlabel Watts\n";
-    print "graph_category power\n";
-    print "graph_info This graph shows the power being supplied by the PDU.\n";
-
-    print "power.label Power\n";
-    print "power.type GAUGE\n";
-    print "power.info Current power draw in watts.\n";
-    print "power.draw LINE2\n";
-} else {
-    my $power = $session->get_single(".1.3.6.1.4.1.318.1.1.26.6.3.1.7.1");
-
-    $power = $power * 10 unless $power eq "U";
-
-    print "power.value ${power}\n";
-}
diff --git a/cookbooks/munin/files/default/plugins/snmp__apcpdu_temperature b/cookbooks/munin/files/default/plugins/snmp__apcpdu_temperature
deleted file mode 100755 (executable)
index 309f473..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/perl
-
-=head1 MAGIC MARKERS
-
-  #%# family=snmpauto
-  #%# capabilities=snmpconf
-
-=cut
-
-use strict;
-use warnings;
-use Munin::Plugin::SNMP;
-
-my $session = Munin::Plugin::SNMP->session;
-
-if (defined $ARGV[0] and $ARGV[0] eq "config") {
-    my $host = $session->hostname;
-    my $warning = $session->get_single(".1.3.6.1.4.1.318.1.1.26.10.2.1.1.11.1");
-    my $critical = $session->get_single(".1.3.6.1.4.1.318.1.1.26.10.2.1.1.10.1");
-
-    print "host_name $host\n" unless $host eq "localhost";
-    print "graph_title Temperature\n";
-    print "graph_args -l 0\n";
-    print "graph_vlabel Degrees Celsius\n";
-    print "graph_category sensors\n";
-    print "graph_info This graph shows the temperature from the PDUs environmental sensor.\n";
-
-    print "temperature.label Temperature\n";
-    print "temperature.type GAUGE\n";
-    print "temperature.info Temperature in degrees celsius.\n";
-    print "temperature.draw LINE2\n";
-    print "temperature.warning :${warning}\n";
-    print "temperature.critical :${critical}\n";
-} else {
-    my $temperature = $session->get_single(".1.3.6.1.4.1.318.1.1.26.10.2.2.1.8.1");
-
-    $temperature = $temperature / 10 unless $temperature eq "U";
-    
-    print "temperature.value ${temperature}\n";
-}
diff --git a/cookbooks/munin/files/default/plugins/snmp__apcpdu_voltage b/cookbooks/munin/files/default/plugins/snmp__apcpdu_voltage
deleted file mode 100755 (executable)
index 362d44c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/perl
-
-=head1 MAGIC MARKERS
-
-  #%# family=snmpauto
-  #%# capabilities=snmpconf
-
-=cut
-
-use strict;
-use warnings;
-use Munin::Plugin::SNMP;
-
-my $session = Munin::Plugin::SNMP->session;
-
-if (defined $ARGV[0] and $ARGV[0] eq "config") {
-    my $host = $session->hostname;
-
-    print "host_name $host\n" unless $host eq "localhost";
-    print "graph_title Voltage\n";
-    print "graph_args --base 1000 -l 0\n";
-    print "graph_vlabel Volts\n";
-    print "graph_category power\n";
-    print "graph_info This graph shows the voltage being supplied by the PDU.\n";
-
-    print "voltage.label Voltage\n";
-    print "voltage.type GAUGE\n";
-    print "voltage.info Current voltage.\n";
-    print "voltage.draw LINE2\n";
-} else {
-    my $voltage = $session->get_single(".1.3.6.1.4.1.318.1.1.26.6.3.1.6.1");
-
-    print "voltage.value ${voltage}\n";
-}
diff --git a/cookbooks/munin/files/default/plugins/squid_delay_pools b/cookbooks/munin/files/default/plugins/squid_delay_pools
deleted file mode 100755 (executable)
index 1349954..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-#
-# Plugin to monitor the number of IPs being slowed down by Squid delay pools
-# This monitors the number of IPs being delayed in the last 128 pools, which
-# are the normal requests.
-#
-# Parameters:
-#
-#      config   (required)
-#      autoconf (optional - used by munin-config)
-#
-
-if [ "$1" = "config" ]; then
-
-       echo 'graph_title IPs being delayed with referer'
-       echo 'graph_args --base 1000 -l 0'
-       echo 'graph_vlabel IPs'
-       echo 'graph_category squid'
-       echo 'squid_delay1.label IPs'
-       echo 'squid_delay1.min 0'
-       echo 'squid_delay1.draw AREA'
-
-       exit 0
-fi
-
-req0=`squidclient -h 127.0.0.1 mgr:delay|awk '\$1 == "Pool:"  && \$2 < 128 { pr = 0; } \$1 == "Pool:" && \$2 >= 128 { pr = 1; } { if (pr) { print \$0; } }'|fgrep Current|egrep --count '[0-9]{1,3}:-?[0-9]{1,3} '`
-
-echo "squid_delay1.value " `expr 0 + $req0`
diff --git a/cookbooks/munin/files/default/plugins/squid_delay_pools_noreferer b/cookbooks/munin/files/default/plugins/squid_delay_pools_noreferer
deleted file mode 100644 (file)
index a35da11..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-#
-# Plugin to monitor the number of IPs being slowed down by Squid delay pools
-# This monitors the number of IPs being delayed in the first 128 pools, which
-# are the ones which have no referer.
-#
-# Parameters:
-#
-#      config   (required)
-#      autoconf (optional - used by munin-config)
-#
-
-if [ "$1" = "config" ]; then
-
-       echo 'graph_title No-referer IPs being delayed'
-       echo 'graph_args --base 1000 -l 0'
-       echo 'graph_vlabel IPs'
-       echo 'graph_category squid'
-       echo 'squid_delay2.label IPs'
-       echo 'squid_delay2.min 0'
-       echo 'squid_delay2.draw AREA'
-
-       exit 0
-fi
-
-req0=`squidclient -h 127.0.0.1 mgr:delay|awk '\$1 == "Pool:"  && \$2 < 128 { pr = 1; } \$1 == "Pool:" && \$2 >= 128 { pr = 0; } { if (pr) { print \$0; } }'|fgrep Current|egrep --count '[0-9]{1,3}:-?[0-9]{1,3} '`
-
-echo "squid_delay2.value " `expr 0 + $req0`
diff --git a/cookbooks/munin/files/default/plugins/squid_icp b/cookbooks/munin/files/default/plugins/squid_icp
deleted file mode 100755 (executable)
index e960d2b..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-#!/usr/bin/perl -w
-# -*- perl -*-
-
-=head1 NAME
-
-squid_icp - Plugin to graph traffic to the ICP peers
-
-=head1 CONFIGURATION
-
-The following configuration variables are used by this plugin:
-
- [squid_icp]
-  env.squidhost    - host (default "localhost")
-  env.squidport    - port (default "3128")
-  env.squiduser    - username (default "")
-  env.squidpasswd  - password (default "")
-
-=head1 ABOUT
-
-When using squid as a "load balancer" (of sorts), who gets the
-request?
-
-=head1 AUTHORS
-
-Copyright (C) 2004 Jimmy Olsen
-
-=head1 LICENSE
-
-Gnu GPLv2
-
-=begin comment
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; version 2 dated June, 1991.
-
-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, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301 USA.
-
-=end comment
-
-=head1 MAGIC MARKERS
-
- #%# family=manual
- #%# capabilities=autoconf
-
-=cut
-
-my $ret = undef;
-
-if (! eval "require IO::Socket;")
-{
-       $ret = "IO::Socket not found";
-}
-if (! eval "require MIME::Base64;")
-{
-       $ret = "MIME::Base64 not found";
-}
-if (! eval "require Net::hostent;")
-{
-       $ret = "Net::hostent not found";
-}
-
-$squid_host = $ENV{squidhost} || "localhost";
-$squid_port = $ENV{squidport} || 3128;
-$user = $ENV{squiduser} || "";
-$passwd = $ENV{squidpasswd} || "";
-
-if($ARGV[0] and $ARGV[0] eq "autoconf") {
-    &autoconf($squid_host, $squid_port, $user, $passwd);
-}
-
-sub autoconf {
-    my ($host, $port, $user, $passwd) = @_;
-
-       if ($ret)
-       {
-               print "no ($ret)\n";
-               exit 0;
-       }
-
-    my $cachemgr = IO::Socket::INET->new(PeerAddr => $host,
-                                       PeerPort => $port,
-                                       Proto    => 'tcp',
-                                       Timeout  => 5);
-
-    if (!$cachemgr)
-    {
-       print "no (could not connect: $!)\n";
-       exit 0;
-    }
-
-    my $request = "GET cache_object://$host/counters HTTP/1.0\r\n" .
-       "Accept: */*\r\n" .
-       &make_auth_header($user, $passwd) .
-       "\r\n";
-                 
-    $cachemgr->syswrite($request, length($request));
-    my @lines = $cachemgr->getlines();
-
-    print "yes\n";
-    exit 0;
-}
-
-sub make_auth_header {
-    my ($user, $passwd) = @_;
-
-    if(!defined $passwd || $passwd eq "") {
-       return "";
-    } else {
-       my $auth = MIME::Base64::encode_base64(($user ? $user : "") . ":$passwd", "");
-       return "Authorization: Basic $auth\r\n" .
-           "Proxy-Authorization: Basic $auth\r\n";
-    }
-}
-
-
-sub query_squid {
-    my ($host, $port, $user, $passwd) = @_;
-    my $ret;
-
-    my $cachemgr = IO::Socket::INET->new(PeerAddr => $host,
-                                       PeerPort => $port,
-                                       Proto    => 'tcp') or die($!);
-
-    
-
-    my $request = "GET cache_object://$host/server_list HTTP/1.0\r\n" .
-       "Accept: */*\r\n" .
-       &make_auth_header($user, $passwd) .
-       "\r\n";
-                 
-    $cachemgr->syswrite($request, length($request));
-    my @lines = $cachemgr->getlines();
-    my $id = "";
-    for(my $i = 0; $i <= $#lines; $i++) {
-       chomp $lines[$i];
-       if($lines[$i] =~ /Host[^:]+:\s*(\S+)\/\d+\/\d+\s*$/) {
-           my $host = $1;
-           $id = $host;
-           $id =~ s/\./_/g;
-
-            unless(exists($ret->{$id})) {
-                $ret->{$id}->{host} = $host;
-                $ret->{$id}->{fetches} = 0;
-            }
-       }
-       elsif($lines[$i] =~ /FETCHES\s*:\s*(\d+)/) {
-           $ret->{$id}->{fetches} += $1;
-       }
-    }
-    return $ret;
-}
-
-my $hosts = &query_squid($squid_host, $squid_port, $user, $passwd);
-
-if($ARGV[0] and $ARGV[0] eq "config") {
-    my $first = 1;
-    print "graph_title Squid relay statistics\n";
-    print "graph_vlabel requests / \${graph_period}\n";
-    print "graph_args -l 0 --base 1000\n";
-    print "graph_total total\n";
-       print "graph_category squid\n";
-    foreach my $i (sort keys %{$hosts}) {
-       print "$i.label ", $hosts->{$i}->{host}, "\n";
-       print "$i.type DERIVE\n";
-       print "$i.max 500000\n";
-       print "$i.min 0\n";
-       if ($first) {
-           print "$i.draw AREA\n";
-           $first = 0;
-       } else {
-           print "$i.draw STACK\n";
-       }
-    }
-    exit 0;
-}
-
-foreach my $i (keys %{$hosts}) {
-    print "$i.value ", $hosts->{$i}->{fetches}, "\n";
-}
-
-# vim:syntax=perl
diff --git a/cookbooks/munin/files/default/plugins/squid_times b/cookbooks/munin/files/default/plugins/squid_times
deleted file mode 100755 (executable)
index c16612e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/sh
-#
-# Copyright (C) 2008 Olivier DELHOMME. All rights reserved.
-# License GPL V2 or higher
-#
-# Abstract
-# munin plugin that logs the cache mean services times 
-#
-# Authors
-#  . Olivier Delhomme <olivierdelhomme at gmail dot com>
-#  . Grant Slater
-#
-#%# family=auto
-#%# capabilities=autoconf
-
-if [ "$1" = "autoconf" ]; then
-       SQUID_STATS=$(squidclient -h 127.0.0.1 cache_object://localhost/info)
-       if [ -n "${SQUID_STATS}" ]; then
-               echo yes 
-               exit 0
-       else
-               echo "no (HTTP GET failed)"
-               exit 1
-       fi
-fi
-
-if [ "$1" = "config" ]; then
-       echo 'graph_title Squid Median Services Times'
-       echo 'graph_info This graph shows the proxy median services response times.'
-       echo 'graph_category squid'
-       echo 'graph_args --lower-limit 0'
-       echo 'graph_vlabel median reponse times (s)'
-
-       echo 'mean_http.label Http'
-       echo 'mean_cmis.label Cache misses'     
-       echo 'mean_chits.label Cache hits'
-       echo 'mean_nhits.label Near hits'
-       echo 'mean_nmr.label Not-modified replies'
-       echo 'mean_dnsl.label Dns lookups'
-       echo 'mean_icpq.label Icp queries'
-
-       exit 0
-fi 
-
-SQUID_TIME=$(squidclient -h 127.0.0.1 cache_object://localhost/info)
-
-SQUID_TIME_HTTP=$(echo "$SQUID_TIME" | grep "HTTP Requests (All)" | cut -d':' -f2 | sed -e "s/^\ *//" | cut -d' ' -f1)
-SQUID_TIME_CACHE_MISSES=$(echo "$SQUID_TIME" | grep "Cache Misses" | cut -d':' -f2 | sed -e "s/^\ *//" | cut -d' ' -f1)
-SQUID_TIME_CACHE_HITS=$(echo "$SQUID_TIME" | grep "Cache Hits" | cut -d':' -f2 | sed -e "s/^\ *//" | cut -d' ' -f1)
-SQUID_TIME_NEAR_HITS=$(echo "$SQUID_TIME" | grep "Near Hits" | cut -d':' -f2 | sed -e "s/^\ *//" | cut -d' ' -f1)
-SQUID_TIME_NM_REPLIES=$(echo "$SQUID_TIME" | grep "Not-Modified Replies" | cut -d':' -f2 | sed -e "s/^\ *//" | cut -d' ' -f1)
-SQUID_TIME_DNS_LOOKUPS=$(echo "$SQUID_TIME" | grep "DNS Lookups" | cut -d':' -f2 | sed -e "s/^\ *//" | cut -d' ' -f1)
-SQUID_TIME_ICP_QUERIES=$(echo "$SQUID_TIME" | grep "ICP Queries" | cut -d':' -f2 | sed -e "s/^\ *//" | cut -d' ' -f1)
-
-echo "mean_http.value $SQUID_TIME_HTTP"
-echo "mean_cmis.value $SQUID_TIME_CACHE_MISSES"
-echo "mean_chits.value $SQUID_TIME_CACHE_HITS" 
-echo "mean_nhits.value $SQUID_TIME_NEAR_HITS"
-echo "mean_nmr.value $SQUID_TIME_NM_REPLIES"
-echo "mean_dnsl.value $SQUID_TIME_DNS_LOOKUPS"
-echo "mean_icpq.value $SQUID_TIME_ICP_QUERIES"
diff --git a/cookbooks/munin/files/default/www/favicon.ico b/cookbooks/munin/files/default/www/favicon.ico
deleted file mode 100644 (file)
index 975e1cb..0000000
Binary files a/cookbooks/munin/files/default/www/favicon.ico and /dev/null differ
diff --git a/cookbooks/munin/files/default/www/robots.txt b/cookbooks/munin/files/default/www/robots.txt
deleted file mode 100644 (file)
index 1f53798..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-User-agent: *
-Disallow: /
diff --git a/cookbooks/munin/libraries/expand.rb b/cookbooks/munin/libraries/expand.rb
deleted file mode 100644 (file)
index 248c5ad..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-class Chef
-  class Munin
-    def self.expand(template, nodes, separator = " ")
-      nodes.map do |node|
-        if node.is_a?(Hash)
-          template
-            .gsub(/%%%([^%]+)%%%/) { node[Regexp.last_match[1].to_sym].tr("-", "_") }
-            .gsub(/%%([^%]+)%%/) { node[Regexp.last_match[1].to_sym] }
-        else
-          template
-            .gsub("%%%", node.tr("-", "_"))
-            .gsub("%%", node)
-        end
-      end.join(separator)
-    end
-  end
-end
diff --git a/cookbooks/munin/recipes/default.rb b/cookbooks/munin/recipes/default.rb
deleted file mode 100644 (file)
index cf2b767..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-#
-# Cookbook:: munin
-# Recipe:: default
-#
-# Copyright:: 2010, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-package "munin-node"
-
-service "munin-node" do
-  action [:enable, :start]
-  supports :status => true, :restart => true, :reload => true
-end
-
-servers = search(:node, "recipes:munin\\:\\:server")
-
-servers.each do |server|
-  server.interfaces(:role => :external) do |interface|
-    firewall_rule "accept-munin-#{server}" do
-      action :accept
-      family interface[:family]
-      source "#{interface[:zone]}:#{interface[:address]}"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports "munin"
-      source_ports "1024:"
-    end
-  end
-end
-
-template "/etc/munin/munin-node.conf" do
-  source "munin-node.conf.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :servers => servers
-  notifies :restart, "service[munin-node]"
-end
-
-remote_directory "/usr/local/share/munin/plugins" do
-  source "plugins"
-  owner "root"
-  group "root"
-  mode 0o755
-  files_owner "root"
-  files_group "root"
-  files_mode 0o755
-  purge true
-end
-
-remote_directory "/etc/munin/plugin-conf.d" do
-  source "plugin-conf.d"
-  owner "root"
-  group "munin"
-  mode 0o750
-  files_owner "root"
-  files_group "root"
-  files_mode 0o644
-  purge false
-  notifies :restart, "service[munin-node]"
-end
-
-if Dir.glob("/proc/acpi/thermal_zone/*/temperature").empty?
-  munin_plugin "acpi" do
-    action :delete
-  end
-else
-  munin_plugin "acpi"
-end
-
-# apcpdu_
-munin_plugin "cpu"
-
-if File.exist?("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state")
-  munin_plugin "cpuspeed"
-else
-  munin_plugin "cpuspeed" do
-    action :delete
-  end
-end
-
-munin_plugin_conf "df" do
-  template "df.erb"
-end
-
-munin_plugin "df"
-munin_plugin "df_inode"
-
-munin_plugin_conf "diskstats" do
-  template "diskstats.erb"
-end
-
-munin_plugin "diskstats"
-munin_plugin "entropy"
-munin_plugin "forks"
-
-if node[:kernel][:modules].include?("nf_conntrack")
-  package "conntrack"
-
-  munin_plugin "fw_conntrack"
-  munin_plugin "fw_forwarded_local"
-else
-  munin_plugin "fw_conntrack" do
-    action :delete
-  end
-
-  munin_plugin "fw_forwarded_local" do
-    action :delete
-  end
-end
-
-if File.read("/proc/sys/net/ipv4/ip_forward").chomp == "1"
-  munin_plugin "fw_packets"
-else
-  munin_plugin "fw_packets" do
-    action :delete
-  end
-end
-
-if File.exist?("/sbin/hpasmcli")
-  munin_plugin "hpasmcli2_temp" do
-    target "hpasmcli2_"
-  end
-
-  munin_plugin "hpasmcli2_fans" do
-    target "hpasmcli2_"
-  end
-else
-  munin_plugin "hpasmcli2_temp" do
-    action :delete
-  end
-
-  munin_plugin "hpasmcli2_fans" do
-    action :delete
-  end
-end
-
-munin_plugin "hpasmcli_temp" do
-  action :delete
-end
-
-munin_plugin "hpasmcli_fans" do
-  action :delete
-end
-
-munin_plugin "http_loadtime" do
-  action :delete
-end
-
-node[:network][:interfaces].each do |ifname, ifattr|
-  if ifattr[:flags]&.include?("UP") && !ifattr[:flags].include?("LOOPBACK")
-    if node[:hardware] &&
-       node[:hardware][:network] &&
-       node[:hardware][:network][ifname][:device] =~ /^virtio/
-      munin_plugin_conf "if_#{ifname}" do
-        template "if.erb"
-        variables :ifname => ifname
-      end
-    else
-      munin_plugin_conf "if_#{ifname}" do
-        action :delete
-      end
-    end
-
-    munin_plugin "if_err_#{ifname}" do
-      target "if_err_"
-    end
-
-    munin_plugin "if_#{ifname}" do
-      target "if_"
-    end
-  else
-    munin_plugin "if_err_#{ifname}" do
-      action :delete
-    end
-
-    munin_plugin "if_#{ifname}" do
-      action :delete
-    end
-  end
-end
-
-munin_plugin "interrupts"
-munin_plugin "iostat"
-munin_plugin "iostat_ios"
-
-if Dir.glob("/dev/ipmi*").empty?
-  munin_plugin_conf "ipmi" do
-    action :delete
-  end
-
-  munin_plugin "ipmi_fans" do
-    action :delete
-  end
-
-  munin_plugin "ipmi_temp" do
-    action :delete
-  end
-
-  munin_plugin "ipmi_power" do
-    action :delete
-  end
-else
-  munin_plugin_conf "ipmi" do
-    template "ipmi.erb"
-  end
-
-  munin_plugin "ipmi_fans" do
-    target "ipmi_"
-  end
-
-  munin_plugin "ipmi_temp" do
-    target "ipmi_"
-  end
-
-  munin_plugin "ipmi_power" do
-    target "ipmi_"
-  end
-end
-
-munin_plugin "irqstats"
-munin_plugin "load"
-munin_plugin "memory"
-munin_plugin "netstat"
-
-if node[:kernel][:modules].include?("nfsv3")
-  munin_plugin "nfs_client"
-else
-  munin_plugin "nfs_client" do
-    action :delete
-  end
-end
-
-if node[:kernel][:modules].include?("nfsv4")
-  munin_plugin "nfs4_client"
-else
-  munin_plugin "nfs4_client" do
-    action :delete
-  end
-end
-
-if node[:kernel][:modules].include?("nfsd")
-  munin_plugin "nfsd"
-  munin_plugin "nfsd4"
-else
-  munin_plugin "nfsd" do
-    action :delete
-  end
-
-  munin_plugin "nfsd4" do
-    action :delete
-  end
-end
-
-munin_plugin "open_files"
-munin_plugin "open_inodes"
-
-munin_plugin "postfix_mailqueue" do
-  action :delete
-end
-
-munin_plugin "postfix_mailvolume" do
-  action :delete
-end
-
-munin_plugin "processes"
-munin_plugin "proc_pri"
-
-sensors_fan = false
-sensors_temp = false
-sensors_volt = false
-
-Dir.glob("/sys/class/hwmon/hwmon*").each do |hwmon|
-  hwmon = "#{hwmon}/device" unless File.exist?("#{hwmon}/name")
-
-  sensors_fan = true unless Dir.glob("#{hwmon}/fan*_input").empty?
-  sensors_temp = true unless Dir.glob("#{hwmon}/temp*_input").empty?
-  sensors_volt = true unless Dir.glob("#{hwmon}/in*_input").empty?
-end
-
-package "lm-sensors" if sensors_fan || sensors_temp || sensors_volt
-
-if sensors_fan
-  munin_plugin "sensors_fan" do
-    target "sensors_"
-  end
-else
-  munin_plugin "sensors_fan" do
-    action :delete
-  end
-end
-
-if sensors_temp
-  munin_plugin "sensors_temp" do
-    target "sensors_"
-  end
-else
-  munin_plugin "sensors_temp" do
-    action :delete
-  end
-end
-
-if sensors_volt
-  munin_plugin "sensors_volt" do
-    target "sensors_"
-    conf "sensors_volt.erb"
-  end
-else
-  munin_plugin "sensors_volt" do
-    action :delete
-  end
-end
-
-munin_plugin "swap"
-munin_plugin "tcp"
-munin_plugin "threads"
-munin_plugin "uptime"
-munin_plugin "users"
-munin_plugin "vmstat"
diff --git a/cookbooks/munin/recipes/server.rb b/cookbooks/munin/recipes/server.rb
deleted file mode 100644 (file)
index f9fe98d..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#
-# Cookbook:: munin
-# Recipe:: server
-#
-# Copyright:: 2010, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-include_recipe "apache"
-
-package "munin"
-package "rrdcached"
-package "libcgi-fast-perl"
-
-template "/etc/default/rrdcached" do
-  source "rrdcached.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
-directory "/var/lib/munin/rrdcached" do
-  owner "munin"
-  group "munin"
-  mode 0o755
-end
-
-service "rrdcached" do
-  action [:enable, :start]
-  subscribes :restart, "template[/etc/default/rrdcached]"
-end
-
-munin_plugin "rrdcached"
-
-expiry_time = 14 * 86400
-
-clients = search(:node, "recipes:munin\\:\\:default").sort_by(&:name)
-frontends = search(:node, "recipes:web\\:\\:frontend").reject { |n| Time.now - Time.at(n[:ohai_time]) > expiry_time }.map(&:name).sort
-backends = search(:node, "recipes:web\\:\\:backend").reject { |n| Time.now - Time.at(n[:ohai_time]) > expiry_time }.map(&:name).sort
-tilecaches = search(:node, "roles:tilecache").reject { |n| Time.now - Time.at(n[:ohai_time]) > expiry_time }.sort_by(&:name).map do |n|
-  { :name => n.name.split(".").first, :interface => n.interfaces(:role => :external).first[:interface].tr(".", "_") }
-end
-renderers = search(:node, "roles:tile").reject { |n| Time.now - Time.at(n[:ohai_time]) > expiry_time }.sort_by(&:name).map do |n|
-  { :name => n.name.split(".").first, :interface => n.interfaces(:role => :external).first[:interface].tr(".", "_") }
-end
-geocoders = search(:node, "roles:nominatim").reject { |n| Time.now - Time.at(n[:ohai_time]) > expiry_time }.sort_by(&:name).map do |n|
-  { :name => n.name.split(".").first, :interface => n.interfaces(:role => :external).first[:interface].tr(".", "_") }
-end
-
-template "/etc/munin/munin.conf" do
-  source "munin.conf.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :expiry_time => expiry_time, :clients => clients,
-            :frontends => frontends, :backends => backends,
-            :tilecaches => tilecaches, :renderers => renderers,
-            :geocoders => geocoders
-end
-
-apache_module "fcgid"
-apache_module "rewrite"
-apache_module "headers"
-
-remote_directory "/srv/munin.openstreetmap.org" do
-  source "www"
-  owner "root"
-  group "root"
-  mode 0o755
-  files_owner "root"
-  files_group "root"
-  files_mode 0o644
-end
-
-# directory to put dumped files in
-directory "/srv/munin.openstreetmap.org/dumps" do
-  owner "www-data"
-  group "www-data"
-  mode 0o755
-end
-
-ssl_certificate "munin.openstreetmap.org" do
-  domains ["munin.openstreetmap.org", "munin.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "munin.openstreetmap.org" do
-  template "apache.erb"
-end
-
-template "/etc/cron.daily/munin-backup" do
-  source "backup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o755
-end
-
-munin_plugin "munin_stats"
-munin_plugin "munin_update"
-munin_plugin "munin_rrdcached"
diff --git a/cookbooks/munin/resources/plugin.rb b/cookbooks/munin/resources/plugin.rb
deleted file mode 100644 (file)
index dede3cb..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#
-# Cookbook:: munin
-# Provider:: munin_plugin
-#
-# Copyright:: 2013, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-default_action :create
-
-property :plugin, :kind_of => String, :name_attribute => true
-property :target, :kind_of => String
-property :conf, :kind_of => String
-property :conf_cookbook, :kind_of => String
-property :conf_variables, :kind_of => Hash, :default => {}
-property :restart_munin, :kind_of => [TrueClass, FalseClass], :default => true
-
-action :create do
-  link_action = case target_path
-                when nil then :delete
-                else :create
-                end
-
-  link plugin_path do
-    action link_action
-    to target_path
-  end
-
-  if new_resource.conf
-    munin_plugin_conf new_resource.plugin do
-      cookbook new_resource.conf_cookbook
-      template new_resource.conf
-      variables new_resource.conf_variables
-      restart_munin false
-    end
-  end
-end
-
-action :delete do
-  link plugin_path do
-    action :delete
-  end
-
-  if new_resource.conf
-    munin_plugin_conf new_resource.plugin do
-      action :delete
-      restart_munin false
-    end
-  end
-end
-
-action_class do
-  def plugin_path
-    "/etc/munin/plugins/#{new_resource.plugin}"
-  end
-
-  def target_path
-    if ::File.exist?(target)
-      target
-    elsif ::File.exist?("/usr/local/share/munin/plugins/#{target}")
-      "/usr/local/share/munin/plugins/#{target}"
-    elsif ::File.exist?("/usr/share/munin/plugins/#{target}")
-      "/usr/share/munin/plugins/#{target}"
-    end
-  end
-
-  def target
-    new_resource.target || new_resource.plugin
-  end
-end
-
-def after_created
-  notifies :restart, "service[munin-node]" if restart_munin && node[:recipes].include?("munin")
-end
diff --git a/cookbooks/munin/resources/plugin_conf.rb b/cookbooks/munin/resources/plugin_conf.rb
deleted file mode 100644 (file)
index 1355052..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# Cookbook:: munin
-# Resource:: munin_plugin_conf
-#
-# Copyright:: 2013, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-default_action :create
-
-property :plugin_conf, :kind_of => String, :name_attribute => true
-property :cookbook, :kind_of => [String, nil]
-property :template, :kind_of => String, :required => true
-property :variables, :kind_of => Hash, :default => {}
-property :restart_munin, :kind_of => [TrueClass, FalseClass], :default => true
-
-action :create do
-  declare_resource :template, config_file do
-    cookbook new_resource.cookbook
-    source new_resource.template
-    owner "root"
-    group "root"
-    mode 0o644
-    variables new_resource.variables.merge(:name => new_resource.plugin_conf)
-  end
-end
-
-action :delete do
-  file config_file do
-    action :delete
-  end
-end
-
-action_class do
-  def config_file
-    "/etc/munin/plugin-conf.d/#{new_resource.plugin_conf}"
-  end
-end
-
-def after_created
-  notifies :restart, "service[munin-node]" if restart_munin
-end
diff --git a/cookbooks/munin/templates/default/apache.erb b/cookbooks/munin/templates/default/apache.erb
deleted file mode 100644 (file)
index 77a2157..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-       ServerName munin.openstreetmap.org
-       ServerAlias munin.osm.org
-       ServerAdmin webmaster@openstreetmap.org
-
-       CustomLog /var/log/apache2/munin.openstreetmap.org-access.log combined
-       ErrorLog /var/log/apache2/munin.openstreetmap.org-error.log
-
-       SSLEngine on
-       SSLCertificateFile /etc/ssl/certs/munin.openstreetmap.org.pem
-       SSLCertificateKeyFile /etc/ssl/private/munin.openstreetmap.org.key
-
-        SetEnv RRDCACHED_ADDRESS /var/run/rrdcached.sock
-
-       DocumentRoot /srv/munin.openstreetmap.org
-       Alias /static/favicon.ico /srv/munin.openstreetmap.org/favicon.ico
-       Alias /static/ /etc/munin/static/
-       ScriptAlias /munin-cgi/ /usr/lib/munin/cgi/
-
-       # Remove Proxy request header to mitigate https://httpoxy.org/
-       RequestHeader unset Proxy early
-
-       RewriteEngine on
-       RewriteCond %{REQUEST_URI} !^/static/
-       RewriteCond %{REQUEST_URI} !^/dumps/
-       RewriteRule ^(/.*\.html)?$ /munin-cgi/munin-cgi-html/$1 [PT]
-</VirtualHost>
-
-<VirtualHost *:80>
-       ServerName munin.openstreetmap.org
-       ServerAlias munin.osm.org
-       ServerAdmin webmaster@openstreetmap.org
-
-       CustomLog /var/log/apache2/munin.openstreetmap.org-access.log combined
-       ErrorLog /var/log/apache2/munin.openstreetmap.org-error.log
-
-       RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-       RedirectPermanent / https://munin.openstreetmap.org/
-</VirtualHost>
-
-<Directory /srv/munin.openstreetmap.org>
-       Require all granted
-</Directory>
-
-<Directory /srv/munin.openstreetmap.org/dumps>
-       Options +Indexes
-</Directory>
-
-<Directory /etc/munin/static>
-       Require all granted
-</Directory>
-
-<Directory /usr/lib/munin/cgi>
-       Options +ExecCGI
-       SetHandler fcgid-script
-       Require all granted
-</Directory>
diff --git a/cookbooks/munin/templates/default/backup.cron.erb b/cookbooks/munin/templates/default/backup.cron.erb
deleted file mode 100644 (file)
index 6b84605..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-T=$(mktemp -d -t -p /var/tmp munin.XXXXXXXXXX)
-D=$(date +%Y-%m-%d)
-B=munin-$D.tar.gz
-
-mkdir $T/munin-$D
-ln -s /var/lib/munin/openstreetmap $T/munin-$D
-ln -s /var/lib/munin/*.storable $T/munin-$D
-
-export GZIP="--rsyncable -9"
-export RSYNC_RSH="ssh -ax"
-
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B munin-$D
-nice rsync --preallocate --fuzzy $T/$B backup::backup
-
-rm -rf $T
diff --git a/cookbooks/munin/templates/default/munin-node.conf.erb b/cookbooks/munin/templates/default/munin-node.conf.erb
deleted file mode 100644 (file)
index 8c88fd6..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Configure logging
-log_level 4
-log_file /var/log/munin/munin-node.log
-pid_file /var/run/munin/munin-node.pid
-
-# Run in the background
-background 1
-setsid 1
-
-# Run as root
-user root
-group root
-
-# Regexps for files to ignore
-ignore_file ~$
-ignore_file DEADJOE$ 
-ignore_file \.bak$
-ignore_file %$
-ignore_file \.dpkg-(tmp|new|old|dist)$
-ignore_file \.rpm(save|new)$
-ignore_file \.pod$
-
-# Set the hostname
-host_name <%= node.name %>
-
-# List on port 4949 on all interfaces
-host *
-port 4949
-
-# List the addresses that are allowed to connect
-allow ^127\.0\.0\.1$
-<% @servers.each do |server| -%>
-<% server.interfaces do |interface| -%>
-allow ^<%= Regexp.quote(interface[:address]) %>$
-<% end -%>
-<% if server[:openvpn] -%>
-allow ^<%= Regexp.quote(server[:openvpn][:address]) %>$
-<% end -%>
-<% end -%>
-<% node[:munin][:allow].each do |address| -%>
-allow ^<%= Regexp.quote(address) %>$
-<% end -%>
diff --git a/cookbooks/munin/templates/default/munin.conf.erb b/cookbooks/munin/templates/default/munin.conf.erb
deleted file mode 100644 (file)
index add1593..0000000
+++ /dev/null
@@ -1,812 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Set maximum number of update processes to run at once
-max_processes 64
-
-# Maximum number of graphs to generate at once
-max_graph_jobs 24
-max_cgi_graph_jobs 24
-
-# Render pages and graphs on demand
-html_strategy cgi
-graph_strategy cgi
-
-# Use rrdcached
-rrdcached_socket /var/run/rrdcached.sock
-
-# Configure alert targets
-contact.admins.command mail -s "Munin Notification for ${var:host}" admins@openstreetmap.org
-contact.admins.always_send invalid
-contact.null.command cat > /dev/null
-contact.null.always_send invalid
-
-# Send alerts to the admins by default
-contacts admins
-
-# Ignore uncontactable hosts for twelve hours
-unknown_limit 144
-<% @clients.sort { |a,b| a.name <=> b.name }.each do |client| -%>
-
-# Configure monitoring for <%= client.name %>
-[<%= client.name %>]
-<% if Time.now - Time.at(client[:ohai_time]) > @expiry_time -%>
-    update no
-<% end -%>
-<% if client[:networking][:roles][:external][:zone] == "ucl" -%>
-    address <%= client.internal_ipaddress || client.external_ipaddress %>
-<% elsif client[:networking][:roles][:external][:zone] == "ams" -%>
-    address <%= client.internal_ipaddress || client.external_ipaddress %>
-<% elsif client[:networking][:roles][:external][:zone] == "bm" -%>
-    address <%= client.internal_ipaddress || client.external_ipaddress %>
-<% elsif client.external_ipaddress -%>
-    address <%= client.external_ipaddress %>
-<% end -%>
-    use_node_name yes
-<% if client[:munin][:plugins] -%>
-<% client[:munin][:plugins].keys.sort.each do |plugin| -%>
-<% client[:munin][:plugins][plugin].keys.sort.each do |value| -%>
-<% if client[:munin][:plugins][plugin][value].kind_of?(Hash) -%>
-<% if client[:munin][:plugins][plugin][value][:graph] -%>
-    <%= plugin %>.<%= value %>.graph <%= client[:munin][:plugins][plugin][value][:graph] %>
-<% end -%>
-<% if client[:munin][:plugins][plugin][value][:draw] -%>
-    <%= plugin %>.<%= value %>.draw <%= client[:munin][:plugins][plugin][value][:draw] %>
-<% end -%>
-<% if client[:munin][:plugins][plugin][value][:label] -%>
-    <%= plugin %>.<%= value %>.label <%= client[:munin][:plugins][plugin][value][:label] %>
-<% end -%>
-<% if client[:munin][:plugins][plugin][value][:warning] -%>
-    <%= plugin %>.<%= value %>.warning <%= client[:munin][:plugins][plugin][value][:warning] %>
-<% end -%>
-<% if client[:munin][:plugins][plugin][value][:critical] -%>
-    <%= plugin %>.<%= value %>.critical <%= client[:munin][:plugins][plugin][value][:critical] %>
-<% end -%>
-<% else -%>
-    <%= plugin %>.<%= value %> <%= client[:munin][:plugins][plugin][value] %>
-<% end -%>
-<% end -%>
-<% end -%>
-<% end -%>
-<% if client[:munin][:graphs] -%>
-<% client[:munin][:graphs].keys.sort.each do |graph| -%>
-<% if client[:munin][:graphs][graph][:title] -%>
-    <%= graph %>.graph_title <%= client[:munin][:graphs][graph][:title] %>
-<% end -%>
-<% if client[:munin][:graphs][graph][:vlabel] -%>
-    <%= graph %>.graph_vlabel <%= client[:munin][:graphs][graph][:vlabel] %>
-<% end -%>
-<% if client[:munin][:graphs][graph][:category] -%>
-    <%= graph %>.graph_category <%= client[:munin][:graphs][graph][:category] %>
-<% end -%>
-<% client[:munin][:graphs][graph][:values].keys.sort.each do |value| -%>
-<% if client[:munin][:graphs][graph][:values][value][:sum] -%>
-    <%= graph %>.<%= value %>.sum <%= client[:munin][:graphs][graph][:values][value][:sum].join(" ") %>
-<% end -%>
-<% if client[:munin][:graphs][graph][:values][value][:label] -%>
-    <%= graph %>.<%= value %>.label <%= client[:munin][:graphs][graph][:values][value][:label] %>
-<% end -%>
-<% end -%>
-<% end -%>
-<% end -%>
-<% end -%>
-
-# Configure monitoring for switch1.openstreetmap.org
-[openstreetmap.org;switch1.openstreetmap.org]
-    address 10.0.48.10
-    use_node_name no
-
-# Configure monitoring for pdu1.ams.openstreetmap.org
-[openstreetmap.org;pdu1.ams.openstreetmap.org]
-    address 10.0.48.10
-    use_node_name no
-
-# Configure monitoring for pdu1.ams.openstreetmap.org
-[openstreetmap.org;pdu2.ams.openstreetmap.org]
-    address 10.0.48.10
-    use_node_name no
-
-# Configure compound graphs for ams.openstreetmap.org
-[ams.openstreetmap.org]
-    update no
-    apcpdu_current.graph_title Load
-    apcpdu_current.graph_args --lower-limit 0
-    apcpdu_current.graph_vlabel Amps
-    apcpdu_current.graph_category power
-    apcpdu_current.graph_order pdu1=pdu1.ams.openstreetmap.org:snmp_pdu1_ams_openstreetmap_org_apcpdu_current.current pdu2=pdu2.ams.openstreetmap.org:snmp_pdu2_ams_openstreetmap_org_apcpdu_current.current
-    apcpdu_current.graph_total total
-    apcpdu_current.pdu1.label PDU A
-    apcpdu_current.pdu1.draw AREASTACK
-    apcpdu_current.pdu1.min 0
-    apcpdu_current.pdu2.label PDU B
-    apcpdu_current.pdu2.draw AREASTACK
-    apcpdu_current.pdu2.min 0
-    apcpdu_power.graph_title Power
-    apcpdu_power.graph_args --base 1000 --lower-limit 0
-    apcpdu_power.graph_vlabel Watts
-    apcpdu_power.graph_category power
-    apcpdu_power.graph_order pdu1=pdu1.ams.openstreetmap.org:snmp_pdu1_ams_openstreetmap_org_apcpdu_power.power pdu2=pdu2.ams.openstreetmap.org:snmp_pdu2_ams_openstreetmap_org_apcpdu_power.power
-    apcpdu_power.graph_total total
-    apcpdu_power.pdu1.label PDU A
-    apcpdu_power.pdu1.draw AREASTACK
-    apcpdu_power.pdu1.min 0
-    apcpdu_power.pdu2.label PDU B
-    apcpdu_power.pdu2.draw AREASTACK
-    apcpdu_power.pdu2.min 0
-    apcpdu_temperature.graph_title Temperature
-    apcpdu_temperature.graph_args --lower-limit 0
-    apcpdu_temperature.graph_vlabel Degrees Celsius
-    apcpdu_temperature.graph_category sensors
-    apcpdu_temperature.graph_order temperature=pdu1.ams.openstreetmap.org:snmp_pdu1_ams_openstreetmap_org_apcpdu_temperature.temperature
-    apcpdu_temperature.temperature.label Temperature
-    apcpdu_temperature.temperature.draw LINE2
-    apcpdu_temperature.temperature.min 0
-    apcpdu_humidity.graph_title Humidity
-    apcpdu_humidity.graph_args --lower-limit 0
-    apcpdu_humidity.graph_vlabel %
-    apcpdu_humidity.graph_category sensors
-    apcpdu_humidity.graph_order humidity=pdu1.ams.openstreetmap.org:snmp_pdu1_ams_openstreetmap_org_apcpdu_humidity.humidity
-    apcpdu_humidity.humidity.label Humidity
-    apcpdu_humidity.humidity.draw LINE2
-    apcpdu_humidity.humidity.min 0
-<% unless @frontends.empty? && @backends.empty? -%>
-
-# Configure compound graphs for www.openstreetmap.org
-[www.openstreetmap.org]
-    update no
-    apache_accesses.graph_title Apache accesses
-    apache_accesses.graph_vlabel accesses / ${graph_period}
-    apache_accesses.graph_category apache
-    apache_accesses.graph_args --lower-limit 0
-    apache_accesses.accesses80.sum <%= Chef::Munin.expand "%%:apache_accesses.accesses80", @frontends %>
-    apache_accesses.accesses80.label port 80
-    apache_accesses.accesses80.min 0
-    apache_volume.graph_title Apache volume
-    apache_volume.graph_vlabel bytes per ${graph_period}
-    apache_volume.graph_category apache
-    apache_volume.graph_args --lower-limit 0
-    apache_volume.volume80.sum <%= Chef::Munin.expand "%%:apache_volume.volume80", @frontends %>
-    apache_volume.volume80.label port 80
-    apache_volume.volume80.min 0
-    if_eth0.graph_title eth0 traffic
-    if_eth0.graph_vlabel bits in (-) / out (+) per ${graph_period}
-    if_eth0.graph_category network
-    if_eth0.graph_order down up
-    if_eth0.down.sum <%= Chef::Munin.expand "%%:if_eth0.down", @frontends %>
-    if_eth0.down.label received
-    if_eth0.down.cdef down,8,*
-    if_eth0.up.sum <%= Chef::Munin.expand "%%:if_eth0.up", @frontends %>
-    if_eth0.up.label sent
-    if_eth0.up.cdef up,8,*
-    if_eth1.graph_title eth1 traffic
-    if_eth1.graph_vlabel bits in (-) / out (+) per ${graph_period}
-    if_eth1.graph_category network
-    if_eth1.graph_order down up
-    if_eth1.down.sum <%= Chef::Munin.expand "%%:if_eth1.down", @frontends %>
-    if_eth1.down.label received
-    if_eth1.down.cdef down,8,*
-    if_eth1.up.sum <%= Chef::Munin.expand "%%:if_eth1.up", @frontends %>
-    if_eth1.up.label sent
-    if_eth1.up.cdef up,8,*
-    api_calls_www.graph_title Active requests
-    api_calls_www.graph_vlabel Number of requests
-    api_calls_www.graph_category api
-    api_calls_www.graph_order map upload amf history full trkpts web other
-    api_calls_www.web.sum <%= Chef::Munin.expand "%%:api_calls_%%%.web", @frontends %>
-    api_calls_www.web.label Web site traffic
-    api_calls_www.upload.sum <%= Chef::Munin.expand "%%:api_calls_%%%.upload", @frontends %>
-    api_calls_www.upload.label Changeset diff uploads
-    api_calls_www.other.sum <%= Chef::Munin.expand "%%:api_calls_%%%.other", @frontends %>
-    api_calls_www.other.label Other API calls
-    api_calls_www.amf.sum <%= Chef::Munin.expand "%%:api_calls_%%%.amf", @frontends %>
-    api_calls_www.amf.label AMF API calls
-    api_calls_www.history.sum <%= Chef::Munin.expand "%%:api_calls_%%%.history", @frontends %>
-    api_calls_www.history.label Element history fetches
-    api_calls_www.full.sum <%= Chef::Munin.expand "%%:api_calls_%%%.full", @frontends %>
-    api_calls_www.full.label Full element fetches
-    api_calls_www.map.sum <%= Chef::Munin.expand "%%:api_calls_%%%.map", @frontends %>
-    api_calls_www.map.label Map API calls
-    api_calls_www.trkpts.sum <%= Chef::Munin.expand "%%:api_calls_%%%.trkpts", @frontends %>
-    api_calls_www.trkpts.label GPX trackpoints calls
-    api_calls_error.graph_title HTTP errors
-    api_calls_error.graph_vlabel Number of errors per ${graph_period}
-    api_calls_error.graph_category api
-    api_calls_error.graph_order http401 http422 http500 http502 http503 http509
-    api_calls_error.http401.sum <%= Chef::Munin.expand "%%:api_calls_status.http401", @frontends %>
-    api_calls_error.http401.label 401 Unauthorized
-    api_calls_error.http401.warning :0.5
-    api_calls_error.http422.sum <%= Chef::Munin.expand "%%:api_calls_status.http422", @frontends %>
-    api_calls_error.http422.label 422 Unprocessable Entity
-    api_calls_error.http422.warning :0.5
-    api_calls_error.http500.sum <%= Chef::Munin.expand "%%:api_calls_status.http500", @frontends %>
-    api_calls_error.http500.label 500 Internal Server Error
-    api_calls_error.http500.warning :0.5
-    api_calls_error.http502.sum <%= Chef::Munin.expand "%%:api_calls_status.http502", @frontends %>
-    api_calls_error.http502.label 502 Bad Gateway
-    api_calls_error.http502.warning :0.5
-    api_calls_error.http503.sum <%= Chef::Munin.expand "%%:api_calls_status.http503", @frontends %>
-    api_calls_error.http503.label 503 Service Unavailable
-    api_calls_error.http503.warning :0.5
-    api_calls_error.http509.sum <%= Chef::Munin.expand "%%:api_calls_status.http509", @frontends %>
-    api_calls_error.http509.label 509 Bandwidth Limit Exceeded
-    api_calls_error.http509.warning :5
-    api_calls_num.graph_title Requests processed
-    api_calls_num.graph_vlabel Number of requests per ${graph_period}
-    api_calls_num.graph_category api
-    api_calls_num.graph_order map upload amf history full trkpts web other
-    api_calls_num.web.sum <%= Chef::Munin.expand "%%:api_calls_num.web", @frontends %>
-    api_calls_num.web.label Web site traffic
-    api_calls_num.upload.sum <%= Chef::Munin.expand "%%:api_calls_num.upload", @frontends %>
-    api_calls_num.upload.label Changeset diff uploads
-    api_calls_num.other.sum <%= Chef::Munin.expand "%%:api_calls_num.other", @frontends %>
-    api_calls_num.other.label Other API calls
-    api_calls_num.amf.sum <%= Chef::Munin.expand "%%:api_calls_num.amf", @frontends %>
-    api_calls_num.amf.label AMF API calls
-    api_calls_num.history.sum <%= Chef::Munin.expand "%%:api_calls_num.history", @frontends %>
-    api_calls_num.history.label Element history fetches
-    api_calls_num.full.sum <%= Chef::Munin.expand "%%:api_calls_num.full", @frontends %>
-    api_calls_num.full.label Full element fetches
-    api_calls_num.map.sum <%= Chef::Munin.expand "%%:api_calls_num.map", @frontends %>
-    api_calls_num.map.label Map API calls
-    api_calls_num.trkpts.sum <%= Chef::Munin.expand "%%:api_calls_num.trkpts", @frontends %>
-    api_calls_num.trkpts.label GPX trackpoints calls
-    api_waits_www.graph_title Wait times for active requests
-    api_waits_www.graph_vlabel Average time of requests
-    api_waits_www.graph_category api
-    api_waits_www.graph_order map upload amf history full trkpts web other
-    api_waits_www.web.sum <%= Chef::Munin.expand "%%:api_waits_%%%.web", @frontends %>
-    api_waits_www.web.label Web site traffic
-    api_waits_www.web.cdef web,2,/
-    api_waits_www.upload.sum <%= Chef::Munin.expand "%%:api_waits_%%%.upload", @frontends %>
-    api_waits_www.upload.label Changeset diff uploads
-    api_waits_www.upload.cdef upload,2,/
-    api_waits_www.other.sum <%= Chef::Munin.expand "%%:api_waits_%%%.other", @frontends %>
-    api_waits_www.other.label Other API calls
-    api_waits_www.other.cdef other,2,/
-    api_waits_www.amf.sum <%= Chef::Munin.expand "%%:api_waits_%%%.amf", @frontends %>
-    api_waits_www.amf.label AMF API calls
-    api_waits_www.amf.cdef amf,2,/
-    api_waits_www.history.sum <%= Chef::Munin.expand "%%:api_waits_%%%.history", @frontends %>
-    api_waits_www.history.label Element history fetches
-    api_waits_www.history.cdef history,2,/
-    api_waits_www.full.sum <%= Chef::Munin.expand "%%:api_waits_%%%.full", @frontends %>
-    api_waits_www.full.label Full element fetches
-    api_waits_www.full.cdef full,2,/
-    api_waits_www.map.sum <%= Chef::Munin.expand "%%:api_waits_%%%.map", @frontends %>
-    api_waits_www.map.label Map API calls
-    api_waits_www.map.cdef map,2,/
-    api_waits_www.trkpts.sum <%= Chef::Munin.expand "%%:api_waits_%%%.trkpts", @frontends %>
-    api_waits_www.trkpts.label GPX trackpoints calls
-    api_waits_www.trkpts.cdef trkpts,2,/
-    memcached_multi_commands.graph_title Commands
-    memcached_multi_commands.graph_vlabel Commands per ${graph_period}
-    memcached_multi_commands.graph_category memcached
-    memcached_multi_commands.graph_order cmd_get cmd_set cmd_touch get_hits get_misses delete_hits delete_misses incr_hits incr_misses decr_hits decr_misses touch_hits touch_misses
-    memcached_multi_commands.cmd_get.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.cmd_get", @backends %>
-    memcached_multi_commands.cmd_get.label Gets
-    memcached_multi_commands.cmd_set.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.cmd_set", @backends %>
-    memcached_multi_commands.cmd_set.label Sets
-    memcached_multi_commands.cmd_touch.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.cmd_touch", @backends %>
-    memcached_multi_commands.cmd_touch.label Touches
-    memcached_multi_commands.get_hits.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.get_hits", @backends %>
-    memcached_multi_commands.get_hits.label Get Hits
-    memcached_multi_commands.get_misses.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.get_misses", @backends %>
-    memcached_multi_commands.get_misses.label Get Misses
-    memcached_multi_commands.delete_hits.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.delete_hits", @backends %>
-    memcached_multi_commands.delete_hits.label Delete Hits
-    memcached_multi_commands.delete_misses.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.delete_misses", @backends %>
-    memcached_multi_commands.delete_misses.label Delete Misses
-    memcached_multi_commands.incr_hits.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.incr_hits", @backends %>
-    memcached_multi_commands.incr_hits.label Increment Hits
-    memcached_multi_commands.incr_misses.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.incr_misses", @backends %>
-    memcached_multi_commands.incr_misses.label Increment Misses
-    memcached_multi_commands.decr_hits.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.decr_hits", @backends %>
-    memcached_multi_commands.decr_hits.label Decrement Hits
-    memcached_multi_commands.decr_misses.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.decr_misses", @backends %>
-    memcached_multi_commands.decr_misses.label Decrement Misses
-    memcached_multi_commands.touch_hits.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.touch_hits", @backends %>
-    memcached_multi_commands.touch_hits.label Touch Hits
-    memcached_multi_commands.touch_misses.sum <%= Chef::Munin.expand "%%:memcached_multi_commands.touch_misses", @backends %>
-    memcached_multi_commands.touch_misses.label Touch Misses
-    memcached_multi_conns.graph_title Connections
-    memcached_multi_conns.graph_vlabel Connections per ${graph_period}
-    memcached_multi_conns.graph_category memcached
-    memcached_multi_conns.graph_order max_conns curr_conns avg_conns
-    memcached_multi_conns.curr_conns.sum <%= Chef::Munin.expand "%%:memcached_multi_conns.curr_conns", @backends %>
-    memcached_multi_conns.curr_conns.label Current Connections
-    memcached_multi_conns.max_conns.sum <%= Chef::Munin.expand "%%:memcached_multi_conns.max_conns", @backends %>
-    memcached_multi_conns.max_conns.label Max Connections
-    memcached_multi_conns.avg_conns.sum <%= Chef::Munin.expand "%%:memcached_multi_conns.avg_conns", @backends %>
-    memcached_multi_conns.avg_conns.label Avg Connections
-    memcached_multi_evictions.graph_title Evictions
-    memcached_multi_evictions.graph_vlabel Evictions per ${graph_period}
-    memcached_multi_evictions.graph_category memcached
-    memcached_multi_evictions.evictions.sum <%= Chef::Munin.expand "%%:memcached_multi_evictions.evictions", @backends %>
-    memcached_multi_evictions.evictions.label Evictions
-    memcached_multi_evictions.evicted_nonzero.sum <%= Chef::Munin.expand "%%:memcached_multi_evictions.evicted_nonzero", @backends %>
-    memcached_multi_evictions.evicted_nonzero.label Evictions prior to Expire
-    memcached_multi_evictions.reclaimed.sum <%= Chef::Munin.expand "%%:memcached_multi_evictions.reclaimed", @backends %>
-    memcached_multi_evictions.reclaimed.label Reclaimed Items
-    memcached_multi_items.graph_title Items
-    memcached_multi_items.graph_vlabel Items in Memcached
-    memcached_multi_items.graph_category memcached
-    memcached_multi_items.graph_order curr_items total_items
-    memcached_multi_items.curr_items.sum <%= Chef::Munin.expand "%%:memcached_multi_items.curr_items", @backends %>
-    memcached_multi_items.curr_items.label Current Items
-    memcached_multi_items.total_items.sum <%= Chef::Munin.expand "%%:memcached_multi_items.total_items", @backends %>
-    memcached_multi_items.total_items.label New Items
-    memcached_multi_memory.graph_title Memory Usage
-    memcached_multi_memory.graph_vlabel Bytes Used
-    memcached_multi_memory.graph_category memcached
-    memcached_multi_memory.graph_order limit_maxbytes bytes
-    memcached_multi_memory.limit_maxbytes.sum <%= Chef::Munin.expand "%%:memcached_multi_memory.limit_maxbytes", @backends %>
-    memcached_multi_memory.limit_maxbytes.label Maximum Bytes Allocated
-    memcached_multi_memory.bytes.sum <%= Chef::Munin.expand "%%:memcached_multi_memory.bytes", @backends %>
-    memcached_multi_memory.bytes.label Current Bytes Used
-    memcached_multi_bytes.graph_title Network Traffic
-    memcached_multi_bytes.graph_args --base 1000
-    memcached_multi_bytes.graph_vlabel bits in (-) / out (+)
-    memcached_multi_bytes.graph_category memcached
-    memcached_multi_bytes.graph_order bytes_read bytes_written
-    memcached_multi_bytes.bytes_read.sum <%= Chef::Munin.expand "%%:memcached_multi_bytes.bytes_read", @backends %>
-    memcached_multi_bytes.bytes_read.label Network Traffic coming in (-)
-    memcached_multi_bytes.bytes_read.cdef bytes_read,8,*
-    memcached_multi_bytes.bytes_read.graph no
-    memcached_multi_bytes.bytes_written.sum <%= Chef::Munin.expand "%%:memcached_multi_bytes.bytes_written", @backends %>
-    memcached_multi_bytes.bytes_written.negative bytes_read
-    memcached_multi_bytes.bytes_written.label Traffic in (-) / out (+)
-    memcached_multi_bytes.bytes_written.cdef bytes_written,8,*
-<% end -%>
-<% unless @tilecaches.empty? -%>
-
-# Configure compound graphs for tile.openstreetmap.org
-[tile.openstreetmap.org]
-    update no
-    network_in.graph_title Inbound network traffic
-    network_in.graph_vlabel bits in per ${graph_period}
-    network_in.graph_category network
-    network_in.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:if_%%interface%%.down", @tilecaches %>
-    network_in.graph_total total
-    network_in.graph_args --lower-limit 0
-<% @tilecaches.each do |tc| -%>
-    network_in.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-    network_in.<%= tc[:name].tr("-", "_") %>.cdef <%= tc[:name].tr("-", "_") %>,8,*
-    network_in.<%= tc[:name].tr("-", "_") %>.draw AREASTACK
-    network_in.<%= tc[:name].tr("-", "_") %>.min 0
-<% end -%>
-    network_out.graph_title Outbound network traffic
-    network_out.graph_vlabel bits out per ${graph_period}
-    network_out.graph_category network
-    network_out.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:if_%%interface%%.up", @tilecaches %>
-    network_out.graph_total total
-    network_out.graph_args --lower-limit 0
-<% @tilecaches.each do |tc| -%>
-    network_out.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-    network_out.<%= tc[:name].tr("-", "_") %>.cdef <%= tc[:name].tr("-", "_") %>,8,*
-    network_out.<%= tc[:name].tr("-", "_") %>.draw AREASTACK
-    network_out.<%= tc[:name].tr("-", "_") %>.min 0
-<% end -%>
-    squid_delay_pools.graph_title IPs being delayed with referer
-    squid_delay_pools.graph_args --base 1000 -l 0
-    squid_delay_pools.graph_vlabel IPs
-    squid_delay_pools.graph_order squid_delay1
-    squid_delay_pools.graph_category squid
-    squid_delay_pools.squid_delay1.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:squid_delay_pools.squid_delay1", @tilecaches %>
-    squid_delay_pools.squid_delay1.label IPs
-    squid_delay_pools.squid_delay1.min 0
-    squid_delay_pools.squid_delay1.draw AREA
-    squid_delay_pools_noreferer.graph_title No-referer IPs being delayed
-    squid_delay_pools_noreferer.graph_args --base 1000 -l 0
-    squid_delay_pools_noreferer.graph_vlabel IPs
-    squid_delay_pools_noreferer.graph_order squid_delay2
-    squid_delay_pools_noreferer.graph_category squid
-    squid_delay_pools_noreferer.squid_delay2.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:squid_delay_pools_noreferer.squid_delay2", @tilecaches %>
-    squid_delay_pools_noreferer.squid_delay2.label IPs
-    squid_delay_pools_noreferer.squid_delay2.min 0
-    squid_delay_pools_noreferer.squid_delay2.draw AREA
-    squid_requests.graph_title Squid client requests
-    squid_requests.graph_args --base 1000 -l 0
-    squid_requests.graph_vlabel requests / ${graph_period}
-    squid_requests.graph_order <%= Chef::Munin.expand "%%%name%%%_hits=%%name%%.openstreetmap.org:squid_requests.hits %%%name%%%_errors=%%name%%.openstreetmap.org:squid_requests.errors %%%name%%%_requests=%%name%%.openstreetmap.org:squid_requests.requests", @tilecaches %> hits=<%= @tilecaches.first[:name] %>.openstreetmap.org:squid_requests.hits errors=<%= @tilecaches.first[:name] %>.openstreetmap.org:squid_requests.errors requests=<%= @tilecaches.first[:name] %>.openstreetmap.org:squid_requests.requests
-    squid_requests.graph_total total
-    squid_requests.graph_category squid
-<% @tilecaches.each do |tc| -%>
-    squid_requests.<%= tc[:name].tr("-", "_") %>_hits.graph no
-    squid_requests.<%= tc[:name].tr("-", "_") %>_errors.graph no
-    squid_requests.<%= tc[:name].tr("-", "_") %>_requests.graph no
-<% end -%>
-    squid_requests.hits.cdef 0,<%= Chef::Munin.expand "%%%name%%%_hits", @tilecaches, ",+," %>,+
-    squid_requests.hits.label hits
-    squid_requests.hits.draw AREA
-    squid_requests.errors.cdef 0,<%= Chef::Munin.expand "%%%name%%%_errors", @tilecaches, ",+," %>,+
-    squid_requests.errors.label errors
-    squid_requests.errors.draw STACK
-    squid_requests.requests.cdef 0,<%= Chef::Munin.expand "%%%name%%%_requests", @tilecaches, ",+," %>,+,hits,-,errors,-
-    squid_requests.requests.label misses
-    squid_requests.requests.draw STACK
-    squid_traffic.graph_title Squid traffic status
-    squid_traffic.graph_args --base 1000
-    squid_traffic.graph_vlabel bits per ${graph_period}
-    squid_traffic.graph_order kbytes_in kbytes_out hit_kbytes_out
-    squid_traffic.graph_category squid
-    squid_traffic.kbytes_in.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:squid_traffic.kbytes_in", @tilecaches %>
-    squid_traffic.kbytes_in.label received
-    squid_traffic.kbytes_in.cdef kbytes_in,8096,*
-    squid_traffic.kbytes_out.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:squid_traffic.kbytes_out", @tilecaches %>
-    squid_traffic.kbytes_out.label sent
-    squid_traffic.kbytes_out.cdef kbytes_out,8096,*
-    squid_traffic.hit_kbytes_out.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:squid_traffic.hit_kbytes_out", @tilecaches %>
-    squid_traffic.hit_kbytes_out.label from cache
-    squid_traffic.hit_kbytes_out.cdef hit_kbytes_out,8096,*
-    squid_times_http.graph_title Squid Http Service Times
-    squid_times_http.graph_category squid
-    squid_times_http.graph_args --lower-limit 0
-    squid_times_http.graph_vlabel median reponse times (s)
-    squid_times_http.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:squid_times.mean_http", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_times_http.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-<% end -%>
-    squid_times_cmis.graph_title Squid Cache Miss Service Times
-    squid_times_cmis.graph_category squid
-    squid_times_cmis.graph_args --lower-limit 0
-    squid_times_cmis.graph_vlabel median reponse times (s)
-    squid_times_cmis.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:squid_times.mean_cmis", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_times_cmis.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-<% end -%>
-    squid_times_chits.graph_title Squid Cache Hit Service Times
-    squid_times_chits.graph_category squid
-    squid_times_chits.graph_args --lower-limit 0
-    squid_times_chits.graph_vlabel median reponse times (s)
-    squid_times_chits.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:squid_times.mean_chits", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_times_chits.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-<% end -%>
-    squid_times_nhits.graph_title Squid Cache Near Hit Service Times
-    squid_times_nhits.graph_category squid
-    squid_times_nhits.graph_args --lower-limit 0
-    squid_times_nhits.graph_vlabel median reponse times (s)
-    squid_times_nhits.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:squid_times.mean_nhits", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_times_nhits.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-<% end -%>
-    squid_times_nmr.graph_title Squid Cache Not Modified Service Times
-    squid_times_nmr.graph_category squid
-    squid_times_nmr.graph_args --lower-limit 0
-    squid_times_nmr.graph_vlabel median reponse times (s)
-    squid_times_nmr.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:squid_times.mean_nmr", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_times_nmr.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-<% end -%>
-    squid_times_dnsl.graph_title Squid Cache DNS Lookup Service Times
-    squid_times_dnsl.graph_category squid
-    squid_times_dnsl.graph_args --lower-limit 0
-    squid_times_dnsl.graph_vlabel median reponse times (s)
-    squid_times_dnsl.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:squid_times.mean_dnsl", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_times_dnsl.<%= tc[:name].tr("-", "_") %>.label <%= tc[:name] %>
-<% end -%>
-    squid_request_hitrates.graph_title Squid Cache Request Hit Rates
-    squid_request_hitrates.graph_category squid
-    squid_request_hitrates.graph_args --lower-limit 0 --upper-limit 100
-    squid_request_hitrates.graph_vlabel %
-    squid_request_hitrates.graph_order <%= Chef::Munin.expand "%%%name%%%_total=%%name%%.openstreetmap.org:squid_requests.requests %%%name%%%_hits=%%name%%.openstreetmap.org:squid_requests.hits", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_request_hitrates.<%= tc[:name].tr("-", "_") %>_total.graph no
-    squid_request_hitrates.<%= tc[:name].tr("-", "_") %>_hits.cdef <%= tc[:name].tr("-", "_") %>_hits,<%= tc[:name].tr("-", "_") %>_total,/,100,*
-    squid_request_hitrates.<%= tc[:name].tr("-", "_") %>_hits.label <%= tc[:name] %>
-    squid_request_hitrates.<%= tc[:name].tr("-", "_") %>_hits.draw LINE1
-<% end -%>
-    squid_byte_hitrates.graph_title Squid Cache Byte Hit Rates
-    squid_byte_hitrates.graph_category squid
-    squid_byte_hitrates.graph_args --lower-limit 0 --upper-limit 100
-    squid_byte_hitrates.graph_vlabel %
-    squid_byte_hitrates.graph_order <%= Chef::Munin.expand "%%%name%%%_total=%%name%%.openstreetmap.org:squid_traffic.kbytes_out %%%name%%%_hits=%%name%%.openstreetmap.org:squid_traffic.hit_kbytes_out", @tilecaches %>
-<% @tilecaches.each do |tc| -%>
-    squid_byte_hitrates.<%= tc[:name].tr("-", "_") %>_total.graph no
-    squid_byte_hitrates.<%= tc[:name].tr("-", "_") %>_hits.cdef <%= tc[:name].tr("-", "_") %>_hits,<%= tc[:name].tr("-", "_") %>_total,/,100,*
-    squid_byte_hitrates.<%= tc[:name].tr("-", "_") %>_hits.label <%= tc[:name] %>
-    squid_byte_hitrates.<%= tc[:name].tr("-", "_") %>_hits.draw LINE1
-<% end -%>
-<% end -%>
-<% unless @renderers.empty? -%>
-
-# Configure compound graphs for render.openstreetmap.org
-[render.openstreetmap.org]
-    update no
-    apache_accesses.graph_title Apache accesses
-    apache_accesses.graph_vlabel accesses / ${graph_period}
-    apache_accesses.graph_category apache
-    apache_accesses.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:apache_accesses.accesses80", @renderers %>
-    apache_accesses.graph_total total
-    apache_accesses.graph_args --lower-limit 0
-<% @renderers.each do |rs| -%>
-    apache_accesses.<%= rs[:name].tr("-", "_") %>.label <%= rs[:name] %>
-    apache_accesses.<%= rs[:name].tr("-", "_") %>.draw AREASTACK
-    apache_accesses.<%= rs[:name].tr("-", "_") %>.min 0
-<% end -%>
-    apache_volume.graph_title Apache volume
-    apache_volume.graph_vlabel bytes per ${graph_period}
-    apache_volume.graph_category apache
-    apache_volume.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:apache_volume.volume80", @renderers %>
-    apache_volume.graph_total total
-    apache_volume.graph_args --lower-limit 0
-<% @renderers.each do |rs| -%>
-    apache_volume.<%= rs[:name].tr("-", "_") %>.label <%= rs[:name] %>
-    apache_volume.<%= rs[:name].tr("-", "_") %>.draw AREASTACK
-    apache_volume.<%= rs[:name].tr("-", "_") %>.min 0
-<% end -%>
-    network_in.graph_title Inbound network traffic
-    network_in.graph_vlabel bits in per ${graph_period}
-    network_in.graph_category network
-    network_in.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:if_%%interface%%.down", @renderers %>
-    network_in.graph_total total
-    network_in.graph_args --lower-limit 0
-<% @renderers.each do |rs| -%>
-    network_in.<%= rs[:name].tr("-", "_") %>.label <%= rs[:name] %>
-    network_in.<%= rs[:name].tr("-", "_") %>.cdef <%= rs[:name].tr("-", "_") %>,8,*
-    network_in.<%= rs[:name].tr("-", "_") %>.draw AREASTACK
-    network_in.<%= rs[:name].tr("-", "_") %>.min 0
-<% end -%>
-    network_out.graph_title Outbound network traffic
-    network_out.graph_vlabel bits out per ${graph_period}
-    network_out.graph_category network
-    network_out.graph_order <%= Chef::Munin.expand "%%%name%%%=%%name%%.openstreetmap.org:if_%%interface%%.up", @renderers %>
-    network_out.graph_total total
-    network_out.graph_args --lower-limit 0
-<% @renderers.each do |rs| -%>
-    network_out.<%= rs[:name].tr("-", "_") %>.label <%= rs[:name] %>
-    network_out.<%= rs[:name].tr("-", "_") %>.cdef <%= rs[:name].tr("-", "_") %>,8,*
-    network_out.<%= rs[:name].tr("-", "_") %>.draw AREASTACK
-    network_out.<%= rs[:name].tr("-", "_") %>.min 0
-<% end -%>
-    mod_tile_fresh.graph_title freshness of served tiles
-    mod_tile_fresh.graph_args --base 1000 -l 0
-    mod_tile_fresh.graph_vlabel tiles per ${graph_period}
-    mod_tile_fresh.graph_order fresh freshrender old oldrender outdated outdatedrender
-    mod_tile_fresh.graph_category mod_tile
-    mod_tile_fresh.fresh.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_fresh.fresh", @renderers %>
-    mod_tile_fresh.fresh.label Fresh from disk
-    mod_tile_fresh.fresh.draw AREA
-    mod_tile_fresh.freshrender.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_fresh.freshrender", @renderers %>
-    mod_tile_fresh.freshrender.label Freshly rendered
-    mod_tile_fresh.freshrender.draw STACK
-    mod_tile_fresh.old.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_fresh.old", @renderers %>
-    mod_tile_fresh.old.label Old from disk
-    mod_tile_fresh.old.draw STACK
-    mod_tile_fresh.oldrender.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_fresh.oldrender", @renderers %>
-    mod_tile_fresh.oldrender.label Old tile, attempted render
-    mod_tile_fresh.oldrender.draw STACK
-    mod_tile_fresh.outdated.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_fresh.outdated", @renderers %>
-    mod_tile_fresh.outdated.label Outdated from disk
-    mod_tile_fresh.outdated.draw STACK
-    mod_tile_fresh.outdatedrender.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_fresh.outdatedrender", @renderers %>
-    mod_tile_fresh.outdatedrender.label Outdated tile, attempted render
-    mod_tile_fresh.outdatedrender.draw STACK
-    mod_tile_response.graph_title mod_tile HTTP response codes
-    mod_tile_response.graph_args --base 1000 -l 0
-    mod_tile_response.graph_vlabel responses per ${graph_period}
-    mod_tile_response.graph_order response200 response304 response404 response500
-    mod_tile_response.graph_category mod_tile
-    mod_tile_response.response200.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_response.response200", @renderers %>
-    mod_tile_response.response200.label 200 OK
-    mod_tile_response.response200.draw AREA
-    mod_tile_response.response304.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_response.response304", @renderers %>
-    mod_tile_response.response304.label 304 Not Modified
-    mod_tile_response.response304.draw STACK
-    mod_tile_response.response404.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_response.response404", @renderers %>
-    mod_tile_response.response404.label 404 Not Found
-    mod_tile_response.response404.draw STACK
-    mod_tile_response.response500.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_response.response500", @renderers %>
-    mod_tile_response.response500.label 500 Internal Error
-    mod_tile_response.response500.draw STACK
-    mod_tile_zoom.graph_title mod_tile responses by zoom layer
-    mod_tile_zoom.graph_args --base 1000 -l 0
-    mod_tile_zoom.graph_vlabel responses per ${graph_period}
-    mod_tile_zoom.graph_order z1 z2 z3 z4 z5 z6
-    mod_tile_zoom.graph_category mod_tile
-    mod_tile_zoom.z1.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_zoom.z1", @renderers %>
-    mod_tile_zoom.z1.label z1-8
-    mod_tile_zoom.z1.draw AREA
-    mod_tile_zoom.z2.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_zoom.z2", @renderers %>
-    mod_tile_zoom.z2.label z9-12
-    mod_tile_zoom.z2.draw STACK
-    mod_tile_zoom.z3.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_zoom.z3", @renderers %>
-    mod_tile_zoom.z3.label z13-14
-    mod_tile_zoom.z3.draw STACK
-    mod_tile_zoom.z4.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_zoom.z4", @renderers %>
-    mod_tile_zoom.z4.label z15-16
-    mod_tile_zoom.z4.draw STACK
-    mod_tile_zoom.z5.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_zoom.z5", @renderers %>
-    mod_tile_zoom.z5.label z17-18
-    mod_tile_zoom.z5.draw STACK
-    mod_tile_zoom.z6.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:mod_tile_zoom.z6", @renderers %>
-    mod_tile_zoom.z6.label z19-20
-    mod_tile_zoom.z6.draw STACK
-    renderd_queue.graph_title Renderd queue length
-    renderd_queue.graph_args --base 1000 -l 0
-    renderd_queue.graph_vlabel metatiles
-    renderd_queue.graph_order reqPrio req reqLow dirty reqBulk
-    renderd_queue.graph_category renderd
-    renderd_queue.reqPrio.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue.reqPrio", @renderers %>
-    renderd_queue.reqPrio.label Priority request Queue
-    renderd_queue.reqPrio.type GAUGE
-    renderd_queue.req.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue.req", @renderers %>
-    renderd_queue.req.label Request Queue
-    renderd_queue.req.type GAUGE
-    renderd_queue.reqLow.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue.reqLow", @renderers %>
-    renderd_queue.reqLow.label Low priority request Queue
-    renderd_queue.reqLow.type GAUGE
-    renderd_queue.dirty.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue.dirty", @renderers %>
-    renderd_queue.dirty.label Dirty Queue
-    renderd_queue.dirty.type GAUGE
-    renderd_queue.reqBulk.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue.reqBulk", @renderers %>
-    renderd_queue.reqBulk.label Bulk request Queue
-    renderd_queue.reqBulk.type GAUGE
-    renderd_processed.graph_title Renderd throughput
-    renderd_processed.graph_args --base 1000 -l 0
-    renderd_processed.graph_vlabel Metatiles per ${graph_period}
-    renderd_processed.graph_order reqPrio req reqLow dirty reqBulk dropped
-    renderd_processed.graph_category renderd
-    renderd_processed.graph_info Displays the number of metatiles being rendered by renderd per ${graph_period}
-    renderd_processed.reqPrio.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_processed.reqPrio", @renderers %>
-    renderd_processed.reqPrio.label Priority request Queue
-    renderd_processed.reqPrio.draw AREA
-    renderd_processed.reqPrio.info Throughput of Metatiles submitted high priority for on the fly rendering
-    renderd_processed.req.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_processed.req", @renderers %>
-    renderd_processed.req.label Request Queue
-    renderd_processed.req.draw STACK
-    renderd_processed.req.info Throughput of Metatiles submitted for on the fly rendering
-    renderd_processed.reqLow.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_processed.reqLow", @renderers %>
-    renderd_processed.reqLow.label Low priority request Queue
-    renderd_processed.reqLow.draw STACK
-    renderd_processed.reqLow.info Throughput of Metatiles submitted low priority for on the fly rendering
-    renderd_processed.dirty.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_processed.dirty", @renderers %>
-    renderd_processed.dirty.label Dirty Queue
-    renderd_processed.dirty.draw STACK
-    renderd_processed.dirty.info Throughput of dirty Metatiles submitted for re-render
-    renderd_processed.reqBulk.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_processed.reqBulk", @renderers %>
-    renderd_processed.reqBulk.label Bulk request Queue
-    renderd_processed.reqBulk.draw STACK
-    renderd_processed.reqBulk.info Throughput of Metatiles submitted with background priority
-    renderd_processed.dropped.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_processed.dropped", @renderers %>
-    renderd_processed.dropped.label Dropped (x20)
-    renderd_processed.dropped.draw LINE2
-    renderd_processed.dropped.info Number of Tiles dropped due to queue overload (x20)
-    renderd_processed.dropped.cdef dropped,20,/
-    renderd_zoom.graph_title Renderd throughput by zoom
-    renderd_zoom.graph_args --base 1000 -l 0
-    renderd_zoom.graph_vlabel Metatiles per ${graph_period}
-    renderd_zoom.graph_order z1 z2 z3 z4 z5 z6
-    renderd_zoom.graph_category renderd
-    renderd_zoom.graph_info Displays the number of metatiles being rendered by renderd per ${graph_period}
-    renderd_zoom.z1.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom.z1", @renderers %>
-    renderd_zoom.z1.label zoom z0 - z8
-    renderd_zoom.z1.draw AREA
-    renderd_zoom.z1.info Throughput of Metatiles for z0 - z8
-    renderd_zoom.z2.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom.z2", @renderers %>
-    renderd_zoom.z2.label zoom z9 - z12
-    renderd_zoom.z2.draw STACK
-    renderd_zoom.z2.info Throughput of Metatiles for z9 - z12
-    renderd_zoom.z3.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom.z3", @renderers %>
-    renderd_zoom.z3.label zoom z13 - z14
-    renderd_zoom.z3.draw STACK
-    renderd_zoom.z3.info Throughput of Metatiles for z13 - z14
-    renderd_zoom.z4.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom.z4", @renderers %>
-    renderd_zoom.z4.label zoom z15 - z16
-    renderd_zoom.z4.draw STACK
-    renderd_zoom.z4.info Throughput of Metatiles for z15 - z16
-    renderd_zoom.z5.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom.z5", @renderers %>
-    renderd_zoom.z5.label zoom z17 - z18
-    renderd_zoom.z5.draw STACK
-    renderd_zoom.z5.info Throughput of Metatiles for z17 - z18
-    renderd_zoom.z6.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom.z6", @renderers %>
-    renderd_zoom.z6.label zoom z19 - z20
-    renderd_zoom.z6.draw STACK
-    renderd_zoom.z6.info Throughput of Metatiles for z19 - z20
-    renderd_queue_time.graph_title Renderd time spent by queue
-    renderd_queue_time.graph_args --base 1000 -l 0
-    renderd_queue_time.graph_vlabel metatiles
-    renderd_queue_time.graph_order reqPrio req reqLow dirty reqBulk
-    renderd_queue_time.graph_category renderd
-    renderd_queue_time.reqPrio.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue_time.reqPrio", @renderers %>
-    renderd_queue_time.reqPrio.label Priority request queue
-    renderd_queue_time.reqPrio.cdef reqPrio,1000,/
-    renderd_queue_time.reqPrio.draw AREA
-    renderd_queue_time.reqPrio.info Time for priority request queue
-    renderd_queue_time.req.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue_time.req", @renderers %>
-    renderd_queue_time.req.label Request queue
-    renderd_queue_time.req.cdef req,1000,/
-    renderd_queue_time.req.draw STACK
-    renderd_queue_time.req.info Time for Request queue
-    renderd_queue_time.reqLow.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue_time.reqLow", @renderers %>
-    renderd_queue_time.reqLow.label Low priority request queue
-    renderd_queue_time.reqLow.cdef reqLow,1000,/
-    renderd_queue_time.reqLow.draw STACK
-    renderd_queue_time.reqLow.info Time for low priority request queue
-    renderd_queue_time.dirty.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue_time.dirty", @renderers %>
-    renderd_queue_time.dirty.label Dirty queue
-    renderd_queue_time.dirty.cdef dirty,1000,/
-    renderd_queue_time.dirty.draw STACK
-    renderd_queue_time.dirty.info Time for dirty queue
-    renderd_queue_time.reqBulk.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_queue_time.reqBulk", @renderers %>
-    renderd_queue_time.reqBulk.label Bulk queue
-    renderd_queue_time.reqBulk.cdef reqBulk,1000,/
-    renderd_queue_time.reqBulk.draw STACK
-    renderd_queue_time.reqBulk.info Time for bulk queue
-    renderd_zoom_time.graph_title Renderd time spent by zoom
-    renderd_zoom_time.graph_args --base 1000 -l 0
-    renderd_zoom_time.graph_vlabel time spent per ${graph_period}
-    renderd_zoom_time.graph_order zoomtime1 zoomtime2 zoomtime3 zoomtime4 zoomtime5 zoomtime6
-    renderd_zoom_time.graph_category renderd
-    renderd_zoom_time.graph_info Displays the amount of time renderd has spent rendering tiles of a given zoom per ${graph_period}
-    renderd_zoom_time.zoomtime1.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom_time.zoomtime1", @renderers %>
-    renderd_zoom_time.zoomtime1.label zoom z0 - z8
-    renderd_zoom_time.zoomtime1.cdef zoomtime1,1000,/
-    renderd_zoom_time.zoomtime1.draw AREA
-    renderd_zoom_time.zoomtime1.info Time for Metatiles z0 - z8
-    renderd_zoom_time.zoomtime2.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom_time.zoomtime2", @renderers %>
-    renderd_zoom_time.zoomtime2.label zoom z9 - z12
-    renderd_zoom_time.zoomtime2.cdef zoomtime2,1000,/
-    renderd_zoom_time.zoomtime2.draw STACK
-    renderd_zoom_time.zoomtime2.info Time for Metatiles for z9 - z12
-    renderd_zoom_time.zoomtime3.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom_time.zoomtime3", @renderers %>
-    renderd_zoom_time.zoomtime3.label zoom z13 - z14
-    renderd_zoom_time.zoomtime3.cdef zoomtime3,1000,/
-    renderd_zoom_time.zoomtime3.draw STACK
-    renderd_zoom_time.zoomtime3.info Time for Metatiles for z13 - z14
-    renderd_zoom_time.zoomtime4.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom_time.zoomtime4", @renderers %>
-    renderd_zoom_time.zoomtime4.label zoom z15 - z16
-    renderd_zoom_time.zoomtime4.cdef zoomtime4,1000,/
-    renderd_zoom_time.zoomtime4.draw STACK
-    renderd_zoom_time.zoomtime4.info Time for Metatiles for z15 - z16
-    renderd_zoom_time.zoomtime5.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom_time.zoomtime5", @renderers %>
-    renderd_zoom_time.zoomtime5.label zoom z17 - z18
-    renderd_zoom_time.zoomtime5.cdef zoomtime5,1000,/
-    renderd_zoom_time.zoomtime5.draw STACK
-    renderd_zoom_time.zoomtime5.info Time for Metatiles for z17 - z18
-    renderd_zoom_time.zoomtime6.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:renderd_zoom_time.zoomtime6", @renderers %>
-    renderd_zoom_time.zoomtime6.label zoom z19 - z20
-    renderd_zoom_time.zoomtime6.cdef zoomtime6,1000,/
-    renderd_zoom_time.zoomtime6.draw STACK
-    renderd_zoom_time.zoomtime6.info Time for Metatiles for z19 - z20
-<% end -%>
-<% unless @geocoders.empty? -%>
-
-# Configure compound graphs for nominatim.openstreetmap.org
-[nominatim.openstreetmap.org]
-    update no
-    nominatim_requests.graph_title Requests by API call
-    nominatim_requests.graph_args --base 1000 -l 0
-    nominatim_requests.graph_vlabel requests per minute
-    nominatim_requests.graph_category nominatim
-    nominatim_requests.graph_order z1 z2 z3 z4
-    nominatim_requests.z1.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:nominatim_requests.z1", @geocoders %>
-    nominatim_requests.z1.label reverse
-    nominatim_requests.z1.draw AREA
-    nominatim_requests.z1.type GAUGE
-    nominatim_requests.z2.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:nominatim_requests.z2", @geocoders %>
-    nominatim_requests.z2.label search (successful)
-    nominatim_requests.z2.draw STACK
-    nominatim_requests.z2.type GAUGE
-    nominatim_requests.z3.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:nominatim_requests.z3", @geocoders %>
-    nominatim_requests.z3.label search (no result)
-    nominatim_requests.z3.draw STACK
-    nominatim_requests.z3.type GAUGE
-    nominatim_requests.z4.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:nominatim_requests.z4", @geocoders %>
-    nominatim_requests.z4.label details
-    nominatim_requests.z4.draw STACK
-    nominatim_requests.z4.type GAUGE
-    nominatim_throttled_ips.graph_title Restricted IPs
-    nominatim_throttled_ips.graph_args -l 0
-    nominatim_throttled_ips.graph_vlabel number of IPs
-    nominatim_throttled_ips.graph_category nominatim
-    nominatim_throttled_ips.graph_order bulk block
-    nominatim_throttled_ips.bulk.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:nominatim_throttled_ips.bulk", @geocoders %>
-    nominatim_throttled_ips.bulk.label bulk
-    nominatim_throttled_ips.bulk.draw AREA
-    nominatim_throttled_ips.bulk.type GAUGE
-    nominatim_throttled_ips.block.sum <%= Chef::Munin.expand "%%name%%.openstreetmap.org:nominatim_throttled_ips.block", @geocoders %>
-    nominatim_throttled_ips.block.label blocked
-    nominatim_throttled_ips.block.draw STACK
-    nominatim_throttled_ips.block.type GAUGE
-<% end -%>
diff --git a/cookbooks/munin/templates/default/rrdcached.erb b/cookbooks/munin/templates/default/rrdcached.erb
deleted file mode 100644 (file)
index 8d2ae8a..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Full path to daemon
-DAEMON=/usr/bin/rrdcached
-
-# Optional override flush interval, in seconds.
-WRITE_TIMEOUT=1800
-
-# Optional override maximum write delay, in seconds.
-WRITE_JITTER=1800
-
-# Optional override number of write_threads
-#WRITE_THREADS=4
-
-# Where database files are placed.  If left unset, the default /tmp will
-# be used.  NB: The daemon will reject a directory that has symlinks as
-# components.  NB: You may want to have -B in BASE_OPTS.
-BASE_PATH=/var/lib/munin/
-
-# Where journal files are placed.  If left unset, journaling will
-# be disabled.
-JOURNAL_PATH=/var/lib/munin/rrdcached/
-
-# FHS standard placement for process ID file.
-PIDFILE=/var/run/rrdcached.pid
-
-# FHS standard placement for local control socket.
-SOCKFILE=/var/run/rrdcached.sock
-
-# Optional override group that should own/access the local control
-# socket
-SOCKGROUP=munin
-
-# Optional override access mode of local control socket.
-SOCKMODE=0666
-
-# Optional unprivileged group to run under when daemon.  If unset
-# retains invocation group privileges.
-#DAEMON_GROUP=_rrdcached
-
-# Optional unprivileged user to run under when daemon.  If unset
-# retains invocation user privileges.
-#DAEMON_USER=_rrdcached
-
-# Network socket address requests.  Use in conjunction with SOCKFILE to
-# also listen on INET domain sockets.  The option is a lower-case ell
-# ASCII 108 = 0x6c, and should be repeated for each address.  The
-# parameter is an optional IP address, followed by an optional port with
-# a colon separating it from the address.  The empty string is
-# interpreted as "open sockets on the default port on all available
-# interfaces", but generally does not pass through init script functions
-# so use -L with no parameters for that configuration.
-#NETWORK_OPTIONS="-L"
-
-# Any other options not specifically supported by the script (-P, -f,
-# -F, -B).
-BASE_OPTIONS="-F -B"
diff --git a/cookbooks/munin/templates/default/sensors_volt.erb b/cookbooks/munin/templates/default/sensors_volt.erb
deleted file mode 100644 (file)
index 1224ef3..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[sensors_volt]
-env.volt_warn_percent 0
index 516c38a41b88571e3e07e700beb4adffac7a6900..ec9743c946b964574cf8f8754c45435c7eed7b20 100644 (file)
@@ -85,7 +85,9 @@ module OpenStreetMap
     end
 
     def mysql_users
-      @mysql_users ||= query("SELECT * FROM user").each_with_object({}) do |user, users|
+      privilege_columns = USER_PRIVILEGES.collect { |privilege| "#{privilege}_priv" }.join(", ")
+
+      @mysql_users ||= query("SELECT user, host, #{privilege_columns} FROM user").each_with_object({}) do |user, users|
         name = "'#{user[:user]}'@'#{user[:host]}'"
 
         users[name] = USER_PRIVILEGES.each_with_object({}) do |privilege, privileges|
@@ -131,6 +133,12 @@ module OpenStreetMap
       case privilege
       when :grant
         "GRANT OPTION"
+      when :show_db
+        "SHOW DATABASES"
+      when :repl_slave
+        "REPLICATION SLAVE"
+      when :repl_client
+        "REPLICATION CLIENT"
       when :create_tmp_table
         "CREATE TEMPORARY TABLES"
       else
index 6dd2041bb304b602595ec0c3b00cacefebd82a76..bf6f4683319f030be1f67965255eaff01852ea96 100644 (file)
@@ -6,4 +6,5 @@ description       "Installs and configures mysql"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "munin"
+depends           "chef"
+depends           "prometheus"
index bbbca3c616cfd6c91c2262dd19c47f5487c2a22c..baeff798e8327d72f41d8ad0250a72ac20d1db1c 100644 (file)
 # limitations under the License.
 #
 
-package "mysql-server"
-package "mysql-client"
+include_recipe "prometheus"
 
-service "mysql" do
+mysql_variant = if platform?("ubuntu")
+                  "mysql"
+                else
+                  "mariadb"
+                end
+
+package "#{mysql_variant}-server"
+package "#{mysql_variant}-client"
+
+service "#{mysql_variant}" do
   action [:enable, :start]
   supports :status => true, :restart => true
 end
 
-template "/etc/mysql/mysql.conf.d/zzz-chef.cnf" do
+template "/etc/mysql/#{mysql_variant}.conf.d/zzz-chef.cnf" do
   source "my.cnf.erb"
   owner "root"
   group "root"
-  mode 0o644
-  notifies :restart, "service[mysql]"
+  mode "644"
+  notifies :restart, "service[#{mysql_variant}]"
 end
 
-package "libdbd-mysql-perl"
-package "libcache-cache-perl"
-
-%w[
-  commands connections files handler_read handler_tmp handler_transaction
-  handler_write innodb_bpool innodb_bpool_act innodb_history_list_length
-  innodb_insert_buf innodb_io innodb_io_pend innodb_log innodb_queries
-  innodb_read_views innodb_rows innodb_semaphores innodb_srv_master_thread
-  innodb_tnx max_mem mrr myisam_indexes network_traffic performance
-  qcache qcache_mem select_types slow sorts table_definitions table_locks
-  tmp_tables
-].each do |stat|
-  munin_plugin "mysql_#{stat}" do
-    target "mysql_"
-  end
+service "apparmor" do
+  action :nothing
+end
+
+template "/etc/apparmor.d/local/usr.sbin.mysqld" do
+  source "apparmor.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  notifies :restart, "service[apparmor]"
+  only_if { ::Dir.exist?("/sys/kernel/security/apparmor") }
+end
+
+mysql_password = persistent_token("mysql", "prometheus", "password")
+
+mysql_user "prometheus" do
+  password mysql_password
+  process true
+  repl_client true
 end
 
-%w[
-  bin_relay_log files_tables replication
-].each do |stat|
-  munin_plugin "mysql_#{stat}" do
-    action :delete
-  end
+prometheus_exporter "mysqld" do
+  port 9104
+  options "--mysqld.username=prometheus"
+  environment "MYSQLD_EXPORTER_PASSWORD" => mysql_password
 end
index be985f56381986cfc27072c6ec4591c8111c1159..69e4e795fe9d038cd97f78a8682b8aee943ca12f 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :database, :kind_of => String, :name_attribute => true
+property :database, :kind_of => String, :name_property => true
 property :permissions, :kind_of => Hash, :default => {}
 
 action :create do
index 13e344966517418ad79825429cbc52233608529f..944cfcc6f3ef5c2a570b7708ad9e2f6267008c79 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :user, :kind_of => String, :name_attribute => true
+property :user, :kind_of => String, :name_property => true
 property :password, :kind_of => String
 
 OpenStreetMap::MySQL::USER_PRIVILEGES.each do |privilege|
diff --git a/cookbooks/mysql/templates/default/apparmor.erb b/cookbooks/mysql/templates/default/apparmor.erb
new file mode 100644 (file)
index 0000000..9239e88
--- /dev/null
@@ -0,0 +1,4 @@
+# DO NOT EDIT - This file is being maintained by Chef
+<% if node[:mysql][:settings][:mysqld]&.dig(:secure_file_priv) -%>
+<%= node[:mysql][:settings][:mysqld][:secure_file_priv] %>/* rw,
+<% end -%>
index f7db87730f14ded5b8d719defc7f30957d654a12..9832ce8f3f8c7527e92760fe76792642258043f8 100644 (file)
@@ -1,11 +1,17 @@
-default[:networking][:firewall][:inet] = []
-default[:networking][:firewall][:inet6] = []
-default[:networking][:firewall][:http_rate_limit] = "-"
-default[:networking][:firewall][:http_connection_limit] = "-"
-default[:networking][:firewall][:log] = true
-default[:networking][:firewall][:mark] = true
-default[:networking][:firewall][:raw] = true
-default[:networking][:firewall][:mangle] = true
+default[:networking][:firewall][:enabled] = true
+default[:networking][:firewall][:sets] = []
+default[:networking][:firewall][:helpers] = []
+default[:networking][:firewall][:incoming] = []
+default[:networking][:firewall][:outgoing] = []
+default[:networking][:firewall][:http_rate_limit] = nil
+default[:networking][:firewall][:http_connection_limit] = nil
+default[:networking][:firewall][:allowlist] = []
+default[:networking][:roles] = {}
 default[:networking][:interfaces] = {}
-default[:networking][:nameservers] = []
+default[:networking][:nameservers] = %w[8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844]
 default[:networking][:search] = []
+default[:networking][:dnssec] = "allow-downgrade"
+default[:networking][:hostname] = node.name
+default[:networking][:wireguard][:enabled] = true
+default[:networking][:wireguard][:keepalive] = 180
+default[:networking][:wireguard][:peers] = []
diff --git a/cookbooks/networking/definitions/firewall_rule.rb b/cookbooks/networking/definitions/firewall_rule.rb
deleted file mode 100644 (file)
index 0196c41..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Cookbook:: networking
-# Definition:: firewall_rule
-#
-# Copyright:: 2011, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-define :firewall_rule, :action => :accept do
-  rule = Hash[
-    :action => params[:action].to_s.upcase,
-    :source => params[:source],
-    :dest => params[:dest],
-    :proto => params[:proto],
-    :dest_ports => params[:dest_ports] || "-",
-    :source_ports => params[:source_ports] || "-",
-    :rate_limit => params[:rate_limit] || "-",
-    :connection_limit => params[:connection_limit] || "-",
-    :helper => params[:helper] || "-"
-  ]
-
-  if params[:family].nil?
-    node.default[:networking][:firewall][:inet] << rule
-    node.default[:networking][:firewall][:inet6] << rule
-  elsif params[:family].to_s == "inet"
-    node.default[:networking][:firewall][:inet] << rule
-  elsif params[:family].to_s == "inet6"
-    node.default[:networking][:firewall][:inet6] << rule
-  else
-    log "Unsupported network family" do
-      level :error
-    end
-  end
-end
index c2f170b9c73a2f56c290d0a0f3cc38110c563eae..64aecdeca7fb32b5ea9ebc774f1c3f6ccd46f884 100644 (file)
@@ -1,23 +1,16 @@
-class Chef
-  class Node
-    def interfaces(options = {}, &block)
-      interfaces = []
+module OpenStreetMap
+  module Mixin
+    module Interfaces
+      def interfaces(role: nil)
+        networking = construct_attributes[:networking] || {}
+        networking_interfaces = networking[:interfaces] || {}
 
-      networking = construct_attributes[:networking] || {}
-      networking_interfaces = networking[:interfaces] || {}
-
-      networking_interfaces.each_value  do |interface|
-        next unless options[:role].nil? || interface[:role].to_s == options[:role].to_s
-        next unless options[:family].nil? || interface[:family].to_s == options[:family].to_s
-
-        if block.nil?
-          interfaces << interface
-        else
-          yield interface
+        networking_interfaces.each_value.select do |interface|
+          role.nil? || interface[:role].to_s == role.to_s
         end
       end
-
-      interfaces
     end
   end
 end
+
+Chef::Node.include(OpenStreetMap::Mixin::Interfaces)
index d31d885f995076af73eef0d034023e4f5a97cb07..5f746c9aa1e4bd754c684a95037ae3b88930ddf8 100644 (file)
@@ -1,27 +1,55 @@
-class Chef
-  class Node
-    def ipaddresses(options = {}, &block)
-      addresses = []
-
-      interfaces(options).each do |interface|
-        address = interface[:public_address] || interface[:address]
-
-        if block.nil?
-          addresses << address
-        else
-          yield address
+require "ipaddr"
+
+module OpenStreetMap
+  module Mixin
+    module IPAddresses
+      class Address
+        attr_reader :address, :prefix, :gateway, :network, :netmask
+
+        def initialize(address)
+          @address = address[:public_address] || address[:address]
+          @prefix = address[:prefix]
+          @gateway = address[:gateway]
+
+          ip = IPAddr.new(address[:address]).mask(address[:prefix])
+
+          @network = ip.to_s
+          @netmask = ip.netmask
+        end
+
+        def <=>(other)
+          address <=> other.address
+        end
+
+        def to_s
+          address
+        end
+
+        def to_str
+          address
+        end
+
+        def subnet
+          "#{@network}/#{@prefix}"
         end
       end
 
-      addresses
-    end
+      def ipaddresses(role: nil, family: nil)
+        interfaces(:role => role).each_with_object([]) do |interface, addresses|
+          addresses << Address.new(interface[:inet]) if interface[:inet] && (family.nil? || family == :inet)
+          addresses << Address.new(interface[:inet6]) if interface[:inet6] && (family.nil? || family == :inet6)
+        end
+      end
 
-    def internal_ipaddress
-      ipaddresses(:role => :internal).first
-    end
+      def internal_ipaddress(family: nil)
+        ipaddresses(:role => :internal, :family => family).first
+      end
 
-    def external_ipaddress
-      ipaddresses(:role => :external).first
+      def external_ipaddress(family: nil)
+        ipaddresses(:role => :external, :family => family).first
+      end
     end
   end
 end
+
+Chef::Node.include(OpenStreetMap::Mixin::IPAddresses)
index 3d2944c1555e8fe0bad7da8125dbcba30cebf282..c37012709faf15c9ef5d126c3153770ca8b6d3d2 100644 (file)
@@ -5,5 +5,4 @@ license           "Apache-2.0"
 description       "Configures networking"
 
 version           "1.0.0"
-
-supports          "ubuntu"
+depends           "chef"
index dfa73f196c5aa909e3203a5c20bb81c405aca570..ea87c3b7b0b4ab94264d558bcf5571c46dc54dcf 100644 (file)
 require "ipaddr"
 require "yaml"
 
-netplan = {
-  "network" => {
-    "version" => 2,
-    "renderer" => "networkd",
-    "ethernets" => {},
-    "bonds" => {},
-    "vlans" => {}
-  }
-}
+keys = data_bag_item("networking", "keys")
+
+file "/etc/netplan/00-installer-config.yaml" do
+  action :delete
+end
+
+file "/etc/netplan/01-netcfg.yaml" do
+  action :delete
+end
+
+file "/etc/netplan/50-cloud-init.yaml" do
+  action :delete
+end
+
+file "/etc/netplan/99-chef.yaml" do
+  action :delete
+end
+
+package "ifupdown" do
+  action :purge
+end
+
+package "netplan.io" do
+  action :purge
+end
+
+package "cloud-init" do
+  action :purge
+end
+
+interfaces = node[:networking][:interfaces].collect do |name, interface|
+  [interface[:interface], name]
+end.to_h
 
 node[:networking][:interfaces].each do |name, interface|
-  if interface[:interface]
-    if interface[:role] && (role = node[:networking][:roles][interface[:role]])
-      if role[interface[:family]]
-        node.normal[:networking][:interfaces][name][:prefix] = role[interface[:family]][:prefix]
-        node.normal[:networking][:interfaces][name][:gateway] = role[interface[:family]][:gateway]
-      end
+  if interface[:interface] =~ /^(.*)\.(\d+)$/
+    vlan_interface = Regexp.last_match(1)
+    vlan_id = Regexp.last_match(2)
+
+    parent = interfaces[vlan_interface] || "vlans_#{vlan_interface}"
+
+    node.default_unless[:networking][:interfaces][parent][:interface] = vlan_interface
+    node.default_unless[:networking][:interfaces][parent][:vlans] = []
 
-      node.normal[:networking][:interfaces][name][:metric] = role[:metric]
-      node.normal[:networking][:interfaces][name][:zone] = role[:zone]
+    node.default[:networking][:interfaces][parent][:vlans] << vlan_id
+  end
+
+  next unless interface[:role] && (role = node[:networking][:roles][interface[:role]])
+
+  if interface[:inet] && role[:inet]
+    node.default_unless[:networking][:interfaces][name][:inet][:prefix] = role[:inet][:prefix]
+    node.default_unless[:networking][:interfaces][name][:inet][:gateway] = role[:inet][:gateway]
+    node.default_unless[:networking][:interfaces][name][:inet][:routes] = role[:inet][:routes]
+  end
+
+  if interface[:inet6] && role[:inet6]
+    node.default_unless[:networking][:interfaces][name][:inet6][:prefix] = role[:inet6][:prefix]
+    node.default_unless[:networking][:interfaces][name][:inet6][:gateway] = role[:inet6][:gateway]
+    node.default_unless[:networking][:interfaces][name][:inet6][:routes] = role[:inet6][:routes]
+  end
+
+  node.default_unless[:networking][:interfaces][name][:metric] = role[:metric]
+  node.default_unless[:networking][:interfaces][name][:zone] = role[:zone]
+end
+
+node[:networking][:interfaces].each do |_, interface|
+  if interface[:interface] =~ /^.*\.(\d+)$/
+    template "/etc/systemd/network/10-#{interface[:interface]}.netdev" do
+      source "vlan.netdev.erb"
+      owner "root"
+      group "root"
+      mode "644"
+      variables :interface => interface, :vlan => Regexp.last_match(1)
+      notifies :run, "notify_group[networkctl-reload]"
+    end
+  elsif interface[:interface] =~ /^bond\d+$/
+    template "/etc/systemd/network/10-#{interface[:interface]}.netdev" do
+      source "bond.netdev.erb"
+      owner "root"
+      group "root"
+      mode "644"
+      variables :interface => interface
+      notifies :run, "notify_group[networkctl-reload]"
     end
 
-    prefix = node[:networking][:interfaces][name][:prefix]
-
-    node.normal[:networking][:interfaces][name][:netmask] = (~IPAddr.new(interface[:address]).mask(0)).mask(prefix)
-    node.normal[:networking][:interfaces][name][:network] = IPAddr.new(interface[:address]).mask(prefix)
-
-    interface = node[:networking][:interfaces][name]
-
-    deviceplan = if interface[:interface] =~ /^(.*)\.(\d+)$/
-                   netplan["network"]["vlans"][interface[:interface]] ||= {
-                     "id" => Regexp.last_match(2).to_i,
-                     "link" => Regexp.last_match(1),
-                     "accept-ra" => false,
-                     "addresses" => [],
-                     "routes" => []
-                   }
-                 elsif interface[:interface] =~ /^bond\d+$/
-                   netplan["network"]["bonds"][interface[:interface]] ||= {
-                     "accept-ra" => false,
-                     "addresses" => [],
-                     "routes" => []
-                   }
-                 else
-                   netplan["network"]["ethernets"][interface[:interface]] ||= {
-                     "accept-ra" => false,
-                     "addresses" => [],
-                     "routes" => []
-                   }
-                 end
-
-    deviceplan["addresses"].push("#{interface[:address]}/#{prefix}")
-
-    if interface[:mtu]
-      deviceplan["mtu"] = interface[:mtu]
+    interface[:bond][:slaves].each do |slave|
+      template "/etc/systemd/network/10-#{slave}.network" do
+        source "slave.network.erb"
+        owner "root"
+        group "root"
+        mode "644"
+        variables :master => interface, :slave => slave
+        notifies :run, "notify_group[networkctl-reload]"
+      end
     end
+  end
 
-    if interface[:bond]
-      deviceplan["interfaces"] = interface[:bond][:slaves].to_a
+  template "/etc/systemd/network/10-#{interface[:interface]}.network" do
+    source "network.erb"
+    owner "root"
+    group "root"
+    mode "644"
+    variables :interface => interface
+    notifies :run, "notify_group[networkctl-reload]"
+  end
+end
 
-      deviceplan["parameters"] = {
-        "mode" => interface[:bond][:mode] || "active-backup",
-        "primary" => interface[:bond][:slaves].first,
-        "mii-monitor-interval" => interface[:bond][:miimon] || 100,
-        "down-delay" => interface[:bond][:downdelay] || 200,
-        "up-delay" => interface[:bond][:updelay] || 200
-      }
+package "systemd-resolved" do
+  action :install
+  only_if { platform?("ubuntu") && node[:lsb][:release].to_f > 22.04 || platform?("debian") && node[:lsb][:release].to_f > 11.0 }
+end
+
+service "systemd-networkd" do
+  action [:enable, :start]
+end
+
+if node[:networking][:wireguard][:enabled]
+  wireguard_id = persistent_token("networking", "wireguard")
+
+  node.default[:networking][:wireguard][:address] = "fd43:e709:ea6d:1:#{wireguard_id[0, 4]}:#{wireguard_id[4, 4]}:#{wireguard_id[8, 4]}:#{wireguard_id[12, 4]}"
 
-      deviceplan["parameters"]["transmit-hash-policy"] = interface[:bond][:xmithashpolicy] if interface[:bond][:xmithashpolicy]
-      deviceplan["parameters"]["lacp-rate"] = interface[:bond][:lacprate] if interface[:bond][:lacprate]
+  package "wireguard-tools" do
+    compile_time true
+    options "--no-install-recommends"
+  end
+
+  directory "/var/lib/systemd/wireguard" do
+    owner "root"
+    group "systemd-network"
+    mode "750"
+    compile_time true
+  end
+
+  file "/var/lib/systemd/wireguard/private.key" do
+    action :create_if_missing
+    owner "root"
+    group "systemd-network"
+    mode "640"
+    content %x(wg genkey)
+    compile_time true
+  end
+
+  node.default[:networking][:wireguard][:public_key] = %x(wg pubkey < /var/lib/systemd/wireguard/private.key).chomp
+
+  file "/var/lib/systemd/wireguard/preshared.key" do
+    action :create_if_missing
+    owner "root"
+    group "systemd-network"
+    mode "640"
+    content keys["wireguard"]
+  end
+
+  if node[:roles].include?("gateway")
+    search(:node, "roles:gateway") do |gateway|
+      next if gateway.name == node.name
+      next unless gateway[:networking][:wireguard] && gateway[:networking][:wireguard][:enabled]
+
+      allowed_ips = gateway.ipaddresses(:role => :internal).map(&:subnet)
+
+      node.default[:networking][:wireguard][:peers] << {
+        :public_key => gateway[:networking][:wireguard][:public_key],
+        :allowed_ips => allowed_ips,
+        :endpoint => "#{gateway.name}:51820"
+      }
     end
 
-    if interface[:gateway]
-      if interface[:family] == "inet"
-        default_route = "0.0.0.0/0"
-      elsif interface[:family] == "inet6"
-        default_route = "::/0"
-      end
+    search(:node, "roles:prometheus") do |server|
+      allowed_ips = server.ipaddresses(:role => :internal).map(&:subnet)
 
-      deviceplan["routes"].push(
-        "to" => default_route,
-        "via" => interface[:gateway],
-        "metric" => interface[:metric],
-        "on-link" => true
-      )
-
-      # This ordering relies on systemd-networkd adding routes
-      # in reverse order and will need moving before the previous
-      # route once that is fixed:
-      #
-      # https://github.com/systemd/systemd/issues/5430
-      # https://github.com/systemd/systemd/pull/10938
-      if interface[:family] == "inet6" &&
-         !interface[:network].include?(interface[:gateway]) &&
-         !IPAddr.new("fe80::/64").include?(interface[:gateway])
-        deviceplan["routes"].push(
-          "to" => interface[:gateway],
-          "scope" => "link"
-        )
+      if server[:networking][:private_address]
+        allowed_ips << "#{server[:networking][:private_address]}/32"
       end
+
+      node.default[:networking][:wireguard][:peers] << {
+        :public_key => server[:networking][:wireguard][:public_key],
+        :allowed_ips => allowed_ips,
+        :endpoint => "#{server.name}:51820"
+      }
+    end
+
+    node.default[:networking][:wireguard][:peers] << {
+      :public_key => "7Oj9ufNlgidyH/xDc+aHQKMjJPqTmD/ab13agMh6AxA=",
+      :allowed_ips => "10.0.16.1/32",
+      :endpoint => "gate.compton.nu:51820"
+    }
+
+    # Grant home
+    node.default[:networking][:wireguard][:peers] << {
+      :public_key => "RofATnvlWxP3mt87+QKRXFE5MVxtoCcTsJ+yftZYEE4=",
+      :allowed_ips => "10.89.122.1/32",
+      :endpoint => "gate.firefishy.com:51820"
+    }
+
+    # Grant roaming
+    node.default[:networking][:wireguard][:peers] << {
+      :public_key => "YbUkREE9TAmomqgL/4Fh2e5u2Hh7drN/2o5qg3ndRxg=",
+      :allowed_ips => "10.89.123.1/32",
+      :endpoint => "roaming.firefishy.com:51820"
+    }
+  elsif node[:roles].include?("shenron")
+    search(:node, "roles:gateway") do |gateway|
+      allowed_ips = gateway.ipaddresses(:role => :internal).map(&:subnet)
+
+      node.default[:networking][:wireguard][:peers] << {
+        :public_key => gateway[:networking][:wireguard][:public_key],
+        :allowed_ips => allowed_ips,
+        :endpoint => "#{gateway.name}:51820"
+      }
     end
-  else
-    node.rm(:networking, :interfaces, name)
   end
-end
 
-netplan["network"]["bonds"].each_value do |bond|
-  bond["interfaces"].each do |interface|
-    netplan["network"]["ethernets"][interface] ||= { "accept-ra" => false }
+  file "/etc/systemd/network/wireguard.netdev" do
+    action :delete
   end
-end
 
-netplan["network"]["vlans"].each_value do |vlan|
-  unless vlan["link"] =~ /^bond\d+$/
-    netplan["network"]["ethernets"][vlan["link"]] ||= { "accept-ra" => false }
+  template "/etc/systemd/network/10-wg0.netdev" do
+    source "wireguard.netdev.erb"
+    owner "root"
+    group "systemd-network"
+    mode "640"
+    notifies :run, "execute[networkctl-delete-wg0]"
+    notifies :run, "notify_group[networkctl-reload]"
   end
-end
 
-file "/etc/netplan/01-netcfg.yaml" do
-  action :delete
-end
+  file "/etc/systemd/network/wireguard.network" do
+    action :delete
+  end
 
-file "/etc/netplan/50-cloud-init.yaml" do
-  action :delete
+  template "/etc/systemd/network/10-wg0.network" do
+    source "wireguard.network.erb"
+    owner "root"
+    group "root"
+    mode "644"
+    notifies :run, "execute[networkctl-reload]"
+  end
+
+  execute "networkctl-delete-wg0" do
+    action :nothing
+    command "networkctl delete wg0"
+    only_if { ::File.exist?("/sys/class/net/wg0") }
+  end
 end
 
-file "/etc/netplan/99-chef.yaml" do
+# Setup dokken network in systemd-networkd to avoid systemd-networkd-wait-online delay
+template "/etc/systemd/network/dokken.network" do
+  source "dokken.network.erb"
   owner "root"
   group "root"
-  mode 0o644
-  content YAML.dump(netplan)
+  mode "644"
+  notifies :run, "execute[networkctl-reload]", :immediately
+  only_if { kitchen? }
 end
 
-package "cloud-init" do
-  action :purge
+notify_group "networkctl-reload"
+
+execute "networkctl-reload" do
+  action :nothing
+  command "networkctl reload"
+  subscribes :run, "notify_group[networkctl-reload]"
 end
 
-execute "hostname" do
+ohai "reload-hostname" do
   action :nothing
-  command "/bin/hostname -F /etc/hostname"
+  plugin "hostname"
 end
 
-template "/etc/hostname" do
-  source "hostname.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  notifies :run, "execute[hostname]"
+execute "hostnamectl-set-hostname" do
+  command "hostnamectl set-hostname #{node[:networking][:hostname]}"
+  notifies :reload, "ohai[reload-hostname]"
+  not_if { kitchen? || node[:hostnamectl][:static_hostname] == node[:networking][:hostname] }
 end
 
 template "/etc/hosts" do
   source "hosts.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
+  not_if { kitchen? }
 end
 
 service "systemd-resolved" do
@@ -187,302 +310,118 @@ end
 directory "/etc/systemd/resolved.conf.d" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 template "/etc/systemd/resolved.conf.d/99-chef.conf" do
   source "resolved.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
-  notifies :restart, "service[systemd-resolved]"
+  mode "644"
+  notifies :restart, "service[systemd-resolved]", :immediately
 end
 
-if node[:networking][:tcp_fastopen_key]
-  fastopen_keys = data_bag_item("networking", "fastopen")
-
-  node.normal[:sysctl][:tcp_fastopen] = {
-    :comment => "Set shared key for TCP fast open",
-    :parameters => {
-      "net.ipv4.tcp_fastopen_key" => fastopen_keys[node[:networking][:tcp_fastopen_key]]
-    }
-  }
-end
-
-node.interfaces(:role => :internal) do |interface|
-  if interface[:gateway] && interface[:gateway] != interface[:address]
-    search(:node, "networking_interfaces*address:#{interface[:gateway]}") do |gateway|
-      next unless gateway[:openvpn]
-
-      gateway[:openvpn][:tunnels].each_value do |tunnel|
-        if tunnel[:peer][:address]
-          route tunnel[:peer][:address] do
-            netmask "255.255.255.255"
-            gateway interface[:gateway]
-            device interface[:interface]
-          end
-        end
-
-        next unless tunnel[:peer][:networks]
-
-        tunnel[:peer][:networks].each do |network|
-          route network[:address] do
-            netmask network[:netmask]
-            gateway interface[:gateway]
-            device interface[:interface]
-          end
-        end
-      end
-    end
+if node[:filesystem][:by_mountpoint][:"/etc/resolv.conf"]
+  execute "umount-resolve-conf" do
+    command "umount -c /etc/resolv.conf"
   end
 end
 
-zones = {}
+link "/etc/resolv.conf" do
+  to "../run/systemd/resolve/stub-resolv.conf"
+end
+
+hosts = { :inet => [], :inet6 => [] }
 
 search(:node, "networking:interfaces").collect do |n|
   next if n[:fqdn] == node[:fqdn]
 
   n.interfaces.each do |interface|
-    next unless interface[:role] == "external" && interface[:zone]
+    next unless interface[:role] == "external"
 
-    zones[interface[:zone]] ||= {}
-    zones[interface[:zone]][interface[:family]] ||= []
-    zones[interface[:zone]][interface[:family]] << interface[:address]
+    hosts[:inet] << interface[:inet][:address] if interface[:inet]
+    hosts[:inet6] << interface[:inet6][:address] if interface[:inet6]
   end
 end
 
-package "shorewall"
-
-template "/etc/default/shorewall" do
-  source "shorewall-default.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  notifies :restart, "service[shorewall]"
-end
-
-template "/etc/shorewall/shorewall.conf" do
-  source "shorewall.conf.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  notifies :restart, "service[shorewall]"
-end
-
-template "/etc/shorewall/zones" do
-  source "shorewall-zones.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :type => "ipv4"
-  notifies :restart, "service[shorewall]"
-end
+package "nftables"
 
-template "/etc/shorewall/interfaces" do
-  source "shorewall-interfaces.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  notifies :restart, "service[shorewall]"
-end
+interfaces = []
 
-template "/etc/shorewall/hosts" do
-  source "shorewall-hosts.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :zones => zones
-  notifies :restart, "service[shorewall]"
+node.interfaces(:role => :external).each do |interface|
+  interfaces << interface[:interface]
 end
 
-template "/etc/shorewall/conntrack" do
-  source "shorewall-conntrack.erb"
+template "/etc/nftables.conf" do
+  source "nftables.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
-  notifies :restart, "service[shorewall]"
-  only_if { node[:networking][:firewall][:raw] }
+  mode "755"
+  variables :interfaces => interfaces, :hosts => hosts
+  notifies :reload, "service[nftables]"
 end
 
-template "/etc/shorewall/policy" do
-  source "shorewall-policy.erb"
+directory "/var/lib/nftables" do
   owner "root"
   group "root"
-  mode 0o644
-  notifies :restart, "service[shorewall]"
+  mode "755"
 end
 
-template "/etc/shorewall/rules" do
-  source "shorewall-rules.erb"
+template "/usr/local/bin/nftables" do
+  source "nftables.erb"
   owner "root"
   group "root"
-  mode 0o644
-  variables :family => "inet"
-  notifies :restart, "service[shorewall]"
+  mode "755"
 end
 
-service "shorewall" do
-  action [:enable, :start]
-  supports :restart => true
-  status_command "shorewall status"
-end
-
-template "/etc/logrotate.d/shorewall" do
-  source "logrotate.shorewall.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :name => "shorewall"
-end
-
-firewall_rule "limit-icmp-echo" do
-  action :accept
-  family :inet
-  source "net"
-  dest "fw"
-  proto "icmp"
-  dest_ports "echo-request"
-  rate_limit "s:1/sec:5"
+systemd_service "nftables-stop" do
+  action :delete
+  service "nftables"
+  dropin "stop"
 end
 
-%w[ucl ams bm].each do |zone|
-  firewall_rule "accept-openvpn-#{zone}" do
-    action :accept
-    source zone
-    dest "fw"
-    proto "udp"
-    dest_ports "1194:1197"
-    source_ports "1194:1197"
-  end
+systemd_service "nftables-chef" do
+  service "nftables"
+  dropin "chef"
+  exec_start "/usr/local/bin/nftables start"
+  exec_reload "/usr/local/bin/nftables reload"
+  exec_stop "/usr/local/bin/nftables stop"
 end
 
-if node[:roles].include?("gateway")
-  template "/etc/shorewall/masq" do
-    source "shorewall-masq.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    notifies :restart, "service[shorewall]"
+if node[:networking][:firewall][:enabled]
+  service "nftables" do
+    action [:enable, :start]
   end
 else
-  file "/etc/shorewall/masq" do
-    action :delete
-    notifies :restart, "service[shorewall]"
+  service "nftables" do
+    action [:disable, :stop]
   end
 end
 
-unless node.interfaces(:family => :inet6).empty?
-  package "shorewall6"
-
-  template "/etc/default/shorewall6" do
-    source "shorewall-default.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    notifies :restart, "service[shorewall6]"
-  end
-
-  template "/etc/shorewall6/shorewall6.conf" do
-    source "shorewall6.conf.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    notifies :restart, "service[shorewall6]"
-  end
-
-  template "/etc/shorewall6/zones" do
-    source "shorewall-zones.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    variables :type => "ipv6"
-    notifies :restart, "service[shorewall6]"
-  end
-
-  template "/etc/shorewall6/interfaces" do
-    source "shorewall6-interfaces.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    notifies :restart, "service[shorewall6]"
-  end
-
-  template "/etc/shorewall6/hosts" do
-    source "shorewall6-hosts.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    variables :zones => zones
-    notifies :restart, "service[shorewall6]"
-  end
-
-  template "/etc/shorewall6/conntrack" do
-    source "shorewall-conntrack.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    notifies :restart, "service[shorewall6]"
-    only_if { node[:networking][:firewall][:raw] }
-  end
-
-  template "/etc/shorewall6/policy" do
-    source "shorewall-policy.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    notifies :restart, "service[shorewall6]"
-  end
-
-  template "/etc/shorewall6/rules" do
-    source "shorewall-rules.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    variables :family => "inet6"
-    notifies :restart, "service[shorewall6]"
-  end
-
-  service "shorewall6" do
-    action [:enable, :start]
-    supports :restart => true
-    status_command "shorewall6 status"
-  end
-
-  template "/etc/logrotate.d/shorewall6" do
-    source "logrotate.shorewall.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    variables :name => "shorewall6"
-  end
-
-  firewall_rule "limit-icmp6-echo" do
+if node[:networking][:wireguard][:enabled]
+  firewall_rule "accept-wireguard" do
     action :accept
-    family :inet6
-    source "net"
-    dest "fw"
-    proto "ipv6-icmp"
-    dest_ports "echo-request"
-    rate_limit "s:1/sec:5"
+    context :incoming
+    protocol :udp
+    source :osm unless node[:roles].include?("gateway")
+    dest_ports "51820"
+    source_ports "51820"
   end
 end
 
-firewall_rule "accept-http" do
+firewall_rule "accept-http-osm" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "tcp:syn"
-  dest_ports "http"
-  rate_limit node[:networking][:firewall][:http_rate_limit]
-  connection_limit node[:networking][:firewall][:http_connection_limit]
+  context :incoming
+  protocol :tcp
+  source :osm
+  dest_ports %w[http https]
 end
 
-firewall_rule "accept-https" do
+firewall_rule "accept-http" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "tcp:syn"
-  dest_ports "https"
+  context :incoming
+  protocol :tcp
+  dest_ports %w[http https]
   rate_limit node[:networking][:firewall][:http_rate_limit]
   connection_limit node[:networking][:firewall][:http_connection_limit]
 end
diff --git a/cookbooks/networking/resources/firewall_rule.rb b/cookbooks/networking/resources/firewall_rule.rb
new file mode 100644 (file)
index 0000000..22bde6c
--- /dev/null
@@ -0,0 +1,148 @@
+#
+# Cookbook:: networking
+# Resource:: firewall_rule
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "ipaddr"
+
+resource_name :firewall_rule
+provides :firewall_rule
+
+unified_mode true
+
+default_action :nothing
+
+property :rule, :kind_of => String, :name_property => true
+property :context, :kind_of => Symbol, :required => true, :is => [:incoming, :outgoing]
+property :protocol, :kind_of => Symbol, :required => true, :is => [:udp, :tcp]
+property :source, :kind_of => [String, Symbol, Array]
+property :dest, :kind_of => [String, Symbol, Array]
+property :dest_ports, :kind_of => [String, Integer, Array]
+property :source_ports, :kind_of => [String, Integer, Array]
+property :rate_limit, :kind_of => String
+property :connection_limit, :kind_of => [String, Integer]
+property :helper, :kind_of => String
+
+property :compile_time, TrueClass, :default => true
+
+action :accept do
+  add_rule(:accept, "ip")
+  add_rule(:accept, "ip6")
+end
+
+action :drop do
+  add_rule(:drop, "ip")
+  add_rule(:drop, "ip6")
+end
+
+action :reject do
+  add_rule(:reject, "ip")
+  add_rule(:reject, "ip6")
+end
+
+action_class do
+  def add_rule(action, ip)
+    rule = []
+
+    protocol = new_resource.protocol.to_s
+
+    source = addresses(new_resource.source, ip)
+    dest = addresses(new_resource.dest, ip)
+
+    return if new_resource.source && source.empty?
+    return if new_resource.dest && dest.empty?
+
+    rule << "#{protocol} sport #{format_ports(new_resource.source_ports)}"  if new_resource.source_ports
+    rule << "#{protocol} dport #{format_ports(new_resource.dest_ports)}" if new_resource.dest_ports
+    rule << "#{ip} saddr #{format_addresses(source, ip)}" if new_resource.source
+    rule << "#{ip} daddr #{format_addresses(dest, ip)}" if new_resource.dest
+    rule << "ct state new" if new_resource.protocol == :tcp
+
+    if new_resource.connection_limit
+      set = "connlimit-#{new_resource.rule}-#{ip}"
+
+      node.default[:networking][:firewall][:sets] << {
+        :name => set, :type => set_type(ip), :flags => %w[dynamic]
+      }
+
+      rule << "add @#{set} { #{ip} saddr ct count #{new_resource.connection_limit} }"
+    end
+
+    if new_resource.rate_limit =~ %r{^s:(\d+)/sec:(\d+)$}
+      set = "ratelimit-#{new_resource.rule}-#{ip}"
+      rate = Regexp.last_match(1)
+      burst = Regexp.last_match(2)
+
+      node.default[:networking][:firewall][:sets] << {
+        :name => set, :type => set_type(ip), :flags => %w[dynamic], :timeout => 120
+      }
+
+      rule << "update @#{set} { #{ip} saddr limit rate #{rate}/second burst #{burst} packets }"
+    end
+
+    if new_resource.helper
+      helper = "#{new_resource.rule}-#{new_resource.helper}"
+
+      node.default[:networking][:firewall][:helpers] << {
+        :name => helper, :helper => new_resource.helper, :protocol => protocol
+      }
+
+      rule << "ct helper set #{helper}"
+    end
+
+    rule << case action
+            when :accept then "accept"
+            when :drop then "jump log-and-drop"
+            when :reject then "jump log-and-reject"
+            end
+
+    node.default[:networking][:firewall][new_resource.context] << rule.join(" ")
+  end
+
+  def addresses(addresses, ip)
+    if addresses.is_a?(Symbol)
+      addresses
+    else
+      Array(addresses).map do |address|
+        if ip == "ip" && IPAddr.new(address.to_s).ipv4?
+          address
+        elsif ip == "ip6" && IPAddr.new(address.to_s).ipv6?
+          address
+        end
+      end.compact
+    end
+  end
+
+  def format_ports(ports)
+    "{ #{Array(ports).map(&:to_s).join(', ')} }"
+  end
+
+  def format_addresses(addresses, ip)
+    if addresses.is_a?(Symbol)
+      "@#{ip}-#{addresses}-addresses"
+    else
+      "{ #{Array(addresses).map(&:to_s).join(', ')} }"
+    end
+  end
+
+  def set_type(ip)
+    case ip
+    when "ip" then "ipv4_addr"
+    when "ip6" then "ipv6_addr"
+    end
+  end
+end
diff --git a/cookbooks/networking/templates/default/bond.netdev.erb b/cookbooks/networking/templates/default/bond.netdev.erb
new file mode 100644 (file)
index 0000000..971d127
--- /dev/null
@@ -0,0 +1,15 @@
+[NetDev]
+Name=<%= @interface[:interface] %>
+Kind=bond
+
+[Bond]
+Mode=<%= @interface[:bond][:mode] || "active-backup" %>
+<% if @interface[:bond][:xmithashpolicy] -%>
+TransmitHashPolicy=<%= @interface[:bond][:xmithashpolicy] %>
+<% end -%>
+<% if @interface[:bond][:lacprate] -%>
+LACPTransmitRate=<%= @interface[:bond][:lacprate] %>
+<% end -%>
+MIIMonitorSec=<%= @interface[:bond][:miimon] || "100ms" %>
+UpDelaySec=<%= @interface[:bond][:updelay] || "200ms" %>
+DownDelaySec=<%= @interface[:bond][:downdelay] || "200ms" %>
diff --git a/cookbooks/networking/templates/default/dokken.network.erb b/cookbooks/networking/templates/default/dokken.network.erb
new file mode 100644 (file)
index 0000000..bf46c95
--- /dev/null
@@ -0,0 +1,10 @@
+[Match]
+Name=eth0
+
+[Link]
+RequiredForOnline=routable
+
+[Network]
+DHCP=no
+LinkLocalAddressing=no
+KeepConfiguration=yes
diff --git a/cookbooks/networking/templates/default/hostname.erb b/cookbooks/networking/templates/default/hostname.erb
deleted file mode 100644 (file)
index 9842667..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<%= node[:fqdn] %>
diff --git a/cookbooks/networking/templates/default/network.erb b/cookbooks/networking/templates/default/network.erb
new file mode 100644 (file)
index 0000000..796bf67
--- /dev/null
@@ -0,0 +1,106 @@
+[Match]
+Name=<%= @interface[:interface] %>
+
+[Network]
+<% if @interface.dig(:inet6, :dhcp) -%>
+DHCP=ipv6
+<% end -%>
+<% if @interface[:inet] -%>
+Address=<%= @interface[:inet][:address] %>/<%== @interface[:inet][:prefix] %>
+<% end -%>
+<% if @interface[:inet6] -%>
+Address=<%= @interface[:inet6][:address] %>/<%== @interface[:inet6][:prefix] %>
+<% end -%>
+IPv6AcceptRA=no
+<% Array(@interface[:vlans]).sort.uniq.each do |vlan| -%>
+VLAN=<%= @interface[:interface] %>.<%= vlan %>
+<% end -%>
+<% if @interface.dig(:inet6, :dhcp) -%>
+
+[DHCPv6]
+<% if @interface[:inet6][:dhcp][:duidtype] -%>
+DUIDType=<%= @interface[:inet6][:dhcp][:duidtype] %>
+<% end -%>
+<% if @interface[:inet6][:dhcp][:duidrawdata] -%>
+DUIDRawData=<%= @interface[:inet6][:dhcp][:duidrawdata] %>
+<% end -%>
+WithoutRA=solicit
+<% end -%>
+<% if @interface.dig(:inet, :gateway) && @interface[:inet][:gateway] != @interface[:inet][:address] -%>
+
+[Route]
+Gateway=<%= @interface[:inet][:gateway] %>
+GatewayOnLink=true
+<% if @interface[:metric] -%>
+Metric=<%= @interface[:metric] %>
+<% end -%>
+<% if @interface[:source_route_table] -%>
+
+[Route]
+Gateway=<%= @interface[:inet][:gateway] %>
+GatewayOnLink=true
+<% if @interface[:metric] -%>
+Metric=<%= @interface[:metric] %>
+<% end -%>
+Table=<%= @interface[:source_route_table] %>
+
+[RoutingPolicyRule]
+From=<%= @interface[:inet][:address] %>
+Table=<%= @interface[:source_route_table] %>
+<% end -%>
+<% end -%>
+<% if @interface.dig(:inet6, :gateway) && @interface[:inet6][:gateway] != @interface[:inet6][:address] -%>
+
+[Route]
+Gateway=<%= @interface[:inet6][:gateway] %>
+GatewayOnLink=true
+<% if @interface[:metric] -%>
+Metric=<%= @interface[:metric] %>
+<% end -%>
+<% if @interface[:source_route_table] -%>
+
+[Route]
+Gateway=<%= @interface[:inet6][:gateway] %>
+GatewayOnLink=true
+<% if @interface[:metric] -%>
+Metric=<%= @interface[:metric] %>
+<% end -%>
+Table=<%= @interface[:source_route_table] %>
+
+[RoutingPolicyRule]
+From=<%= @interface[:inet6][:address] %>
+Table=<%= @interface[:source_route_table] %>
+<% end -%>
+<% end -%>
+<% Hash(@interface.dig(:inet, :routes)).sort.each do |destination, details| -%>
+<% unless details[:via] == @interface[:inet][:address] -%>
+
+[Route]
+<% if details[:via] -%>
+Gateway=<%= details[:via] %>
+<% end -%>
+Destination=<%= destination %>
+<% if details[:metric] -%>
+Metric=<%= details[:metric] %>
+<% end -%>
+<% if details[:type] -%>
+Type=<%= details[:type] %>
+<% end -%>
+<% end -%>
+<% end -%>
+<% Hash(@interface.dig(:inet6, :routes)).sort.each do |destination, details| -%>
+<% unless details[:via] == @interface[:inet6][:address] -%>
+
+[Route]
+<% if details[:via] -%>
+Gateway=<%= details[:via] %>
+<% end -%>
+Destination=<%= destination %>
+<% if details[:metric] -%>
+Metric=<%= details[:metric] %>
+<% end -%>
+<% if details[:type] -%>
+Type=<%= details[:type] %>
+<% end -%>
+<% end -%>
+<% end -%>
diff --git a/cookbooks/networking/templates/default/nftables.conf.erb b/cookbooks/networking/templates/default/nftables.conf.erb
new file mode 100644 (file)
index 0000000..7273cff
--- /dev/null
@@ -0,0 +1,174 @@
+#!/usr/sbin/nft -f
+
+<% unless @interfaces.empty? -%>
+define external-interfaces = { <%= @interfaces.sort.uniq.join(", ") %> }
+<% end -%>
+
+define ip-private-addresses = { 0.0.0.0, 10.0.0.0/8, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.2.0/24, 192.168.0.0/16 }
+define ip-multicast-addresses = { 224.0.0.0/4 }
+define ip6-private-addresses = { 2001:db8::/32, fc00::/7 }
+define ip6-multicast-addresses = { ff00::/8 }
+
+table inet chef-filter {
+  set ip-osm-addresses {
+    type ipv4_addr
+<% unless Array(@hosts[:inet]).empty? -%>
+    elements = { <%= Array(@hosts[:inet]).sort.join(", ") %> }
+<% end -%>
+  }
+
+  set ip6-osm-addresses {
+    type ipv6_addr
+<% unless Array(@hosts[:inet6]).empty? -%>
+    elements = { <%= Array(@hosts[:inet6]).sort.join(", ") %> }
+<% end -%>
+  }
+
+  set ip-blocklist {
+    type ipv4_addr
+    flags interval
+  }
+
+  set ip6-blocklist {
+    type ipv6_addr
+    flags interval
+  }
+
+  set ratelimit-icmp-echo-ip {
+    type ipv4_addr
+    flags dynamic
+    timeout 120s
+  }
+
+  set ratelimit-icmp-echo-ip6 {
+    type ipv6_addr
+    flags dynamic
+    timeout 120s
+  }
+
+<% node[:networking][:firewall][:sets].each do |set| -%>
+  set <%= set[:name] %> {
+    type <%= set[:type] %>
+<% if set[:flags] -%>
+    flags <%= set[:flags].join(", ") %>
+<% end -%>
+<% if set[:timeout] -%>
+    timeout <%= set[:timeout] %>s
+<% end -%>
+  }
+
+<% end -%>
+
+<% node[:networking][:firewall][:helpers].each do |helper| -%>
+  ct helper <%= helper[:name] %> {
+    type "<%= helper[:helper] %>" protocol <%= helper[:protocol] %>
+  }
+
+<% end -%>
+  chain log-and-drop {
+    limit rate 1/second log
+    drop
+  }
+
+  chain log-and-reject {
+    limit rate 1/second log
+    reject
+  }
+
+  chain incoming {
+<% if node[:networking][:firewall][:allowlist].empty? -%>
+    ip saddr { $ip-private-addresses, $ip-multicast-addresses } jump log-and-drop
+<% else -%>
+    ip saddr { $ip-private-addresses, $ip-multicast-addresses } ip saddr != { <%= node[:networking][:firewall][:allowlist].sort.join(", ") %> } jump log-and-drop
+<% end -%>
+    ip6 saddr { $ip6-private-addresses, $ip6-multicast-addresses } jump log-and-drop
+
+    ip saddr @ip-blocklist jump log-and-drop
+    ip6 saddr @ip6-blocklist jump log-and-drop
+
+    icmp type { echo-request } update @ratelimit-icmp-echo-ip { ip saddr limit rate 1/second } accept
+    icmp type { echo-request } drop
+
+    icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert, nd-router-solicit, nd-router-advert } accept
+    icmpv6 type { echo-request } update @ratelimit-icmp-echo-ip6 { ip6 saddr limit rate 1/second } accept
+    icmpv6 type { echo-request } drop
+
+    ct state { established, related } accept
+
+    meta l4proto { icmp, icmpv6 } jump log-and-drop
+
+    tcp flags & (fin|syn|rst|psh|ack|urg) == fin|psh|urg jump log-and-drop
+    tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 jump log-and-drop
+    tcp flags & (syn|rst) == syn|rst jump log-and-drop
+    tcp flags & (fin|rst) == fin|rst jump log-and-drop
+    tcp flags & (fin|syn) == fin|syn jump log-and-drop
+    tcp flags & (fin|psh|ack) == fin|psh jump log-and-drop
+    tcp sport 0 tcp flags & (fin|syn|rst|ack) == syn jump log-and-drop
+
+<% node[:networking][:firewall][:incoming].uniq.each do |rule| -%>
+    <%= rule %>
+<% end -%>
+
+    jump log-and-drop
+  }
+
+  chain outgoing {
+<% if node[:networking][:firewall][:allowlist].empty? -%>
+    ip daddr { $ip-private-addresses } jump log-and-drop
+<% else -%>
+    ip daddr { $ip-private-addresses } ip daddr != { <%= node[:networking][:firewall][:allowlist].sort.join(", ") %> } jump log-and-drop
+<% end -%>
+    ip6 daddr { $ip6-private-addresses } jump log-and-drop
+
+<% node[:networking][:firewall][:outgoing].each do |rule| -%>
+    <%= rule %>
+<% end -%>
+
+    accept
+  }
+
+  chain input {
+    type filter hook input priority filter;
+
+<% unless @interfaces.empty? -%>
+    iifname { $external-interfaces } jump incoming
+<% end -%>
+
+    accept
+  }
+
+  chain forward {
+    type filter hook forward priority filter;
+
+<% unless @interfaces.empty? -%>
+    iifname { $external-interfaces } jump incoming
+    oifname { $external-interfaces } jump outgoing
+<% end -%>
+
+    accept
+  }
+
+  chain output {
+    type filter hook output priority filter;
+
+<% unless @interfaces.empty? -%>
+    oifname { $external-interfaces } jump outgoing
+<% end -%>
+
+    accept
+  }
+}
+<% if node[:roles].include?("gateway") -%>
+
+table ip chef-nat {
+  chain postrouting {
+    type nat hook postrouting priority srcnat;
+
+<% node.interfaces(:role => :external).each do |external| -%>
+<% node.ipaddresses(:role => :internal, :family => :inet).each do |internal| -%>
+    oifname { <%= external[:interface] %> } ip saddr { <%= internal.subnet %> } snat <%= external[:inet][:address] %>
+<% end -%>
+<% end -%>
+  }
+}
+<% end -%>
diff --git a/cookbooks/networking/templates/default/nftables.erb b/cookbooks/networking/templates/default/nftables.erb
new file mode 100644 (file)
index 0000000..363e846
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/sh -e
+
+start() {
+  /usr/sbin/nft -f /etc/nftables.conf
+  [ -f /var/lib/nftables/ip-blocklist.nft ] && /usr/sbin/nft -f /var/lib/nftables/ip-blocklist.nft || :
+  [ -f /var/lib/nftables/ip6-blocklist.nft ] && /usr/sbin/nft -f /var/lib/nftables/ip6-blocklist.nft || :
+}
+
+stop() {
+  /usr/sbin/nft list set inet chef-filter ip-blocklist > /var/lib/nftables/ip-blocklist.nft
+  /usr/sbin/nft list set inet chef-filter ip6-blocklist > /var/lib/nftables/ip6-blocklist.nft
+  /usr/sbin/nft delete table inet chef-filter
+<% if node[:roles].include?("gateway") -%>
+  /usr/sbin/nft delete table ip chef-nat
+<% end -%>
+}
+
+reload() {
+  stop
+  start
+}
+
+block() {
+  for address in "$@"
+  do
+    case "$address" in
+      *.*) /usr/sbin/nft --check add element inet chef-filter ip-blocklist "{ $address }" && /usr/sbin/nft add element inet chef-filter ip-blocklist "{ $address }" ;;
+      *:*) /usr/sbin/nft --check add element inet chef-filter ip6-blocklist "{ $address }" && /usr/sbin/nft add element inet chef-filter ip6-blocklist "{ $address }" ;;
+    esac
+  done
+}
+
+unblock() {
+  for address in "$@"
+  do
+    case "$address" in
+      *.*) /usr/sbin/nft --check delete element inet chef-filter ip-blocklist "{ $address }" && /usr/sbin/nft delete element inet chef-filter ip-blocklist "{ $address }" ;;
+      *:*) /usr/sbin/nft --check delete element inet chef-filter ip6-blocklist "{ $address }" && /usr/sbin/nft delete element inet chef-filter ip6-blocklist "{ $address }" ;;
+    esac
+  done
+}
+
+flush() {
+  /usr/sbin/nft --check flush set inet chef-filter ip-blocklist && /usr/sbin/nft flush set inet chef-filter ip-blocklist
+  /usr/sbin/nft --check flush set inet chef-filter ip6-blocklist && /usr/sbin/nft flush set inet chef-filter ip6-blocklist
+}
+
+command=$1
+shift
+
+case "$command" in
+  start) start;;
+  stop) stop;;
+  reload) reload;;
+  block) block "$@";;
+  unblock) unblock "$@";;
+  flush) flush;;
+esac
+
+exit 0
index 035d692dfe515ef95af13a31347d5648f83b5b95..d57e78828ff1674412cf954c770d66c5d01d702f 100644 (file)
@@ -2,4 +2,4 @@
 DNS=<%= node[:networking][:nameservers].join(" ") %>
 FallbackDNS=1.1.1.1 9.9.9.10 8.8.8.8 2606:4700:4700::1111 2620:fe::10 2001:4860:4860::8888
 Domains=<%= node[:networking][:search].join(" ") %>
-DNSSEC=allow-downgrade
+DNSSEC=<%= node[:networking][:dnssec] %>
diff --git a/cookbooks/networking/templates/default/shorewall-conntrack.erb b/cookbooks/networking/templates/default/shorewall-conntrack.erb
deleted file mode 100644 (file)
index 4d5e726..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-?FORMAT 3
-
-# ACTION       SOURCE  DEST    PROTO   DPORT   SPORT   USER    SWITCH
-NOTRACK:P      lo      -       -       -       -       -       -
-NOTRACK:O      -       lo      -       -       -       -       -
diff --git a/cookbooks/networking/templates/default/shorewall-default.erb b/cookbooks/networking/templates/default/shorewall-default.erb
deleted file mode 100644 (file)
index 03f3ffc..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Allow shorewall to start
-startup=1
-
-# Program options
-OPTIONS=""
diff --git a/cookbooks/networking/templates/default/shorewall-hosts.erb b/cookbooks/networking/templates/default/shorewall-hosts.erb
deleted file mode 100644 (file)
index 86c294c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# ZONE HOST                    OPTIONS
-<% node.interfaces(:family => :inet, :role => :external).each do |interface| -%>
-<% if interface[:interface] -%>
-<% @zones.keys.sort.each do |zone| -%>
-<% if @zones[zone]["inet"] -%>
-<% @zones[zone]["inet"].sort.each do |ra| -%>
-<%= zone %>    <%= interface[:interface] %>:<%= ra %>
-<% end -%>
-<% end -%>
-<% end -%>
-<% end -%>
-<% end -%>
diff --git a/cookbooks/networking/templates/default/shorewall-interfaces.erb b/cookbooks/networking/templates/default/shorewall-interfaces.erb
deleted file mode 100644 (file)
index 4701b96..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-?FORMAT 2
-
-# ZONE INTERFACE       OPTIONS
-<% node[:networking][:interfaces].each do |name,interface| -%>
-<% if interface[:interface] && interface[:family] == "inet" -%>
-<% if interface[:role] == "internal" -%>
-loc    <%= interface[:interface] %>            nosmurfs,tcpflags
-<% elsif interface[:role] == "external" -%>
-net    <%= interface[:interface] %>            nosmurfs,tcpflags
-<% end -%>
-<% end -%>
-<% end -%>
-loc    tun+            nosmurfs,tcpflags
diff --git a/cookbooks/networking/templates/default/shorewall-masq.erb b/cookbooks/networking/templates/default/shorewall-masq.erb
deleted file mode 100644 (file)
index 856f60e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# INTERFACE    SOURCE          ADDRESS
-<% node.interfaces(:role => :external).each do |external| -%>
-<% node.interfaces(:role => :internal).each do |internal| -%>
-<%= external[:interface] %>            <%= internal[:network] %>/<%= internal[:prefix] %>      detect
-<% end -%>
-<% end -%>
diff --git a/cookbooks/networking/templates/default/shorewall-policy.erb b/cookbooks/networking/templates/default/shorewall-policy.erb
deleted file mode 100644 (file)
index 4f29377..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# FROM         TO              POLICY          LOG LEVEL       BURST:LIMIT
-net            all             DROP
-all            all             ACCEPT
diff --git a/cookbooks/networking/templates/default/shorewall-rules.erb b/cookbooks/networking/templates/default/shorewall-rules.erb
deleted file mode 100644 (file)
index c5101be..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-?SECTION NEW
-
-# ACTION       SOURCE    DEST  PROTO           DEST            SOURCE  ORIGINAL        RATE    USER/   MARK    CONNLIMIT  TIME  HEADERS  SWITCH  HELPER
-#                                              PORTS           PORTS   DEST            LIMIT   GROUP
-<% node[:networking][:firewall][@family].each do |r| # ~FC034 -%>
-<%= r[:action] %>              <%= r[:source] %>       <%= r[:dest] %> <%= r[:proto] %>                <%= r[:dest_ports] %>   <%= r[:source_ports] %> -       <%= r[:rate_limit] %>   -       -       <%= r[:connection_limit] %> -   -       - <%= r[:helper] %>
-<% end -%>
diff --git a/cookbooks/networking/templates/default/shorewall-zones.erb b/cookbooks/networking/templates/default/shorewall-zones.erb
deleted file mode 100644 (file)
index b91e46f..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# ZONE         TYPE            OPTIONS         IN OPTIONS      OUT OPTIONS
-fw             firewall
-loc            <%= @type %>
-net            <%= @type %>
-osm:net                <%= @type %>
-ucl:osm                <%= @type %>
-ic:osm         <%= @type %>
-ams:osm                <%= @type %>
-bm:osm         <%= @type %>
-ts:osm         <%= @type %>
-yx:osm         <%= @type %>
-ra:osm         <%= @type %>
-pa:osm         <%= @type %>
-bx:osm         <%= @type %>
-ff:osm         <%= @type %>
-pr:osm         <%= @type %>
-ly:osm         <%= @type %>
-ov:osm         <%= @type %>
-hz:osm         <%= @type %>
-bh:osm         <%= @type %>
-dt:osm         <%= @type %>
-nc:osm         <%= @type %>
-ool:osm                <%= @type %>
-cnt:osm                <%= @type %>
-jn:osm         <%= @type %>
-es:osm         <%= @type %>
-sz:osm         <%= @type %>
-ex:osm         <%= @type %>
-dh:osm         <%= @type %>
-aws:osm                <%= @type %>
-ds:osm         <%= @type %>
-uz:osm          <%= @type %>
-ovh:osm         <%= @type %>
-ffr:osm         <%= @type %>
-ixz:osm         <%= @type %>
-grn:osm         <%= @type %>
-g5s:osm         <%= @type %>
-na:osm          <%= @type %>
-tnn:osm         <%= @type %>
-av:osm          <%= @type %>
-grf:osm         <%= @type %>
diff --git a/cookbooks/networking/templates/default/shorewall.conf.erb b/cookbooks/networking/templates/default/shorewall.conf.erb
deleted file mode 100644 (file)
index 290c73f..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-###############################################################################
-#                     S T A R T U P   E N A B L E D
-###############################################################################
-
-STARTUP_ENABLED=Yes
-
-###############################################################################
-#                            V E R B O S I T Y
-###############################################################################
-
-VERBOSITY=1
-
-###############################################################################
-#                              P A G E R
-###############################################################################
-
-PAGER=
-
-###############################################################################
-#                           F I R E W A L L
-###############################################################################
-
-FIREWALL=
-
-###############################################################################
-#                             L O G G I N G
-###############################################################################
-
-<% if node[:networking][:firewall][:log] -%>
-LOG_LEVEL="info"
-<% else -%>
-LOG_LEVEL="none"
-<% end -%>
-
-BLACKLIST_LOG_LEVEL=
-
-INVALID_LOG_LEVEL=
-
-LOG_BACKEND=
-
-LOG_MARTIANS=Yes
-
-LOG_VERBOSITY=2
-
-LOGALLNEW=
-
-LOGFILE=/var/log/messages
-
-LOGFORMAT="%s %s "
-
-LOGTAGONLY=No
-
-LOGLIMIT="s:1/sec:10"
-
-MACLIST_LOG_LEVEL="$LOG_LEVEL"
-
-RELATED_LOG_LEVEL=
-
-RPFILTER_LOG_LEVEL="$LOG_LEVEL"
-
-SFILTER_LOG_LEVEL="$LOG_LEVEL"
-
-SMURF_LOG_LEVEL="$LOG_LEVEL"
-
-STARTUP_LOG=/var/log/shorewall-init.log
-
-TCP_FLAGS_LOG_LEVEL="$LOG_LEVEL"
-
-UNTRACKED_LOG_LEVEL=
-
-###############################################################################
-#      L O C A T I O N   O F   F I L E S   A N D   D I R E C T O R I E S
-###############################################################################
-
-ARPTABLES=
-
-CONFIG_PATH=":${CONFDIR}/shorewall:${SHAREDIR}/shorewall"
-
-GEOIPDIR=/usr/share/xt_geoip/LE
-
-IPTABLES=
-
-IP=
-
-IPSET=
-
-LOCKFILE=
-
-MODULESDIR=
-
-NFACCT=
-
-PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
-
-PERL=/usr/bin/perl
-
-RESTOREFILE=restore
-
-SHOREWALL_SHELL=/bin/sh
-
-SUBSYSLOCK=""
-
-TC=
-
-###############################################################################
-#              D E F A U L T   A C T I O N S / M A C R O S
-###############################################################################
-
-ACCEPT_DEFAULT="none"
-BLACKLIST_DEFAULT="Broadcast(DROP),Multicast(DROP),dropNotSyn:$LOG_LEVEL,dropInvalid:$LOG_LEVEL,DropDNSrep:$LOG_LEVEL"
-DROP_DEFAULT="Broadcast(DROP),Multicast(DROP)"
-NFQUEUE_DEFAULT="none"
-QUEUE_DEFAULT="none"
-REJECT_DEFAULT="Broadcast(DROP),Multicast(DROP)"
-
-###############################################################################
-#                        R S H / R C P  C O M M A N D S
-###############################################################################
-
-RCP_COMMAND='scp ${files} ${root}@${system}:${destination}'
-RSH_COMMAND='ssh ${root}@${system} ${command}'
-
-###############################################################################
-#                      F I R E W A L L   O P T I O N S
-###############################################################################
-
-ACCOUNTING=Yes
-
-ACCOUNTING_TABLE=filter
-
-ADD_IP_ALIASES=No
-
-ADD_SNAT_ALIASES=No
-
-ADMINISABSENTMINDED=Yes
-
-AUTOCOMMENT=Yes
-
-AUTOHELPERS=Yes
-
-AUTOMAKE=Yes
-
-BALANCE_PROVIDERS=No
-
-BASIC_FILTERS=No
-
-<% if node[:networking][:firewall][:raw] -%>
-BLACKLIST="NEW,INVALID,UNTRACKED"
-<% else -%>
-BLACKLIST="NEW,INVALID"
-<% end -%>
-
-CLAMPMSS=No
-
-CLEAR_TC=Yes
-
-COMPLETE=No
-
-DEFER_DNS_RESOLUTION=Yes
-
-DELETE_THEN_ADD=Yes
-
-DETECT_DNAT_IPADDRS=No
-
-DISABLE_IPV6=No
-
-DOCKER=No
-
-DONT_LOAD=
-
-DYNAMIC_BLACKLIST=Yes
-
-EXPAND_POLICIES=Yes
-
-EXPORTMODULES=Yes
-
-FASTACCEPT=No
-
-FORWARD_CLEAR_MARK=
-
-HELPERS=
-
-IGNOREUNKNOWNVARIABLES=No
-
-IMPLICIT_CONTINUE=No
-
-INLINE_MATCHES=No
-
-IPSET_WARNINGS=Yes
-
-IP_FORWARDING=Keep
-
-KEEP_RT_TABLES=No
-
-LOAD_HELPERS_ONLY=Yes
-
-MACLIST_TABLE=filter
-
-MACLIST_TTL=
-
-MANGLE_ENABLED=Yes
-
-MAPOLDACTIONS=No
-
-MARK_IN_FORWARD_CHAIN=No
-
-MINIUPNPD=No
-
-MULTICAST=No
-
-MUTEX_TIMEOUT=60
-
-NULL_ROUTE_RFC1918=No
-
-OPTIMIZE=All
-
-OPTIMIZE_ACCOUNTING=No
-
-PERL_HASH_SEED=0
-
-REJECT_ACTION=
-
-REQUIRE_INTERFACE=No
-
-RESTART=restart
-
-RESTORE_DEFAULT_ROUTE=Yes
-
-RESTORE_ROUTEMARKS=Yes
-
-RETAIN_ALIASES=No
-
-ROUTE_FILTER=Yes
-
-SAVE_ARPTABLES=No
-
-SAVE_IPSETS=No
-
-<% if node[:networking][:firewall][:mangle] -%>
-TC_ENABLED=Internal
-<% else -%>
-TC_ENABLED=No
-<% end -%>
-
-TC_EXPERT=No
-
-TC_PRIOMAP="2 3 3 3 2 3 1 1 2 2 2 2 2 2 2 2"
-
-TRACK_PROVIDERS=Yes
-
-TRACK_RULES=No
-
-USE_DEFAULT_RT=No
-
-USE_NFLOG_SIZE=No
-
-USE_PHYSICAL_NAMES=No
-
-USE_RT_NAMES=No
-
-VERBOSE_MESSAGES=Yes
-
-WARNOLDCAPVERSION=Yes
-
-WORKAROUNDS=No
-
-ZERO_MARKS=No
-
-ZONE2ZONE=-
-
-###############################################################################
-#                      P A C K E T   D I S P O S I T I O N
-###############################################################################
-
-BLACKLIST_DISPOSITION=DROP
-
-INVALID_DISPOSITION=CONTINUE
-
-MACLIST_DISPOSITION=REJECT
-
-RELATED_DISPOSITION=ACCEPT
-
-RPFILTER_DISPOSITION=DROP
-
-SMURF_DISPOSITION=DROP
-
-SFILTER_DISPOSITION=DROP
-
-TCP_FLAGS_DISPOSITION=DROP
-
-UNTRACKED_DISPOSITION=CONTINUE
-
-################################################################################
-#                      P A C K E T  M A R K  L A Y O U T
-################################################################################
-
-TC_BITS=
-
-PROVIDER_BITS=
-
-PROVIDER_OFFSET=
-
-MASK_BITS=
-
-ZONE_BITS=0
diff --git a/cookbooks/networking/templates/default/shorewall6-hosts.erb b/cookbooks/networking/templates/default/shorewall6-hosts.erb
deleted file mode 100644 (file)
index c2ac663..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# ZONE HOST                                            OPTIONS
-<% node.interfaces(:family => :inet6, :role => :external).each do |interface| -%>
-<% @zones.keys.sort.each do |zone| -%>
-<% if @zones[zone]["inet6"] -%>
-<% @zones[zone]["inet6"].sort.each do |ra| -%>
-<%= zone %>    <%= interface[:interface] %>:[<%= ra %>]
-<% end -%>
-<% end -%>
-<% end -%>
-<% end -%>
diff --git a/cookbooks/networking/templates/default/shorewall6-interfaces.erb b/cookbooks/networking/templates/default/shorewall6-interfaces.erb
deleted file mode 100644 (file)
index 8ba6b8c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-?FORMAT 2
-  
-# ZONE INTERFACE       OPTIONS
-<% node[:networking][:interfaces].each do |name,interface| -%>
-<% if interface[:family] == "inet6" -%>
-<% if interface[:role] == "internal" -%>
-loc    <%= interface[:interface] %>            -
-<% elsif interface[:role] == "external" -%>
-net    <%= interface[:interface] %>            -
-<% end -%>
-<% end -%>
-<% end -%>
diff --git a/cookbooks/networking/templates/default/shorewall6.conf.erb b/cookbooks/networking/templates/default/shorewall6.conf.erb
deleted file mode 100644 (file)
index a98408e..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-###############################################################################
-#                     S T A R T U P   E N A B L E D
-###############################################################################
-
-STARTUP_ENABLED=Yes
-
-###############################################################################
-#                            V E R B O S I T Y
-###############################################################################
-
-VERBOSITY=1
-
-###############################################################################
-#                              P A G E R
-###############################################################################
-
-PAGER=
-
-###############################################################################
-#                           F I R E W A L L
-###############################################################################
-
-FIREWALL=
-
-###############################################################################
-#                             L O G G I N G
-###############################################################################
-
-<% if node[:networking][:firewall][:log] -%>
-LOG_LEVEL="info"
-<% else -%>
-LOG_LEVEL="none"
-<% end -%>
-
-BLACKLIST_LOG_LEVEL=
-
-INVALID_LOG_LEVEL=
-
-LOG_BACKEND=
-
-LOG_VERBOSITY=2
-
-LOGALLNEW=
-
-LOGFILE=/var/log/messages
-
-LOGFORMAT="%s %s "
-
-LOGLIMIT="s:1/sec:10"
-
-LOGTAGONLY=No
-
-MACLIST_LOG_LEVEL="$LOG_LEVEL"
-
-RELATED_LOG_LEVEL=
-
-RPFILTER_LOG_LEVEL="$LOG_LEVEL"
-
-SFILTER_LOG_LEVEL="$LOG_LEVEL"
-
-SMURF_LOG_LEVEL="$LOG_LEVEL"
-
-STARTUP_LOG=/var/log/shorewall6-init.log
-
-TCP_FLAGS_LOG_LEVEL="$LOG_LEVEL"
-
-UNTRACKED_LOG_LEVEL=
-
-###############################################################################
-#      L O C A T I O N   O F   F I L E S   A N D   D I R E C T O R I E S
-###############################################################################
-
-CONFIG_PATH=":${CONFDIR}/shorewall6:/usr/share/shorewall6:${SHAREDIR}/shorewall"
-
-GEOIPDIR=/usr/share/xt_geoip/LE
-
-IP6TABLES=
-
-IP=
-
-IPSET=
-
-LOCKFILE=
-
-MODULESDIR=
-
-NFACCT=
-
-PERL=/usr/bin/perl
-
-PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin"
-
-RESTOREFILE=restore
-
-SHOREWALL_SHELL=/bin/sh
-
-SUBSYSLOCK=""
-
-TC=
-
-###############################################################################
-#              D E F A U L T   A C T I O N S / M A C R O S
-###############################################################################
-
-ACCEPT_DEFAULT="none"
-BLACKLIST_DEFAULT="AllowICMPs,Broadcast(DROP),Multicast(DROP),dropNotSyn:$LOG_LEVEL,dropInvalid:$LOG_LEVEL,DropDNSrep:$LOG_LEVEL"
-DROP_DEFAULT="AllowICMPs,Broadcast(DROP),Multicast(DROP)"
-NFQUEUE_DEFAULT="none"
-QUEUE_DEFAULT="none"
-REJECT_DEFAULT="AllowICMPs,Broadcast(DROP),Multicast(DROP)"
-
-###############################################################################
-#                        R S H / R C P  C O M M A N D S
-###############################################################################
-
-RCP_COMMAND='scp ${files} ${root}@${system}:${destination}'
-RSH_COMMAND='ssh ${root}@${system} ${command}'
-
-###############################################################################
-#                      F I R E W A L L   O P T I O N S
-###############################################################################
-
-ACCOUNTING=Yes
-
-ACCOUNTING_TABLE=filter
-
-ADMINISABSENTMINDED=Yes
-
-AUTOCOMMENT=Yes
-
-AUTOHELPERS=Yes
-
-AUTOMAKE=Yes
-
-BALANCE_PROVIDERS=No
-
-BASIC_FILTERS=No
-
-<% if node[:networking][:firewall][:raw] -%>
-BLACKLIST="NEW,INVALID,UNTRACKED"
-<% else -%>
-BLACKLIST="NEW,INVALID"
-<% end -%>
-
-CLAMPMSS=No
-
-CLEAR_TC=No
-
-COMPLETE=No
-
-DEFER_DNS_RESOLUTION=Yes
-
-DELETE_THEN_ADD=Yes
-
-DONT_LOAD=
-
-DYNAMIC_BLACKLIST=Yes
-
-EXPAND_POLICIES=Yes
-
-EXPORTMODULES=Yes
-
-FASTACCEPT=No
-
-<% if node[:networking][:firewall][:mark] -%>
-FORWARD_CLEAR_MARK=Yes
-<% else -%>
-FORWARD_CLEAR_MARK=No
-<% end -%>
-
-HELPERS=
-
-IGNOREUNKNOWNVARIABLES=No
-
-IMPLICIT_CONTINUE=No
-
-INLINE_MATCHES=No
-
-IPSET_WARNINGS=Yes
-
-IP_FORWARDING=Keep
-
-KEEP_RT_TABLES=No
-
-LOAD_HELPERS_ONLY=Yes
-
-MACLIST_TABLE=filter
-
-MACLIST_TTL=
-
-MANGLE_ENABLED=Yes
-
-MARK_IN_FORWARD_CHAIN=No
-
-MINIUPNPD=No
-
-MUTEX_TIMEOUT=60
-
-OPTIMIZE=All
-
-OPTIMIZE_ACCOUNTING=No
-
-PERL_HASH_SEED=0
-
-REJECT_ACTION=
-
-REQUIRE_INTERFACE=No
-
-RESTART=restart
-
-RESTORE_DEFAULT_ROUTE=Yes
-
-RESTORE_ROUTEMARKS=Yes
-
-SAVE_IPSETS=No
-
-<% if node[:networking][:firewall][:mangle] -%>
-TC_ENABLED=Shared
-<% else -%>
-TC_ENABLED=No
-<% end -%>
-
-TC_EXPERT=No
-
-TC_PRIOMAP="2 3 3 3 2 3 1 1 2 2 2 2 2 2 2 2"
-
-TRACK_PROVIDERS=Yes
-
-TRACK_RULES=No
-
-USE_DEFAULT_RT=Yes
-
-USE_NFLOG_SIZE=No
-
-USE_PHYSICAL_NAMES=No
-
-USE_RT_NAMES=No
-
-VERBOSE_MESSAGES=Yes
-
-WARNOLDCAPVERSION=Yes
-
-WORKAROUNDS=No
-
-ZERO_MARKS=No
-
-ZONE2ZONE=
-
-###############################################################################
-#                      P A C K E T   D I S P O S I T I O N
-###############################################################################
-
-BLACKLIST_DISPOSITION=DROP
-
-INVALID_DISPOSITION=CONTINUE
-
-MACLIST_DISPOSITION=REJECT
-
-RELATED_DISPOSITION=ACCEPT
-
-SFILTER_DISPOSITION=DROP
-
-RPFILTER_DISPOSITION=DROP
-
-SMURF_DISPOSITION=DROP
-
-TCP_FLAGS_DISPOSITION=DROP
-
-UNTRACKED_DISPOSITION=CONTINUE
-
-################################################################################
-#                      P A C K E T  M A R K  L A Y O U T
-################################################################################
-
-TC_BITS=
-
-PROVIDER_BITS=
-
-PROVIDER_OFFSET=
-
-MASK_BITS=
-
-ZONE_BITS=0
-
-#LAST LINE -- DO NOT REMOVE
diff --git a/cookbooks/networking/templates/default/slave.network.erb b/cookbooks/networking/templates/default/slave.network.erb
new file mode 100644 (file)
index 0000000..609f38f
--- /dev/null
@@ -0,0 +1,15 @@
+[Match]
+Name=<%= @slave %>
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+LinkLocalAddressing=no
+IPv6AcceptRA=no
+Bond=<%= @master[:interface] %>
+<% if @master[:bond][:mode].nil? || @master[:bond][:mode] == "active-backup" -%>
+<% if @master[:bond][:slaves].first == @slave -%>
+PrimarySlave=true
+<% end -%>
+<% end -%>
diff --git a/cookbooks/networking/templates/default/vlan.netdev.erb b/cookbooks/networking/templates/default/vlan.netdev.erb
new file mode 100644 (file)
index 0000000..8446f35
--- /dev/null
@@ -0,0 +1,6 @@
+[NetDev]
+Name=<%= @interface[:interface] %>
+Kind=vlan
+
+[VLAN]
+Id=<%= @vlan %>
diff --git a/cookbooks/networking/templates/default/wireguard.netdev.erb b/cookbooks/networking/templates/default/wireguard.netdev.erb
new file mode 100644 (file)
index 0000000..979e68e
--- /dev/null
@@ -0,0 +1,20 @@
+[NetDev]
+Name=wg0
+Kind=wireguard
+
+[WireGuard]
+PrivateKeyFile=/var/lib/systemd/wireguard/private.key
+ListenPort=51820
+<% node[:networking][:wireguard][:peers].sort_by { |p| p[:public_key] }.each do |peer| -%>
+
+[WireGuardPeer]
+PublicKey=<%= peer[:public_key] %>
+PresharedKeyFile=/var/lib/systemd/wireguard/preshared.key
+AllowedIPs=<%= Array(peer[:allowed_ips]).sort.join(",") %>
+<% if peer[:endpoint] -%>
+Endpoint=<%= peer[:endpoint] %>
+<% end -%>
+<% if node[:networking][:wireguard][:keepalive] -%>
+PersistentKeepalive=<%= node[:networking][:wireguard][:keepalive] %>
+<% end -%>
+<% end -%>
diff --git a/cookbooks/networking/templates/default/wireguard.network.erb b/cookbooks/networking/templates/default/wireguard.network.erb
new file mode 100644 (file)
index 0000000..481fe14
--- /dev/null
@@ -0,0 +1,23 @@
+[Match]
+Name=wg0
+
+[Network]
+<% if node.internal_ipaddress -%>
+Address=<%= node.internal_ipaddress %>/32
+<% end -%>
+<% if node[:networking][:private_address] -%>
+Address=<%= node[:networking][:private_address] %>/32
+<% end -%>
+Address=<%= node[:networking][:wireguard][:address] %>/128
+
+[Route]
+Destination=fd43:e709:ea6d:1::/64
+<% node[:networking][:wireguard][:peers].sort_by { |p| p[:public_key] }.each do |peer| -%>
+<% Array(peer[:allowed_ips]).sort.each do |ip| -%>
+<% unless ip =~ /^fd43:e709:ea6d:1::/ -%>
+
+[Route]
+Destination=<%= ip %>
+<% end -%>
+<% end -%>
+<% end -%>
diff --git a/cookbooks/nfs/README.md b/cookbooks/nfs/README.md
deleted file mode 100644 (file)
index da1c028..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# NFS Cookbook
-
-This cookbook configures NFS (the Network File System) which is used on
-various servers. There are two recipes:
-
-* default: configures NFS clients based on node attributes.
-* server: configures the central NFS server.
diff --git a/cookbooks/nfs/recipes/default.rb b/cookbooks/nfs/recipes/default.rb
deleted file mode 100644 (file)
index 80d3d9e..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Cookbook:: nfs
-# Recipe:: default
-#
-# Copyright:: 2010, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-package "nfs-common"
-
-node[:nfs].each do |mountpoint, details|
-  mount_options = if details[:readonly]
-                    "ro,bg,soft,tcp,rsize=8192,wsize=8192,nfsvers=4"
-                  else
-                    "rw,bg,tcp,rsize=8192,wsize=8192,nfsvers=4"
-                  end
-
-  directory mountpoint do
-    owner "root"
-    group "root"
-    mode 0o755
-    recursive true
-    not_if { File.exist?(mountpoint) }
-  end
-
-  mount mountpoint do
-    action [:mount, :enable]
-    device "#{details[:host]}:#{details[:path]}"
-    fstype "nfs"
-    options mount_options
-    ignore_failure true
-  end
-end
diff --git a/cookbooks/nfs/recipes/server.rb b/cookbooks/nfs/recipes/server.rb
deleted file mode 100644 (file)
index 0378075..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# Cookbook:: nfs
-# Recipe:: server
-#
-# Copyright:: 2010, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-package "nfs-kernel-server"
-
-service "rpcbind" do
-  action [:enable, :start]
-end
-
-service "nfs-server" do
-  action [:enable, :start]
-end
-
-exports = {}
-
-search(:node, "*:*") do |client|
-  next unless client[:nfs]
-
-  client[:nfs].each_value do |mount|
-    next unless mount[:host] == node[:hostname]
-
-    client.ipaddresses do |address|
-      exports[mount[:path]] ||= {}
-
-      exports[mount[:path]][address] = if mount[:readonly]
-                                         "ro"
-                                       else
-                                         "rw"
-                                       end
-    end
-  end
-end
-
-execute "exportfs" do
-  action :nothing
-  command "/usr/sbin/exportfs -ra"
-end
-
-template "/etc/exports" do
-  source "exports.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :exports => exports
-  notifies :run, "execute[exportfs]"
-end
diff --git a/cookbooks/nfs/templates/default/exports.erb b/cookbooks/nfs/templates/default/exports.erb
deleted file mode 100644 (file)
index 7c5c2a5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<% @exports.sort.each do |directory,clients| -%>
-<% clients.sort.each do |address,options| -%>
-<%= directory -%> -sync,subtree_check,<%= options %> <%= address %>
-<% end -%>
-<% end -%>
-/store/planet -sync,subtree_check,rw 10.0.48.50 10.0.48.5
index c6e77de0ad4d89a102e2b94eb9807112fdb12948..e37b429997350aa7afe3e7507afc5079ac842a66 100644 (file)
@@ -11,6 +11,6 @@ default[:nginx][:cache][:fastcgi][:max_size] = "8192M"
 # Tuning for nginx proxy cache zone
 default[:nginx][:cache][:proxy][:enable] = false
 default[:nginx][:cache][:proxy][:directory] = "/var/cache/nginx/proxy-cache"
-default[:nginx][:cache][:proxy][:keys_zone] = "proxy_cache_zone:48M"
+default[:nginx][:cache][:proxy][:keys_zone] = "proxy_cache_zone:128M"
 default[:nginx][:cache][:proxy][:inactive] = "45d"
-default[:nginx][:cache][:proxy][:max_size] = "8192M"
+default[:nginx][:cache][:proxy][:max_size] = "16384M"
index edd5573b0753883092ecbce1af97f2396827509d..b7e571c7c6411dacbf507e9eda1fd40728df0f3f 100644 (file)
@@ -6,4 +6,8 @@ description       "Installs and configures nginx"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "apt"
+depends           "networking"
+depends           "prometheus"
 depends           "ssl"
+depends           "systemd"
index 93aab56906afd96dabce0acc328ffbc0a3ff5a62..d8e9d4d2bc566abd1d184c5aaacabf4cc643d4bc 100644 (file)
 # limitations under the License.
 #
 
-package "nginx"
+include_recipe "apt::nginx"
+include_recipe "prometheus"
+include_recipe "ssl"
 
-resolvers = node[:networking][:nameservers].map do |resolver|
-  IPAddr.new(resolver).ipv6? ? "[#{resolver}]" : resolver
-end
+package "nginx"
 
 template "/etc/nginx/nginx.conf" do
   source "nginx.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
-  variables :resolvers => resolvers
+  mode "644"
 end
 
 directory node[:nginx][:cache][:fastcgi][:directory] do
   owner "www-data"
   group "root"
-  mode 0o755
+  mode "755"
   recursive true
   only_if { node[:nginx][:cache][:fastcgi][:enable] }
 end
@@ -42,7 +41,7 @@ end
 directory node[:nginx][:cache][:proxy][:directory] do
   owner "www-data"
   group "root"
-  mode 0o755
+  mode "755"
   recursive true
   only_if { node[:nginx][:cache][:proxy][:enable] }
 end
@@ -53,11 +52,7 @@ service "nginx" do
   subscribes :restart, "template[/etc/nginx/nginx.conf]"
 end
 
-munin_plugin_conf "nginx" do
-  template "munin.erb"
+prometheus_exporter "nginx" do
+  port 9113
+  options "--nginx.scrape-uri=http://localhost:8050/nginx_status"
 end
-
-package "libwww-perl"
-
-munin_plugin "nginx_request"
-munin_plugin "nginx_status"
index 5ebaca69b4f49868e683435dad52066545850aab..b1a4b5970ddbcc01e4845511636aee257930db88 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :site, :kind_of => String, :name_attribute => true
+property :site, :kind_of => String, :name_property => true
 property :directory, :kind_of => String
 property :cookbook, :kind_of => String
-property :template, :kind_of => String, :required => true
+property :template, :kind_of => String, :required => [:create]
 property :variables, :kind_of => Hash, :default => {}
-property :restart_nginx, :kind_of => [TrueClass, FalseClass], :default => true
 
 action :create do
   declare_resource :template, conf_path do
@@ -32,7 +33,7 @@ action :create do
     source new_resource.template
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables new_resource.variables.merge(:name => new_resource.site, :directory => directory)
   end
 end
@@ -40,6 +41,7 @@ end
 action :delete do
   file conf_path do
     action :delete
+    notifies :reload, "service[nginx]"
   end
 end
 
@@ -54,5 +56,5 @@ action_class do
 end
 
 def after_created
-  notifies :restart, "service[nginx]" if restart_nginx
+  notifies :reload, "service[nginx]"
 end
diff --git a/cookbooks/nginx/templates/default/munin.erb b/cookbooks/nginx/templates/default/munin.erb
deleted file mode 100644 (file)
index 56a2eff..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[nginx*]
-  env.url http://localhost:8050/nginx_status
index a3f6b241181d74bff40632564f228d204665ed65..0d2387b2e30b4fa01988383845e8ce40b8c20410 100644 (file)
@@ -47,7 +47,7 @@ http {
     ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
 
     ssl_dhparam /etc/ssl/certs/dhparam.pem;
-    resolver <%= @resolvers.join(" ") %>;
+    resolver 127.0.0.53 ipv6=off;
     resolver_timeout 5s;
 
     <% if node['nginx']['cache']['fastcgi']['enable'] -%>
@@ -57,7 +57,7 @@ http {
     proxy_cache_path <%= node['nginx']['cache']['proxy']['directory'] %> levels=2:2:2 use_temp_path=off keys_zone=<%= node['nginx']['cache']['proxy']['keys_zone'] %> inactive=<%= node['nginx']['cache']['proxy']['inactive'] %> max_size=<%= node['nginx']['cache']['proxy']['max_size'] %>;
     <% end -%>
 
-    # Internal site for munin monitoring
+    # Internal site for stats monitoring
     server {
       listen 127.0.0.1:8050;
       server_name localhost;
index 5cd33627c77dd7a64337bda994adc3377f1052bd..6285913540a9011b8c3d8e56a28326a1baf994c6 100644 (file)
@@ -6,3 +6,4 @@ description       "Installs and configures Node.js"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "apt"
index ac82c3c98aa033bb80b94a523e3f7d65cb258b96..9483d5893f9f98d0ebf824b98d8f480355ff01ad 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "apt::nodesource"
+include_recipe "apt::yarn"
+
 package %w[
   nodejs
-  npm
+  yarn
   g++
   make
 ]
index 9d30c164fcb032f6ba00b1861496ff86d5d81d5f..5279cc91a09f851c0a052b79b95937e542947513 100644 (file)
 
 require "json"
 
+unified_mode true
+
 default_action :install
 
-property :package, :kind_of => String, :name_attribute => true
+property :package, :kind_of => String, :name_property => true
 property :version, :kind_of => String
 
 action :install do
index 190378ca2d62a13eba4ca14f0f54199a854bc65e..8c5fa3780f3318bee2cc7801c99ee9d8866f72e5 100644 (file)
@@ -1,9 +1,3 @@
 # Nominatim Cookbook
 
 This cookbook installs and configures the Nominatim geocoding service.
-
-It contains three recipes:
-* default: sets up a complete Nominatim installation including postgres backend
-           and apache frontend
-* master: defines additional attributes for running the server as DB master
-* slave: defines additional attributes for running the server as DB slave
index 67708f9a1423691af2605039184c44f67dcaca77..ad9dffae5e54c98f8d12cc9ff06f28bc653b8990 100644 (file)
@@ -1,29 +1,41 @@
 default[:nominatim][:state] = "off" # or: standalone, master, slave
 default[:nominatim][:dbadmins] = []
+default[:nominatim][:dbcluster] = "14/main"
 default[:nominatim][:dbname] = "nominatim"
 default[:nominatim][:tablespaces] = []
+default[:nominatim][:postgis] = "3"
 default[:nominatim][:logdir] = "/var/log/nominatim"
 default[:nominatim][:repository] = "https://git.openstreetmap.org/public/nominatim.git"
-default[:nominatim][:revision] = "master"
+default[:nominatim][:revision] = "deploy"
 default[:nominatim][:enable_backup] = false
 default[:nominatim][:enable_git_updates] = true
+default[:nominatim][:enable_qa_tiles] = false
+default[:nominatim][:ui_repository] = "https://git.openstreetmap.org/public/nominatim-ui.git"
+default[:nominatim][:ui_revision] = "master"
+default[:nominatim][:qa_repository] = "https://github.com/osm-search/Nominatim-Data-Analyser"
+default[:nominatim][:qa_revision] = "main"
+default[:nominatim][:api_flavour] = "php"
+default[:nominatim][:api_workers] = 10
+default[:nominatim][:api_pool_size] = 10
+default[:nominatim][:api_query_timeout] = 5
+default[:nominatim][:api_request_timeout] = 20
 
 default[:nominatim][:fpm_pools] = {
-  :www => {
-    :port => "8000",
+  "nominatim.openstreetmap.org" => {
     :pm => "dynamic",
-    :max_children => "60"
-  },
-  :bulk => {
-    :port => "8001",
-    :pm => "static",
-    :max_children => "10"
-  },
-  :details => {
-    :port => "8002",
-    :pm => "static",
-    :max_children => "2"
+    :max_children => 60,
+    :prometheus_port => 9253
   }
 }
 
+default[:nominatim][:config] = {
+  :tokenizer => "icu",
+  :forward_dependencies => "no"
+}
+
 default[:nominatim][:redirects] = {}
+
+default[:postgresql][:versions] |= [node[:nominatim][:dbcluster].split("/").first]
+default[:postgresql][:monitor_database] = "nominatim"
+
+default[:accounts][:users][:nominatim][:status] = :role
diff --git a/cookbooks/nominatim/files/default/website/403.html b/cookbooks/nominatim/files/default/website/403.html
new file mode 100644 (file)
index 0000000..8d8e323
--- /dev/null
@@ -0,0 +1,23 @@
+<html>
+<head>
+<title>Access blocked</title>
+</head>
+<body>
+<h1>Access blocked</h1>
+
+<p>You have been blocked because you have violated the
+<a href="https://operations.osmfoundation.org/policies/nominatim/">usage policy</a>
+of OSM's Nominatim geocoding service. Please be aware that OSM's resources are
+limited and shared between many users. The usage policy is there to ensure that
+the service remains usable for everybody.</p>
+
+<p>Please review the terms and make sure that your
+software adheres to the terms. You should in particular verify that you have set a
+<b>custom HTTP referrer or HTTP user agent</b> that identifies your application, and
+that you are not overusing the service with massive bulk requests.</p>
+
+<p>If you feel that this block is unjustified or remains after you have adopted
+your usage, you may contact the Nominatim system administrator at
+nominatim@openstreetmap.org to have this block lifted.</p>
+</body>
+</head>
diff --git a/cookbooks/nominatim/files/default/website/509.html b/cookbooks/nominatim/files/default/website/509.html
new file mode 100644 (file)
index 0000000..628c53b
--- /dev/null
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>Bandwidth limit exceeded</title>
+</head>
+<body>
+<h1>Bandwidth limit exceeded</h1>
+
+<p>You have been temporarily blocked because you have been overusing OSM's geocoding service or because you have not provided sufficient identification of your application. This block will be automatically lifted after a while. Please take the time and adapt your scripts to reduce the number of requests and make sure that you send a valid UserAgent or Referer.</p>
+
+<p>For more information, consult the <a href="https://operations.osmfoundation.org/policies/nominatim/">usage policy</a> for the OSM Nominatim server.</p>
+</body>
+</html>
diff --git a/cookbooks/nominatim/files/default/website/crossdomain.xml b/cookbooks/nominatim/files/default/website/crossdomain.xml
new file mode 100644 (file)
index 0000000..963a682
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+           <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
+           <cross-domain-policy>
+           <allow-access-from domain="*" />
+           </cross-domain-policy> 
diff --git a/cookbooks/nominatim/files/default/website/favicon.ico b/cookbooks/nominatim/files/default/website/favicon.ico
new file mode 100644 (file)
index 0000000..0157ea0
Binary files /dev/null and b/cookbooks/nominatim/files/default/website/favicon.ico differ
diff --git a/cookbooks/nominatim/files/default/website/nominatim.xml b/cookbooks/nominatim/files/default/website/nominatim.xml
new file mode 100644 (file)
index 0000000..4e8a30e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"
+                       xmlns:moz="http://www.mozilla.org/2006/browser/search/">
+    <ShortName>Nominatim</ShortName>
+    <LongName>Nominatim OSM Search</LongName>
+    <Description>Search for a place in OpenStreetMap Nominatim</Description>
+    <InputEncoding>UTF-8</InputEncoding>
+    <OutputEncoding>UTF-8</OutputEncoding>
+    <Url type="text/html" method="get" template="https://nominatim.openstreetmap.org/ui/search.html">
+      <Param name="q" value="{searchTerms}"/>
+    </Url>
+    <Query role="example" searchTerms="Reigate" />
+    <Developer>Sarah Hoffmann</Developer>
+    <AdultContent>false</AdultContent>
+    <Attribution>Data &amp;copy; OpenStreetMap contributors. ODbL, http://www.osm.org/copyright.</Attribution>
+</OpenSearchDescription>
+
diff --git a/cookbooks/nominatim/files/default/website/robots.txt b/cookbooks/nominatim/files/default/website/robots.txt
new file mode 100644 (file)
index 0000000..9624d97
--- /dev/null
@@ -0,0 +1,14 @@
+User-agent: ia_archiver
+Allow: /
+
+User-agent: *
+Disallow: /search.php
+Disallow: /search
+Disallow: /details.php
+Disallow: /details
+Disallow: /reverse.php
+Disallow: /reverse
+Disallow: /hierarchy
+Disallow: /hierarchy.php
+Disallow: /lookup
+Disallow: /lookup.php
diff --git a/cookbooks/nominatim/files/default/website/taginfo.json b/cookbooks/nominatim/files/default/website/taginfo.json
new file mode 100644 (file)
index 0000000..3fce413
--- /dev/null
@@ -0,0 +1 @@
+{"data_format":1,"data_url":"https://nominatim.openstreetmap.org/taginfo.json","project":{"name":"Nominatim","description":"OSM search engine.","project_url":"https://nominatim.openstreetmap.org","doc_url":"https://nominatim.org/release-docs/develop/","contact_name":"Sarah Hoffmann","contact_email":"lonvia@denofr.de"},"tags":[{"key":"historic","description":"POI/feature in the search database (except for values: yes, no)."},{"key":"military","description":"POI/feature in the search database (except for values: yes, no)."},{"key":"man_made","description":"POI/feature in the search database"},{"key":"landuse","description":"POI/feature in the search database"},{"key":"place","description":"POI/feature in the search database"},{"key":"highway","description":"POI/feature in the search database (except for values: no, turning_circle, mini_roundabout, noexit, crossing, give_way, stop)."},{"key":"waterway","description":"POI/feature in the search database (except for values: riverbank)."},{"key":"natural","description":"POI/feature in the search database (except for values: yes, no, coastline)."},{"key":"mountain_pass","description":"POI/feature in the search database (except for values: no)."},{"key":"healthcare","description":"POI/feature in the search database"},{"key":"club","description":"POI/feature in the search database (except for values: no)."},{"key":"bridge","description":"POI/feature in the search database (except for values: no)."},{"key":"leisure","description":"POI/feature in the search database (except for values: no)."},{"key":"emergency","description":"POI/feature in the search database (except for values: yes, no, fire_hydrant)."},{"key":"building","description":"POI/feature in the search database (except for values: no)."},{"key":"office","description":"POI/feature in the search database (except for values: no)."},{"key":"aeroway","description":"POI/feature in the search database (except for values: no)."},{"key":"railway","description":"POI/feature in the search database (except for values: level_crossing, no, rail, switch, abandoned, signal, buffer_stop, razed)."},{"key":"craft","description":"POI/feature in the search database (except for values: no)."},{"key":"junction","description":"POI/feature in the search database"},{"key":"tunnel","description":"POI/feature in the search database (except for values: no)."},{"key":"shop","description":"POI/feature in the search database (except for values: no)."},{"key":"tourism","description":"POI/feature in the search database (except for values: yes, no)."},{"key":"amenity","description":"POI/feature in the search database (except for values: no, parking_space, parking_entrance)."},{"key":"boundary","description":"POI/feature in the search database (except for values: place, land_area)."},{"key":"aerialway","description":"POI/feature in the search database (except for values: pylon, no)."},{"key":"int_ref","description":"Searchable name of the place."},{"key":"loc_name","description":"Searchable name of the place."},{"key":"pcode","description":"Searchable name of the place."},{"key":"addr:housename","description":"Searchable name of the place."},{"key":"old_name","description":"Searchable name of the place."},{"key":"name","description":"Searchable name of the place."},{"key":"short_name","description":"Searchable name of the place."},{"key":"brand","description":"Searchable name of the place."},{"key":"ref","description":"Searchable name of the place."},{"key":"reg_ref","description":"Searchable name of the place."},{"key":"reg_name","description":"Searchable name of the place."},{"key":"old_ref","description":"Searchable name of the place."},{"key":"loc_ref","description":"Searchable name of the place."},{"key":"iata","description":"Searchable name of the place."},{"key":"ISO3166-2","description":"Searchable name of the place."},{"key":"nat_name","description":"Searchable name of the place."},{"key":"alt_name","description":"Searchable name of the place."},{"key":"official_name","description":"Searchable name of the place."},{"key":"icao","description":"Searchable name of the place."},{"key":"nat_ref","description":"Searchable name of the place."},{"key":"int_name","description":"Searchable name of the place."},{"key":"place_name","description":"Searchable name of the place."},{"key":"tiger:zip_right","description":"Used to determine the address of a place."},{"key":"tiger:county","description":"Used to determine the address of a place."},{"key":"addr:country_code","description":"Used to determine the address of a place."},{"key":"postal_code","description":"Used to determine the address of a place."},{"key":"addr:housenumber","description":"Used to determine the address of a place."},{"key":"is_in","description":"Used to determine the address of a place."},{"key":"addr","description":"Used to determine the address of a place."},{"key":"is_in:country_code","description":"Used to determine the address of a place."},{"key":"is_in:country","description":"Used to determine the address of a place."},{"key":"postcode","description":"Used to determine the address of a place."},{"key":"addr:country","description":"Used to determine the address of a place."},{"key":"addr:streetnumber","description":"Used to determine the address of a place."},{"key":"addr:postcode","description":"Used to determine the address of a place."},{"key":"tiger:zip_left","description":"Used to determine the address of a place."},{"key":"addr:conscriptionnumber","description":"Used to determine the address of a place."},{"key":"country_code","description":"Used to determine the address of a place."},{"key":"ISO3166-1","description":"Used to determine the address of a place."},{"key":"addr:interpolation","description":"Used to determine the address of a place."}]}
index 5909c6caf2c19703f917d2d7b61df9c93d6e2186..ade7ed0b2d12f1fc60e717bd20cc09896ace52c4 100644 (file)
@@ -6,8 +6,12 @@ description       "Installs and configures nominatim servers"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "apache"
-depends           "postgresql"
-depends           "git"
+depends           "accounts"
 depends           "fail2ban"
+depends           "git"
+depends           "nginx"
+depends           "php"
+depends           "postgresql"
+depends           "prometheus"
 depends           "python"
+depends           "systemd"
index e38d0c993a4edc682dcc7e338a37acbfd7e95101..ab1c5aaa2690382b4c545043569d9c9f205472f8 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
+include_recipe "prometheus"
+
+if node[:nominatim][:api_flavour] == "php"
+  include_recipe "php::fpm"
+end
+
 basedir = data_bag_item("accounts", "nominatim")["home"]
 email_errors = data_bag_item("accounts", "lonvia")["email"]
 
 directory basedir do
   owner "nominatim"
   group "nominatim"
-  mode 0o755
+  mode "755"
   recursive true
 end
 
+## Log directory setup
+
 directory node[:nominatim][:logdir] do
   owner "nominatim"
   group "nominatim"
-  mode 0o755
+  mode "755"
   recursive true
 end
 
@@ -38,14 +47,14 @@ file "#{node[:nominatim][:logdir]}/query.log" do
   action :create_if_missing
   owner "www-data"
   group "adm"
-  mode 0o664
+  mode "664"
 end
 
 file "#{node[:nominatim][:logdir]}/update.log" do
   action :create_if_missing
   owner "nominatim"
   group "adm"
-  mode 0o664
+  mode "664"
 end
 
 ## Postgresql
@@ -76,25 +85,20 @@ postgresql_user "www-data" do
   only_if { node[:nominatim][:state] != "slave" }
 end
 
-postgresql_munin "nominatim" do
-  cluster node[:nominatim][:dbcluster]
-  database node[:nominatim][:dbname]
-end
-
 directory "#{basedir}/tablespaces" do
   owner "postgres"
   group "postgres"
-  mode 0o700
+  mode "700"
 end
 
-# Note: tablespaces must be exactly in the same location on each
+# NOTE: tablespaces must be exactly in the same location on each
 #       Nominatim instance when replication is in use. Therefore
 #       use symlinks to canonical directory locations.
 node[:nominatim][:tablespaces].each do |name, location|
   directory location do
     owner "postgres"
     group "postgres"
-    mode 0o700
+    mode "700"
     recursive true
   end
 
@@ -108,33 +112,12 @@ node[:nominatim][:tablespaces].each do |name, location|
   end
 end
 
-if node[:nominatim][:state] == "master"
-  postgresql_user "replication" do
-    cluster node[:nominatim][:dbcluster]
-    password data_bag_item("nominatim", "passwords")["replication"]
-    replication true
-  end
-
-  directory node[:rsyncd][:modules][:archive][:path] do
-    owner "postgres"
-    group "postgres"
-    mode 0o700
-  end
-
-  template "/usr/local/bin/clean-db-nominatim" do
-    source "clean-db-nominatim.erb"
-    owner "root"
-    group "root"
-    mode 0o755
-    variables :archive_dir => node[:rsyncd][:modules][:archive][:path],
-              :update_stop_file => "#{basedir}/status/updates_disabled",
-              :streaming_clients => search(:node, "nominatim_state:slave").map { |slave| slave[:fqdn] }.join(" ")
-  end
-end
-
 ## Nominatim backend
 
 include_recipe "git"
+include_recipe "python"
+
+python_directory = "#{basedir}/venv"
 
 package %w[
   build-essential
@@ -145,23 +128,134 @@ package %w[
   libboost-filesystem-dev
   libexpat1-dev
   zlib1g-dev
-  libxml2-dev
   libbz2-dev
   libpq-dev
-  libgeos++-dev
   libproj-dev
+  liblua5.3-dev
+  libluajit-5.1-dev
+  libicu-dev
+  nlohmann-json3-dev
+  lua5.3
   python3-pyosmium
-  pyosmium
+  python3-psycopg2
+  python3-dotenv
+  python3-psutil
+  python3-jinja2
+  python3-icu
+  python3-datrie
+  python3-yaml
+  python3-sqlalchemy-ext
+  python3-geoalchemy2
+  python3-asyncpg
+  python3-dev
+  pkg-config
+  ruby
+  ruby-file-tail
+  ruby-pg
+  ruby-webrick
 ]
 
-source_directory = "#{basedir}/nominatim"
-build_directory = "#{basedir}/bin"
+if node[:nominatim][:api_flavour] == "php"
+  package %w[
+    php-pgsql
+    php-intl
+  ]
+elsif node[:nominatim][:api_flavour] == "python"
+
+  python_virtualenv python_directory do
+    interpreter "/usr/bin/python3"
+  end
+
+  python_package "SQLAlchemy" do
+    python_virtualenv python_directory
+    version "2.0.29"
+  end
+
+  python_package "PyICU" do
+    python_virtualenv python_directory
+    version "2.12"
+  end
+
+  python_package "psycopg[binary]" do
+    python_virtualenv python_directory
+    version "3.1.18"
+  end
+
+  python_package "psycopg2-binary" do
+    python_virtualenv python_directory
+    version "2.9.9"
+  end
+
+  python_package "python-dotenv" do
+    python_virtualenv python_directory
+    version "0.21.0"
+  end
+
+  python_package "pygments" do
+    python_virtualenv python_directory
+    version "2.17.2"
+  end
+
+  python_package "PyYAML" do
+    python_virtualenv python_directory
+    version "6.0.1"
+  end
+
+  python_package "falcon" do
+    python_virtualenv python_directory
+    version "3.1.3"
+  end
+
+  python_package "uvicorn" do
+    python_virtualenv python_directory
+    version "0.29.0"
+  end
+
+  python_package "gunicorn" do
+    python_virtualenv python_directory
+    version "22.0.0"
+  end
+end
+
+source_directory = "#{basedir}/src/nominatim"
+build_directory = "#{basedir}/src/build"
+project_directory = "#{basedir}/planet-project"
+bin_directory = "#{basedir}/bin"
+cfg_directory = "#{basedir}/etc"
+ui_directory = "#{basedir}/ui"
+qa_bin_directory = "#{basedir}/src/Nominatim-Data-Analyser"
+qa_data_directory = "#{basedir}/qa-data"
 
-directory build_directory do
+[basedir, "#{basedir}/src", cfg_directory, bin_directory, build_directory, project_directory].each do |path|
+  directory path do
+    owner "nominatim"
+    group "nominatim"
+    mode "755"
+    recursive true
+  end
+end
+
+directory "#{bin_directory}/maintenance" do
   owner "nominatim"
   group "nominatim"
-  mode 0o755
-  recursive true
+  mode "775"
+end
+
+if node[:nominatim][:flatnode_file]
+  directory File.dirname(node[:nominatim][:flatnode_file]) do
+    recursive true
+  end
+end
+
+remote_directory "#{project_directory}/static-website" do
+  source "website"
+  owner "nominatim"
+  group "nominatim"
+  mode "755"
+  files_owner "nominatim"
+  files_group "nominatim"
+  files_mode "644"
+  purge false
 end
 
 # Normally syncing via chef is a bad idea because syncing might involve
@@ -177,7 +271,15 @@ git source_directory do
   user "nominatim"
   group "nominatim"
   not_if { node[:nominatim][:state] != "slave" && File.exist?("#{source_directory}/README.md") }
-  notifies :run, "execute[compile_nominatim]", :immediately
+  notifies :run, "execute[compile_nominatim]"
+end
+
+remote_file "#{source_directory}/data/country_osm_grid.sql.gz" do
+  action :create_if_missing
+  source "https://nominatim.org/data/country_grid.sql.gz"
+  owner "nominatim"
+  group "nominatim"
+  mode "644"
 end
 
 execute "compile_nominatim" do
@@ -185,221 +287,350 @@ execute "compile_nominatim" do
   user "nominatim"
   cwd build_directory
   command "cmake #{source_directory} && make"
+  notifies :run, "execute[install_nominatim]"
 end
 
-template "#{source_directory}/.git/hooks/post-merge" do
-  source "git-post-merge-hook.erb"
-  owner "nominatim"
-  group "nominatim"
-  mode 0o755
-  variables :srcdir => source_directory,
-            :builddir => build_directory,
-            :dbname => node[:nominatim][:dbname]
+execute "install_nominatim" do
+  action :nothing
+  cwd build_directory
+  command "make install"
 end
 
-template "#{build_directory}/settings/local.php" do
-  source "settings.erb"
+# Project directory
+
+template "#{project_directory}/.env" do
+  source "nominatim.env.erb"
   owner "nominatim"
   group "nominatim"
-  mode 0o664
+  mode "664"
   variables :base_url => node[:nominatim][:state] == "off" ? node[:fqdn] : "nominatim.openstreetmap.org",
             :dbname => node[:nominatim][:dbname],
             :flatnode_file => node[:nominatim][:flatnode_file],
-            :log_file => "#{node[:nominatim][:logdir]}/query.log"
+            :log_file => "#{node[:nominatim][:logdir]}/query.log",
+            :tokenizer => node[:nominatim][:config][:tokenizer],
+            :forward_dependencies => node[:nominatim][:config][:forward_dependencies],
+            :pool_size => node[:nominatim][:api_pool_size],
+            :query_timeout => node[:nominatim][:api_query_timeout],
+            :request_timeout => node[:nominatim][:api_request_timeout]
 end
 
-if node[:nominatim][:flatnode_file]
-  directory File.dirname(node[:nominatim][:flatnode_file]) do
-    recursive true
-  end
+remote_file "#{project_directory}/secondary_importance.sql.gz" do
+  action :create_if_missing
+  source "https://nominatim.org/data/wikimedia-secondary-importance.sql.gz"
+  owner "nominatim"
+  group "nominatim"
+  mode "644"
 end
 
-template "/etc/logrotate.d/nominatim" do
-  source "logrotate.nominatim.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+remote_file "#{project_directory}/wikimedia-importance.sql.gz" do
+  action :create_if_missing
+  source "https://nominatim.org/data/wikimedia-importance.sql.gz"
+  owner "nominatim"
+  group "nominatim"
+  mode "644"
 end
 
-external_data = [
-  "wikimedia-importance.sql.gz",
-  "gb_postcode_data.sql.gz"
-]
+%w[gb_postcodes.csv.gz us_postcodes.csv.gz].each do |fname|
+  remote_file "#{project_directory}/#{fname}" do
+    action :create
+    source "https://nominatim.org/data/#{fname}"
+    owner "nominatim"
+    group "nominatim"
+    mode "644"
+  end
+end
+
+# Webserver + frontend
 
-external_data.each do |fname|
-  remote_file "#{source_directory}/data/#{fname}" do
+%w[user_agent referrer email generic].each do |name|
+  file "#{cfg_directory}/nginx_blocked_#{name}.conf" do
     action :create_if_missing
-    source "https://www.nominatim.org/data/#{fname}"
     owner "nominatim"
-    group "nominatim"
-    mode 0o644
+    group "adm"
+    mode "664"
   end
 end
 
-remote_file "#{source_directory}/data/country_osm_grid.sql.gz" do
-  action :create_if_missing
-  source "https://www.nominatim.org/data/country_grid.sql.gz"
-  owner "nominatim"
-  group "nominatim"
-  mode 0o644
+if node[:nominatim][:api_flavour] == "php"
+  node[:nominatim][:fpm_pools].each do |name, data|
+    php_fpm name do
+      port data[:port]
+      pm data[:pm]
+      pm_max_children data[:max_children]
+      pm_start_servers 20
+      pm_min_spare_servers 10
+      pm_max_spare_servers 20
+      pm_max_requests 10000
+      prometheus_port data[:prometheus_port]
+    end
+  end
+elsif node[:nominatim][:api_flavour] == "python"
+  systemd_service "nominatim" do
+    description "Nominatim running as a gunicorn application"
+    user "www-data"
+    group "www-data"
+    working_directory project_directory
+    standard_output "append:#{node[:nominatim][:logdir]}/gunicorn.log"
+    standard_error "inherit"
+    exec_start "#{python_directory}/bin/gunicorn --max-requests 200000 -b unix:/run/gunicorn-nominatim.openstreetmap.org.sock -w #{node[:nominatim][:api_workers]} -k uvicorn.workers.UvicornWorker nominatim.server.falcon.server:run_wsgi"
+    exec_reload "/bin/kill -s HUP $MAINPID"
+    environment :PYTHONPATH => "/usr/local/lib/nominatim/lib-python/"
+    kill_mode "mixed"
+    timeout_stop_sec 5
+    private_tmp true
+    requires "nominatim.socket"
+    after "network.target"
+  end
+
+  systemd_socket "nominatim" do
+    description "Gunicorn socket for Nominatim"
+    listen_stream "/run/gunicorn-nominatim.openstreetmap.org.sock"
+    socket_user "www-data"
+  end
 end
 
-template "/etc/cron.d/nominatim" do
-  action node[:nominatim][:state] == "off" ? :delete : :create
-  source "nominatim.cron.erb"
-  owner "root"
-  group "root"
-  mode "0644"
-  variables :bin_directory => "#{source_directory}/utils",
-            :mailto => email_errors,
-            :update_maintenance_trigger => "#{basedir}/status/update_maintenance"
+ssl_certificate node[:fqdn] do
+  domains [node[:fqdn],
+           "nominatim.openstreetmap.org",
+           "nominatim.osm.org",
+           "nominatim.openstreetmap.com",
+           "nominatim.openstreetmap.net",
+           "nominatim.openstreetmaps.org",
+           "nominatim.openmaps.org",
+           "nominatim.qgis.org"]
+  notifies :reload, "service[nginx]"
 end
 
-template "#{source_directory}/utils/nominatim-update" do
-  source "updater.erb"
-  user "nominatim"
-  group "nominatim"
-  mode 0o755
-  variables :bindir => build_directory,
-            :srcdir => source_directory,
-            :logfile => "#{node[:nominatim][:logdir]}/update.log",
-            :branch => node[:nominatim][:revision],
-            :update_stop_file => "#{basedir}/status/updates_disabled",
-            :update_maintenance_trigger => "#{basedir}/status/update_maintenance"
+include_recipe "nginx"
+
+nginx_site "default" do
+  action [:delete]
 end
 
-template "/etc/init.d/nominatim-update" do
-  source "updater.init.erb"
-  user "nominatim"
-  group "nominatim"
-  mode 0o755
-  variables :source_directory => source_directory
+frontends = search(:node, "recipes:web\\:\\:frontend").sort_by(&:name)
+
+nginx_site "nominatim" do
+  template "nginx.erb"
+  directory project_directory
+  variables :pools => node[:nominatim][:fpm_pools],
+            :frontends => frontends,
+            :confdir => "#{basedir}/etc",
+            :ui_directory => ui_directory
 end
 
-%w[backup-nominatim vacuum-db-nominatim].each do |fname|
-  template "/usr/local/bin/#{fname}" do
+template "/etc/logrotate.d/nginx" do
+  source "logrotate.nginx.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+# Updates
+
+%w[nominatim-update
+   nominatim-update-source
+   nominatim-update-refresh-db
+   nominatim-update-data
+   nominatim-daily-maintenance].each do |fname|
+  template "#{bin_directory}/#{fname}" do
     source "#{fname}.erb"
-    owner "root"
-    group "root"
-    mode 0o755
-    variables :db => node[:nominatim][:dbname]
+    owner "nominatim"
+    group "nominatim"
+    mode "554"
+    variables :bindir => bin_directory,
+              :srcdir => source_directory,
+              :builddir => build_directory,
+              :projectdir => project_directory,
+              :qabindir => qa_bin_directory,
+              :qadatadir => qa_data_directory
   end
 end
 
-## webserver frontend
+systemd_service "nominatim-update" do
+  description "Update the Nominatim database"
+  exec_start "#{bin_directory}/nominatim-update"
+  restart "on-success"
+  standard_output "append:#{node[:nominatim][:logdir]}/update.log"
+  standard_error "inherit"
+  working_directory project_directory
+end
 
-template "#{build_directory}/settings/ip_blocks.conf" do
-  action :create_if_missing
-  source "ipblocks.erb"
-  owner "nominatim"
-  group "nominatim"
-  mode 0o664
+systemd_service "nominatim-update-maintenance-trigger" do
+  description "Trigger daily maintenance tasks for Nominatim DB"
+  exec_start "ln -sf #{bin_directory}/nominatim-daily-maintenance #{bin_directory}/maintenance/"
+  user "nominatim"
 end
 
-file "#{build_directory}/settings/apache_blocks.conf" do
-  action :create_if_missing
-  owner "nominatim"
+systemd_timer "nominatim-update-maintenance-trigger" do
+  action node[:nominatim][:state] != "off" ? :create : :delete
+  description "Schedule daily maintenance tasks for Nominatim DB"
+  on_calendar "*-*-* 02:03:00 UTC"
+end
+
+service "nominatim-update-maintenance-trigger" do
+  action node[:nominatim][:state] != "off" ? :enable : :disable
+end
+
+# Nominatim UI
+
+git ui_directory do
+  action :sync
+  repository node[:nominatim][:ui_repository]
+  revision node[:nominatim][:ui_revision]
+  user "nominatim"
   group "nominatim"
-  mode 0o664
 end
 
-file "#{build_directory}/settings/ip_blocks.map" do
-  action :create_if_missing
+template "#{ui_directory}/dist/theme/config.theme.js" do
+  source "ui-config.js.erb"
   owner "nominatim"
   group "nominatim"
-  mode 0o664
+  mode "664"
 end
 
-include_recipe "apache"
+# Nominatim QA
 
-package "php"
-package "php-fpm"
-package "php-pgsql"
-package "php-intl"
+if node[:nominatim][:enable_qa_tiles]
+  package "python3-geojson"
 
-apache_module "rewrite"
-apache_module "proxy"
-apache_module "proxy_fcgi"
-apache_module "proxy_http"
-apache_module "headers"
+  git qa_bin_directory do
+    repository node[:nominatim][:qa_repository]
+    revision node[:nominatim][:qa_revision]
+    enable_submodules true
+    user "nominatim"
+    group "nominatim"
+    notifies :run, "execute[compile_qa]"
+  end
 
-service "php7.2-fpm" do
-  action [:enable, :start]
-  supports :status => true, :restart => true, :reload => true
-end
+  execute "compile_qa" do
+    action :nothing
+    user "nominatim"
+    cwd "#{qa_bin_directory}/clustering-vt"
+    command "make"
+  end
 
-node[:nominatim][:fpm_pools].each do |name, data|
-  template "/etc/php/7.2/fpm/pool.d/#{name}.conf" do
-    source "fpm.conf.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    variables data.merge(:name => name)
-    notifies :reload, "service[php7.2-fpm]"
+  directory qa_data_directory do
+    owner "nominatim"
+    group "nominatim"
+    mode "755"
+    recursive true
   end
-end
 
-systemd_service "apache-nominatim" do
-  service "apache2"
-  dropin "nominatim"
-  tasks_max 12000
-  notifies :restart, "service[apache2]"
-end
+  template "#{qa_bin_directory}/analyser/config/config.yaml" do
+    source "qa_config.erb"
+    owner "nominatim"
+    group "nominatim"
+    mode "755"
+    variables :outputdir => "#{qa_data_directory}/new"
+  end
 
-ssl_certificate "nominatim.openstreetmap.org" do
-  domains ["nominatim.openstreetmap.org",
-           "nominatim.osm.org",
-           "nominatim.openstreetmap.com",
-           "nominatim.openstreetmap.net",
-           "nominatim.openstreetmaps.org",
-           "nominatim.openmaps.org"]
-  notifies :reload, "service[apache2]"
-end
+  ssl_certificate "qa-tile.nominatim.openstreetmap.org" do
+    domains ["qa-tile.nominatim.openstreetmap.org"]
+    notifies :reload, "service[nginx]"
+  end
+
+  nginx_site "qa-tiles.nominatim" do
+    template "nginx-qa-tiles.erb"
+    directory build_directory
+    variables :qa_data_directory => qa_data_directory
+  end
 
-apache_site "nominatim.openstreetmap.org" do
-  template "apache.erb"
-  directory build_directory
-  variables :pools => node[:nominatim][:fpm_pools]
-  only_if { node[:nominatim][:state] != "off" }
 end
 
-apache_site "default" do
-  action [:disable]
+# Replication
+
+cron_d "nominatim-clean-db" do
+  action node[:nominatim][:state] == "master" ? :create : :delete
+  minute "5"
+  hour "*/4"
+  user "postgres"
+  command "#{bin_directory}/clean-db-nominatim"
+  mailto email_errors
 end
 
-template "/etc/logrotate.d/apache2" do
-  source "logrotate.apache.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+if node[:nominatim][:state] == "master"
+  postgresql_user "replication" do
+    cluster node[:nominatim][:dbcluster]
+    password data_bag_item("nominatim", "passwords")["replication"]
+    replication true
+  end
+
+  directory node[:rsyncd][:modules][:archive][:path] do
+    owner "postgres"
+    group "postgres"
+    mode "700"
+  end
+
+  template "#{bin_directory}/clean-db-nominatim" do
+    source "clean-db-nominatim.erb"
+    owner "nominatim"
+    group "nominatim"
+    mode "755"
+    variables :archive_dir => node[:rsyncd][:modules][:archive][:path],
+              :update_stop_file => "#{basedir}/status/updates_disabled",
+              :streaming_clients => search(:node, "nominatim_state:slave").map { |slave| slave[:fqdn] }.join(" ")
+  end
 end
 
-include_recipe "fail2ban"
+# Maintenance
 
-munin_plugin_conf "nominatim" do
-  template "munin.erb"
-  variables :db => node[:nominatim][:dbname],
-            :querylog => "#{node[:nominatim][:logdir]}/query.log"
+cron_d "nominatim-backup" do
+  action (node[:nominatim][:enable_backup] && node[:nominatim][:state] != "off") ? :create : :delete
+  minute "0"
+  hour "3"
+  day "1"
+  user "nominatim"
+  command "#{bin_directory}/backup-nominatim"
+  mailto email_errors
 end
 
-munin_plugin "nominatim_importlag" do
-  target "#{source_directory}/munin/nominatim_importlag"
+cron_d "nominatim-vacuum-db" do
+  action node[:nominatim][:state] != "off" ? :create : :delete
+  minute "20"
+  hour "0"
+  user "postgres"
+  command "#{bin_directory}/vacuum-db-nominatim"
+  mailto email_errors
 end
 
-munin_plugin "nominatim_query_speed" do
-  target "#{source_directory}/munin/nominatim_query_speed_querylog"
+%w[backup-nominatim vacuum-db-nominatim].each do |fname|
+  template "#{bin_directory}/#{fname}" do
+    source "#{fname}.erb"
+    owner "nominatim"
+    group "nominatim"
+    mode "755"
+    variables :db => node[:nominatim][:dbname]
+  end
 end
 
-munin_plugin "nominatim_requests" do
-  target "#{source_directory}/munin/nominatim_requests_querylog"
+# Logging
+
+template "/etc/logrotate.d/nominatim" do
+  source "logrotate.nominatim.erb"
+  owner "root"
+  group "root"
+  mode "644"
 end
 
-munin_plugin "nominatim_throttled_ips" do
-  target "#{source_directory}/munin/nominatim_throttled_ips"
+# Monitoring
+prometheus_exporter "nominatim" do
+  port 8082
+  user "www-data"
+  restrict_address_families "AF_UNIX"
+  options [
+    "--nominatim.query-log=#{node[:nominatim][:logdir]}/query.log",
+    "--nominatim.database-name=#{node[:nominatim][:dbname]}"
+  ]
 end
 
-directory "#{basedir}/status" do
-  owner "nominatim"
-  group "postgres"
-  mode 0o775
+include_recipe "fail2ban"
+
+frontend_addresses = frontends.collect { |f| f.ipaddresses(:role => :external) }
+
+fail2ban_jail "nominatim_limit_req" do
+  filter "nginx-limit-req"
+  logpath "#{node[:nominatim][:logdir]}/nominatim.openstreetmap.org-error.log"
+  ports [80, 443]
+  maxretry 20
+  ignoreips frontend_addresses.flatten.sort
 end
diff --git a/cookbooks/nominatim/templates/default/apache.erb b/cookbooks/nominatim/templates/default/apache.erb
deleted file mode 100644 (file)
index 9d29290..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-    ServerName <%= node[:fqdn] %>
-    ServerAlias nominatim.openstreetmap.org
-    ServerAlias nominatim.osm.org
-    ServerAlias nominatim.openstreetmap.com
-    ServerAlias nominatim.openstreetmap.net
-    ServerAlias nominatim.openstreetmaps.org
-    ServerAlias nominatim.openmaps.org
-    ServerAdmin webmaster@openstreetmap.org
-
-    # Enable SSL
-    SSLEngine on
-    SSLProxyEngine on
-    SSLCertificateFile /etc/ssl/certs/nominatim.openstreetmap.org.pem
-    SSLCertificateKeyFile /etc/ssl/private/nominatim.openstreetmap.org.key
-
-    # Remove Proxy request header to mitigate https://httpoxy.org/
-    RequestHeader unset Proxy early
-
-    RequestReadTimeout header=15-30,MinRate=500 body=15-30,MinRate=500
-
-    CustomLog <%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-access.log combined
-    ErrorLog /var/log/apache2/nominatim.openstreetmap.org-error.log
-
-    DocumentRoot <%= @directory %>/website
-    <Directory "<%= @directory %>/website/">
-        DirectoryIndex search.php
-        Options FollowSymLinks
-        Require all granted
-    </Directory>
-
-    ProxyPassMatch ^/([^/]*\.php(/.*)?)$ fcgi://127.0.0.1:<%= @pools[:www][:port ]%><%= @directory %>/website/$1
-
-    <% @pools.each do |name,details| -%>
-    Alias /pool-<%= name %>/ "<%= @directory %>/website/"
-    <% node[:nominatim][:redirects].each do |url,host| -%>
-    ProxyPassMatch ^/pool-<%= name %>/(<%= url %>\.php(/.*)?) http<% if port == 443 -%>s<% end -%>://<%= host %>/pool-<%= name %>/$1
-    <% end -%>
-    ProxyPassMatch ^/pool-<%= name %>/(.*\.php(/.*)?) fcgi://127.0.0.1:<%= details[:port ]%><%= @directory %>/website/$1
-    <% end -%>
-
-    Redirect 429 /pool-block/
-    ErrorDocument 429 /509.html
-    <Location /pool-block>
-        ErrorDocument 429 /509.html
-    </Location>
-    Redirect 403 /pool-ban/
-    <Location /pool-ban>
-        ErrorDocument 403 /403.html
-    </Location>
-    ErrorDocument 403 /403.html
-
-    RewriteEngine On
-
-    # manual blocks
-    Include <%= @directory %>/settings/apache_blocks.conf
-
-    # regular requests and autoblocks
-    RewriteMap bulklist txt:<%= @directory %>/settings/ip_blocks.map
-    RewriteRule ^/(search|reverse|lookup)(\.php)?(/.*)? /pool-${bulklist:%{REMOTE_ADDR}|www}/$1.php$3 [PT]
-    RewriteRule ^/details(\.php)?(/.*)? /pool-${bulklist:%{REMOTE_ADDR}|details}/details.php$2 [PT]
-</VirtualHost>
-
-<VirtualHost *:80>
-    ServerName <%= node[:fqdn] %>
-    ServerAlias nominatim.openstreetmap.org
-    ServerAlias nominatim.osm.org
-    ServerAlias nominatim.openstreetmap.com
-    ServerAlias nominatim.openstreetmap.net
-    ServerAlias nominatim.openstreetmaps.org
-    ServerAlias nominatim.openmaps.org
-    ServerAdmin webmaster@openstreetmap.org
-
-    CustomLog <%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-access.log combined
-    ErrorLog /var/log/apache2/nominatim.openstreetmap.org-error.log
-
-    RewriteEngine On
-
-    # manual blocks
-    Include <%= @directory %>/settings/apache_blocks.conf
-
-    RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-    RedirectPermanent / https://nominatim.openstreetmap.org/
-</VirtualHost>
diff --git a/cookbooks/nominatim/templates/default/fpm.conf.erb b/cookbooks/nominatim/templates/default/fpm.conf.erb
deleted file mode 100644 (file)
index 386769e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-; DO NOT EDIT - This file is being maintained by Chef
-
-[<%= @name %>]
-<% if @port -%>
-listen = 127.0.0.1:<%= @port %>
-<% else -%>
-listen = /var/run/php5-fpm-<%= @name %>.sock
-listen.owner = www-data
-listen.group = www-data
-<% end -%>
-
-user = www-data
-group = www-data
-
-pm = <%= @pm %>
-pm.max_children = <%= @max_children %>
-pm.start_servers = 20
-pm.min_spare_servers = 10
-pm.max_spare_servers = 20
-pm.max_requests = 10000
-
-security.limit_extensions = .php .phpx .phpj
diff --git a/cookbooks/nominatim/templates/default/git-post-merge-hook.erb b/cookbooks/nominatim/templates/default/git-post-merge-hook.erb
deleted file mode 100644 (file)
index a1ee317..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-cd <%= @srcdir %>
-
-git submodule update
-
-cd <%= @builddir %>
-
-cmake <%= @srcdir %> &&
-make
-
-psql -d <%= @dbname %> -c "SELECT version();" >/dev/null 2>&1
-if [[ "$?" == "0" ]]; then
-  ./utils/setup.php --create-functions --create-partition-functions --enable-diff-updates
-  ./utils/update.php --update-address-levels
-fi
diff --git a/cookbooks/nominatim/templates/default/ipblocks.erb b/cookbooks/nominatim/templates/default/ipblocks.erb
deleted file mode 100644 (file)
index 9fb36fe..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-LOGFILE='<%= node[:nominatim][:logdir] %>/restricted_ips.log'
-# space-separated list of IPs that are never banned
-WHITELIST = ''
-# space-separated list of IPs manually blocked
-BLACKLIST = ''
-# user-agents that should be blocked from bulk mode
-# (matched with startswith)
-UA_BLOCKLIST = ()
-
-# time before a automatically blocked IP is allowed back
-BLOCKCOOLOFF_PERIOD='1 hour'
-# quiet time before an IP is released from the bulk pool
-BULKCOOLOFF_PERIOD='15 min'
-
-BULKLONG_LIMIT=8000
-BULKSHORT_LIMIT=2000
-BLOCK_UPPER=19000
-BLOCK_LOWER=4000
-BLOCK_LOADFAC=380
-BULK_LOADFAC=160
-BULK_LOWER=1500
-MAX_BULK_IPS=85
-
diff --git a/cookbooks/nominatim/templates/default/logrotate.apache.erb b/cookbooks/nominatim/templates/default/logrotate.apache.erb
deleted file mode 100644 (file)
index 8835397..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-/var/log/apache2/*.log {
-  daily
-  missingok
-  rotate 42
-  compress
-  delaycompress
-  notifempty
-  create 640 root adm
-  sharedscripts
-  postrotate
-    /bin/systemctl reload apache2
-  endscript
-}
-
-
-<%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-access.log {
-  daily
-  missingok
-  rotate 42
-  compress
-  delaycompress
-  notifempty
-  create 640 root adm
-  sharedscripts
-  postrotate
-    /bin/systemctl reload apache2
-  endscript
-}
diff --git a/cookbooks/nominatim/templates/default/logrotate.nginx.erb b/cookbooks/nominatim/templates/default/logrotate.nginx.erb
new file mode 100644 (file)
index 0000000..e0eed7f
--- /dev/null
@@ -0,0 +1,29 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+/var/log/nginx/*.log {
+  daily
+  missingok
+  rotate 7
+  compress
+  delaycompress
+  notifempty
+  create 640 www-data adm
+  sharedscripts
+  postrotate
+    [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
+  endscript
+}
+
+<%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-*.log {
+  daily
+  missingok
+  rotate 28
+  compress
+  delaycompress
+  notifempty
+  create 640 www-data adm
+  sharedscripts
+  postrotate
+    [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
+  endscript
+}
index e1fc714162514a83c357b44f8789fc13bc521bcb..497cb41cf402b26b211aa22626a2f04ed6368e7e 100644 (file)
   compress
   delaycompress
   notifempty
+<% if node[:nominatim][:api_flavour] == "python" %>
+  postrotate
+        systemctl reload nominatim.service
+  endscript
+<% end -%>
   create 640 www-data adm
 }
-
-<%= node[:nominatim][:logdir] %>/restricted_ips.log {
-  weekly
-  missingok
-  rotate 5
-  compress
-  delaycompress
-  notifempty
-  create 660 nominatim adm
-}
diff --git a/cookbooks/nominatim/templates/default/munin.erb b/cookbooks/nominatim/templates/default/munin.erb
deleted file mode 100644 (file)
index 2843145..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[nominatim_*]
-user www-data
-env.PGDATABASE <%= @db %>
-env.PGUSER www-data
-env.NOMINATIM_QUERYLOG <%= @querylog %>
diff --git a/cookbooks/nominatim/templates/default/nginx-qa-tiles.erb b/cookbooks/nominatim/templates/default/nginx-qa-tiles.erb
new file mode 100644 (file)
index 0000000..7dbd605
--- /dev/null
@@ -0,0 +1,23 @@
+server {
+    listen 80;
+    listen [::]:80;
+
+    listen 443 ssl http2;
+    listen [::]:443 ssl http2;
+
+    ssl_certificate /etc/ssl/certs/qa-tile.nominatim.openstreetmap.org.pem;
+    ssl_certificate_key /etc/ssl/private/qa-tile.nominatim.openstreetmap.org.key;
+
+    server_name qa-tile.nominatim.openstreetmap.org;
+
+    root <%= @qa_data_directory %>/current;
+
+    access_log <%= node[:nominatim][:logdir] %>/qa-tile.nominatim.openstreetmap.org-access.log combined;
+    error_log <%= node[:nominatim][:logdir] %>/qa-tile.nominatim.openstreetmap.org-error.log;
+
+    rewrite ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 permanent;
+
+    location / {
+        add_header Access-Control-Allow-Origin "*" always;
+    }
+}
diff --git a/cookbooks/nominatim/templates/default/nginx.erb b/cookbooks/nominatim/templates/default/nginx.erb
new file mode 100644 (file)
index 0000000..5e74bef
--- /dev/null
@@ -0,0 +1,256 @@
+upstream nominatim_service {
+<% if node[:nominatim][:api_flavour] == "php" %>
+  server unix:/run/php/php-nominatim.openstreetmap.org-fpm.sock fail_timeout=0;
+<% elsif node[:nominatim][:api_flavour] == "python"  %>
+  server unix:/run/gunicorn-nominatim.openstreetmap.org.sock fail_timeout=0;
+<% end -%>
+}
+
+map $uri $nominatim_script_name {
+    ~^/*(.+?)\.php        $1;
+    ~^/*([^/]+)           $1;
+    ^$                   search;
+}
+
+map $uri $nominatim_path_info {
+    ~^/([^/]+)(.*)$      $2;
+}
+
+map $args $format {
+    default                  default;
+    ~(^|&)format=html(&|$)   html;
+    ~(^|&)format=            other;
+}
+
+map $uri/$format $forward_to_ui {
+    default               1;
+    ~^/ui                 0;
+    ~/other$              0;
+    ~/reverse.*/default   0;
+    ~/lookup.*/default    0;
+    ~/status.*/default    0;
+}
+
+map $query_string $email_id {
+    ~(^|&)email=([^&]+)  $2;
+}
+
+map $email_id $missing_email {
+    default "";
+    "" 1;
+}
+
+map $http_user_agent $missing_ua {
+    default "";
+    "" 1;
+}
+
+map $http_referer $missing_referer {
+    default "";
+    "" 1;
+}
+
+# Whitelisted IPs
+geo $whitelisted {
+    default 0;
+<% @frontends.each do |frontend| -%>
+<% frontend.ipaddresses(:role => :external).sort.each do |address| -%>
+    <%= address %> 1;
+<% end -%>
+<% end -%>
+    46.235.224.148 1;
+    209.132.180.180 1;
+    209.132.180.168 1;
+    8.43.85.3 1; # gnome
+    8.43.85.4 1; # gnome
+    8.43.85.5 1; # gnome
+    2620:52:3:1:5054:ff:fe0a:75a4 1; # gnome
+    2620:52:3:1:5054:ff:fe0a:75a2 1; # gnome
+    2620:52:3:1:5054:ff:fe0a:75aa 1; # gnome
+}
+
+map $missing_email$missing_referer$http_user_agent $blocked_user_agent {
+   default 0;
+   "11" 2; # block any requests without identifier
+   include <%= @confdir %>/nginx_blocked_user_agent.conf;
+}
+
+map $missing_email$missing_ua$http_referer $blocked_referrer {
+   default 0;
+   include <%= @confdir %>/nginx_blocked_referrer.conf;
+}
+
+map $missing_referer$missing_ua$email_id $blocked_email {
+   default 0;
+   include <%= @confdir %>/nginx_blocked_email.conf;
+}
+
+map $whitelisted $limit_www {
+    1 "";
+    0 $binary_remote_addr;
+}
+
+map $blocked_user_agent $limit_tarpit {
+    0 "";
+    1 $binary_remote_addr;
+    2 $binary_remote_addr;
+}
+
+map $missing_email$missing_referer$http_user_agent $generic_mozilla {
+    default 0;
+    ~^11Mozilla/4.0 1;
+    ~^11Mozilla/5.0 2;
+}
+
+map $whitelisted$generic_mozilla$uri $limit_reverse {
+    default "";
+    ~01/reverse.*  $binary_remote_addr;
+    ~02/reverse.*  $binary_remote_addr;
+}
+
+limit_req_zone $limit_www zone=www:50m rate=2r/s;
+limit_req_zone $limit_tarpit zone=tarpit:10m rate=1r/s;
+limit_req_zone $binary_remote_addr zone=blocked:10m rate=20r/m;
+limit_req_zone $limit_reverse zone=reverse:10m rate=10r/m;
+
+server {
+    listen 80 default_server;
+    listen [::]:80 default_server;
+
+    access_log <%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-access.log combined;
+    error_log <%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-error.log;
+
+    location /nginx_status {
+        stub_status on;
+        access_log   off;
+        allow 127.0.0.1;
+        allow ::1;
+        deny all;
+    }
+
+     rewrite ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 permanent;
+
+     location / {
+         return 301 https://$host$request_uri;
+     }
+}
+
+server {
+    # IPv4
+    listen       443 ssl http2 default_server;
+    # IPv6
+    listen       [::]:443 ssl http2 default_server;
+    server_name  localhost;
+
+    ssl_certificate /etc/ssl/certs/<%= node[:fqdn] %>.pem;
+    ssl_certificate_key /etc/ssl/private/<%= node[:fqdn] %>.key;
+
+    root <%= @directory %>/static-website;
+    index /search;
+
+    access_log <%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-access.log combined;
+    error_log <%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-error.log;
+
+    location /nginx_status {
+        stub_status on;
+        access_log   off;
+        allow 127.0.0.1;
+        allow ::1;
+        deny all;
+    }
+
+    error_page 403 /403.html;
+    location /403.html {
+        limit_req zone=blocked burst=5;
+    }
+
+    error_page 429 /509.html;
+    location /509.html {
+        limit_req zone=blocked burst=5;
+    }
+
+    location / {
+        try_files $uri $uri/ @php;
+    }
+
+    location /ui/ {
+        alias <%= @ui_directory %>/dist/;
+        index search.html;
+    }
+
+    location /qa-data/ {
+        add_header Access-Control-Allow-Origin "*" always;
+    }
+
+    location ~* ^/(search|reverse)(\.php)?/ {
+        error_page 404 /404-old-search-syntax.html;
+        return 404;
+    }
+
+    location @php {
+        if ($forward_to_ui) {
+            rewrite ^(/[^/]*) https://$host/ui$1.html redirect;
+        }
+        if ($blocked_user_agent ~ ^2$)
+        { return 403; }
+        if ($blocked_referrer)
+        { return 403; }
+        if ($blocked_email)
+        { return 403; }
+        if ($args ~* "q=[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[ &]")
+        { return 418; }
+        include <%= @confdir %>/nginx_blocked_generic.conf;
+
+        limit_req zone=www burst=10;
+        limit_req zone=tarpit burst=5;
+        limit_req zone=reverse burst=5;
+        limit_req_status 429;
+<% if node[:nominatim][:api_flavour] == "php" %>
+        fastcgi_pass nominatim_service;
+        include fastcgi_params;
+        fastcgi_param QUERY_STRING    $args;
+        fastcgi_param PATH_INFO       "$nominatim_path_info";
+        fastcgi_param SCRIPT_FILENAME  "<%= @directory %>/website/$nominatim_script_name";
+<% elsif node[:nominatim][:api_flavour] == "python" %>
+
+        if ($request_method = 'OPTIONS') {
+          add_header 'Content-Type' 'text/plain; charset=UTF-8';
+          add_header 'Content-Length' 0;
+          add_header Access-Control-Allow-Origin "*";
+          add_header Access-Control-Allow-Methods 'GET,OPTIONS';
+          add_header Access-Control-Allow-Headers $http_access_control_request_headers;
+          return 204;
+        }
+
+        proxy_set_header Host $http_host;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+        proxy_redirect off;
+        proxy_pass http://nominatim_service;
+<% end -%>
+    }
+
+<% if node[:nominatim][:api_flavour] == "php" %>
+    location ~* \.php$ {
+        if ($blocked_user_agent ~ ^2$)
+        { return 403; }
+        if ($blocked_referrer)
+        { return 403; }
+        if ($blocked_email)
+        { return 403; }
+        include <%= @confdir %>/nginx_blocked_generic.conf;
+
+        limit_req zone=www burst=10;
+        limit_req zone=tarpit burst=2;
+        limit_req zone=reverse burst=5;
+        limit_req_status 429;
+        fastcgi_pass    nominatim_service;
+        include         fastcgi_params;
+        fastcgi_param   SCRIPT_FILENAME    <%= @directory %>/website/$fastcgi_script_name;
+
+        if ($forward_to_ui) {
+            rewrite (.*).php https://$host/ui$1.html redirect;
+        }
+    }
+<% end -%>
+}
diff --git a/cookbooks/nominatim/templates/default/nominatim-daily-maintenance.erb b/cookbooks/nominatim/templates/default/nominatim-daily-maintenance.erb
new file mode 100644 (file)
index 0000000..837f4af
--- /dev/null
@@ -0,0 +1,15 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+nominatim refresh --postcodes --word-tokens --threads 4 -v
+
+<% if node[:nominatim][:enable_qa_tiles] -%>
+pushd <%= @qabindir %>
+if python3 cli.py --execute-all; then
+  rm -rf "<%= @qadatadir %>/old"
+  if [ -d "<%= @qadatadir %>/current" ]; then
+    mv "<%= @qadatadir %>/current" "<%= @qadatadir %>/old"
+  fi
+  mv "<%= @qadatadir %>/new" "<%= @qadatadir %>/current"
+fi
+popd
+<% end -%>
diff --git a/cookbooks/nominatim/templates/default/nominatim-update-data.erb b/cookbooks/nominatim/templates/default/nominatim-update-data.erb
new file mode 100644 (file)
index 0000000..69c832e
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+date "+%c === Downloading and updating latest data from OSM"
+
+cd <%= @projectdir %>
+
+# First execute any maintenance task that may be there.
+
+for task in `find <%= @bindir %>/maintenance -type f,l`; do
+  date "+%c === Running maintenance task ${task}"
+  . ${task}
+  rm ${task}
+done
+
+# Then catch up with the database.
+
+num_cpus=`cat /proc/cpuinfo | grep -c processor`
+num_cpus=$((num_cpus - 2))
+current_load=`cat /proc/loadavg | cut -f 2 -d ' ' | sed 's:\..*::'`
+
+if [[ $current_load -lt $num_cpus ]]
+then
+    INST=4
+else
+    INST=2
+fi
+
+nominatim replication --catch-up --threads $INST
diff --git a/cookbooks/nominatim/templates/default/nominatim-update-refresh-db.erb b/cookbooks/nominatim/templates/default/nominatim-update-refresh-db.erb
new file mode 100644 (file)
index 0000000..6d7b415
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+date "+%c === Refresh database after software updates"
+
+cd <%= @projectdir %>
+
+# Run the migrations from the nominatim version in the build directory,
+# so they can execute while the frontend doesn't have the new code yet.
+<%= @builddir %>/nominatim admin --migrate
+<%= @builddir %>/nominatim refresh --functions --address-levels --website
diff --git a/cookbooks/nominatim/templates/default/nominatim-update-source.erb b/cookbooks/nominatim/templates/default/nominatim-update-source.erb
new file mode 100644 (file)
index 0000000..dacb619
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash -e
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+# Note: the script must return 0 only when new updates have been applied.
+
+date "+%c === Checking for new versions of Nominatim"
+
+cd <%= @srcdir %>
+
+git fetch origin
+git fetch origin -tf
+
+if git diff --exit-code <%= node[:nominatim][:revision] %> >/dev/null; then
+  # signal that there are no new updates
+  exit 99
+fi
+
+git checkout --detach <%= node[:nominatim][:revision] %>
+git submodule update
+
+cd <%= @builddir %>
+cmake .
+make
diff --git a/cookbooks/nominatim/templates/default/nominatim-update.erb b/cookbooks/nominatim/templates/default/nominatim-update.erb
new file mode 100644 (file)
index 0000000..145ae6a
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+date "+%c === Starting Nominatim update cycle"
+
+starttime=`date +%s`
+
+<% if node[:nominatim][:enable_git_updates] -%>
+if /sbin/runuser -u nominatim -- <%= @bindir %>/nominatim-update-source; then
+
+  if ! /sbin/runuser -u nominatim -- <%= @bindir %>/nominatim-update-refresh-db; then
+    date "+%c === Database refresh failed. Stopping updates."
+    exit 1
+  fi
+
+  pushd <%= @builddir %>
+  make install
+
+<% if node[:nominatim][:api_flavour] == "python" -%>
+  systemctl reload nominatim
+<% end -%>
+fi
+<% end -%>
+
+if ! /sbin/runuser -u nominatim -- <%= @bindir %>/nominatim-update-data; then
+  date "+%c === Data update failed. Stopping updates."
+  exit 1
+fi
+
+date "+%c === Nominatim update cycle finished"
+
+# sleep a bit if updates take less than a minute
+endtime=`date +%s`
+elapsed=$((endtime - starttime))
+if [[ $elapsed -lt 60 ]]; then
+  sleepy=$((60 - $elapsed))
+  date "+%c === Sleeping for ${sleepy}s..."
+  sleep $sleepy
+fi
diff --git a/cookbooks/nominatim/templates/default/nominatim.cron.erb b/cookbooks/nominatim/templates/default/nominatim.cron.erb
deleted file mode 100644 (file)
index 5ae8f3a..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Maintained by chef. DO NOT EDIT.
-
-MAILTO=<%= @mailto %>
-
-* * * * * lonvia <%= @bin_directory %>/cron_ipanalyse.py <%= node[:nominatim][:logdir] %>/nominatim.openstreetmap.org-access.log
-<% if node[:nominatim][:enable_backup] -%>
-00 3 1 * * nominatim /usr/local/bin/backup-nominatim
-<% end -%>
-20 0 * * * postgres /usr/local/bin/vacuum-db-nominatim
-<% if node[:nominatim][:state] == "master" -%>
-05 */4 * * * postgres /usr/local/bin/clean-db-nominatim
-<% end -%>
-18 1 * * * nominatim touch <%= @update_maintenance_trigger %>
diff --git a/cookbooks/nominatim/templates/default/nominatim.env.erb b/cookbooks/nominatim/templates/default/nominatim.env.erb
new file mode 100644 (file)
index 0000000..9f38b02
--- /dev/null
@@ -0,0 +1,34 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+NOMINATIM_DATABASE_DSN="pgsql:dbname=<%= @dbname %>"
+NOMINATIM_MAPICON_URL="https://<%= @base_url %>/ui/mapicons"
+
+<% if @flatnode_file -%>
+NOMINATIM_FLATNODE_FILE="<%= @flatnode_file %>"
+<% end -%>
+
+NOMINATIM_SERVE_LEGACY_URLS=yes
+NOMINATIM_API_POOL_SIZE=<%= @pool_size %>
+NOMINATIM_QUERY_TIMEOUT=<%= @query_timeout %>
+NOMINATIM_REQUEST_TIMEOUT=<%= @request_timeout %>
+
+NOMINATIM_IMPORT_STYLE=extratags
+
+NOMINATIM_USE_US_TIGER_DATA=yes
+
+NOMINATIM_TOKENIZER="<%= @tokenizer %>"
+NOMINATIM_UPDATE_FORWARD_DEPENDENCIES="<%= @forward_dependencies %>"
+
+NOMINATIM_TABLESPACE_SEARCH_DATA=dsearch
+NOMINATIM_TABLESPACE_SEARCH_INDEX=isearch
+NOMINATIM_TABLESPACE_OSM_DATA=dosm
+NOMINATIM_TABLESPACE_OSM_INDEX=iosm
+NOMINATIM_TABLESPACE_PLACE_DATA=dplace
+NOMINATIM_TABLESPACE_PLACE_INDEX=iplace
+NOMINATIM_TABLESPACE_ADDRESS_DATA=daddress
+NOMINATIM_TABLESPACE_ADDRESS_INDEX=iaddress
+NOMINATIM_TABLESPACE_AUX_DATA=daux
+NOMINATIM_TABLESPACE_AUX_INDEX=iaux
+
+NOMINATIM_LOG_DB=no
+NOMINATIM_LOG_FILE="<%= @log_file %>"
diff --git a/cookbooks/nominatim/templates/default/qa_config.erb b/cookbooks/nominatim/templates/default/qa_config.erb
new file mode 100644 (file)
index 0000000..9f18856
--- /dev/null
@@ -0,0 +1,9 @@
+# DO NOT EDIT - This file is being maintained by Chef
+#Data source name for the database connection.
+Dsn: 'dbname=<%= node[:nominatim][:dbname] %>'
+
+#Path to the folder where rules data are stored (geojson, vector tiles, etc).
+RulesFolderPath: '<%= @outputdir %>'
+
+#Prefix path of the web URL to access the rules data (ex: https://nominatim.org/QA-data).
+WebPrefixPath: 'https://qa-tile.nominatim.openstreetmap.org'
diff --git a/cookbooks/nominatim/templates/default/settings.erb b/cookbooks/nominatim/templates/default/settings.erb
deleted file mode 100644 (file)
index 18858ca..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-# DO NOT EDIT - This file is being maintained by Chef
-
-@define('CONST_Database_DSN', 'pgsql:dbname=<%= @dbname %>');
-@define('CONST_Website_BaseURL', 'https://<%= @base_url %>/');
-
-<% if @flatnode_file -%>
-@define('CONST_Osm2pgsql_Flatnode_File', '<%= @flatnode_file %>');
-<% end -%>
-@define('CONST_Search_NameOnlySearchFrequencyThreshold', 500);
-
-@define('CONST_Use_US_Tiger_Data', true);
-
-@define('CONST_Tablespace_Osm2pgsql_Data', 'dosm');
-@define('CONST_Tablespace_Osm2pgsql_Index', 'iosm');
-@define('CONST_Tablespace_Place_Data', 'dplace');
-@define('CONST_Tablespace_Place_Index', 'iplace');
-@define('CONST_Tablespace_Address_Data', 'daddress');
-@define('CONST_Tablespace_Address_Index', 'iaddress');
-@define('CONST_Tablespace_Search_Data', 'dsearch');
-@define('CONST_Tablespace_Search_Index', 'isearch');
-@define('CONST_Tablespace_Aux_Data', 'daux');
-@define('CONST_Tablespace_Aux_Index', 'iaux');
-
-@define('CONST_Log_File', '<%= @log_file %>');
-@define('CONST_Log_DB', false);
diff --git a/cookbooks/nominatim/templates/default/ui-config.js.erb b/cookbooks/nominatim/templates/default/ui-config.js.erb
new file mode 100644 (file)
index 0000000..14ae831
--- /dev/null
@@ -0,0 +1,6 @@
+// DO NOT EDIT - This file is being maintained by Chef
+
+Nominatim_Config['Nominatim_API_Endpoint'] = '/';
+Nominatim_Config['Images_Base_Url'] = '/ui/mapicons/';
+
+Nominatim_Config['Page_Title'] = 'Nominatim';
diff --git a/cookbooks/nominatim/templates/default/updater.erb b/cookbooks/nominatim/templates/default/updater.erb
deleted file mode 100644 (file)
index ade5845..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/bash -e
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Change to Nominatim directory
-cd <%= @bindir %>
-
-num_cpus=`cat /proc/cpuinfo | grep -c processor`
-num_cpus=$((num_cpus - 2))
-
-while [ ! -f "<%= @update_stop_file %>" ]
-do
-    # Send output to the log (logrotatable)
-    exec >> <%= @logfile %> 2>&1
-
-    current_load=`cat /proc/loadavg | cut -f 2 -d ' ' | sed 's:\..*::'`
-
-    if [[ $current_load -lt $num_cpus ]]
-    then
-        INST=2
-    else
-        INST=1
-    fi
-
-    ./utils/update.php --import-osmosis --index-instances $INST
-
-<% if node[:nominatim][:enable_git_updates] -%>
-    pushd <%= @srcdir %>
-    if git fetch origin; then
-      # will trigger recompilation if necessary
-      git merge origin/<%= @branch %>
-    else
-      echo "WARNING: git fetch failed."
-    fi
-    popd
-<% end -%>
-
-    if [ -f "<%= @update_maintenance_trigger %>" ]; then
-        rm <%= @update_maintenance_trigger %>
-        ./utils/update.php --calculate-postcodes
-    fi
-done
diff --git a/cookbooks/nominatim/templates/default/updater.init.erb b/cookbooks/nominatim/templates/default/updater.init.erb
deleted file mode 100644 (file)
index cafc825..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-start() {
-  start-stop-daemon --start --chuid nominatim --background --make-pidfile --pidfile /var/run/nominatim-update.pid --exec <%= @source_directory %>/utils/nominatim-update
-}
-
-stop() {
-  start-stop-daemon --stop --retry 3600 --pidfile /var/run/nominatim-update.pid
-}
-
-case "$1" in
-  start)
-    start
-    ;;
-  stop)
-    stop
-    ;;
-  restart)
-    stop || exit $?
-    start
-    ;;
-esac
-
index e1be595e94c9c1280a33140e28795bc97abaeaf9..ce027f6063833d855cb0a43f7d55a2c53b5e81a3 100644 (file)
@@ -6,8 +6,3 @@
 # Vaccum all tables with indices on integer arrays.
 # Agressive vacuuming seems to help against index bloat.
 psql -q -d <%= @db %> -c 'VACUUM ANALYSE search_name'
-
-for i in `seq 0 250`; do
-  psql -q -d <%= @db %> -c "VACUUM ANALYSE search_name_${i}"
-done
-
index 910386b24b710d30afad603fd364b869a0449f4d..b512bb56a70d69557c888af542a1dce8b4ca338f 100644 (file)
@@ -6,3 +6,5 @@ description       "Installs and configures ntp as a client or server"
 
 version           "0.8.2"
 supports          "ubuntu"
+depends           "prometheus"
+depends           "systemd"
index 66acd1991e3c6308d1d71695cc540dac2823b4e1..9a15297f0e859612136885107123c170c8fc40c0 100644 (file)
@@ -17,6 +17,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+include_recipe "prometheus"
+
 package %w[
   chrony
   tzdata
@@ -40,7 +42,7 @@ template "/etc/chrony/chrony.conf" do
   source "chrony.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :restart, "service[chrony]"
 end
 
@@ -48,8 +50,26 @@ service "systemd-timesyncd" do
   action [:stop, :disable]
 end
 
+systemd_service "chrony-restart" do
+  service "chrony"
+  dropin "restart"
+  restart "on-failure"
+  notifies :restart, "service[chrony]"
+end
+
 service "chrony" do
   action [:enable, :start]
 end
 
-munin_plugin "chrony"
+prometheus_exporter "chrony" do
+  port 9123
+end
+
+# chrony occasionally marks all servers offline during a network outage.
+# force online all sources during a chef run
+execute "chronyc-online" do
+  command "/usr/bin/chronyc online"
+  user "root"
+  group "root"
+  ignore_failure true
+end
index 9f7b30d491f583d31f75b5ec29bbe405ba66b340..b3948809db4add73ed8bd03dad2f45a7c19d0f88 100644 (file)
@@ -1,9 +1,31 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
+<% if node[:lsb][:release].to_f >= 22.04 -%>
+# Include configuration files found in /etc/chrony/conf.d.
+confdir /etc/chrony/conf.d
+<% end -%>
+
 # Servers
 <% node[:ntp][:servers].each do |server| -%>
 pool <%= server %> iburst
 <% end -%>
+# Add additional non-pool NTP servers
+# pool.ntp.org can sometimes be aggressive with KoD
+pool time.cloudflare.com iburst
+pool time.google.com iburst
+
+# Allow local queries for monitoring
+allow 127.0.0.1/32
+allow ::1/128
+
+# Run an initial NTP sync on daemon startup
+# Use a few IPs here to workaround DNSSEC failure if time is wrong: https://github.com/openstreetmap/operations/issues/654
+initstepslew 30 216.239.35.0 216.239.35.4 216.239.35.8 216.239.35.12 time.google.com time.cloudflare.com <%= node[:ntp][:servers].join(" ") %>
+
+<% if node[:lsb][:release].to_f >= 22.04 -%>
+# Use NTP sources found in /etc/chrony/sources.d.
+sourcedir /etc/chrony/sources.d
+<% end -%>
 
 # This directive specify the location of the file containing ID/key pairs for
 # NTP authentication.
@@ -13,6 +35,11 @@ keyfile /etc/chrony/chrony.keys
 # information.
 driftfile /var/lib/chrony/chrony.drift
 
+<% if node[:lsb][:release].to_f >= 22.04 -%>
+# Save NTS keys and cookies.
+ntsdumpdir /var/lib/chrony
+<% end -%>
+
 # Uncomment the following line to turn logging on.
 #log tracking measurements statistics
 
@@ -29,8 +56,6 @@ rtcsync
 <% if node[:virtualization][:role] == "guest" -%>
 # Allow anytime step on VM guests
 makestep 1 -1
-# Allow 1h changes and do not exit
-maxchange 3600 1 -1
 <% else -%>
 # Step the system clock instead of slewing it if the adjustment is larger than
 # one second, but only in the first three clock updates.
@@ -40,3 +65,6 @@ makestep 1 3
 # Enable leap second slew
 leapsecmode slew
 maxslewrate 1000
+
+# Enable hardware timestamps if available
+hwtimestamp *
index 54e40108270c24c9a8b0808f6d0f54e4176bdd9c..72719e2ec21214016a8d1bff8f8b15290ebc4027 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :plugin, :kind_of => String, :name_attribute => true
-property :template, :kind_of => String, :required => true
+property :plugin, :kind_of => String, :name_property => true
+property :template, :kind_of => String, :required => [:create]
 
 action :create do
   ohai new_resource.plugin do
     action :nothing
   end
 
+  directory "/etc/chef/ohai/plugins" do
+    owner "root"
+    group "root"
+    mode "755"
+    recursive true
+  end
+
   declare_resource :template, plugin_path do
     source new_resource.template
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     notifies :reload, "ohai[#{new_resource.plugin}]"
   end
 end
@@ -44,6 +53,6 @@ end
 
 action_class do
   def plugin_path
-    "/etc/chef/ohai/#{new_resource.plugin}.rb"
+    "/etc/chef/ohai/plugins/#{new_resource.plugin}.rb"
   end
 end
index d829ee259f49fdaf34055c2fee3b46bc14a1fc82..7e5d783070834b01b88b514c908a2ef2dc971756 100644 (file)
@@ -1 +1,2 @@
 default[:openssh][:port] = 22
+default[:openssh][:password_authentication] = false
index 49c890b34a42c863fa5ebe4839fbb5aa2727bbf1..8b57aaaef75ef5e799b1ab08be8e6440cc811817 100644 (file)
@@ -23,26 +23,35 @@ include_recipe "networking"
 package "openssh-client"
 package "openssh-server"
 
+template "/etc/ssh/sshd_config.d/chef.conf" do
+  source "sshd_config.conf.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  notifies :restart, "service[ssh]"
+  only_if { Dir.exist?("/etc/ssh/sshd_config.d") }
+end
+
 service "ssh" do
   action [:enable, :start]
   supports :status => true, :restart => true, :reload => true
 end
 
 hosts = search(:node, "networking:interfaces").sort_by { |n| n[:hostname] }.collect do |node|
-  names = [node[:hostname]]
+  name = node.name.split(".").first
 
-  node.interfaces(:role => :external).each do |interface|
-    names |= ["#{node[:hostname]}.openstreetmap.org"]
-    names |= ["#{node[:hostname]}.#{interface[:zone]}.openstreetmap.org"]
-  end
+  names = [name]
 
   unless node.interfaces(:role => :internal).empty?
-    names |= ["#{node[:hostname]}.#{node[:networking][:roles][:external][:zone]}.openstreetmap.org"]
+    names.unshift("#{name}.#{node[:networking][:roles][:external][:zone]}.openstreetmap.org")
+  end
+
+  unless node.interfaces(:role => :external).empty?
+    names.unshift("#{name}.openstreetmap.org")
   end
 
   keys = {
-    "ssh-rsa" => node[:keys][:ssh][:host_rsa_public],
-    "ssh-dss" => node[:keys][:ssh][:host_dsa_public]
+    "ssh-rsa" => node[:keys][:ssh][:host_rsa_public]
   }
 
   if node[:keys][:ssh][:host_ecdsa_public]
@@ -56,22 +65,15 @@ hosts = search(:node, "networking:interfaces").sort_by { |n| n[:hostname] }.coll
   end
 
   Hash[
-    :names => names.sort,
+    :names => names,
     :addresses => node.ipaddresses.sort,
     :keys => keys
   ]
 end
 
-template "/etc/ssh/ssh_config" do
-  source "ssh_config.erb"
-  mode 0o644
-  owner "root"
-  group "root"
-end
-
 template "/etc/ssh/ssh_known_hosts" do
   source "ssh_known_hosts.erb"
-  mode 0o444
+  mode "444"
   owner "root"
   group "root"
   backup false
@@ -82,8 +84,7 @@ end
 
 firewall_rule "accept-ssh" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "tcp:syn"
+  context :incoming
+  protocol :tcp
   dest_ports node[:openssh][:port]
 end
diff --git a/cookbooks/openssh/templates/default/ssh_config.erb b/cookbooks/openssh/templates/default/ssh_config.erb
deleted file mode 100644 (file)
index d1e425e..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-Host *
-    SendEnv LANG LC_*
-    HashKnownHosts yes
-    GSSAPIAuthentication yes
-    GSSAPIDelegateCredentials no
-
-Host *.oob
-    HostKeyAlgorithms ssh-rsa,ssh-dss
-
-Host *.oob.openstreetmap.org
-    HostKeyAlgorithms ssh-rsa,ssh-dss
index 5a853562cd02e01e7e4d2295e68a126d6dfb4d9d..5aba9bcde0e4e03942a3489ebd6045914e69ced4 100644 (file)
@@ -1,68 +1,61 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
+# Automatically generated records
+
 <% @hosts.each do |host| -%>
 <% host[:keys].keys.sort.each do |type| -%>
 <%= host[:names].join(",") -%>,<%= host[:addresses].join(",") -%> <%= type %> <%= host[:keys][type] %>
 <% end -%>
 <% end -%>
-ridley.oob,ridley.oob.openstreetmap.org,10.0.1.3 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCohCtONR/6e/RvHnLlSbvl0GqY+EJeTn+Sxu2PyWsw+W1OAfa2jmb2DQg7S54CwbkyI/owJdVrM8Gj3s5CVOi1kIddu7+pbkqrIZKo4Mf+jviFypyZoGYHnPSBwEfgAWKtfBepnbW2RIZ9+JEXLjUyOFwU6jT8QnQMKJc5FiDP3Q==
-ridley.oob,ridley.oob.openstreetmap.org,10.0.1.3 ssh-dss AAAAB3NzaC1kc3MAAACBAKzNiUprAK/uF6ippll2gTyE7QIYg8kcE1a59/4iyyh56ChG3W4bq8jgA6ZLvJRks+rbKnjs98duqFKFoGC7sXmvNvLGD7jtSbAUkiPzNUsQ1uwPatNJk/mY5zzHjaxmgOUfA0EtDxKgvxli0atn8Xj8PGy49BbtlBPdnS+tItQ/AAAAFQCO2II1Su14H1gaeU0ogUCkG20ePQAAAIEAo0+0I7Ha53KM9xJWt1qQAVTV3FTGrOwrmedpz6JYcyELhNhC/ZUDOXu5GKqkp5SRcXZ9NRV4FiDMZgKvMGyvRcF1ZOkytNGtx12FiXAzVsM55O+hszLouqZocJVXY6Km3SKmVkymGi+unoowCHWMWJEIAjz80KyR7dsXHQKqIXEAAACAdlDbeOLTQLcgwTGRMbJR63fz6zvQQMZVJ3DDYzQxiW/0qB2CeaB0CuS9DDSJBLVlp2C9MIVnDxxaQi1KmUOvNs2fqb0NEZ8AQG7clCASgf9nXN0EBju+dZ+lGcB6c5ZIcDB/z0gFEp/16sHe8bay70Zp+S4ot6jXD5UM/pLSmF4=
-urmel.oob,urmel.oob.openstreetmap.org,10.0.1.6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC/Z50neDHObFvqY7SjrvtebendKtlfZ5KdpUHJXzootFg5zli09HaMep8YuEqBK9n1H06qnLQY6Hr3tKUEMBjjn1VS/hiB3OQlAqci0YEqcgwyiBTz2Etkb7lDXgJVDcFA5Pjj5sKnXw7gi4Nmkgg6cfQb81fed1ySGArcFY6PFQ==
-urmel.oob,urmel.oob.openstreetmap.org,10.0.1.6 ssh-rsa AAAAB3NzaC1kc3MAAACBAJr/RfX1uZxsD/wuhnTwManZnbVET7yjqGx9H9oVXgDfGNDpk22U0/7VKh0BVHi7iC6Z92YWgCG2Os/SuZgOLqXxdJAjZv9iYqBFQBszzBjGpbtpmOZPzi4q/B4KtXmsiWVPk/eQoW7JodeaalGEflJbYY4rdtfNhWl7uR79NH9lAAAAFQCGJ68LbEk6z0t0fV6UuM2C3KDODwAAAIEAilB3PdoejxgWtd5zVWfK1pYooWyplBp0/qkQ/WV1sT/4+LsuDk1ttszD4DkyvSFwgXKULdcWl56YI2+rFS9busxyNVhM8u5ou7rMvL/laNqkruK8FGdObo1CrpqNS1CuTEcZnIXJcz9grYdmwx9Vt51V0TP7ExKggijX0FmYN4YAAACAJZy0ekCJk2l2kJwTN6D7J4NLIip4Xyv7YZhOuguhEXjmowQrAqsXRyBED0cMdC4DuUOO0AmbLJ7cw/IJ9rf5d87ZVRx8EBaGLd+WAtDGoSsLnYgY9iRWpKkYqfhLAwSfXA9d5iO1rh+FWngLsCBJ3aDurJvQHCw/xVai76tnWTU=
-#zark.oob,zark.oob.openstreetmap.org,10.0.1.8 ssh-rsa
-#zark.oob,zark.oob.openstreetmap.org,10.0.1.8 ssh-dss
-eustace.oob,eustace.oob.openstreetmap.org,10.0.1.9 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC9wLWa3gAdXL/oUw67cLoHKiIOd959u++OOjXLR2OcyDkSLNTQgYkawEOcNgRVBcLjXh7ej9ktuTFbLWwR/Uvx7ftP5MH0Luo7Z9CvrQjw9Eu+G/CdGzvilHSeSAdCJYWemHXqKT9Qo9zJt2BI7wRfkFKdA5uXezwMYQtiQRHMkw==
-eustace.oob,eustace.oob.openstreetmap.org,10.0.1.9 ssh-dss AAAAB3NzaC1kc3MAAACBAMaxIrNlpW+VWMGGZ2NWdXC5Dbub7WluWXVf0kNwadZcwqn60wchAUDWnOL6grGjmYNPuHLW1P7tromy/uAssMML9YiNhCbJGUMF0IDWGl7bGjoOBsdp2slRaC9oZEceXH/yaRZJbxx9dri85WFLP9hz2A9mgi6Yx2k5oc4b2jr9AAAAFQD3k+OjolSAPwhQcYB97d5DDWjiawAAAIEAo7nRfP1i3VC3ovNAvY/SlvIq6iGorlkg8kMuBdTb5HPTPR8kOdplHGQ2+8es5H8a43GZorXbaUjsrzlQ98OzHrlw3BEzFvFZgY0kJwD64aeHOsDhltHzWV0tLz0Al5lR2ZpAE7V7Wv3x3wg3a+d9pmGkkgSwAqVQAsbPTp3wma4AAACBAJnhfhHZWrgNNnagbn+cuPpIC8vSwp/GNKK6VoQm7jq1u4t4eXPqHDuNA18pE1ngqPgZk1DYQUp98G1zKlhVJrUYHqi6wNG/qBMN8NuOyDeJ3a0iO6XIccEHvS15xzy4hpRerrg6yFeIhwZc1MbsEZqnPQzB2nJKtf5BqaeOjmcN
-eddie.oob,eddie.oob.openstreetmap.org,10.0.1.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+CNWzEucmDqWDAP2yq5gNGq1yC/1h5KohNb2sxOkac5RSij6/6UumO8tiW6PVY6wmiI01L+6UyRIfxWzqD/p+Pm60fNGJATrUsED/EEEbxKppWqbr5RjQfmfRqu/Msv0/QR1XnCEiEH2ixiubBBN8091Jn4m/GpZkLkcizpwOE3w3/FtUhydhdHgRKxQN8Mvu/pu9/6DocI7dNWEKWVUG8gbktUHe4+gHW9RQTPe1XISECt93i1NR3DKD2ldbtZbVeo9H0oRw1v9hmQdKXz6MUBQDenr1f1nzVmMqoLXJkdO2xBh2H9a6QME63nT+eO48BT/fo3VHomqFrR0MceGJ
-eddie.oob,eddie.oob.openstreetmap.org,10.0.1.10 ssh-dss AAAAB3NzaC1kc3MAAACBAIPneLfNaMa1qPVwRTKArXULa3ZRkKxia22DdT6ajV3HB9c0vjbMsI08vjjx9nWk2YWsZVuxx2kXi92o7uPJabFrstETbOv0TGTj6VVWThgGAqa5k7orMiSPOvyLPP3E9BOdf8nRpSPIq3cs/cBi4Oz0sPvbfljomXhgt1yC6EoRAAAAFQDqrUdtdgM33cYRUGqZ4MmZuyrHawAAAIATBEq5xAT0fH0hUJ47EBV9LRyi4kJfMyBlNwrSthUdIXhnhUTsO0se35I/1NOQhTcyI4fD+ZjR8qyy5SaR/QHFar1RKUksVa1S5JH+EaLHMSEEcdZCa7chx4Rg3UMJIHEE9zoPXn7VrbiAVtHck8IY/yIrSQpznIwuZGGonregnwAAAIBVv82Vkry8ypz8o/na00b03+n2KWRrkkWqKZvXSN43zVV6GQuwpgZpDjA6bLJjAkX27H2+jYB9QO3h/r0NndV7jkSPfHlCYgOg1HICI221Bnj2r466Fz0UdKI/wQqkJovJzNjrvwfESUqPfeTGGGo8AbyLlTI/JEUrHADmshS6LA==
-draco.oob,draco.oob.openstreetmap.org,10.0.1.11 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgHj1uavQKI1MXJaspRJasiPvhrM+EB+p47PuFh/BgFK4P5DnirS5sfApEheuGY7vcIiBnG2kcpNLiFmVylYXG1DbvBXsN0zLyJiyegdbT/SFjMq6AXyBfqFOA5na977JmJNBwzG7Z7jjeo4ZowRMSyQ3DjmGdj6vmSyT/BYO4E5Z
-sarel.oob,sarel.oob.openstreetmap.org,10.0.1.12 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCohCtONR/6e/RvHnLlSbvl0GqY+EJeTn+Sxu2PyWsw+W1OAfa2jmb2DQg7S54CwbkyI/owJdVrM8Gj3s5CVOi1kIddu7+pbkqrIZKo4Mf+jviFypyZoGYHnPSBwEfgAWKtfBepnbW2RIZ9+JEXLjUyOFwU6jT8QnQMKJc5FiDP3Q==
-sarel.oob,sarel.oob.openstreetmap.org,10.0.1.12 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgQCXV76oba/hqR50+HL1YjMeMPjBj8DfyNPcuEJwSO+TFbn4IW4xkxYYl3w4NuD8H6gj2Myk55Wza5BIR0oTWtuQuGiAKld+sIcMb7R2rT2KustEVuvy5GM1/NkAJ+sUa4lTTl64KPpFukFIC8Ma4hiEhXA4LnN02DZe0NdvyqkC9Q==
-noquiklos.oob,noquiklos.oob.openstreetmap.org,10.0.1.13 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDE5XeF6tG4hu9M0m+JWh4QJmL/52+cfeXbV4qfWwdJjSH9yBzYP9LiDM97gMXMUSnomAs7GO0KMwEdO9xuIZWeYFyHvs+1a73fAus8bcAbrZPuFfPfrW3JHKtWsfhUqYNJuRHLaimLIRyqgsXy3WAHf35v9kY1DmMWkf5/VTrp0w==
-noquiklos.oob,noquiklos.oob.openstreetmap.org,10.0.1.13 ssh-dss AAAAB3NzaC1kc3MAAACBAPK6Av/wAEtRnOx12117EtAhBPnodjQur0/k0pTAaGCZNnLY3E5SD7CvSqtB+LhRO/VSHXl1Obkh4mvR6oKEDE2XOWEG5Ofq3mWngT9Ejo0Rretzc1JU7L6WPZ8N/D+3kQUXpxDYzK9CcKz90k0msZUFRfGkHVE12ip9f7G/BWPRAAAAFQC5wUn4ZkWjt0z+/bUUOe298i0QvwAAAIEAz6dx6w5equWz3T8DWPM8LRGhE6ASrwR2UNpFe+sW5EBp/M+Zgg5Ztne1nIQaDSh1iKL0qzSGYxTIb/sIDKAxy6CzTjEhWRGmuDRTPQkXwD9iXcNaLChEEP6AryrI193LnLKRGKVve6gP2vH4tpn3Ve68HSKL4Ggz2L9ysKxJppEAAACABSHM7Ez/2oMaDGNRvgWc+ViB3QZOB1CTnDOkRZuhZXFMmTGXaWPzlwqPLZKg+wVOnJgBJ4BTUV6WovPGPYWadNuqhlsKjflFQyYSkyBA+4gvZ45TwbDE4HTQ1BGlXJVA3vq5HAqcxlo2CAj4HCQJgVHzd7sfH+WwyruGDu58ThU=
-errol.oob,errol.oob.openstreetmap.org,10.0.1.14 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1riMj4gWqiovniYhlFNUxMm/AGmV/C2GjcMP+NcJ1ZyP4OdytGeGfhUm5GwVwraimkFQQlfEDcUWY7OX4EG115E8i15cUt6s6Ya2E6AXydigvBbrdp8MNnPOWBifVN3/5Cgi8nrAebmPs88ZZx2KM/Df5qIB2rHYpuHYyl+MpqE=
-errol.oob,errol.oob.openstreetmap.org,10.0.1.14 ssh-dss AAAAB3NzaC1kc3MAAACBAKcnhyMz3C4sku0e1/nFailjoPcMwLazXq4H/kUsdlt+f2By73F5KdUWffxoeRNL0UVT7+VCKG6IXmXGkKVfvpTipFjkP1N+b7I4SuJcQ/EUNPTCGAfC3l691K8jUBD6WSlQUqZtKGnpDS1zI/ZIYiNqrQnWu2RTYnP3QvY7JigDAAAAFQDI6aaH6mWx7vTVS9m3tyXQ4GQ08wAAAIAQjAM+q8Hfp1h45UjTeD2jIA74asQl0M+4q+4EcnNPnKXRbEBIg4rCWkHdd06uhayXZ91KzCDcj1b2LSb2zOE4U1MDEpdVnz22PuEl/f6/epKmLOqHoOGu9/9Lud6OoZQSveEPYmcpEEpt1RCN9ZvkVtFdLwtQ8+CSSGXg8yfCxgAAAIEAjQztmG1LN/e7pNRY0MtV148rJY3mR2knJegg0yBOEWHUGtKY91lgboWie1YTGR3RiXckJFFYkOGWAxqEVM//+rW0hatCxEp/mWEt/GWKPpV52fc4BUhJbi9hb8sg+dAvfoHwUL3CzHzqapaRNxxbfest8dfvascAjRDFP7yxU9w=
-yevaud.oob,yevaud.oob.openstreetmap.org,10.0.1.15 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAuWeUQd5ssUd5VFyTMXgC+U6c7s63mtuEj+cL6x8EU8PqNS12RGwLpeAI5VL8UzM0YLyPjPh/yzdQN2tl9ufK7KZF0apvoSZgp/uwyG+CgdFSf66nTrZN4NA/QP1ikH3kbqcM87LfNjCrMXnqMBJ/OCqz2z+An8t0KGDXS8haxlU=
-yevaud.oob,yevaud.oob.openstreetmap.org,10.0.1.15 ssh-dss AAAAB3NzaC1kc3MAAACBAL6RC7IMuQEtD4JIRmBJEownC0a7ZEvfCTw20PV5MjWb6twZlGBK3IA/0yV0oJ+75W6VWizn3cWSBS3y1zD8KktF4fh4+FVyin9WTyFuwME8cYmRPV+kuOa1lF1sLJxqvZJRjKMjweLeNTKnl1mb03049SL2YoGwMOTdVgVBjEyFAAAAFQC7rQIvnfLYbQdX87DwlzfMDALOoQAAAIEAmAu2kK8atEOR1Sc6maxYKSf68MYMHoTpm2MW9q2x5ls982kfEUMJ3h641cbRgOAuCmQU3gHnt73sl5LY3K3oLijIhSQm8+l+GkrXVhdwx7ScLXf+8TJZRWiP6Q98VWM4E3L4wmiJksLbTlxdoew3lv8gGhbpk0XuSyLWIBZIKJAAAACATogkqFXhPFzOMRJAR6G8J4bOqg9Ae2cGtf4aMZ9xdm/Hm7YLSu3kn5IhawwU+DL494VF+ky69T01iY3e4m/kQhYB4emlqsRHzVscblVH+GL6sVEkct0HMzfqzEFcfYWqqMdig9EwTzHwJzkAb4WqZdGnWG3Ln88x3liyDZTpGco=
-clifford.oob,clifford.oob.openstreetmap.org,10.0.1.17 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCsCrNQ+QQg2UUGhBpgjlLAF4gI48VDGmcF9prulYDxduyGJIrqhOjQtKLjNksMr8TEblmJsI4JzPf1lY1rVL3Q/aZWJD5X4Q0DgEtNzfinI9JAy77JASj1osBPU2RfWSvK9C2TnEoXHxuyGKMw9iuuPLppNMjZ103PYprQeAXi1w==
-clifford.oob,clifford.oob.openstreetmap.org,10.0.1.17 ssh-dss AAAAB3NzaC1kc3MAAACBAM+YhVzoOuKt/0UrkDpWCsDgYKPvbfuvSrLeyZfssRuRP1bVsY39yfl5avZM6YwYhzuyRAbcOLYa+9ien1QTeTbV2qNogx+/yt57DWKVv7nX6WTSVfYFAvx+CMy+L6O8N6VnKXJaCcbQxOFx74c0ysXorNYU0c8++KyNfMmVVjJ1AAAAFQDoCl23tnp1pcVbUFAAxAEUb77aAwAAAIAOpGMpxWPrd1y+IxLLLCohRMCv7JlUy324PMMwNx2/u2fF3oh4kL/EUarD4/6iU1n5PJo441bLuOj5Mb58/O8qdWYwBjbUoj1CiA7qF3TXWGmPX84AlwwLE12TIH1sTRlZTdrD6+js1KUUMSzMz8tEi4tJs+bXYf++ng12sqP48AAAAIBvm/z7yPKGdLPP9i9LzWShLJKrbY9zx0BOsIzzeVJjShdyB4+NZdxQR1jjDcqJ+r0DXtanmhS5DLOS6zGYfnzzsCNTxHM/Ne0wF4goc4LQGKg2aClmyx8ZvqwF96d8nQcUIbLUydbE32xmh0bIbzVchLKEm5PuNYf/aU4snCyDGQ==
-grindtooth.oob,grindtooth.oob.openstreetmap.org,10.0.1.19 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgDwRqYuKXX3gENA5JHkVTBEL5MxC0N5Re0uX/hAVTv7AurDlJyaN34ZdK+k89XjQBPNMn7DhwA/+ddXCWg0Bb4KEngfKys9oMhZcwEWCD8LFWJcKugATfFHJPtduJrMx5dNEfQtpA0od7Ep6XamGcJ/Hwxa5iQRlD+8Kr419qNTY
-pummelzacken.oob,pummelzacken.oob.openstreetmap.org,10.0.1.20 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEhjC0AfmTSwq1TgcwvSUZgzGJp6fP1DXkYfgREfgX6MQX0uRBTLgWKM1Nz2tYb14mjycJLdCjSBCzuHQg10ufX3+5nzR+xKIy7cgwqkl6I5/jX7BZNK6t8XZfdmwnhAhLqYfG5FA49eyaVNdArgHu1fv7xczKjRAMOlKhh083038bCD8BYmBoKwj2J6D6fp6wHOD2UU4rvTP2nCEYsvTd6s3/yvTOB2bFhz2qaqOhdNI1w+dvcZLPUYO5hdndw1LGC6v56IbmMquxcieWuOtU+fbTMnI9teNo4CLPVEzb3kmwhl4LyJEA1Sx65Bz7Ve4wfgUInPoBfiX1gdSjAqH9
-pummelzacken.oob,pummelzacken.oob.openstreetmap.org,10.0.1.20 ssh-dss AAAAB3NzaC1kc3MAAACBAN3kGdbPfrsSjQuX+9kk/an83YUlJ+Yd4V+AYbRrMRYBJEIQQOYxFOFwMOdmGRIFyLj2ZXKuYY3/5UFXHFeWZxqY6kWJ0JybFfOJaZu3Iwgh8gLlBnfkRWAD8WbzvXYTCwg8yrM335tj550AqrQ/6R09l0jveeK4EyA2w8Afdle9AAAAFQCOclxhmRDMVD8adpeBrpXJ0q1SvwAAAIEAt+0ZFeCMnteeadmiCrVbHpMot2FRcem87KouLdNgdOxOpuizMJgSSHEXBA6IwvRAzrLInpm/DoCdW+bdnrJkq8qs4gEhM6Dg3tDAiUz419S/sV/uZZb9O1aN/MBEzfysO+hnxemQvmQiA1vymhWov5dNl78UwFzETUj9xwW4kaUAAACBAIgjeLkkakNDkSRAYYh0X5hGjExvYRerNWdZ6hQsGKGlf3Ud0sUkKrtzpYUvWFQLnqniQXs9q0hTTxa4rVWHiCU5+R6gBOk5VgoVyM+evuOKFT5a7TorE5STDII+PQFSHQ2dJR2QsVaKmNbcSxQC+k3ttC8vBEAmIOl28m+QZ9kA
-grisu.oob,grisu.oob.openstreetmap.org,10.0.33.20 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDTEivJ/aHG2g7TVGEXJUDcOrbQKMOwYEzWiKvMTsftxOKqMW2uKzCZDkW3BNXIBiAXoswaqK0qkh519i56tY9ff7XjH5YoYbPyWwbhMPoBlIc6wBF+uMV3dBRrb7iRe0HFhpl/XsTo5vw8x+5T/ITrlvI8T7ZfE6uTLxKFDxYOiQ==
-grisu.oob,grisu.oob.openstreetmap.org,10.0.33.20 ssh-dss AAAAB3NzaC1kc3MAAACBAIrAKvS58z4zmaRWwebJxgUUiy/P2+AWODjz2FcqspmkXXnSkXD/tz3djsp/PwgPUPt/y1J+H2dfDY0qnTtY4SM1DJi0848/BG/C1P0zb/3mdtJO2FdMVVcwITCX0XZg7ikFf4zZ9CJRiuAbiS6CKCIXcvxHhBx0O4EEaK5/PwLxAAAAFQC6Rg2wsfl3aKpecSD0ed9Ysekx8wAAAIAo1yE6yLCH6+4NEA2+2mz3XWXdf/nzOWzFd1XqZIqg3Jj8MzaNS1GLbm3FlVwl7qlXr60flsXggYkZxwXyLKMH9fhFnyrTZOJMKmLKmeqcDTZqItW7hwsaKvM1vd+ZysmOVkFiXKJuD+25AyTmbFpNUvBdIHYiL1jQaIxLEWnN+wAAAIAuF7tHFgLgrZ84nc3Yb003llMmiwwaSUjF2t9y81t+FJ4fOwhFO7lIapijrsm17v5OBSOgAONfgzNS39U+VlX61PwDmIobe8+Q8zGOv/9tkK79YwNsG/dXhQ3e7gZH4wcyNgO1BufEuAOYMxE454rbv6fdrhvsUlRgEvF+teJqrQ==
-spike-04.oob,spike-04.oob.openstreetmap.org,10.0.33.21 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgQCIrf3Ca5+Cyk7/QYU2krboxC/qhHwjvtzBpcAtVya4YPpkiQa4G5KrJQ8oxvLL7j1atgYs+GnErkeUp89SLLMJ1spbjMMubA//Mr56Bp/V/ZCr7uk6c67vA+P+EIb9QhqJt6eay4fFZ75dccw76GnDunD6ADf1VTzawYykyIrm8Q==
-spike-05.oob,spike-05.oob.openstreetmap.org,10.0.33.22 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgEvdV6XL4KV/RCLZFhyM6sSGOWOia22L2Ddc28mS8MdZTr8b/iYJpFUCmGREovFxNI5MXzPhDKTomiW6UKmoxhQcsS31Y70BdsMA+XcNqwktFUkFfXMaat43gJ8gL5lVDI3AomjxIfGoouFEhIzTrj0JYMNf/q02YJm7fPvAZtuv
-katla.oob,katla.oob.openstreetmap.org,10.0.33.40 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgwCIJ+bSxbMsr6wurBXYkeqoznHnJT4zrN7nHtajgs5CJLIiWO+Eq/Lp+egz6Irxwk3v+kbfKW9RUum5fOMfkWFwaQxP41Cz5RbMmu5Jsm4MQKr4PPVxbLbPk75OeVgo+nfkzBupsBuYGMp/GCpjTJ8rusPmYxzWBek4amKL5udfA9Ld
-katla.oob,katla.oob.openstreetmap.org,10.0.33.40 ssh-dss AAAAB3NzaC1kc3MAAACBAP4oHi33lAVyP8zjoRZe6kxcZGJi1JOgF1vpZqEsxA97yCaLGVjc2cdxi16namqdJ/DgQaRpGRM+chP6AgGN9FD8Z6Wfskm+2sghPpcGRUkr7u6mM7WlJ0xQehD4LDcxFEpZKxtalf6TlxXn9cO0VaL9NNVrpU34c2Pqxl7wg/QnAAAAFQCB10EQxYDOnsxN2xrSHEbmgA3K0wAAAIAWN0b4KREM6Uc6FVkRtOjkiAR8FWmCg8nNQaqlKIPlM4hsrIcPC5yZfc7BzamQSy4PpHNGZG64CkYr8tn8LGWouHVKKbeFOWEXIBsRBSf1NNaYI7cS7WPnGVOmkt6yHvWwPlDcVO8FpPUL9pA7kf6iCuQNdD/MyOBHdbVoU9LcNAAAAIEAsXBb+3EZhsRAYL9Jm22PsrsW2o/hO7aomMeEXvVGG8Wuy77lqmcIvlyW3zhHBs7ubI9TZz1XDsgLK9giCkmqCyKmUsTXGsu9e4veOq+sgvXdbhoBMVi90IFsPLPUdPN5mfovBDHkwi60VtDwOLAX368pFfBfSA50CZWfhwUu26E=
-thorn-04.oob,thorn-04.oob.openstreetmap.org,10.0.33.41 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgH5H4Ra0f4+LfMyJbVpoJIN9wPrC0bbNEJUVIOmtPpxRE4HvoqDOBE8XfHIunhNeTxK5Yzfinz+fCq2XCv/8Sgrr1qJBUQwi9kHfRBNmRJyoylxY0b33Dpsk5kxcAl06+sSugl/OcbXAyW4H3d+dQAUMlRPEVzQCgd98gGrTFF6p
-thorn-05.oob,thorn-05.oob.openstreetmap.org,10.0.33.42 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgQCYjNImXo+2xnRT7T/JiHh+eNl8I5i/sjB4KBaHizKuJnwH4heLbPtmbI9ze9MV0IHJp/289kwT3bSgj0nY9zi9Ucdry0WtPgGQO4JbDZXzCBhwa6MhZVLAIOKU34fK6AIuZqzQJwXeJZuCIiwaoliUwY+QwNcX3rQho80eaK6XFg==
-orm.oob,orm.oob.openstreetmap.org,10.0.49.3 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAn68BVVd15SyHq1vdXYZukNkoxBPlNBgA8gcaXjlQg917A8gXcHaJQ04xSwt/jkbbvELNuvYDuw0EZAqQQHG1vYsXffg8bYrEq/WUs2+oc1O6iiR3xrzgDWAdefEVk+Fk8TXRGI3dy6IBpFoQ6ywvNCbFvVcB41FLRtBGOWdJFZM=
-ouroboros.oob,ouroboros.oob.openstreetmap.org,10.0.49.4 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC0b16+oF2QHYj+iIS2YT5VnH8KfdYckm1ujYSo5WitGONMqhN872W6krqYbW7GjFvrJ2d7GbNaY/3VeVURLumgWBnit77bExpga++/QYsE90DSoiQMeUT0Q4QuPWXcTIzAcGesda4VtQkTRBTt1UlmdEGBP3eDAqL2GoW4DBPCiQ==
-ramoth.oob,ramoth.oob.openstreetmap.org,10.0.49.5 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgnWJq8z9xvNFujhE0P040rCO1yEsH8pnQmGOGehIRcfclQBd2wOO22+8kpy04BMT9FaFdxjgNTUWtfCwT+oBsxbHIreahld34vFVCw/VSCiPEuUhBdZ+fN9hdLGygrnKxA1b2cIs532nm4LLDoP2VpM4RZuh6da+LV3eHnfDlZHO870=
-ramoth.oob,ramoth.oob.openstreetmap.org,10.0.49.5 ssh-dss AAAAB3NzaC1kc3MAAACBAMjYCKyJfA9/EQWTxwqqGBq88dAaWWG0j+ggoGEYuIWqcdA1NeF70BIiRGvAV5/oBy+p/snd0LAxDG6KnWglOo/0cjzcfys/RQl9kTa6gkcFPp9lUqRnuDF+y/egZVTU3KF376k930nNdODMe5PxECnZdC51158Zga9Hwj0+5nalAAAAFQDnh0Gx+gt+6Qc1r74FeNCiIPmzIQAAAIEAs81g5c2sF42ATY/gd5ustNXm82xfIAuRGeMCgxyXBvFM5UXuLnfOx8JVB8wu9eoSmxhDiuVX7ija5FaKAAucPBXWh/YImH+T3SOWLsxfDh8XglH4NvEtj1r+90VWbX/f1Qy7IsmmBolUCr32qD5cdeQ3JPxvUvO/TdSHaIgGK30AAACAZiVJOiM9mfMf05rAg9fjo+NKxL/jsbZ8ptTnNOFBNjq0XydXQF3Rnt01b/cUSv94VmuJgv9hq9L39nk/dSnBVQbKwIYyB0/NR2Fg0sYHpo4qj+7MFndv+ct9pVd+l9pmlEoR8soLeO1hSVeSmj9YvDzc74lx8FYMVE6+yed8ltw=
-spike-01.oob,spike-01.oob.openstreetmap.org,10.0.49.6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDHhi90mKvMe+FL1pdzBPWUfC+a0ckv31Qou7Yby1Kn9xhrR5oHvyoT4bc/xPrYvaxRZUHWn+J66ZdylhyfCZf6/5g8xghJoYVAZJn9yCV0R7xw2fzHCgue3iS/Yrep2V3DRaXt/zy+PCe7wZX7InLLtp1rV/Vx2xG3lV91OGa4Zw==
-spike-01.oob,spike-01.oob.openstreetmap.org,10.0.49.6 ssh-dss AAAAB3NzaC1kc3MAAACBAOE5d8RsNmFZxWkcwXHisg5NowzVyvYjW/cXmDRkeN9r2gvjDRj+WU8CIo4rhVhbJIepEA/BUkzEyDBrBOydFa/pFH9KN+tRnSabRHaVweXr337KX9ltSGoPijSwUlDhVITMMSZ5v50tJ9bokyZEYbgpbzPo+slqgMFbR3fr1MvbAAAAFQDWzbv+xMTMOYcQQ92MCaQKtsXCJwAAAIBW02qjzbss0X9TACVhGHGbAy5DcfybmY8JZhfUgqR0xI5rCufUW5+dY7EQu3FlE8bC/R1rPrks7wngmut6xPMtkpcpMYFoxFPgP8/xfwkTNYMs2J5Vbrb6k6e1XMKt9AID+QzhEjTVxmwLKAT8uZGDZjY8ujYnQMbM3wPbCbv/MgAAAIB4xUK2Of6YBWBOpW/0GPfFH/of8Txv2ErpVmTSTOFaO7KD6x4jcKjn9nFMvVUhW/c52UYYcscE6uArd3XNbJBw/H58i26V8RooTkQVWhKNbp9ktXPh8yADNzVq/rRW6kvNYHZbbTev7WZ0NPvz2aIrTLKPcEcUwLq4wpNBe//1LA==
-spike-02.oob,spike-02.oob.openstreetmap.org,10.0.49.7 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDJfkctRhGPVyPY18EVcegsABPTC7PsCA6Pt2UOkkzANJKkwrOUJyn5GqgJYHkOb3hWqPlS89zdlV9kXlvTdUZ8QKw4xys/5H5+CWwbag0h1EpDR9S0xO9gIgX5DgyB5Y7oNS8o9AolF+hgyUdmBYO3ff+h7eu1PnqBn8TfquqVcw==
-spike-02.oob,spike-02.oob.openstreetmap.org,10.0.49.7 ssh-dss AAAAB3NzaC1kc3MAAACBAMxbg3AjYJcMX0jlgyXslqLbi3MV1zAVunNGqFOipJCW3thZ/D780MbQiXuXglqJQxWsELy+8RVVjt6/rcnZHORsH2H8M0/3WdlEUW0FxMUISXUAVtto0Fk1v4QznUtyxoKIg7sXktmreaNEcLBA7Le1bOBf/Oz14uQbmI4nycelAAAAFQDEMSn6sAPKhEYhYJiFYsDoV0aWfwAAAIAG9y+c73QbYqHBOdNISG22W0BYAnUj1L90lW44xNnmrVOc+CdTKG3VnAQcIc5BeB75sfE29JOmUGfR3/clCgCL54V8D+gEH3omtSG3eG7B+OoWhcUIoIfgO/3w2ZactdU8lA2qwSfZ0p7xLPsrDN4wuORPYFpoOU/vV9hG+dh7VQAAAIEAuk45eD65i9Gx6hHQuCoN5EGQHhL5qvO2gbShYLNqEhkDN+TmdTLK4Wbevy6tOdCrCRKP5zhoycbqm448hINFtwBPXGfRfhDsAGm075pMwljlh/LU3lSXbSU1RkmiXqjYqcjl0ntxkv2qA+zN7G1/oJK85pwScyiMo9kOuwyh3+M=
-spike-03.oob,spike-03.oob.openstreetmap.org,10.0.49.8 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCvTY6CDpJgBcU5T0l7Hmn6UkLZw1d0EQEPlcQM1UvLfdSKayVR79Yl31eVWFbA+R+QqQ8LKcmzx6ztWPuemW3Ym/gZ7NNYH10y1Rw9LywWhVnFOjKIBUVJmjdiuxftyCPveHu672k1KJ+bApXlA3/oMBmtCckr2Wod2qJDx7JIeQ==
-spike-03.oob,spike-03.oob.openstreetmap.org,10.0.49.8 ssh-dss AAAAB3NzaC1kc3MAAACBAKHL6HuJER/kKOFoGbPvQ0ghCw5lJ4ACsZHi4ptTwpBh1rx+/mmktTU6/U+cP8ocGo2XIuoCaBMfNK/eqrh37a8/fZah5+wxwJBWnZqncOhJT9EjRfvRtbJr8GRtCukNxX554zsQBSqCn9CIP6E62EqbYUf0qfROX5o3SZVu2WzFAAAAFQCWHnuBktRY7R5n2ZuCL1Cdx5hevQAAAIARZiVCIAKIJerBY4AnGADzRf/m21PkhksRIKcqge8vDI5z8MMgYkmtcrlqgGPEavnajBPlAF8DdDFRbx/4k8K5ZZdr+4ipp2++V7fbkg6n2MMwR7qTN3FpoNtLwXSHLlsueAArRW3RNlYdtx9wZppUq+cGlqr0J8jXS4UOLH3MdwAAAIA3Y4EPZv6PufNBppuegYI/gziypGwlNc//XODoIagXyDclGxGnqh36J+AUWxuILQeHRTZzdLCVazFZt+EGJeKI7/C3yJOkSp3vNnre4VYmGGRp1hcBKWDVCltjv+phRMXGiuGSQdqCy+AfkGSctNQafRnQuaL5hLBytHxbXIADhA==
-dulcy.oob,dulcy.oob.openstreetmap.org,10.0.49.9 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgmlwXGPIPDqoMz4s5edr+G4iuBnCYcFXjY7Et9jG/ezI6aIKd9lEOXvnHJX5hrC21aqd06dhyMLwZN+eSjJhXNaLtYmm5P442H2ZnGca1KNSpF7yRVhn0eRpX39xWK3biVfMw64mzvV3636C1adCkgBwuaqCvz1EHm/KRrySfuETFLU=
-dulcy.oob,dulcy.oob.openstreetmap.org,10.0.49.9 ssh-dss AAAAB3NzaC1kc3MAAACBANcuNreghg/8rJAmfsdD3Rp58vN84Ee1oEFMgGSxF6+yEVTbXrjQoH632jiBXSayQLXGEzrVTsGaWgujK9xT7OinNa52ydnJ/WZp5qK5FdW95h5m7pnUE3Jmm2cPmYpEJW62OeMStmTGkK0EvN2wwRLuts9R1NK63tWjFWik7QmrAAAAFQDNtW3WKlCugOFZnjIh3fBuDakdlwAAAIAzy/pxXiix8yKhlb0LQJ1izilnn2IXRvAHv4aM6LAiq6QIDj2XyT9oTS/77BguCw39WhVG599eOSRckWXFgUT2p3pWBBuuDbLEhQqIc0KgufYh/ygUdjf7zs0O2jusFkLMPgF/0IgRs/ftb36ERn3KJ4C1P0v1ABk9t55Qs985WAAAAIBZFS2HS1ewjv+/jAdUH68zT0mNBctnrqM8ixqT1Xd2Tl7SKjl6Sz9yer+6+Gq7O50U0FBS0pQPo3f9msazQU6BFYCzuSFRIJQmH7uKGPHHA7mbuow6sEOhtXBzq1VfI4addXyWlYLKXxv94/gt9xlxLZHqU4ZZb3GPGbU7kKJA9g==
-ironbelly.oob,ironbelly.oob.openstreetmap.org,10.0.49.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgwDkRqR1VRgHOON8M7YCNnIG8k0zukAN/r4L5fPKTvWmdhe17UnxywPc+TySjXqNsXQ/jPLGvpO5uoSG3dgT2N7NUdAtdL4Enb87dX7yTbJTJzMMxTb9HSI1SL2/5iSefyAVVo1+R8DMmFqTWa2eFHoD9IoxFSNSTarTZQgmH1oZYoZX
-ironbelly.oob,ironbelly.oob.openstreetmap.org,10.0.49.10 ssh-dss AAAAB3NzaC1kc3MAAACBAJKKtKZBECA+wtvYtrEeMyTzkm3X/4IfC6E8NcnZouMCHYn3F964+pG7mRskZAi7P95VwJYx6TLkiK/MNKIh8mk8M4Xxu2USIXblkTPraPYHyVgTkfZit6F9qTR8cAOlHtoY+9GgKmWMLC+xeOgPtoERvUyuuprXsAztZ9C2BKWjAAAAFQDnPXN3n2g1xxsYZsaQpdPuijb1tQAAAIA7/IpFy3mSgpu/TmmBuYLccdRTCNt493U3wMLb/JdUBu4h1FM6J5DSozcQ70ATglpLLYa3Ru5ztv87Esu8c7CH/TAH+GZ5/3LJtS//HJDt+53yy4CgwO8pcKbYo0rfRy4/QdFXWeBUtM2XN4hHvbaBJ0fzP1gXI1GHvz3OQxWICgAAAIAvZVlk6GX+uGpqLdW4F1ctkuqUnkIGzRziJ9Gk46vOOFCPxU8bUXLGzvC7Zv3SOR04YH7/LDMUof2y68EOCbH9YT8mHNqLdZ9TxOWv8wUaDX5O9J8JXngLwl+U+ONitseg/PrEZKmP2/cR42pFwuTzb59+NSkEVAa0ZK6+2FkWog==
-spike-06.oob,spike-06.oob.openstreetmap.org,10.0.49.11 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDwQVb/cYgKp21vw6+jKr5TLAD77oKunbFbjvwPL34iLRDqdJcEOdJBV1A63ZDUWSWjDUrTa0kyneoiYdD876EpuspZ4bPgmiHBvug5NR3usxa8PAsia1K+fONAGi3+s96H6Us273KHNH5QwyBNDyYaDDjIECkydU4bQT0FSX0j32eAHI62ZO/H82fUyL20PIK/nCUaJUd+5iXgcTfjP+eL66ghgPCgXGF99/w2+3EUxP2IN9J2yI57H/rYn3rj+NdZyQuzc0TAToT341cYh2+a8R1Sb/DEFiMZFE2hJ2NeVEaBYxPSlFfhRtlB6ArXg5QL7e7UScQh/ZHLU26A1ZaB
-spike-06.oob,spike-06.oob.openstreetmap.org,10.0.49.11 ssh-dss AAAAB3NzaC1kc3MAAACBAKwUXFxncoW/AmYePSswZkqbHJDN5zI6MblYRtyLwSzfdthD8KCiDnoG+6opsy18jaX+sX0PTz8hfNVUPCMhtiTSgbGqZuQbriT1z8x3yRbGShqH1ZGC2Tt8x8k7ft17Z1tgnsnmueMrGekks6/kMZWYl+zrHXbrKCM4uPIHjK7DAAAAFQCOmXTNMg+q+8BybEEHDtWH0hbnXQAAAIBhZi+1jUaHu0UEtKnPRnChDyPrWXpgwVOM+goAZCOxfObI6PcxrIhB31gRPWNETR0UzMb2K9t1oCNdyyq7Y2TdFHEVHOTaBTWS5C9Bvtz8CHSou8mibH9sIhK2H8FevdQPOZHeUxQRSx+JzCL+f3qMovs05xVBNhUHO5XLtzIKdgAAAIAGlmX7cp+zx8D2vPiZEcczjJIgK2DvAu7t3ZAemcX5utUNKh0By7xxT8DqzIPYRvoAI+//4xqt11jIdO7KADc28uyv6oBAbB8DwhlbRONM9O84tqBTIxu0bQXtsYpkTAQvLlrDXMYDx5aYLpP1haTbGgdtjbDCz4FH1Qi7cBN0kw==
-spike-07.oob,spike-07.oob.openstreetmap.org,10.0.49.12 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxLxAbMPZw+LgzB8JmTLLxqc6CZXYA3Wo18RM02+EnmtRX6AAf/VFb7E/VpgHfZecwnFK7u21R47+fFdHCb8EDYGeWbOYoEOYMoDh26H8/aFPHbldgG0xs9EwfTryWB7iZ2sD9nLv+nBpDkFXVq53kscmDlUKQrvUyj/zR55xGxcq0ruu3w05ZeGx5I6HRY0xeK+6H4s6sZtF24Zm3CttQ5M7ADgWffE35ZwA9tEdioM3J3c5EcV4HMdhl7wame6pID9+FpDEtcts5z5sfW9Y0yx3FHrXCxRWxHRbyFG9/+4RNwKJBRZrdb+VSLlrYVUFLEfb1AhOxr8ZfSsJU1V0V
-spike-07.oob,spike-07.oob.openstreetmap.org,10.0.49.12 ssh-dss AAAAB3NzaC1kc3MAAACBAKzH4llCRo3t5ifkL9qB1KoWcAw1ROGVAJBwE0GkFZRQvzGQ7CE4anpFdv8BVlUbFx9N6batsC00ERDL9ReWQXWMa1oHr9AJ5Prpgt+azn3AFrKhhkMQZegjnZ0Ddsl/XSmFbRbJX5cnvrSIBL5nEC6kBCVFDiuH8MlsWaUsvUtbAAAAFQCWQKlZ5osk9BZKsnss/W+Mv653RwAAAIEAmbM4n4Sl77tGuTQZrlojpjEF/qm4iUpnAwbE93e2EIr2thnM+6QYtzYZ6VXSXwrh4UW6d9lL2mgSxQnY1HiM37y6e/oNFrsluK5j7AhxAYm4bHT+UpqyU/zl3eUlTdvBxhkTjQTT+wTsBgTwu5zZaJrlEPzoYkCQNJRS5AAw0gAAAACATzzX9K2AYRf7h8gK90abOmp/LYNO9ghhbhifsIrIxfShsFubUSfRO+m9e9wG2/1kwQY2VuVpdM86wwFvjHFlo2VHQkIl1JkP8pmVKs/QKSo4WSDY7aO8bpQK2Xx7QC06PUnllgXsPcyted8BGCoTLMVRkmukMwWls+Qw4fr7z18=
-spike-08.oob,spike-08.oob.openstreetmap.org,10.0.49.13 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCm7BnJ/+IKh/uAI3vIjIlkqq83jFkuxfxPuMty9/jhm9XoVbf+nqTfRQ1zMZn+bqjEjLRFTU3uwsjI61fk1Uxru34JKoJM3axNPK0S0TH6Gh08oLoBCCOti1/tTAiYaSLFfauucnJeEMkKsmIaM4LzawphkIuWu5kUv0LteuycqJAXZKr4jAIYZuxQZ2e3ofdzQoXIjXbEg/9EWyMA+zbUYlAZpELicTOQywhpez+TpZ8GUnMuya7jv5pTWfiTbSkToF0HTrKUxIEg1HYruBs+0OYI+LbABe93z/fAk3j31y3FAPEnR7vqbM7mc4DLSwgtKsKkpGGGeVHLEJtHVhhD
-spike-08.oob,spike-08.oob.openstreetmap.org,10.0.49.13 ssh-dss AAAAB3NzaC1kc3MAAACBAKJKB5ukyM8DRC6fbpXb3KEqSq4CmBqrlqXCFaktWKFerKUJWx5No/xWn6n0H46FwpznH07Dt/Mom6XuN2A0i/ZD1pE0VHnQif23+L3PBu7t3cDPVJkj+eYVB2avPPrwLGhOLOss0oKnBwhOgK3FTerCRUN5MuczzPY8xtz7w495AAAAFQCj87X4s3sLxHybJmuRFEuc68Zd8wAAAIEAhajd+H+3uVBAIKdWpn6GoU6bP0y9/ERnz1GKp+fBlTVHT+eSc1E567HqVErHxc7QSFIBmdlF88MyS0izQSAFKdzevJWqUbDeUKtcB26hGGrvHOp1dLsoALpuUDhOZvKIzehp5linYJmgnN91piZ3BlyxT1acr4zdceIGNL7rJtwAAACAYlD2EQvr2JI99MooGimqEYP/zC/HhChmtCEIJ/XQrOuKxBL4AlegFNECXBMn4JHFbdyb59LYvVlykuCgLgNY2EKObgltKJ5WLmzIRpUTBW2TlwAQiRnGqA6TGUpTTlKZFqAnRSqOJfcvQw9E4HwlN5TeOT5kxN9j1duUaV5WLx0=
-tabaluga.oob,tabaluga.oob.openstreetmap.org,10.0.49.14 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQChE4Wu5bUAgtJxrappT9kZeftw9gdj+D0QmisCGHbLsDxDnww7g5gplexQOf5aEtLon5NU4HNixcEFZ+/RtEtTuVaC7wAdNF1HOdOecexvHcEFlR6KPrdAKykTyo4hWYUd4Uz38zp160V//ViAgylpvU2dhGhAWKcxgmamNMz9iPd99T0fW9bXAzpiB+yBuBskD+JyA9bQu56mfIW4u4rh1xgPBRyUdorqetM97QJ/fcdkN0m4qVda9qP0J5DUli6Cq8IbEbv87r87VPV9o/WOKGBJtclXdUuF9aLAvP3p5V+OuxqUCtvy2r6LDBvVURURb2/VXzn0O9x2pWE6uPeD
-tabaluga.oob,tabaluga.oob.openstreetmap.org,10.0.49.14 ssh-dss AAAAB3NzaC1kc3MAAACBAIQNHSK0uo1CehCFag09Hd+bJ+CDD0LPWoE/6B8Ye3woVQw8XhJPIygWyHlsFo4rbgkTnvz4ooKTUHnisEIoAA6hlqFTVP1LQQarkmba5Gf05x42hYKjM6mYvcoDMAdnkPueqKIa2CQVNCg3sopI2isxaUUWPEqrVeTMgI40ofd7AAAAFQCSNIl/McB7R/7q4fFxZ2dVGtvJGwAAAIBNRHSJrnm4IDYufJetkWyn4KEIkycUMDs1WE1H1LbtmsIaBAGaz1QJKclPCin+hCv/Rne4oPoZWGl3SqB7hjBkvKUOKRaMp4eG1YCpEvAhgNIFjPkgdekctQ1H6/+7CkQmMVelh78cUMOUYEoky7ISiaKUT3z8O9EEjPIndreNBQAAAIAQeqPxG9B+RJtcOqnW5d9M8VVUNeW10A2R2AMtTEH+/hjaoXUPpL3bQ0Fl3aWQKYJMRpOM64GgLswEhxeWf0PzSAi5CwBmyhIEUJpJ0jHOYSUXC6sLpBMV1ad4gF/63CBAgL1fUnQ/FWDtZwDEnBksDbYSS6EJB5m1o1vOx3SHWw==
-odin.oob,odin.oob.openstreetmap.org,10.0.49.15 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCeK2EVK4rbsdoTq84Cl5kLhbJk7gbaNav61yFuSKfSsizzbH/tzxmiFA7mtB39WU/BlFsTHAg1mHY7cCPE01E811CDPIQhZGEyloh5ftbTACCcGAjKBhYpwTPEteBqlIk3lpN1TNTsnJSYaQay3rbOQ+IXTb8nzKYjTgANQ6QXxSq4BfuRmvMRlNw7ZuIerhs8OL2G/pxldL6AYDPDFXBs9mvvqqS0fw8rzxkjFNUc/z9odFoChtlZVbp33/LTIBQU1dY/XTxaekErjT7H93KG9NP8mmIFZtU8oRo8553ogTYVxFr6hD5D6KkbveaFU9oBDRYlJPWtdHksF8RAEpjN
-odin.oob,odin.oob.openstreetmap.org,10.0.49.15 ssh-dss AAAAB3NzaC1kc3MAAACBAMxXgZGeLxWyQCErmy0aGppk2/xHj3GTATPCQgf/Mtm5PYK7c3x8Z/fEop/BBnY2/YDE709g28Tv+61I4SD9D33OO6ABPEapHEwqp3CIYuA8+JFJhuo6Sz9h9bca6fx/KVjdDq9wbmx5IOqEFQlBoCSGJvYw5pTptVFN+nLeiTLjAAAAFQDt76BO4R+GaDn6/SeJvP3xAuqkmwAAAIEAgbhpMfB2Gk+babYDnWTWMkFO1FObUdi8/3NmiS1XUPCzdGkL1h2psoQIMXFtrNfEzSPx320rjC17T+JD1KGzXTBsPSd49MhznMc13JK2YT6KJm3io1CLKuzje4SxrpddM1Uvs/sOLmeAbdNqlUsAM8KUedEYTo/SXeVecos6dboAAACAasbTSjiTPW3NwH1yrEV8xWFCAmsmAPvqwGjaLjrrDdNQCbJ0KHMY+lbUAmT6oZ5qcrwwc2A6B+/v9XBISiT5XWELdP56bhuDcWC78aJDdtfDK1xuMtsHX5tpQcKB7IrPI+2UYVhz7zosvcCbn8FukgDx8sEcp28rHaFB5WPCjig=
-karm.oob,karm.oob.openstreetmap.org,10.0.49.50 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgnWJq8z9xvNFujhE0P040rCO1yEsH8pnQmGOGehIRcfclQBd2wOO22+8kpy04BMT9FaFdxjgNTUWtfCwT+oBsxbHIreahld34vFVCw/VSCiPEuUhBdZ+fN9hdLGygrnKxA1b2cIs532nm4LLDoP2VpM4RZuh6da+LV3eHnfDlZHO870=
-karm.oob,karm.oob.openstreetmap.org,10.0.49.50 ssh-dss AAAAB3NzaC1kc3MAAACBAMjYCKyJfA9/EQWTxwqqGBq88dAaWWG0j+ggoGEYuIWqcdA1NeF70BIiRGvAV5/oBy+p/snd0LAxDG6KnWglOo/0cjzcfys/RQl9kTa6gkcFPp9lUqRnuDF+y/egZVTU3KF376k930nNdODMe5PxECnZdC51158Zga9Hwj0+5nalAAAAFQDnh0Gx+gt+6Qc1r74FeNCiIPmzIQAAAIEAs81g5c2sF42ATY/gd5ustNXm82xfIAuRGeMCgxyXBvFM5UXuLnfOx8JVB8wu9eoSmxhDiuVX7ija5FaKAAucPBXWh/YImH+T3SOWLsxfDh8XglH4NvEtj1r+90VWbX/f1Qy7IsmmBolUCr32qD5cdeQ3JPxvUvO/TdSHaIgGK30AAACAZiVJOiM9mfMf05rAg9fjo+NKxL/jsbZ8ptTnNOFBNjq0XydXQF3Rnt01b/cUSv94VmuJgv9hq9L39nk/dSnBVQbKwIYyB0/NR2Fg0sYHpo4qj+7MFndv+ct9pVd+l9pmlEoR8soLeO1hSVeSmj9YvDzc74lx8FYMVE6+yed8ltw=
-thorn-01.oob,thorn-01.oob.openstreetmap.org,10.0.49.51 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgQCFBaTPsbNtWlUSsGnRzObp3NVC6MOro10p4qSXB0kwAB+hQx/IrIH8BjduR+b6Uv2cm/UMnGRzS/1lGYe15cSs0V/IOUyXdVeX+jB0TXzS4hTqclGKJ0Ay2WEsgW27IdPxIjQg/W77s9AZ2UlyEtT7gK2oergD60yUvRfLLJioYA==
-thorn-02.oob,thorn-02.oob.openstreetmap.org,10.0.49.52 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgEitEET7IzW9j0lgxcgXT9JgzDR/cbQdlYSwV6rcWvHW9cz1ArWmJ6BY2AJ6CG3wTznVbHPupiFKf0jvkX0omKu8K90f5FJc2/BkUP4aG72YmAoPVe4bflGykvKJE9Rd4BDyPWGqI955Okp3VGCEKXBS/fwnoOZlei+9ex334hK2
-thorn-03.oob,thorn-03.oob.openstreetmap.org,10.0.49.53 ssh-dss AAAAB3NzaC1kc3MAAACBAKZf6qtRHGHjPfOP3drwO1m28l4fpN5X5c8ArkeKhV3aTzY404uwCsSvfYQUw/s24E+989MWZxLUO0Ib+nV+hWlK0nxI85bQPIvOjaWNtbggOfNdz4VyNcLxxzsiJqNhQpGQ3LW2zQ7fsP9pM5ALAs7MDOaSdNja58aUgEMY1ta5AAAAFQC1r9L5Mkax780fOnwkDB6eIaNjCwAAAH97vSxdyRel4IucL4Ckn7Y/zVwFeLpwHiVP41MN7dO2aApuWvsygLU/FUAouv/3PRug/bAAS56w2/JLKVvyo1aRPNHAvgPFEDodqLc+dnC1bXFu1VR69ntQYTEe6iReLlwzeEPLwTW5ucGHddXVbP2jG3R+JEmGGt87P3JxicCjAAAAgBrDGGrP1jST/axY9UTs1q0ljkET93/vIitbc/C87pe08ccQUL/PUn0GTrVhXps2Q2nfg2IuI32vYYy0lNKXD53NOpu5G0ZxEB6BYxwejwD5YLZhJQD1mtZ5JvyAPeeWfZa15ZRoI0qzg9RxzB5bp4cRKtHxFcGRAj1jjHkN+80x
+
+# Manually maintained records for Slough
+
+ridley.oob.openstreetmap.org,ridley.oob,10.0.1.3 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCohCtONR/6e/RvHnLlSbvl0GqY+EJeTn+Sxu2PyWsw+W1OAfa2jmb2DQg7S54CwbkyI/owJdVrM8Gj3s5CVOi1kIddu7+pbkqrIZKo4Mf+jviFypyZoGYHnPSBwEfgAWKtfBepnbW2RIZ9+JEXLjUyOFwU6jT8QnQMKJc5FiDP3Q==
+snap-02.oob.openstreetmap.org,snap-02.oob,10.0.1.4 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKyiu+/H4R/Dx1dzhWIH2Z4+SHyhgo6xONxKjlC6te2blHPjbiWgZzS+WWQXj8siiv6w98p/DonTV/+tqW9RP7fJLca0UBjexQwZBGxjBWPsMCG5bdjWLtiQCN5vVD5Hy3A/6TUeHFYfbSbEuUO+VZVHR6fVMJ0sHHy9eIIwDNsyzGoi2SDB/QsuNgSK8y0TGBQzqHPv0AAGhvmvRONGO/htLZ3lsSuvZQ0D9NPx2fNbcFzkPsOUH05I+1+Wq3tnB7doJ/+hzj6/+wyPZar0zqhNs9YJrKrSOxiltVNnObwFHWvEZabHF3jKDNzmr4IHYUgEMwoMeHvXwI1ly0xz8T
+eddie.oob.openstreetmap.org,eddie.oob,10.0.1.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+CNWzEucmDqWDAP2yq5gNGq1yC/1h5KohNb2sxOkac5RSij6/6UumO8tiW6PVY6wmiI01L+6UyRIfxWzqD/p+Pm60fNGJATrUsED/EEEbxKppWqbr5RjQfmfRqu/Msv0/QR1XnCEiEH2ixiubBBN8091Jn4m/GpZkLkcizpwOE3w3/FtUhydhdHgRKxQN8Mvu/pu9/6DocI7dNWEKWVUG8gbktUHe4+gHW9RQTPe1XISECt93i1NR3DKD2ldbtZbVeo9H0oRw1v9hmQdKXz6MUBQDenr1f1nzVmMqoLXJkdO2xBh2H9a6QME63nT+eO48BT/fo3VHomqFrR0MceGJ
+yevaud.oob.openstreetmap.org,yevaud.oob,10.0.1.15 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAuWeUQd5ssUd5VFyTMXgC+U6c7s63mtuEj+cL6x8EU8PqNS12RGwLpeAI5VL8UzM0YLyPjPh/yzdQN2tl9ufK7KZF0apvoSZgp/uwyG+CgdFSf66nTrZN4NA/QP1ikH3kbqcM87LfNjCrMXnqMBJ/OCqz2z+An8t0KGDXS8haxlU=
+
+# Manually maintained records for Amsterdam
+
+switch1.ams.openstreetmap.org,switch1.ams,184.104.179.129,2001:470:1:fa1::1 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCbUecW/591rGCYtkdVTUgAKTBc+lEhraeMCau7CHqMkkUn+/pe68toDySdTaO8jua1q1asuEWH3MZ2AGAPSF+xhrqJLLPQmm0WdEAQfZChxQUoqCPqlWAuM5u+bAc3ntKjw2v2myoGGAqjL27QkZDP8qPdxvKcbm2YpPVOHP56jsyp/9BjVhIpWVmMhkOAfBSjdKU+uP+NueHrJ/AueoqucQE0txeo5Mmw7GlRuLTsMNDU3Khlhjs/2Q0QGiMXV6hQxj5AgnaDZMdSRbp8lXlctDZmipr7jVk3TL+knzySih5wJ7wmeZimW8Dhcxk6HBo2lGgPGdtQgttCF5ZUGcfF
+switch1.ams.openstreetmap.org,switch1.ams,184.104.179.129,2001:470:1:fa1::1 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFPNVsMuGWMe2OP9AIg0hqZLSJP8zyNHWqYrXd5Mnfr12XdhzWEAKLTD14ZnJcz/GBaE0ad3IjT+hVoS/GVtxpQ=
+switch1.ams.openstreetmap.org,switch1.ams,184.104.179.129,2001:470:1:fa1::1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA615MNtLzOv6qPfFsD0I6Pd0itshpHLAVImjt1ME4SM
+oob1.ams.openstreetmap.org,oob1.ams,10.0.48.102 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2oeoe4olettjDauLuRiXRQVg5k6EO+PFfS9Ho3OzlOeYr1+h1SSPLkFtr20yOKcGXQcmYLjTbzvt/sbz2JUbfJHc2n7tMvQKK5ClVxLwqt2jpfSepGbG2KjG6vwxpkcDMH0bquzr/8ehpYmBwh3m8EARgcVNYoVL6J5OV4ILAtjNEllsrB71gitrarC8iqslRLVMjane9YKa7z0AGkwcT9w4qbcyuQ24rJF0Xo/IcraxVAYeX0Xtfx9rD3Zt1kHawaKYQdJM7RZvTtWcgCzHt738lFZ15Qj3at6vxxGpnduZiuHLB3PCW9yP4CFHm3Qs3TUyh3VqrNVFFdFvUXnP+DR3QK2E7TpViagZmXb+2AeCaLtrJ+1h0NEmQmliB4Zm4XKPsdS7k6Ul43pYQ5i1ipwZBNvhJrByQJ6UkpIjrwUlQBxXcEWGZaSL0sqqDQIYPizXZWOh7pQay2LxnHUVp0MZT30iVLYjptu9PcJ6CBwoKzhnVHPh7SON4uzDyMrk=
+oob1.ams.openstreetmap.org,oob1.ams,10.0.48.102 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFLujNadDWF9OqF//izQ3/jm4zElWb2nMjfpeiUVCYh/Jrsl07c1bRJlnSmoxL2H0xeHJXQh1E4PPy4o/5N4GfE=
+oob1.ams.openstreetmap.org,oob1.ams,10.0.48.102 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINxBm8YPJNtUIDh+0YWKY/5XKv8QKQBtF3ecqQcxIQNJ
+faffy.oob.openstreetmap.org,faffy.oob,10.0.49.3 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCuL6kBDuK+/xj40jp4ZP9HVoH1enU1W9MWO4Q0cxlD9sjHaz/mIbLhtPxElrw807QLsUdOx1IeD0jCLi9XAYYEF2xFFZ9DIP+qGp6hQ3XJrmOVgbDuckPjdvJWAxC5TVaWqwvHyp02biJCfSbOzsmjm2cOp03Cqq18HJOCfA3AxQ/zSQDSVemFoFPVeM67M9NgM64z1idPAvMVtW8Kd+unU/oE7V+Jil5TR5vwK+kVKEixxMtZfkJn0bNKVFWX5sJYmKWze+b95O+iQlsxmQW/p7UVM/3krKdBBT8+9b6UOv8TN0Yhopp86aXEgtvUOOyyimjqO3V5ogRMGj3b9G+9
+vhagar.oob.openstreetmap.org,10.0.49.5 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJaXI71RCPjbni+WxBnOf2CzkLi0H5ARG1RxevLO5smM/9LbXVAVgcZRnI3egmbaJF7r6queHtrQq5y27+Rz9OEoJ/DWMS/qaGWMqj1f7LDv+H44juKAxmayOYkLJUnXN/AYITjpNSfLy0kuSo9cGpHVKjQZVFGv92b0c1CPrQ0WJ3Q8Y7ERc77b2PBQmxWow/3RHv6SoeT8riCfoU5Mnuld2aNjlJlEglf79QB8r7Xonx3TDfcr0+bGbvJNhYoMPPDXFC96wCpjvIDQu09BEM91/zP/VRE3E+bvIp0WRugU6vUYAAIcKuyQpON5Fs1kWaY4AZ6/4+Qdql5B8z8twz
+dulcy.oob.openstreetmap.org,dulcy.oob,10.0.49.9 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgmlwXGPIPDqoMz4s5edr+G4iuBnCYcFXjY7Et9jG/ezI6aIKd9lEOXvnHJX5hrC21aqd06dhyMLwZN+eSjJhXNaLtYmm5P442H2ZnGca1KNSpF7yRVhn0eRpX39xWK3biVfMw64mzvV3636C1adCkgBwuaqCvz1EHm/KRrySfuETFLU=
+ironbelly.oob.openstreetmap.org,ironbelly.oob,10.0.49.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgwDkRqR1VRgHOON8M7YCNnIG8k0zukAN/r4L5fPKTvWmdhe17UnxywPc+TySjXqNsXQ/jPLGvpO5uoSG3dgT2N7NUdAtdL4Enb87dX7yTbJTJzMMxTb9HSI1SL2/5iSefyAVVo1+R8DMmFqTWa2eFHoD9IoxFSNSTarTZQgmH1oZYoZX
+spike-06.oob.openstreetmap.org,spike-06.oob,10.0.49.11 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDwQVb/cYgKp21vw6+jKr5TLAD77oKunbFbjvwPL34iLRDqdJcEOdJBV1A63ZDUWSWjDUrTa0kyneoiYdD876EpuspZ4bPgmiHBvug5NR3usxa8PAsia1K+fONAGi3+s96H6Us273KHNH5QwyBNDyYaDDjIECkydU4bQT0FSX0j32eAHI62ZO/H82fUyL20PIK/nCUaJUd+5iXgcTfjP+eL66ghgPCgXGF99/w2+3EUxP2IN9J2yI57H/rYn3rj+NdZyQuzc0TAToT341cYh2+a8R1Sb/DEFiMZFE2hJ2NeVEaBYxPSlFfhRtlB6ArXg5QL7e7UScQh/ZHLU26A1ZaB
+spike-07.oob.openstreetmap.org,spike-07.oob,10.0.49.12 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxLxAbMPZw+LgzB8JmTLLxqc6CZXYA3Wo18RM02+EnmtRX6AAf/VFb7E/VpgHfZecwnFK7u21R47+fFdHCb8EDYGeWbOYoEOYMoDh26H8/aFPHbldgG0xs9EwfTryWB7iZ2sD9nLv+nBpDkFXVq53kscmDlUKQrvUyj/zR55xGxcq0ruu3w05ZeGx5I6HRY0xeK+6H4s6sZtF24Zm3CttQ5M7ADgWffE35ZwA9tEdioM3J3c5EcV4HMdhl7wame6pID9+FpDEtcts5z5sfW9Y0yx3FHrXCxRWxHRbyFG9/+4RNwKJBRZrdb+VSLlrYVUFLEfb1AhOxr8ZfSsJU1V0V
+spike-08.oob.openstreetmap.org,spike-08.oob,10.0.49.13 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCm7BnJ/+IKh/uAI3vIjIlkqq83jFkuxfxPuMty9/jhm9XoVbf+nqTfRQ1zMZn+bqjEjLRFTU3uwsjI61fk1Uxru34JKoJM3axNPK0S0TH6Gh08oLoBCCOti1/tTAiYaSLFfauucnJeEMkKsmIaM4LzawphkIuWu5kUv0LteuycqJAXZKr4jAIYZuxQZ2e3ofdzQoXIjXbEg/9EWyMA+zbUYlAZpELicTOQywhpez+TpZ8GUnMuya7jv5pTWfiTbSkToF0HTrKUxIEg1HYruBs+0OYI+LbABe93z/fAk3j31y3FAPEnR7vqbM7mc4DLSwgtKsKkpGGGeVHLEJtHVhhD
+odin.oob.openstreetmap.org,odin.oob,10.0.49.15 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCeK2EVK4rbsdoTq84Cl5kLhbJk7gbaNav61yFuSKfSsizzbH/tzxmiFA7mtB39WU/BlFsTHAg1mHY7cCPE01E811CDPIQhZGEyloh5ftbTACCcGAjKBhYpwTPEteBqlIk3lpN1TNTsnJSYaQay3rbOQ+IXTb8nzKYjTgANQ6QXxSq4BfuRmvMRlNw7ZuIerhs8OL2G/pxldL6AYDPDFXBs9mvvqqS0fw8rzxkjFNUc/z9odFoChtlZVbp33/LTIBQU1dY/XTxaekErjT7H93KG9NP8mmIFZtU8oRo8553ogTYVxFr6hD5D6KkbveaFU9oBDRYlJPWtdHksF8RAEpjN
+norbert.oob.openstreetmap.org,norbert.oob,10.0.49.17 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAHaxesONNY+jIQmZKVKjsg5PPTYytFpBG9qx5Qjgk7PoPt4VcxZu0X3snv6toy2s4zjmnIo7+T014+ihKF5RzzYB3sRwHgx2QIXp9zjCkeB8HCSyMsnKWUoJcyxDrVy0gS0GgbmzIAL3n47budeyxYW20Bk9iy+b4z2KUGJnMrmhJ76eZkawtsr1DxRIrCWDrXNz66+msk7v/3DDUZFAACkPEF83YVECiNsBeKn5nm82W16OEFKOMsQXM65DjPTzH4iKajlA2j8DTf5qOtgiGGtLVQ8b5erwibgbXFfd1wWsqxhEP25z5omnheSujCkhYoZJ4+larVgqU+CUvCHE7
+snap-01.oob.openstreetmap.org,snap-01.oob,10.0.49.49 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDcKedgjsKRd3zPnZkJNL7iZYHay+KBd73bw4PjyHmblyUOcdtMx5yEntBHGcWAs5lwc4mNZgKbSJfuuW142oq+r+3I8UzcvYQGJKAvR5quKCn/c+iDkX56SQvh7SOtgf0K2K0dfHdQEh/jw56AewKcPxgCV5vBJ63ce0gETq3/Fj6mJwIYLU1kjyJiyusng9EWlgbodx8ma1zFM0dlxdHxeMkE38pcnrpOxNhV7qbGY9doU2VFUPQnCQOzpUtLr6n0J8l/1ubPnBsN/VAAYGMNbxwGgpUt+Hpwgl7dcn+1FQfFUUL54inUuP7Y2EV1bEY/WyhfLDkMRwgm+X96QctT
+karm.oob.openstreetmap.org,karm.oob,10.0.49.50 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgnWJq8z9xvNFujhE0P040rCO1yEsH8pnQmGOGehIRcfclQBd2wOO22+8kpy04BMT9FaFdxjgNTUWtfCwT+oBsxbHIreahld34vFVCw/VSCiPEuUhBdZ+fN9hdLGygrnKxA1b2cIs532nm4LLDoP2VpM4RZuh6da+LV3eHnfDlZHO870=
+
+# Manually maintained records for Dublin
+
+switch1.dub.openstreetmap.org,switch1.dub,184.104.226.97,2001:470:1:b3b::1 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFA/DoB19FSMBmhqWa16pEfuuwvBVZhpcS5I/tWi6doLBn2wTIH5CJpUMvrRCnS6EzwpZuNLHDDoBDK4bBJNKi7CnqwaqIPqC7uLYKUDJ+sinYhhp2pw+p5ba5j2dLfGzF4Ccz51jEp/Zu13xtk14X5vaLIsluegZA/hOQLakTYWw3+Hc2B70/+vwsnaL74ZsFJHvB9fhozY9hi/cG5Ka0rTpDkTJFSPHRjJ9VMAqPxvPhupt80748FSmp0DRa+AK533txyj8b1phzi7jcg6+K0T9pj5prRxhLCiAiMK5h9WDJTs9fp0pk9NdxhXFwUpEoqIuGQPZy15GKk9yLysDJ
+switch1.dub.openstreetmap.org,switch1.dub,184.104.226.97,2001:470:1:b3b::1 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPif4ShP8AO/RlPkQ+cIgVH+mcwVs+c0VRx9vYUqv4kSYvQ/3GXIQ63vfRdkiRZbKqEsGV51yN4q63OcfH+211w=
+switch1.dub.openstreetmap.org,switch1.dub,184.104.226.97,2001:470:1:b3b::1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIZkVZvRpuvd4KXRli1qLaBDtiN8MJxz0NycpOuFsWa+
+pdu1.dub.openstreetmap.org,pdu1.dub,10.0.64.100 ssh-rsa AAAAB3NzaC1yc2EAAAACAQEAAAEBAN5kJioLsL+Oant6nkdwDyFoAmzJGFEUKaL4gTScrQvRX26oJyI9kBDCM3PHgkVqfA6mj96z4PU6WZuK7fz5QUAE4C3vzgnJ2rew/jGTaf45gFj9GgdRD6ilwFrmCaJtLmm+BmuYjWFXZSkVm0vhbo5lRxtrykjicowYuRFj6mm2MXcDdzua3FjnwEwKK+ArBtHPBnuheyPsaZ55wnXJRnN19gbMYPYfJ0XsN1tRkF09o8Jljpziyr7Z0VIfw7O8vC6t5wz1hp8wSB3QMSuNG0Ze0zwoVyxG6h8Uuna5N9SIOQrQDyjPaIb0wpZItAzfjttFvFt6OPpp68NA+CKDV88=
+pdu2.dub.openstreetmap.org,pdu1.dub,10.0.64.101 ssh-rsa AAAAB3NzaC1yc2EAAAACAQEAAAEBAMmzndbQ6jQLNiVJJH9dpz6kOB+xhMM3Yyp/lvSDZ9GwrX04I8KALOTHhW9/Pzq5X4EhcI4aFy6zEspFI5JOnntjWdM/gXBSqG7QW4r2BSaGmmqAsjzHi3uJ8R76oMd2ckI3fsLIX/x2AVo72M0lq1nuTjeC296vGZByUPUXtq/dKN+pW7wFvCljuFp23Y+uNY7jBTqsoTE6R7FrTJnLHMK5na8wVXY+bDWXJeX4knGIg/qDxkK9kCWv+Ghq6wC4D9oJlF5URC+MpZ8nfD7wB1YVVHhwlmnbAOp9OsZNVZNX3V++5WDtWmFGPCMdxwnpfC8MuPwy2HnLZcAWp0mA8aM=
+oob1.dub.openstreetmap.org,oob1.dub,10.0.64.102 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCZrRoYLxml8E86L8ZsKWtLPvVhzt0ng5upbGR/ZE93p1StVGE/rGECjrttuO0xiu3BsIiKtjil36gg0qHnYvZsbVakJ3nLvaA7wSiIQ4rfFP57YlYAaIR/Hgjju9PMFcsQj+mQPiowj6f7W/NdxTVuDBIJjN2D+V0e3KMHrJE4frEcAxUsJBYTfBHdR7qriRqhZDKLdZMnDcurf02PpdOKC0lqlaBKEIDHnj3451R8xOolC3HsFKKfy5CgTqj5+hvb1huzZFGWjasP5cs6/HnbgcOo6qhtrLtboo7AFqpW1oDGTx7A/004bWJYRRhSU+BtmHzchPdyov6XtyaLz7GIWycJkLzap24gb8nPOzDINNiY7IVYZejEja03h/jncptONg1NVn7rIrd9CwO4rJKAndDDjtgZKv4HoXr3RR9+t0Zx+6HAAnNuOnIL906H/bYBFSP5LdgfnLPQoPdFLs/hUjRY1vAKCh4bvLC+GXwdhga93tbtv6cbwUG37gob3/8=
+oob1.dub.openstreetmap.org,oob1.dub,10.0.64.102 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEn1uwIVWRyNma7X/OKwiqUjaf54eooToWM/0x6kjmIJcl5A4wmzCKG6iVvZezwfRPQo4jbz460QPLzJxb+pBYU=
+oob1.dub.openstreetmap.org,oob1.dub,10.0.64.102 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILvhhWXsbYCeIaQkMVEdlljr8GpzEL4taVWxvRzJa4ap
+fafnir.oob.openstreetmap.org,fafnir.oob,10.0.65.2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5myokF4M8yOu2EtUoos0CVp42V3BBx14BErSqdtWwPkgQIOxgvaUOkoFLUwtXW5pm1+4WIcvweT0OVNHpEQSftWlTJqn2Wt5pM8wkpvc3hoq8oqzP0qboW5KCQ+WODClEV3btmQMdAZk+BB6EURS5asE8kqEJsfFx9HnVTG1NZLndrTvdfq64pQa2k+r1AvA1B2bv/ehQEte4oaS3Y8eKCBr8HowKcOUzO8sw692yBaT3BdjI7joX8GpQhm0YlrWtBTPDKLiyxLmTp8AO4mQa7Ezmm/LgTRXpsZs/lDK8/Bwv9h+isKO8HQnmNfGLxpM//9FRohFrcol6RnCFExO5
+spike-01.oob.openstreetmap.org,spike-01.oob,10.0.65.3 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIrpo9i/nmFZ/7/HSADKEytQhaip5mOERFf+JgenyYF7xQorX2NnuFI9QRoq+n7Xfp11p3kNYjeyZoWUVv/T1y27WgvOyH674fuIhFbdTzuww3upRVEJcbG06mAQZXcxXqlB3ceidtWzbB0/S5oNNF3aL6Zij+lAkgxwguIb7OVM5s80ASEtVCTdugftKx6rshzpF6bKsyqbEQhQOaNFzhEArGHzJldNwM9FHoDHMnpKyIX4Rd2dwp/GaAn8BIlpFJ9la9fukGsBi7fgW992Dfi6CG/aH5Gdnu10msiFd6uL3GpabUIckJTz1Ou6LDNzcsRq2U4trCSzlrAsc3z3Vt
+spike-02.oob.openstreetmap.org,spike-02.oob,10.0.65.4 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXlO0w/s1h99D261F0UTEHFrigmhntNOIk5BKwUsEhPBK1yIoV70hU86J3/leLFa2WB8b17SrhfMpooDuM7ImtNkdzoY/pGaQ4Mukxwy0mLgAHhgJbcLEPVUBKg2nw8ZdkMgi8JvYyHj4wSgPTZ4TftdihFJUyaHUOAgfvRS0v9CraAGaRbI1nIDfcRu+zEolmtCJ/JGW6FJW4upBHcZ5EX8E3xYQtVzqG84YRERni9o+beNF/LOtZbfeYdKGhNguRBdILVio8+uIKeSjDGQ++/dMOfQygb6hQT87FHJdLxjr4T8qSVPOaUHxNivj0dUdgKenVDGGPCo729vGYZwy9
+spike-03.oob.openstreetmap.org,spike-03.oob,10.0.65.5 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKNLVCJAoMnqNDTeQiBvbr/K8IGNnxObFsyIIdKQwJBPrgZIaJNNTmQLA7S+qiVrfhreBaJA2Rbz+iEiXvKz5195Wxsu1voxx+vvhoYeaC3e7M3KECDtB+wPfxoWLMXrvhtu5599M3P7HBFiz1IpwsWL6sL/N6id3NAqZiBlEYcPkhzhoqA5We/wf5AM50patjhYVT7VdV2vYts/MssqiQQvHaGAB6jkCGwenOKKsbA3hXzB5dHEh0KaF+0O+4E/UUDEQcBBXuBxAqDCLdrgvBmW9e7uw3CrOVIOR1ZQLsbIPh2R0KEiUipE4T92v/67o3xaS9u82mgHBK42gIGqLv
+idris.oob.openstreetmap.org,idris.oob,10.0.65.6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCiPCJ3dA6oh92HgSktihP27uOb3NP92u5+3dMSdt6v+d+wgsuKzStUZeoDivLgV2Utkw1Ax4CuzCaYSFJ3JGYwpFY9/ifds5O5SuAOPjgNDzy0ODYKCbur6L3pt69x2P6SnbzA5FfJeCpusJBzT9Hi4ZFuL+XHVti9j+oaK4Ipw39k9xcZwzpuHqwSWs7GFEYJpIvgv1C4MUBMgYcsne/SEEYEE29dzERDR0Lc/tcZK/WHh7hgM9TbJV4BkDF+BVwxnKrbPqUZOJMW9IrdPHhHS7esDglJFKPpZEOy8biLeYXrvRYb9E0pSu7iEbpIro3WG7+lKpfeHAtxLOTarKLr
+konqi.oob.openstreetmap.org,konqi.oob,10.0.65.7 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCTpZOi5g9Od2iDo4FEylFN1v7KYiX3//L7eAi8cafAYNipnRVl+dwDrgXJ3qK1QLSRia9eLWyWTFxh8yOCnHq2uH+5vUlaxY1GY1V+ABNPQGIZDYCAGOQiWrTg9L54sjtQAe0oLBI+e4NDPUSuUgNOgxDkSDKOyxSMRmF8ti7V/OFHoXc3VbAgcngLx/P2neOnl7lnacgDfgyEPARHs/c+mloKKcA3o83Dkcej/pmw0uea8ZkpicGNow+fBy0RUDE2HW/pH5kDfKBTS+QsXEC78d/U3FRDoxbrcJ+DlPv9nk1WSsp343vJ9Ipv49HCsf7hn3H4jGPVIKvbeRLDpMQz
+naga.oob.openstreetmap.org,naga.oob,10.0.65.8 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCinNNW6qam2H2ktHcOz0yruZ+tdvgbHE5Sv4to5blnP5XcbNhjMC2v0dgvgYCjqwWByZV6PU8MbWVcfrrnVJLjHNt2PYpp7oAFotf0+pf+dXEhQaZtoBrH+LcmNlXOmtSamjaHKFEyDjkU00YcxBZbf8+wP4U8+mgfj2thtGSAP6bDBWowpCCn9/NAOd2rw/4wUmSwaplAKbu0LVVD1yLVozdCcKFh6DNI5dLKcxGB4Xh17ifzB3kW7ztDi2a0ENKGQWzgBM1wcwjSxzdp1s+japwBywfvJIJHOuXDTHPAnoGey/q91m6pCHv9UaB3xbQeUGbETg24qV1PI7MwyhRZ
+culebre.oob.openstreetmap.org,culebre.oob,10.0.65.9 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCCagcuY4af7L3AqMl29xe5em3SUNYQcq+IPnXjbdVBIR3JXMizGPNLov/9PB8sNXOKb4ZapQTc1M2Kzdv7oqyXzfALEgaDOVOd74q9UPh8a9gpevgD8w+TVgnIHP7S26BWpvjaaHp47NiP8npsENAwRcBYkfjZcvCbHccX95efe7ypAiR18An4Zf/hNPL7pl2HJ1c6CSONboC7JovX5YhdRfAXJvSgRgrV809LTKXnTYNSwFk6BiosiY6bw0HT/CHk3DvojvyHb53Ti8ynCAAkylAoScdNFxnG+TMYH4U223EUXLdsCv0E0QkIAxo/Sj7lvwONtZebMKb0aYpXsCaT
+horntail.oob.openstreetmap.org,horntail.oob,10.0.65.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDuMo/aMNMWT1Wjr2ac7/sJFtzzJqijdGA3yZR96xPgY3zZX4qQwT1dmr2xU8i7K8EcLuS4oVU6JVNzfLGZycAJUNgA6/yg7FgpmibfY1pinI+7jnEJNH+hp8RuVY30ZNh2iKelNuN3RXKNxKd3tc2eEOZnyv6PcDnwIjL1vML/jezAsQzZtkx6zjPo/pb9jscQTA/rqd9Fv0E2IGrX6Klkz7Z8EXPW2pBK2hURA+9q+dr4RI2Y3hTmg5ynSD3mwgFiRRIt2An0DgBMciC3EnHn9fbApCSTa+O44R8Fr8ZbsYCqM7HV4jDRVFy4kPbqlx6j6r3zQ1SXgHfWeT8lpsdp
+jakelong.oob.openstreetmap.org,jakelong.oob,10.0.65.12 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+HV+Z3bTWwicg7+3coDi0IhMuL6+JSVeqMFkz2GI6jRPsBPCJWFhpfCfzFsHOsyu+BImw2bkEqCnIj1wxwFe0nDwyWEs3CgP06K0BBFcrRInRsn7GNHAzXKBsBRkS5azyA5dWnpv92jnMJUrXmbdN1d2uzb1PVxxSre9ChFcQXSQ5jRikE8dvVHOf6rdKKLuErkLanfydVIZbH6noDWgx3bQAObKzxLg4hf6ki4cTnNbhFB5exM8ZvD9aWgf/jAZ52BDBiVYaf3/qApdeTfeFcwQ7xtbKNcGWmcfWG6ryCTph6QRTuv8yST+V7eNUfWwwd+2ZqDvLzBQmL1YChojz
+longma.oob.openstreetmap.org,longma.oob,10.0.65.13 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDA2up2Io+unbTK6ZTnO9Z81L5ptWIy1O1qwtupI6vCCjV5fTPAdFxvfK9hSfDnlWuemtPTcFTZTONU1rGRrIl0MRDYZVBkzVFZEg0z1Fc8yBw3XV1m+H+X5YmDQ9QrWMefQXxvB9CpirZGrv9tVOURtGM7epqsr509FFqiQXZZcdlfM+BpbkF1KV8MQIUf7BRhAqei0HVixuQ4ntm75DL6qE0PS2l+eiYVALGzUV5f+DmnXovr3VCQMrD/R7FNTzwEApnbLZwUZ3Y1YP3tfQCSxLH8g0R0ymIWkzWCyzQLdjfX8WiPOsPXbzqGO+0r1ku1oA/Xk4tsRiW6/mEPotAP
+smaug.oob.openstreetmap.org,smaug.oob,10.0.65.14 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6Td4ugFZ3Ythg7AITMkITw79k5un1WnNhtwWtMnfkGscIBLw0ce4EWFYcNkX9YV9SHz3/6BXQuNkmDJQnu7NxCS5dWKWa02FulggbThWxbgZXt4oWF81VsJrMIDLCN8742Dujjg5L7K6IBG/M6ldypSs09cIo6zBDqp5qUns/y8N6DgsQXFtZg8AjgLEqadOgKJsk7K1S7JdQmKI6fPlMJt966KuqiAkEOK0V8UqLoZVKnI2OWLXNDyIjuq9jeHAqePoy4wxrXTg9DFZ/Txnf35B9bHtn99czSTWOWofvc3C4etJzrtd718CYCf87LFZeip4h2ZsOhnprtbwrZ2FN
+muirdris.oob.openstreetmap.org,muirdris.oob,10.0.65.15 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCnKmAEwBGFvZ7vdlr2JU40Fnc3G1KXtmJURbVzWSNoPe7OEEmPITikyb1tAe1fZI1O6awdhc+8u9sgho3SU5E+c966EyERAPpkGtfn4r00B7PNPPLdtJDFFZMHRDPlu6lBpHEQHAz9degpyCeiCI2tMd4Fhq+QnwwokymcK0JyEqqtV6ijXGNf5UGGuP7VzuynGLTCMZAGhKG5hMT1xWwv/Ws9u7Y9glhVo9Bf2p6bdpEnmgjo7Ai0SKPxpf+ar5x7aBLWscqX/ud0hykvNVY7GvsU2OvQfjYdVRd0aAGAw5qZf6znjIjTt02RZcfEJvWeFUdS0ShMABiRGM266b9Z
+snap-03.oob.openstreetmap.org,snap-03.oob,10.0.65.50 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUrmWEptEG/L/k2f6haLRtvJnJCFTQWxAY1Nt3yXXAsyum0Egx4ks/Y0fNmTTppxzd8+2coFCeXDXoD3woZCMI/m/Sh20jg9J8/PhESA5kHkNgCqgy9UNNMcvNXEd9djIohM4Q45J2hZ7OFr3/p8BXbP5NgSj2wRXFtctONr+0wzsj4ThhxW5J35ZmvZWXXVbP7zqgesVHfmMTejknNghBp5qniwlzkD/kl8+jKWnSvFyPrKFJvwArEy2NjnrqquTpQcxsX6bwfP4piuQ3PRzHqW6NqQmA6iuqVHGko/uwJ4h9zAJgmS1BEZ33OFGpVRcIqNiNz0uEWhZezrq/MK9h
diff --git a/cookbooks/openssh/templates/default/sshd_config.conf.erb b/cookbooks/openssh/templates/default/sshd_config.conf.erb
new file mode 100644 (file)
index 0000000..99e427c
--- /dev/null
@@ -0,0 +1,9 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+Port <%= node[:openssh][:port] %>
+
+<% if node[:openssh][:password_authentication] -%>
+PasswordAuthentication yes
+<% else -%>
+PasswordAuthentication no
+<% end -%>
diff --git a/cookbooks/openvpn/README.md b/cookbooks/openvpn/README.md
deleted file mode 100644 (file)
index 4936476..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# OpenVPN
-
-This cookbook installs and configures OpenVPN used for secure network
-connections between our datacentres.
diff --git a/cookbooks/openvpn/attributes/default.rb b/cookbooks/openvpn/attributes/default.rb
deleted file mode 100644 (file)
index af20e4e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-default[:openvpn][:tunnels] = {}
-default[:openvpn][:keys] = {}
diff --git a/cookbooks/openvpn/recipes/default.rb b/cookbooks/openvpn/recipes/default.rb
deleted file mode 100644 (file)
index 2446fe9..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-#
-# Cookbook:: openvpn
-# Recipe:: default
-#
-# Copyright:: 2012, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-package "openvpn"
-
-service "openvpn" do
-  action [:enable, :start]
-  supports :status => true, :restart => true, :reload => true
-  ignore_failure true
-end
-
-node[:openvpn][:tunnels].each do |name, details|
-  peer = search(:node, "fqdn:#{details[:peer][:host]}").first
-
-  if peer
-    if peer[:openvpn] && !details[:peer][:address]
-      node.default[:openvpn][:tunnels][name][:peer][:address] = peer[:openvpn][:address]
-    end
-
-    node.default[:openvpn][:tunnels][name][:peer][:networks] = peer.interfaces(:role => :internal).collect do |interface|
-      { :address => interface[:network], :netmask => interface[:netmask] }
-    end
-  else
-    node.default[:openvpn][:tunnels][name][:peer][:networks] = []
-  end
-
-  if details[:mode] == "client"
-    execute "openvpn-genkey-#{name}" do
-      command "openvpn --genkey --secret /etc/openvpn/#{name}.key"
-      user "root"
-      group "root"
-      creates "/etc/openvpn/#{name}.key"
-    end
-
-    if File.exist?("/etc/openvpn/#{name}.key")
-      node.normal[:openvpn][:keys][name] = IO.read("/etc/openvpn/#{name}.key")
-    end
-  elsif peer && peer[:openvpn]
-    file "/etc/openvpn/#{name}.key" do
-      owner "root"
-      group "root"
-      mode 0o600
-      content peer[:openvpn][:keys][name]
-    end
-  end
-
-  if node[:openvpn][:tunnels][name][:peer][:address]
-    template "/etc/openvpn/#{name}.conf" do
-      source "tunnel.conf.erb"
-      owner "root"
-      group "root"
-      mode 0o644
-      variables :name => name,
-                :address => node[:openvpn][:address],
-                :port => node[:openvpn][:tunnels][name][:port],
-                :mode => node[:openvpn][:tunnels][name][:mode],
-                :peer => node[:openvpn][:tunnels][name][:peer]
-      notifies :restart, "service[openvpn]"
-    end
-  else
-    file "/etc/openvpn/#{name}.conf" do
-      action :delete
-    end
-  end
-end
diff --git a/cookbooks/openvpn/templates/default/tunnel.conf.erb b/cookbooks/openvpn/templates/default/tunnel.conf.erb
deleted file mode 100644 (file)
index e2fcc35..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Set the local port to use
-port <%= @port %>
-
-# Use UDP
-proto udp
-
-# Use routed IP tunnels
-dev tun
-
-# Use shared secret authentication
-secret <%= @name %>.key
-
-# Run in peer-to-peer mode
-mode p2p
-<% if @mode == "client" -%>
-
-# Connect to the remote machine
-remote <%= @peer[:host] %> <%= @peer[:port] %>
-<% end -%>
-
-# Configure interface and routing
-ifconfig <%= @address %> <%= @peer[:address] %>
-<% @peer[:networks].each do |network| -%>
-route <%= network[:address] %> <%= network[:netmask] %>
-<% end -%>
-
-# Keepalive - check every 10 seconds and reset after 2 minutes
-keepalive 10 120
-
-# Use AES-128 as the cipher
-cipher AES-128-CBC
-
-# Run unprivileged
-user nobody
-group nogroup
-
-# Reuse resources on restart to avoid privilege problems
-persist-key
-persist-tun
-
-# Set log verbosity
-verb 3
index 8d4f9a3b6b10b86b3f0b0626e8a8a3112acb4b13..ef45921001270cf1c6cced4fcc22a7fe374ff0bf 100644 (file)
@@ -1,2 +1,2 @@
 # Set the default version
-default[:osmosis][:version] = "0.43.1"
+default[:osmosis][:version] = "0.47.4"
index a1cf52da58056b38539080724b9dc0a1108318d7..a6485f09c95d5029d5ec377a1d34c3d6bc3a404a 100644 (file)
@@ -6,4 +6,3 @@ description       "Installs and configures osmosis"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "chef"
index 8de53eb37823aef3ce133c5c6eca333eae46f22e..40f0be590134e5f348ec4e23293c97ed09027e5d 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "chef"
-
-package "unzip"
 package "default-jre"
 
-osmosis_package = "osmosis-#{node[:osmosis][:version]}.zip"
-osmosis_directory = "/opt/osmosis-#{node[:osmosis][:version]}"
+cache_dir = Chef::Config[:file_cache_path]
+
+osmosis_version = node[:osmosis][:version]
+osmosis_package = "osmosis-#{osmosis_version}.zip"
+osmosis_directory = "/opt/osmosis-#{osmosis_version}"
 
-Dir.glob("/var/cache/chef/osmosis-*.zip").each do |zip|
-  next if zip == "/var/cache/chef/#{osmosis_package}"
+Dir.glob("#{cache_dir}/osmosis-*.zip").each do |zip|
+  next if zip == "#{cache_dir}/#{osmosis_package}"
 
   file zip do
     action :delete
@@ -37,25 +37,25 @@ end
 directory osmosis_directory do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
-execute "/var/cache/chef/#{osmosis_package}" do
-  action :nothing
-  command "unzip -q /var/cache/chef/#{osmosis_package}"
-  cwd osmosis_directory
-  user "root"
+remote_file "#{cache_dir}/#{osmosis_package}" do
+  action :create_if_missing
+  source "https://github.com/openstreetmap/osmosis/releases/download/#{osmosis_version}/osmosis-#{osmosis_version}.zip"
+  owner "root"
   group "root"
+  mode "644"
+  backup false
 end
 
-remote_file "/var/cache/chef/#{osmosis_package}" do
-  action :create_if_missing
-  source "https://bretth.dev.openstreetmap.org/osmosis-build/#{osmosis_package}"
+archive_file "#{cache_dir}/#{osmosis_package}" do
+  action :nothing
+  destination osmosis_directory
+  overwrite true
   owner "root"
   group "root"
-  mode 0o644
-  backup false
-  notifies :run, "execute[/var/cache/chef/#{osmosis_package}]"
+  subscribes :extract, "remote_file[#{cache_dir}/#{osmosis_package}]"
 end
 
 link "/usr/local/bin/osmosis" do
index 610f68605dbd1ef35da701605bedc919bf63d3c5..394ac7085ce328ad333cd6b73c5b03b746994030 100644 (file)
@@ -1,6 +1,11 @@
 default[:osqa][:user] = "osqa"
 default[:osqa][:group] = nil
+default[:osqa][:database_cluster] = "15/main"
 default[:osqa][:database_name] = "osqa"
 default[:osqa][:database_user] = "osqa"
 default[:osqa][:database_password] = ""
 default[:osqa][:sites] = []
+
+default[:postgresql][:versions] |= ["15"]
+
+default[:accounts][:users][:osqa][:status] = :role
index 02f870410394bf7b57c1b901dc8f4e8b6086ef24..6f47c773c6b08600cbad73860e9d5abbcaa46585 100644 (file)
@@ -6,7 +6,9 @@ description       "Installs and configures OSQA"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
 depends           "memcached"
+depends           "postgresql"
 depends           "python"
 depends           "tools"
index 6e8d00d4afa128a62fba39ff4af256c415c7b1f1..4cbd677a658820edf99e4ffbbb3a0914b2d77d50 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "tools"
+include_recipe "accounts"
 include_recipe "apache"
 include_recipe "memcached"
+include_recipe "postgresql"
 include_recipe "python"
+include_recipe "tools"
 
 package "python-dev"
 package "libmysqlclient-dev"
@@ -28,18 +30,15 @@ package "libpq-dev"
 
 python_directory = "/opt/osqa-python"
 
-python_virtualenv python_directory
+python_virtualenv python_directory do
+  interpreter "/usr/bin/python2"
+end
 
 python_package "Django" do
   python_virtualenv python_directory
   version "1.6.11"
 end
 
-python_package "html5lib" do
-  python_virtualenv python_directory
-  version "0.999"
-end
-
 python_package "Markdown" do
   python_virtualenv python_directory
   version "2.4"
@@ -55,11 +54,6 @@ python_package "python-openid" do
   version "2.2.5"
 end
 
-python_package "MySQL-python" do
-  python_virtualenv python_directory
-  version "1.2.3"
-end
-
 python_package "psycopg2" do
   python_virtualenv python_directory
   version "2.7.6.1"
@@ -70,6 +64,11 @@ python_package "South" do
   version "0.7.6"
 end
 
+python_package "html5lib" do
+  python_virtualenv python_directory
+  version "0.999"
+end
+
 apache_module "rewrite"
 apache_module "wsgi"
 
@@ -81,11 +80,22 @@ node[:osqa][:sites].each do |site|
   site_user = Etc.getpwuid(site_user).name if site_user.is_a?(Integer)
   site_group = site[:group] || node[:osqa][:group] || Etc.getpwnam(site_user).gid
   site_group = Etc.getgrgid(site_group).name if site_group.is_a?(Integer)
+  database_cluster = site[:database_cluster] || node[:osqa][:database_cluster]
   database_name = site[:database_name] || node[:osqa][:database_name]
   database_user = site[:database_user] || node[:osqa][:database_user]
   database_password = site[:database_user] || node[:osqa][:database_password]
   backup_name = site[:backup]
 
+  postgresql_user database_user do
+    cluster database_cluster
+    password database_password
+  end
+
+  postgresql_database database_name do
+    cluster database_cluster
+    owner database_user
+  end
+
   ssl_certificate site_name do
     domains [site_name] + site_aliases
     notifies :reload, "service[apache2]"
@@ -100,7 +110,7 @@ node[:osqa][:sites].each do |site|
   directory directory do
     owner site_user
     group site_group
-    mode 0o755
+    mode "755"
   end
 
   execute "osqa-migrate" do
@@ -116,6 +126,7 @@ node[:osqa][:sites].each do |site|
     action :sync
     repository "https://git.openstreetmap.org/public/osqa.git"
     revision "live"
+    depth 1
     user site_user
     group site_group
     notifies :run, "execute[osqa-migrate]"
@@ -124,14 +135,14 @@ node[:osqa][:sites].each do |site|
   directory "#{directory}/upfiles" do
     user site_user
     group site_group
-    mode 0o755
+    mode "755"
   end
 
   template "#{directory}/osqa/osqa.wsgi" do
     source "osqa.wsgi.erb"
     owner site_user
     group site_group
-    mode 0o644
+    mode "644"
     variables :directory => directory
     notifies :reload, "service[apache2]"
   end
@@ -145,7 +156,7 @@ node[:osqa][:sites].each do |site|
     line.gsub!(/^CACHE_BACKEND = .*/, "CACHE_BACKEND = 'memcached://127.0.0.1:11211/'")
     line.gsub!(%r{^APP_URL = 'http://'}, "APP_URL = 'https://#{site_name}'")
     line.gsub!(%r{^TIME_ZONE = 'America/New_York'}, "TIME_ZONE = 'Europe/London'")
-    line.gsub!(/^DISABLED_MODULES = \[([^\]]+)\]/, "DISABLED_MODULES = [\\1, 'localauth', 'facebookauth', 'oauthauth']")
+    line.gsub!(/^DISABLED_MODULES = \[([^\]]+)\]/, "DISABLED_MODULES = [\\1, 'localauth', 'facebookauth', 'oauthauth', 'mysqlfulltext']")
 
     line
   end
@@ -153,7 +164,7 @@ node[:osqa][:sites].each do |site|
   file "#{directory}/osqa/settings_local.py" do
     owner site_user
     group site_group
-    mode 0o644
+    mode "644"
     content settings
     notifies :reload, "service[apache2]"
   end
@@ -162,7 +173,7 @@ node[:osqa][:sites].each do |site|
     source "backup.cron.erb"
     owner "root"
     group "root"
-    mode 0o755
+    mode "755"
     variables :name => backup_name, :directory => directory, :user => site_user, :database => database_name
   end
 end
index 562f687e37d4046a258ca99772f5626eddae2fd2..1ef85c0404c2258d9a1affde81640f811ed69746 100644 (file)
@@ -1,6 +1,6 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> processes=4 threads=4 inactivity-timeout=600 graceful-timeout=60 maximum-requests=2000 python-home=<%= @python_home %>
+WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> processes=4 threads=8 restart-interval=3600 inactivity-timeout=600 graceful-timeout=60 maximum-requests=2000 python-home=<%= @python_home %>
 
 <VirtualHost *:80>
   ServerName <%= @name %>
@@ -9,7 +9,7 @@ WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> processes=4
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -28,7 +28,7 @@ WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> processes=4
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent / https://<%= @name %>/
@@ -43,7 +43,7 @@ WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> processes=4
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   DocumentRoot <%= @directory %>/osqa
@@ -53,6 +53,27 @@ WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> processes=4
   WSGIScriptAlias / <%= @directory %>/osqa/osqa.wsgi
 
   WSGIProcessGroup <%= @name %>
+
+  # Site is now closed. Block access to login page and other pages.
+  <Location /account>
+    Require all denied
+    ErrorDocument 403 "help.openstreetmap.org is closed. Use community.openstreetmap.org instead."
+  </Location>
+  <Location /questions/ask/>
+    Require all denied
+    ErrorDocument 403 "help.openstreetmap.org is closed. Use community.openstreetmap.org instead."
+  </Location>
+  <Location /contact/>
+    Require all denied
+    ErrorDocument 403 "help.openstreetmap.org is closed. Use community.openstreetmap.org instead."
+  </Location>
+  <Location /search/>
+    Require all denied
+    ErrorDocument 403 "help.openstreetmap.org is closed. Use community.openstreetmap.org instead."
+  </Location>
+  RewriteEngine on
+  RewriteCond %{REQUEST_METHOD} POST
+  RewriteRule ^/questions - [F,NC]
 </VirtualHost>
 
 <Directory <%= @directory %>/osqa>
index 3c2abf6a79c259a493b56127a96bc75b0291937f..020a035497d6910ef7084151595cd514a03a32cf 100644 (file)
@@ -12,10 +12,9 @@ chown <%= @user %> $T/osqa-$D
 sudo -u <%= @user %> pg_dump --format=custom --file=$T/<%= @name %>-$D/osqa.dmp <%= @database %>
 ln -s <%= @directory %>/upfiles $T/<%= @name %>-$D/upfiles
 
-export GZIP="--rsyncable -9"
 export RSYNC_RSH="ssh -ax"
 
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B <%= @name %>-$D
+nice tar --create --dereference --directory=$T <%= @name %>-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
index fff2dc008a371c2eb49bc2c1226dc84e30cea493..037cae612359ddf2f25598d1eaeb85e9c1939d07 100644 (file)
@@ -1,8 +1,13 @@
-default[:otrs][:version] = "6.0.8"
+default[:otrs][:version] = "6.0.48"
 default[:otrs][:user] = "otrs"
 default[:otrs][:group] = nil
-default[:otrs][:database_cluster] = "9.5/main"
+default[:otrs][:database_cluster] = "15/main"
 default[:otrs][:database_name] = "otrs"
 default[:otrs][:database_user] = "otrs"
-default[:otrs][:database_password] = ""
-default[:otrs][:site] = nil
+default[:otrs][:database_password] = "otrs"
+default[:otrs][:site] = "otrs"
+
+default[:postgresql][:versions] |= ["15"]
+
+default[:accounts][:users][:otrs][:status] = :role
+default[:accounts][:groups][:"www-data"][:members] = [:otrs]
index 39f6087c34da50c83d5fd87d2839c10d5c9b00a9..bf330e8cc9f0760c21c926182f23df548d0ca5fd 100644 (file)
@@ -6,6 +6,9 @@ description       "Installs and configures OTRS"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
+depends           "chef"
+depends           "exim"
 depends           "postgresql"
 depends           "tools"
diff --git a/cookbooks/otrs/recipes/debian.rb b/cookbooks/otrs/recipes/debian.rb
new file mode 100644 (file)
index 0000000..fac61b6
--- /dev/null
@@ -0,0 +1,129 @@
+#
+# Cookbook:: otrs
+# Recipe:: debian
+#
+# Copyright:: 2024, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "accounts"
+include_recipe "apache"
+include_recipe "exim"
+include_recipe "postgresql"
+include_recipe "tools"
+
+passwords = data_bag_item("otrs", "passwords")
+
+apache_module "perl" do
+  package "libapache2-mod-perl2"
+end
+
+apache_module "deflate"
+apache_module "headers"
+apache_module "rewrite"
+
+database_cluster = node[:otrs][:database_cluster]
+database_name = node[:otrs][:database_name]
+database_user = node[:otrs][:database_user]
+database_password = passwords[node[:otrs][:database_password]]
+site = node[:otrs][:site]
+site_aliases = node[:otrs][:site_aliases] || []
+
+postgresql_user database_user do
+  cluster database_cluster
+  password database_password
+end
+
+postgresql_database database_name do
+  cluster database_cluster
+  owner database_user
+end
+
+package "dbconfig-common"
+
+template "/etc/dbconfig-common/otrs2.conf" do
+  source "dbconfig.config.erb"
+  owner "root"
+  group "root"
+  mode "600"
+  variables :database_name => database_name,
+            :database_user => database_user,
+            :database_password => database_password,
+            :database_cluster => database_cluster
+end
+
+# Ensure the OTRS package in backports has a priority preference.
+apt_preference "otrs2" do
+  pin "release o=Debian Backports"
+  pin_priority "600"
+end
+
+apt_package "otrs2"
+
+# Ensure debconf is repopulated on a dbconfig change
+execute "dpkg-reconfigure-otrs2" do
+  action :nothing
+  command "dpkg-reconfigure -fnoninteractive otrs2"
+  subscribes :run, "template[/etc/dbconfig-common/otrs2.conf]"
+end
+
+# Disable deb otrs2 apache config
+apache_conf "otrs2" do
+  action :disable
+end
+
+# Disable deb otrs2 cron job
+file "/etc/cron.d/otrs2" do
+  action :delete
+  manage_symlink_source true
+end
+
+systemd_service "otrs" do
+  description "OTRS Daemon"
+  type "forking"
+  user "otrs"
+  group "www-data"
+  exec_start_pre "-/usr/share/otrs/bin/otrs.Daemon.pl stop" # Stop if race with deb cron
+  exec_start "/usr/share/otrs/bin/otrs.Daemon.pl start"
+  private_tmp true
+  protect_system "strict"
+  protect_home true
+  runtime_directory "otrs"
+  runtime_directory_mode 0o770
+  runtime_directory_preserve true
+  read_write_paths ["/var/lib/otrs", "/run/otrs", "/var/log/exim4", "/var/spool/exim4"]
+end
+
+service "otrs" do
+  action [:enable, :start]
+  subscribes :restart, "apt_package[otrs2]"
+  subscribes :restart, "systemd_service[otrs]"
+end
+
+ssl_certificate site do
+  domains [site] + site_aliases
+  notifies :reload, "service[apache2]"
+end
+
+apache_site site do
+  template "apache-debian.erb"
+  variables :aliases => site_aliases
+end
+
+template "/etc/cron.daily/otrs-backup" do
+  source "backup.cron.erb"
+  owner "root"
+  group "root"
+  mode "755"
+end
index b5225e2892413b338fc7b7b0f55c546fa84f6490..f16931b328b6d76ae02b5e2b993674a6242e0138 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "tools"
-include_recipe "postgresql"
+include_recipe "accounts"
 include_recipe "apache"
+include_recipe "exim"
+include_recipe "postgresql"
+include_recipe "tools"
 
 passwords = data_bag_item("otrs", "passwords")
 
-package "libapache2-mod-perl2"
-package "libapache2-reload-perl"
-
-package "libgd-gd2-perl"
-package "libgd-graph-perl"
-package "libgd-text-perl"
-package "libjson-xs-perl"
-package "libmail-imapclient-perl"
-package "libnet-ldap-perl"
-package "libpdf-api2-perl"
-package "libsoap-lite-perl"
-package "libyaml-libyaml-perl"
-package "libcrypt-eksblowfish-perl"
-package "libtemplate-perl"
+package %w[
+  tar
+  bzip2
+  libapache-dbi-perl
+  libapache2-reload-perl
+  libarchive-zip-perl
+  libauthen-ntlm-perl
+  libauthen-sasl-perl
+  libcrypt-eksblowfish-perl
+  libcss-minifier-xs-perl
+  libdatetime-perl
+  libdbd-mysql-perl
+  libencode-hanextra-perl
+  libexcel-writer-xlsx-perl
+  libgd-gd2-perl
+  libgd-graph-perl
+  libgd-text-perl
+  libhtml-parser-perl
+  libio-socket-ssl-perl
+  libjavascript-minifier-xs-perl
+  libjson-perl
+  libjson-xs-perl
+  liblocale-codes-perl
+  libmail-imapclient-perl
+  libmoo-perl
+  libnet-dns-perl
+  libnet-ldap-perl
+  libpdf-api2-perl
+  libsisimai-perl
+  libsoap-lite-perl
+  libspreadsheet-xlsx-perl
+  libtemplate-perl
+  libtext-csv-xs-perl
+  libtext-diff-perl
+  libtimedate-perl
+  libxml-libxml-perl
+  libxml-libxml-simple-perl
+  libxml-libxslt-perl
+  libxml-parser-perl
+  libxml-simple-perl
+  libyaml-libyaml-perl
+  libyaml-perl
+]
+
+apache_module "perl" do
+  package "libapache2-mod-perl2"
+end
 
+apache_module "deflate"
 apache_module "headers"
+apache_module "rewrite"
 
 version = node[:otrs][:version]
 user = node[:otrs][:user]
@@ -59,20 +96,20 @@ postgresql_database database_name do
   owner database_user
 end
 
-remote_file "#{Chef::Config[:file_cache_path]}/otrs-#{version}.tar.bz2" do
-  source "https://ftp.otrs.org/pub/otrs/otrs-#{version}.tar.bz2"
-  not_if { File.exist?("/opt/otrs-#{version}") }
+remote_file "#{Chef::Config[:file_cache_path]}/znuny-#{version}.tar.bz2" do
+  source "https://download.znuny.org/releases/znuny-#{version}.tar.bz2"
+  not_if { ::File.exist?("/opt/znuny-#{version}") }
 end
 
-execute "untar-otrs-#{version}" do
-  command "tar jxf #{Chef::Config[:file_cache_path]}/otrs-#{version}.tar.bz2"
+execute "untar-znuny-#{version}" do
+  command "tar jxf #{Chef::Config[:file_cache_path]}/znuny-#{version}.tar.bz2"
   cwd "/opt"
   user "root"
   group "root"
-  not_if { File.exist?("/opt/otrs-#{version}") }
+  not_if { ::File.exist?("/opt/znuny-#{version}") }
 end
 
-config = edit_file "/opt/otrs-#{version}/Kernel/Config.pm.dist" do |line|
+config = edit_file "/opt/znuny-#{version}/Kernel/Config.pm.dist" do |line|
   line.gsub!(/^( *)\$Self->{Database} = 'otrs'/, "\\1$Self->{Database} = '#{database_name}'")
   line.gsub!(/^( *)\$Self->{DatabaseUser} = 'otrs'/, "\\1$Self->{DatabaseUser} = '#{database_user}'")
   line.gsub!(/^( *)\$Self->{DatabasePw} = 'some-pass'/, "\\1$Self->{DatabasePw} = '#{database_password}'")
@@ -85,50 +122,42 @@ config = edit_file "/opt/otrs-#{version}/Kernel/Config.pm.dist" do |line|
   line
 end
 
-file "/opt/otrs-#{version}/Kernel/Config.pm" do
+file "/opt/znuny-#{version}/Kernel/Config.pm" do
   owner user
   group "www-data"
-  mode 0o664
+  mode "664"
   content config
+  notifies :restart, "service[otrs]"
 end
 
-link "/opt/otrs" do
-  to "/opt/otrs-#{version}"
-end
-
-execute "/opt/otrs/bin/otrs.SetPermissions.pl" do
-  action :run
-  command "/opt/otrs/bin/otrs.SetPermissions.pl --otrs-user=#{user} --web-group=www-data /opt/otrs-#{version}"
+execute "/opt/znuny-#{version}/bin/otrs.SetPermissions.pl" do
+  action :nothing
+  command "/opt/znuny-#{version}/bin/otrs.SetPermissions.pl --otrs-user=#{user} --web-group=www-data /opt/znuny-#{version}"
   user "root"
   group "root"
-  only_if { File.stat("/opt/otrs/README.md").uid != Etc.getpwnam("otrs").uid }
+  subscribes :run, "execute[untar-znuny-#{version}]"
 end
 
-execute "/opt/otrs/bin/otrs.RebuildConfig.pl" do
-  action :run
-  command "/opt/otrs/bin/otrs.RebuildConfig.pl"
-  user "root"
-  group "root"
-  not_if { File.exist?("/opt/otrs/Kernel/Config/Files/ZZZAAuto.pm") }
+link "/opt/otrs" do
+  to "/opt/znuny-#{version}"
 end
 
-execute "/opt/otrs/bin/Cron.sh" do
-  action :nothing
-  command "/opt/otrs/bin/Cron.sh restart"
+systemd_service "otrs" do
+  description "OTRS Daemon"
+  type "forking"
   user "otrs"
   group "otrs"
+  exec_start "/opt/otrs/bin/otrs.Daemon.pl start"
+  private_tmp true
+  protect_system "strict"
+  protect_home true
+  read_write_paths ["/opt/znuny-#{version}/var", "/var/log/exim4", "/var/spool/exim4"]
 end
 
-Dir.glob("/opt/otrs/var/cron/*.dist") do |distname|
-  name = distname.sub(".dist", "")
-
-  file name do
-    owner "otrs"
-    group "www-data"
-    mode 0o664
-    content IO.read(distname)
-    notifies :run, "execute[/opt/otrs/bin/Cron.sh]"
-  end
+service "otrs" do
+  action [:enable, :start]
+  subscribes :restart, "link[/opt/otrs]"
+  subscribes :restart, "systemd_service[otrs]"
 end
 
 ssl_certificate site do
@@ -141,16 +170,9 @@ apache_site site do
   variables :aliases => site_aliases
 end
 
-template "/etc/sudoers.d/otrs" do
-  source "sudoers.erb"
-  owner "root"
-  group "root"
-  mode 0o440
-end
-
 template "/etc/cron.daily/otrs-backup" do
   source "backup.cron.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
diff --git a/cookbooks/otrs/templates/default/apache-debian.erb b/cookbooks/otrs/templates/default/apache-debian.erb
new file mode 100644 (file)
index 0000000..1ec34fd
--- /dev/null
@@ -0,0 +1,114 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<VirtualHost *:80>
+  ServerName <%= @name %>
+<% @aliases.each do |alias_name| -%>
+  ServerAlias <%= alias_name %>
+<% end -%>
+  ServerAdmin webmaster@openstreetmap.org
+
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
+  RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
+  RedirectPermanent / https://<%= @name %>/
+</VirtualHost>
+<% unless @aliases.empty? -%>
+
+<VirtualHost *:443>
+  ServerName <%= @aliases.first %>
+<% @aliases.drop(1).each do |alias_name| -%>
+  ServerAlias <%= alias_name %>
+<% end -%>
+  ServerAdmin webmaster@openstreetmap.org
+
+  SSLEngine on
+  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
+  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
+
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
+  RedirectPermanent / https://<%= @name %>/
+</VirtualHost>
+<% end -%>
+
+<VirtualHost *:443>
+  ServerName <%= @name %>
+  ServerAdmin webmaster@openstreetmap.org
+
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
+  SSLEngine on
+  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
+  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
+
+  ScriptAlias /otrs "/usr/share/otrs/bin/cgi-bin/"
+  Alias /otrs-web "/usr/share/otrs/var/httpd/htdocs/"
+  RedirectMatch ^/$ /otrs/index.pl
+
+  Perlrequire /usr/share/otrs/scripts/apache2-perl-startup.pl
+
+  PerlModule Apache2::Reload
+  PerlInitHandler Apache2::Reload
+
+
+  <Location /otrs>
+    ErrorDocument 403 /otrs/index.pl
+               ErrorDocument 404 /otrs/index.pl
+    SetHandler  perl-script
+    PerlResponseHandler ModPerl::Registry
+    Options +ExecCGI
+    PerlOptions +ParseHeaders
+    PerlOptions +SetupEnv
+    Require all granted
+  </Location>
+
+  <Location /otrs/nph-genericinterface.pl>
+    PerlOptions -ParseHeaders
+  </Location>
+</VirtualHost>
+
+<Directory "/usr/share/otrs/bin/cgi-bin/">
+    AllowOverride None
+    Options +ExecCGI -Includes
+    Require all granted
+</Directory>
+
+<Directory "/usr/share/otrs/var/httpd/htdocs/">
+  AllowOverride None
+  Require all granted
+
+  # Make sure CSS and JS files are read as UTF8 by the browsers.
+  AddCharset UTF-8 .css
+  AddCharset UTF-8 .js
+
+  # Set explicit mime type for woff fonts since it is relatively new and apache may not know about it.
+  AddType application/font-woff .woff
+</Directory>
+
+# Cache css-cache for 30 days
+<Directory "/usr/share/otrs/var/httpd/htdocs/skins/*/*/css-cache">
+    <FilesMatch "\.(css|CSS)$">
+        Header set Cache-Control "max-age=2592000, must-revalidate"
+    </FilesMatch>
+</Directory>
+
+<Directory "/usr/share/otrs/var/httpd/htdocs/skins/*/*/css/thirdparty">
+    <FilesMatch "\.(css|CSS|woff|svg)$">
+        Header set Cache-Control "max-age=14400, must-revalidate"
+    </FilesMatch>
+</Directory>
+
+<Directory "/usr/share/otrs/var/httpd/htdocs/js/js-cache">
+    <FilesMatch "\.(js|JS)$">
+        Header set Cache-Control "max-age=2592000, must-revalidate"
+    </FilesMatch>
+</Directory>
+
+<Directory "/usr/share/otrs/var/httpd/htdocs/js/thirdparty/">
+    <FilesMatch "\.(js|JS)$">
+        Header set Cache-Control "max-age=14400, must-revalidate"
+    </FilesMatch>
+</Directory>
index 0a8735c5016d3faee5448f53f0bdce20b449bd73..a3605a966d968e2509189b7d4222c995ecedd79b 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -26,7 +26,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent / https://<%= @name %>/
@@ -37,7 +37,7 @@
   ServerName <%= @name %>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   SSLEngine on
index bfe5242afb3a34f0eaaaa1e149ffa749b8524270..aecce1c64af1c4feb3ff8e9dce31bff4b5073763 100644 (file)
@@ -13,10 +13,9 @@ sudo -u otrs pg_dump --file=$T/otrs-$D/otrs.dmp otrs
 ln -s /opt/otrs $T/otrs-$D/otrs
 ln -s /etc/apache2/sites-available/otrs.openstreetmap.org.conf $T/otrs-$D/apache2-otrs.openstreetmap.org.conf
 
-export GZIP="--rsyncable -9"
 export RSYNC_RSH="ssh -ax"
 
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B otrs-$D
+nice tar --create --dereference --directory=$T otrs-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
diff --git a/cookbooks/otrs/templates/default/dbconfig.config.erb b/cookbooks/otrs/templates/default/dbconfig.config.erb
new file mode 100644 (file)
index 0000000..b9ac139
--- /dev/null
@@ -0,0 +1,84 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+# dbc_install: configure database with dbconfig-common?
+#              set to anything but "true" to opt out of assistance
+dbc_install='true'
+
+# dbc_upgrade: upgrade database with dbconfig-common?
+#              set to anything but "true" to opt out of assistance
+dbc_upgrade='true'
+
+# dbc_remove: deconfigure database with dbconfig-common?
+#             set to anything but "true" to opt out of assistance
+dbc_remove='false'
+
+# dbc_dbtype: type of underlying database to use
+#      this exists primarily to let dbconfig-common know what database
+#      type to use when a package supports multiple database types.
+#      don't change this value unless you know for certain that this
+#      package supports multiple database types
+dbc_dbtype='pgsql'
+
+# dbc_dbuser: database user
+#      the name of the user who we will use to connect to the database.
+dbc_dbuser='<%= @database_user %>'
+
+# dbc_dbpass: database user password
+#      the password to use with the above username when connecting
+#      to a database, if one is required
+dbc_dbpass='<%= @database_password %>'
+
+# dbc_dballow: allowed host to connect from
+#       only for database types that support specifying the host from
+#       which the database user is allowed to connect from
+#       this string defines for which host the dbc_dbuser is allowed
+#       to connect
+#       this value is only really used again when you reconfigure the
+#       package
+dbc_dballow='localhost'
+
+# dbc_dbserver: database host.
+#      leave unset to use localhost (or a more efficient local method
+#      if it exists).
+dbc_dbserver='localhost'
+
+# dbc_dbport: remote database port
+#      leave unset to use the default.  only applicable if you are
+#      using a remote database.
+# <%= @database_cluster %>
+dbc_dbport='<%= node[:postgresql][:clusters][@database_cluster][:port] %>'
+
+# dbc_dbname: name of database
+#      this is the name of your application's database.
+dbc_dbname='<%= @database_name %>'
+
+# dbc_dbadmin: name of the administrative user
+#      this is the administrative user that is used to create all of the above
+#      The exception is the MySQL/MariaDB localhost case, where this value is
+#      ignored and instead is determined from /etc/mysql/debian.cnf.
+dbc_dbadmin='postgres'
+
+# dbc_basepath: base directory to hold database files
+#      leave unset to use the default.  only applicable if you are
+#      using a local (filesystem based) database.
+dbc_basepath=''
+
+##
+## postgresql specific settings.  if you don't use postgresql,
+## you can safely ignore all of these
+##
+
+# dbc_ssl: should we require ssl?
+#      set to "true" to require that connections use ssl
+dbc_ssl=''
+
+# dbc_authmethod_admin: authentication method for admin
+# dbc_authmethod_user: authentication method for dbuser
+#      see the section titled "AUTHENTICATION METHODS" in
+#      /usr/share/doc/dbconfig-common/README.pgsql for more info
+dbc_authmethod_admin='ident'
+dbc_authmethod_user='password'
+
+##
+## end postgresql specific settings
+##
diff --git a/cookbooks/otrs/templates/default/sudoers.erb b/cookbooks/otrs/templates/default/sudoers.erb
deleted file mode 100644 (file)
index 91c73e9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Allow exim to deliver mail into OTRS
-Debian-exim ALL=(otrs) NOPASSWD: /usr/share/otrs/bin/PostMaster.pl
diff --git a/cookbooks/overpass/README.md b/cookbooks/overpass/README.md
new file mode 100644 (file)
index 0000000..baac18b
--- /dev/null
@@ -0,0 +1,5 @@
+# Overpass Cookbook
+
+This cookbook installs and configures an Overpass API. It can be configured
+to install a stripped down version that can only be used to serve requests
+from the "Query Feature" of the main OSM website.
diff --git a/cookbooks/overpass/attributes/default.rb b/cookbooks/overpass/attributes/default.rb
new file mode 100644 (file)
index 0000000..3bf067f
--- /dev/null
@@ -0,0 +1,16 @@
+default[:overpass][:fqdn] = "overpass.openstreetmap.org"
+default[:overpass][:version] = "0.7.61.8"
+# One of: no, meta, attic
+default[:overpass][:meta_mode] = "attic"
+# One of: no, gz, lz4
+default[:overpass][:compression_mode] = "lz4"
+default[:overpass][:rate_limit] = 2
+default[:overpass][:dispatcher_space] = 10 * 1024 * 1024 * 1024
+default[:overpass][:clone_url] = "http://dev.overpass-api.de/api_drolbr"
+default[:overpass][:replication_url] = "https://planet.openstreetmap.org/replication/minute/"
+# If true only provide an API for the query feature on the website
+default[:overpass][:restricted_api] = true
+
+default[:overpass][:logdir] = "/var/log/overpass"
+
+default[:accounts][:users][:overpass][:status] = :role
diff --git a/cookbooks/overpass/metadata.rb b/cookbooks/overpass/metadata.rb
new file mode 100644 (file)
index 0000000..10f4d1b
--- /dev/null
@@ -0,0 +1,13 @@
+name              "overpass"
+maintainer        "OpenStreetMap Administrators"
+maintainer_email  "admins@openstreetmap.org"
+license           "Apache-2.0"
+description       "Installs and configures an Overpass server"
+
+version           "1.0.0"
+supports          "ubuntu"
+depends           "accounts"
+depends           "apache"
+depends           "prometheus"
+depends           "ruby"
+depends           "systemd"
diff --git a/cookbooks/overpass/recipes/default.rb b/cookbooks/overpass/recipes/default.rb
new file mode 100644 (file)
index 0000000..0cad2a1
--- /dev/null
@@ -0,0 +1,238 @@
+#
+# Cookbook:: overpass
+# Recipe:: default
+#
+# Copyright:: 2021, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "accounts"
+include_recipe "apache"
+include_recipe "prometheus"
+include_recipe "ruby"
+
+username = "overpass"
+basedir = data_bag_item("accounts", username)["home"]
+web_passwords = data_bag_item("web", "passwords")
+
+%w[bin site diffs db src].each do |dirname|
+  directory "#{basedir}/#{dirname}" do
+    owner username
+    group username
+    mode "755"
+    recursive true
+  end
+end
+
+## Install overpass from source
+
+srcdir = "#{basedir}/src/osm-3s_v#{node[:overpass][:version]}"
+
+package %w[
+  build-essential
+  libexpat1-dev
+  zlib1g-dev
+  liblz4-dev
+  pyosmium
+  osmium-tool
+]
+
+remote_file "#{srcdir}.tar.gz" do
+  action :create
+  source "https://dev.overpass-api.de/releases/osm-3s_v#{node[:overpass][:version]}.tar.gz"
+  owner username
+  group username
+  mode "644"
+end
+
+execute "source_tarball" do
+  cwd "#{basedir}/src"
+  command "tar -xf #{srcdir}.tar.gz"
+  user username
+  notifies :run, "execute[install_overpass]"
+  not_if { ::File.exist?(srcdir) }
+end
+
+execute "install_overpass" do
+  action :nothing
+  user username
+  cwd srcdir
+  command "./configure --enable-lz4 --prefix=#{basedir} && make install"
+  notifies :restart, "service[overpass-dispatcher]"
+  notifies :restart, "service[overpass-area-dispatcher]"
+end
+
+## Setup Apache
+
+gem_package "rotp" do
+  gem_binary node[:ruby][:gem]
+end
+
+directory "#{basedir}/apache" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+template "#{basedir}/apache/totp-filter" do
+  source "totp-filter.erb"
+  owner "root"
+  group "root"
+  mode "755"
+  variables :totp_key => web_passwords["totp_key"]
+end
+
+ssl_certificate node[:fqdn] do
+  domains [node[:fqdn],
+           node[:overpass][:fqdn]]
+  notifies :reload, "service[apache2]"
+end
+
+apache_module "cgi"
+apache_module "headers"
+apache_module "rewrite"
+
+apache_site "default" do
+  action :disable
+end
+
+apache_site "#{node[:overpass][:fqdn]}" do
+  template "apache.erb"
+  directory "#{basedir}/site"
+  variables :script_directory => "#{basedir}/cgi-bin"
+end
+
+## Overpass deamons
+
+meta_map_short = {
+  "no" => "",
+  "meta" => "--meta",
+  "attic" => "--attic"
+}
+
+logdir = node[:overpass][:logdir]
+
+directory logdir do
+  owner username
+  group username
+  mode "755"
+  recursive true
+end
+
+%w[overpass-update-db overpass-update-areas].each do |fname|
+  template "#{basedir}/bin/#{fname}" do
+    source "#{fname}.erb"
+    owner "overpass"
+    group "overpass"
+    mode "700"
+    variables :basedir => basedir, :srcdir => srcdir
+  end
+end
+
+template "#{basedir}/bin/overpass-import-db" do
+  source "overpass-import-db.erb"
+  owner "root"
+  group "root"
+  mode "755"
+  variables :basedir => basedir, :username => username, :srcdir => srcdir
+end
+
+systemd_service "overpass-dispatcher" do
+  description "Overpass Main Dispatcher"
+  wants ["overpass-area-dispatcher.service"]
+  working_directory basedir
+  exec_start "#{basedir}/bin/dispatcher --osm-base #{meta_map_short[node[:overpass][:meta_mode]]} --db-dir=#{basedir}/db --rate-limit=#{node[:overpass][:rate_limit]} --space=#{node[:overpass][:dispatcher_space]}"
+  exec_stop "#{basedir}/bin/dispatcher --osm-base --terminate"
+  standard_output "append:#{logdir}/osm_base.log"
+  user username
+end
+
+service "overpass-dispatcher" do
+  action [:enable]
+end
+
+systemd_service "overpass-area-dispatcher" do
+  description "Overpass Area Dispatcher"
+  after ["overpass-dispatcher.service"]
+  working_directory basedir
+  exec_start "#{basedir}/bin/dispatcher --areas #{meta_map_short[node[:overpass][:meta_mode]]} --db-dir=#{basedir}/db"
+  exec_stop "#{basedir}/bin/dispatcher --areas --terminate"
+  standard_output "append:#{logdir}/areas.log"
+  user username
+end
+
+service "overpass-area-dispatcher" do
+  action [:enable]
+end
+
+systemd_service "overpass-update" do
+  description "Overpass Update Application"
+  after ["overpass-dispatcher.service"]
+  wants ["overpass-area-processor.service"]
+  working_directory basedir
+  exec_start "#{basedir}/bin/overpass-update-db"
+  standard_output "append:#{logdir}/update.log"
+  user username
+  restart "on-success"
+end
+
+if node[:overpass][:meta_mode] == "attic"
+  systemd_service "overpass-area-processor" do
+    description "Overpass Area Processor"
+    after ["overpass-area-dispatcher.service", "overpass-update.service"]
+    working_directory basedir
+    exec_start "#{basedir}/bin/overpass-update-areas"
+    standard_output "append:#{logdir}/area-processor.log"
+    restart "on-success"
+    nice 19
+    user username
+  end
+else
+  systemd_service "overpass-area-processor" do
+    description "Overpass Area Processor"
+    after ["overpass-area-dispatcher.service", "overpass-update.service"]
+    working_directory basedir
+    exec_start "#{basedir}/bin/osm3s_query --progress --rules"
+    standard_input "file:#{srcdir}/rules/areas.osm3s"
+    standard_output "append:#{logdir}/area-processor.log"
+    restart "on-success"
+    nice 19
+    user username
+  end
+end
+
+systemd_timer "overpass-area-processor" do
+  action :delete
+end
+
+service "overpass-area-processor" do
+  action [:disable]
+end
+
+template "/etc/logrotate.d/overpass" do
+  source "logrotate.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  variables :logdir => logdir
+end
+
+prometheus_exporter "overpass" do
+  port 9898
+  user username
+  restrict_address_families "AF_UNIX"
+  options [
+    "--overpass.base-directory=#{basedir}"
+  ]
+end
diff --git a/cookbooks/overpass/templates/default/apache.erb b/cookbooks/overpass/templates/default/apache.erb
new file mode 100644 (file)
index 0000000..007e1c2
--- /dev/null
@@ -0,0 +1,59 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+<VirtualHost *:80>
+        ServerName <%= node[:fqdn] %>
+        ServerAlias <%= node[:overpass][:fqdn] %>
+        ServerAdmin webmaster@openstreetmap.org
+
+        CustomLog /var/log/apache2/<%= node[:overpass][:fqdn] %>-access.log combined_extended
+        ErrorLog /var/log/apache2/<%= node[:overpass][:fqdn] %>-error.log
+
+        DocumentRoot <%= @directory %>
+
+        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
+        RedirectPermanent / https://<%= @name %>/
+</VirtualHost>
+
+
+<VirtualHost *:443>
+        ServerName <%= node[:fqdn] %>
+        ServerAlias <%= node[:overpass][:fqdn] %>
+        ServerAdmin webmaster@openstreetmap.org
+
+        CustomLog /var/log/apache2/<%= node[:overpass][:fqdn] %>-access.log combined_extended
+        ErrorLog /var/log/apache2/<%= node[:overpass][:fqdn] %>-error.log
+
+        SSLEngine on
+        SSLCertificateFile /etc/ssl/certs/<%= node[:fqdn] %>.pem
+        SSLCertificateKeyFile /etc/ssl/private/<%= node[:fqdn] %>.key
+
+        DocumentRoot <%= @directory %>
+
+        RewriteEngine on
+        RewriteMap totp prg:/srv/query.openstreetmap.org/apache/totp-filter
+        RewriteCond ${totp:%{HTTP_COOKIE}} =0
+        RewriteRule ^/query-features - [F,L]
+
+<% if node[:overpass][:restricted_api] -%>
+        ScriptAlias /query-features <%= @script_directory %>/interpreter
+        SetEnvIf Origin "http.*(osm.org|openstreetmap.org).*" AccessControlAllowOrigin=$0
+        # Remove Origin so Overpass does not interfere.
+        RequestHeader unset Origin
+        Header always add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
+        Header always add Access-Control-Allow-Credentials true
+<% else -%>
+        ScriptAlias /api/ <%= @script_directory %>/
+<% end -%>
+</VirtualHost>
+
+<Directory "<%= @directory %>">
+        Require all granted
+</Directory>
+
+<Directory "<%= @script_directory %>">
+        SetOutputFilter DEFLATE
+
+        AllowOverride None
+        Options +ExecCGI -MultiViews +FollowSymLinks
+        Require all granted
+</Directory>
similarity index 51%
rename from cookbooks/dns/templates/default/cron.erb
rename to cookbooks/overpass/templates/default/logrotate.erb
index 5ab9b3af7671c69d85f9a615c0ac5f9c6588c691..d9f6ac9ab01c7339c88198edf892bce610479e86 100644 (file)
@@ -1,3 +1,6 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-*/3 * * * * git /usr/local/bin/dns-check
+<%= @logdir %>/*.log {
+    missingok
+    compress
+}
diff --git a/cookbooks/overpass/templates/default/overpass-import-db.erb b/cookbooks/overpass/templates/default/overpass-import-db.erb
new file mode 100644 (file)
index 0000000..b32a84f
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/bash -e
+
+FNAME=$1
+
+if [[ "x$FNAME" == "x" ]]; then
+  echo "Usage: overpass-import-db <OSM file>"
+  exit 1
+fi
+
+case "$FNAME" in
+  *.gz) UNPACKER='gunzip -c' ;;
+  *.bz2) UNPACKER='bunzip2 -c' ;;
+  *) UNPACKER='osmium cat -o - -f xml' ;;
+esac
+
+<% if node[:overpass][:meta_mode] == "meta" -%>
+META=--meta
+<% elsif node[:overpass][:meta_mode] == "attic" -%>
+META=--keep-attic
+<% else -%>
+META=
+<% end -%>
+
+sudo systemctl stop overpass-area-processor || true
+sudo systemctl stop overpass-update || true
+sudo systemctl stop overpass-area-dispatcher || true
+sudo systemctl stop overpass-dispatcher || true
+
+sleep 2
+
+# Remove old database
+sudo -u <%= @username %> rm -rf <%= @basedir %>/db/*
+
+$UNPACKER $FNAME | sudo -u <%= @username %> <%= @basedir %>/bin/update_database --db-dir='<%= @basedir %>/db' --compression-method=<%= node[:overpass][:compression_mode] %> --map-compression-method=<%= node[:overpass][:compression_mode] %> $META
+
+sudo -u <%= @username %> ln -s <%= @srcdir %>/rules <%= @basedir %>/db/rules
+
+echo "Import finished. Catching up with new changes."
+
+sudo systemctl start overpass-dispatcher
+sudo systemctl start overpass-area-dispatcher
+
+PYOSMIUM="sudo -u <%= @username %> pyosmium-get-changes --server <%= node[:overpass][:replication_url] %> -f <%= @basedir %>/db/replicate-id"
+<% if node[:overpass][:meta_mode] == "attic" -%>
+PYOSMIUM="$PYOSMIUM --no-deduplicate"
+<% end -%>
+
+# Get the replication id
+$PYOSMIUM -v -O $FNAME --ignore-osmosis-headers
+
+sudo -u <%= @username %> rm -f <%= @basedir %>/diffs/*
+
+while $PYOSMIUM -v -s 1000 -o <%= @basedir %>/diffs/latest.osc; do
+  if [ ! -f <%= @basedir %>/db/replicate-id ]; then
+    echo "Replication ID not written."
+    exit 1
+  fi
+  DATA_VERSION=`osmium fileinfo -e -g data.timestamp.last <%= @basedir %>/diffs/latest.osc`
+  echo "Downloaded up to timestamp $DATA_VERSION"
+  while ! sudo -u <%= @username %> <%= @basedir %>/bin/update_from_dir --osc-dir=<%= @basedir %>/diffs --version=$DATA_VERSION $META --flush-size=0; do
+    echo "Error while updating. Retry in 1 min."
+    sleep 60
+  done
+  sudo -u <%= @username %> rm <%= @basedir %>/diffs/latest.osc
+  echo "Finished up to $DATA_VERSION."
+done
+
+echo "DB up-to-date. Processing areas."
+
+sudo -u <%= @username %> <%= @basedir %>/bin/osm3s_query --progress --rules <<%= @srcdir %>/rules/areas.osm3s
+
+echo "All updates done."
diff --git a/cookbooks/overpass/templates/default/overpass-update-areas.erb b/cookbooks/overpass/templates/default/overpass-update-areas.erb
new file mode 100644 (file)
index 0000000..e1aa23f
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+echo "`date '+%F %T'`: update started"
+
+if [[ -a <%= @basedir %>/db/area_version ]]; then
+  sed "s/{{area_version}}/$(cat <%= @basedir %>/db/area_version)/g" <%= @srcdir %>/rules/areas_delta.osm3s | <%= @basedir %>/bin/osm3s_query --progress --rules
+else
+  cat <%= @srcdir %>/rules/areas.osm3s | <%= @basedir %>/bin/osm3s_query --progress --rules
+fi
+
+echo "`date '+%F %T'`: update finished"
diff --git a/cookbooks/overpass/templates/default/overpass-update-db.erb b/cookbooks/overpass/templates/default/overpass-update-db.erb
new file mode 100644 (file)
index 0000000..09b8648
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+PYOSMIUM="pyosmium-get-changes --server <%= node[:overpass][:replication_url] %> -f <%= @basedir %>/db/replicate-id"
+<% if node[:overpass][:meta_mode] == "attic" -%>
+PYOSMIUM="$PYOSMIUM --no-deduplicate"
+<% end -%>
+
+<% if node[:overpass][:meta_mode] == "meta" -%>
+META=--meta
+<% elsif node[:overpass][:meta_mode] == "attic" -%>
+META=--keep-attic
+<% else -%>
+META=
+<% end -%>
+
+status=3 # make it sleep on issues
+
+if [ -f <%= @basedir %>/db/replicate-id ]; then
+  # first apply any pending updates
+  if [ -f <%= @basedir %>/diffs/latest.osc ]; then
+    DATA_VERSION=`osmium fileinfo -e -g data.timestamp.last <%= @basedir %>/diffs/latest.osc`
+    if [ "x$DATA_VERSION" != "x" ]; then
+      echo "Downloaded up to timestamp $DATA_VERSION"
+      while ! <%= @basedir %>/bin/update_from_dir --osc-dir=<%= @basedir %>/diffs --version=$DATA_VERSION $META --flush-size=0; do
+        echo "Error while updating. Retry in 1 min."
+        sleep 60
+      done
+    fi
+    rm <%= @basedir %>/diffs/latest.osc
+  fi
+
+  $PYOSMIUM -v -s 1000 -o <%= @basedir %>/diffs/latest.osc
+  status=$?
+fi
+
+if [ $status -eq 0 ]; then
+  echo "Downloaded next batch."
+elif [ $status -eq 3 ]; then
+  rm <%= @basedir %>/diffs/latest.osc
+  echo "No new data, sleeping for a minute."
+  sleep 60
+else
+  echo "Fatal error, stopping updates."
+  exit $status
+fi
diff --git a/cookbooks/overpass/templates/default/totp-filter.erb b/cookbooks/overpass/templates/default/totp-filter.erb
new file mode 100644 (file)
index 0000000..8245f2a
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/ruby
+
+require "cgi"
+require "rotp"
+
+totp = ROTP::TOTP.new("<%= @totp_key %>", :interval => 3600)
+
+STDIN.each_line do |header|
+  cookies = CGI::Cookie.parse(header.chomp)
+
+  if cookie = cookies.fetch("_osm_totp_token", nil)
+    if totp.verify(cookie.value.first, :drift_behind => 3600, :drift_ahead => 3600)
+      STDOUT.syswrite("1\n")
+    else
+      STDOUT.syswrite("0\n")
+    end
+  else
+    STDOUT.syswrite("0\n")
+  end
+end
+
+exit 0
diff --git a/cookbooks/oxidized/README.md b/cookbooks/oxidized/README.md
new file mode 100644 (file)
index 0000000..55cfbc5
--- /dev/null
@@ -0,0 +1,4 @@
+# oxidized cookbook
+
+This cookbook installs and configures [oxidized](https://github.com/ytti/oxidized) to
+backup the configurations of OpenStreetMap equipment.
diff --git a/cookbooks/oxidized/attributes/default.rb b/cookbooks/oxidized/attributes/default.rb
new file mode 100644 (file)
index 0000000..cd69a5d
--- /dev/null
@@ -0,0 +1 @@
+default[:accounts][:users][:oxidized][:status] = :role
similarity index 56%
rename from cookbooks/forum/metadata.rb
rename to cookbooks/oxidized/metadata.rb
index 21edbfe64551245457bc39d4a282a1c5cb4d8a6f..18262803fdc2085f6358786f465b38f8e4c2fb2f 100644 (file)
@@ -1,11 +1,11 @@
-name              "forum"
+name              "oxidized"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures a roundup server"
+description       "Configures oxidized to backup equipment configuration"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "apache"
+depends           "accounts"
 depends           "git"
-depends           "mysql"
+depends           "ruby"
diff --git a/cookbooks/oxidized/recipes/default.rb b/cookbooks/oxidized/recipes/default.rb
new file mode 100644 (file)
index 0000000..66c9199
--- /dev/null
@@ -0,0 +1,166 @@
+#
+# Cookbook:: oxidized
+# Recipe:: default
+#
+# Copyright:: 2022, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "git"
+include_recipe "ruby"
+
+package %w[
+  gcc
+  g++
+  make
+  cmake
+  libssl-dev
+  libssh2-1-dev
+  zlib1g-dev
+  pkg-config
+  libyaml-dev
+]
+
+keys = data_bag_item("oxidized", "keys")
+devices = data_bag_item("oxidized", "devices")
+
+directory "/etc/oxidized" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+template "/etc/oxidized/config" do
+  source "config.erb"
+  owner "oxidized"
+  group "oxidized"
+  mode "444"
+  notifies :restart, "service[oxidized]"
+end
+
+template "/etc/oxidized/routers.db" do
+  source "routers.db.erb"
+  owner "oxidized"
+  group "oxidized"
+  mode "400"
+  variables :devices => devices
+  notifies :restart, "service[oxidized]"
+end
+
+directory "/var/log/oxidized" do
+  owner "oxidized"
+  group "oxidized"
+  mode "755"
+end
+
+directory "/opt/oxidized" do
+  owner "oxidized"
+  group "oxidized"
+  mode "755"
+end
+
+git "/opt/oxidized/daemon" do
+  action :sync
+  repository "https://github.com/openstreetmap/oxidized.git"
+  depth 1
+  user "oxidized"
+  group "oxidized"
+  notifies :run, "bundle_install[/opt/oxidized/daemon]", :immediately
+end
+
+directory "/opt/oxidized/.ssh" do
+  owner "oxidized"
+  group "oxidized"
+  mode "700"
+end
+
+# Key is set as a deployment key in github repo
+file "/opt/oxidized/.ssh/id_ed25519" do
+  content keys["git"].join("\n")
+  owner "oxidized"
+  group "oxidized"
+  mode "400"
+  notifies :delete, "file[/opt/oxidized/.ssh/id_ed25519.pub]", :immediately
+  notifies :restart, "service[oxidized]"
+end
+
+# Ensure public key is deleted if private key is changed. Trigged by notify
+file "/opt/oxidized/.ssh/id_ed25519.pub" do
+  action :nothing
+end
+
+execute "/opt/oxidized/.ssh/id_ed25519.pub" do
+  command "ssh-keygen -f /opt/oxidized/.ssh/id_ed25519 -y > /opt/oxidized/.ssh/id_ed25519.pub"
+  user "oxidized"
+  group "oxidized"
+  creates "/opt/oxidized/.ssh/id_ed25519.pub"
+  notifies :restart, "service[oxidized]"
+end
+
+ssh_known_hosts_entry "github.com" do
+  action [:create, :flush]
+  file_location "/opt/oxidized/.ssh/known_hosts"
+  owner "oxidized"
+  group "oxidized"
+end
+
+directory "/var/lib/oxidized" do
+  owner "oxidized"
+  group "oxidized"
+  mode "750"
+end
+
+git "/var/lib/oxidized/configs.git" do
+  action :sync
+  repository "git@github.com:openstreetmap/oxidized-configs.git" # Uses oxidized ssh key
+  checkout_branch "master" # branch is hardcoded in oxidized
+  user "oxidized"
+  group "oxidized"
+end
+
+bundle_install "/opt/oxidized/daemon" do
+  action :nothing
+  options "--deployment"
+  user "oxidized"
+  group "oxidized"
+  notifies :restart, "service[oxidized]"
+end
+
+# Based on https://github.com/ytti/oxidized/blob/master/extra/oxidized.service
+systemd_service "oxidized" do
+  description "oxidized network device backup daemon"
+  after "network.target"
+  user "oxidized"
+  working_directory "/opt/oxidized/daemon"
+  runtime_directory "oxidized"
+  exec_start "#{node[:ruby][:bundle]} exec oxidized"
+  environment "OXIDIZED_HOME" => "/etc/oxidized",
+              "OXIDIZED_LOGS" => "/var/log/oxidized"
+  nice 10
+  sandbox :enable_network => true
+  read_write_paths ["/run/oxidized", "/var/lib/oxidized", "/var/log/oxidized"]
+  restart "on-failure"
+  notifies :restart, "service[oxidized]"
+end
+
+service "oxidized" do
+  action [:enable, :start]
+end
+
+template "/etc/logrotate.d/oxidized" do
+  source "logrotate.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
diff --git a/cookbooks/oxidized/templates/default/config.erb b/cookbooks/oxidized/templates/default/config.erb
new file mode 100644 (file)
index 0000000..a8684ca
--- /dev/null
@@ -0,0 +1,39 @@
+---
+# DO NOT EDIT - This file is being maintained by Chef
+rest: false
+timeout: 60
+vars:
+  remove_secret: true
+pid: "/run/oxidized/oxidized.pid"
+crash:
+  directory: /var/lib/oxidized/crashes
+input:
+  default: ssh
+output:
+  default: git
+  git:
+    single_repo: true
+    user: oxidized
+    email: oxidized@openstreetmap.org
+    repo: "/var/lib/oxidized/configs.git"
+hooks:
+  push_to_remote:
+    type: githubrepo
+    events: [post_store]
+    remote_repo: git@github.com:openstreetmap/oxidized-configs.git
+    privatekey: /opt/oxidized/.ssh/id_ed25519
+source:
+  default: csv
+  csv:
+    file: "/etc/oxidized/routers.db"
+    delimiter: !ruby/regexp /:/
+    map:
+      name: 0
+      model: 1
+      input: 2
+      username: 3
+      password: 4
+model_map:
+  juniper: junos
+  apc: apc_aos
+  ciscocmb: ciscosmb
similarity index 61%
rename from cookbooks/networking/templates/default/logrotate.shorewall.erb
rename to cookbooks/oxidized/templates/default/logrotate.erb
index c95ba7496df5546fe55cc76df4a46992b4902dc4..81adecb6625d4ee09cbb61a8670288afe6358890 100644 (file)
@@ -1,10 +1,10 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-/var/log/<%= @name %>-init.log {
+/var/log/oxidized/*.log {
+    rotate 12
     weekly
-    rotate 4
+    size 10M
     compress
     delaycompress
     missingok
-    create 0640 root adm
 }
diff --git a/cookbooks/oxidized/templates/default/routers.db.erb b/cookbooks/oxidized/templates/default/routers.db.erb
new file mode 100644 (file)
index 0000000..9a7bf02
--- /dev/null
@@ -0,0 +1,4 @@
+# DO NOT EDIT - This file is being maintained by Chef
+<% @devices[:hardware].keys.sort.each do |d| -%>
+<%= d -%>:<%= @devices[:hardware][d][:device] -%>:<%= @devices[:hardware][d][:input] -%>:<%= @devices[:hardware][d][:username] -%>:<%= @devices[:hardware][d][:password] %>
+<% end -%>
index 753a8d0999802076e150032d12303c9d3c50ff04..2c11cc27aae37cbfd7c0967c97f43ded37674ec0 100644 (file)
@@ -1,6 +1,3 @@
-default[:passenger][:ruby_version] = "2.5"
 default[:passenger][:max_pool_size] = 6
 default[:passenger][:pool_idle_time] = 300
-default[:passenger][:instance_registry_dir] = "/run/passenger"
-
-default[:apt][:sources] = node[:apt][:sources] | ["passenger"]
+default[:passenger][:instance_registry_dir] = "/run/passenger-instreg"
index 24863de8a1533693d3e8c482b972a91d3739fa4c..26f48544f26fa03e05afab5c85cfd5d4694a8a29 100644 (file)
@@ -7,4 +7,7 @@ description       "Installs and configures passenger"
 version           "1.0.0"
 supports          "ubuntu"
 depends           "apache"
-depends           "munin"
+depends           "apt"
+depends           "prometheus"
+depends           "ruby"
+depends           "systemd"
index a9ef419a0259669c1e2e905d95a58b735c12601d..4ad7f8b0ecb8c65152abdf1970aefbeb58879950 100644 (file)
 #
 
 include_recipe "apache"
-
-package "ruby#{node[:passenger][:ruby_version]}"
-package "ruby#{node[:passenger][:ruby_version]}-dev"
-
-if node[:passenger][:ruby_version].to_f < 1.9
-  package "rubygems#{node[:passenger][:ruby_version]}"
-  package "irb#{node[:passenger][:ruby_version]}"
-end
+include_recipe "apt::passenger"
+include_recipe "prometheus"
+include_recipe "ruby"
 
 template "/usr/local/bin/passenger-ruby" do
   source "ruby.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   notifies :reload, "service[apache2]"
 end
 
@@ -46,11 +41,10 @@ apache_module "passenger" do
   conf "passenger.conf.erb"
 end
 
-munin_plugin_conf "passenger" do
-  template "munin.erb"
+prometheus_exporter "passenger" do
+  port 9149
+  user "root"
+  environment "PASSENGER_INSTANCE_REGISTRY_DIR" => node[:passenger][:instance_registry_dir]
+  options "--passenger.command.timeout-seconds=5"
+  restrict_address_families "AF_UNIX"
 end
-
-munin_plugin "passenger_memory"
-munin_plugin "passenger_processes"
-munin_plugin "passenger_queues"
-munin_plugin "passenger_requests"
index f2af9a2e86669f002582b80fb07e7d15dbe5f8b2..5f5e2efbb4c064a0207dceb900301d73f2acdb9e 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :restart
 
-property :application, String, :name_attribute => true
+property :application, String, :name_property => true
 
 action :restart do
   execute new_resource.application do
diff --git a/cookbooks/passenger/templates/default/munin.erb b/cookbooks/passenger/templates/default/munin.erb
deleted file mode 100644 (file)
index 903fcfe..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[passenger_*]
-user root
-env.PASSENGER_INSTANCE_REGISTRY_DIR <%= node[:passenger][:instance_registry_dir] %>
index f15bc0fe915b5223c753519049d5d6705169b1e2..1212f75882d096de2a8e09651eb62d179a71913d 100644 (file)
@@ -7,5 +7,5 @@
   PassengerMaxPoolSize <%= node[:passenger][:max_pool_size] %>
   PassengerPoolIdleTime <%= node[:passenger][:pool_idle_time] %>
   PassengerFriendlyErrorPages off
-  PassengerInstanceRegistryDir /run/passenger
+  PassengerInstanceRegistryDir <%= node[:passenger][:instance_registry_dir] %>
 </IfModule>
index fb7575ab0ad9e424609b8c034e7131cf6f5fc24e..f45fd210eaa6d2f11844bb75baab50b5ecd8df00 100644 (file)
@@ -1,12 +1,7 @@
 #!/bin/sh
 
-<% if node[:passenger][:ruby_version].to_f < 2.1 -%>
-export RUBY_HEAP_MIN_SLOTS=500000
-export RUBY_HEAP_FREE_MIN=100000
-<% else -%>
 export RUBY_GC_HEAP_INIT_SLOTS=500000
 export RUBY_GC_HEAP_FREE_SLOTS=100000
-<% end -%>
 export RUBY_GC_MALLOC_LIMIT=50000000
 
-exec /usr/bin/ruby<%= node[:passenger][:ruby_version] %> "$@"
+exec /usr/bin/ruby<%= node[:ruby][:version] %> "$@"
diff --git a/cookbooks/php/README.md b/cookbooks/php/README.md
new file mode 100644 (file)
index 0000000..135c7db
--- /dev/null
@@ -0,0 +1,3 @@
+# PHP Cookbook
+
+Installs and configures PHP.
diff --git a/cookbooks/php/attributes/default.rb b/cookbooks/php/attributes/default.rb
new file mode 100644 (file)
index 0000000..5dd05a5
--- /dev/null
@@ -0,0 +1,8 @@
+default[:php][:version] = if platform?("debian")
+                            "8.2"
+                          elsif node[:lsb][:release].to_f < 22.04
+                            "7.4"
+                          else
+                            "8.1"
+                          end
+default[:php][:fpm][:options] = {}
similarity index 66%
rename from cookbooks/roundup/metadata.rb
rename to cookbooks/php/metadata.rb
index 678654721b4adec0e2b87d4aff794d7a34e6eef6..db4cfc27a6f0f3eb50f6397810b784be1c88f40c 100644 (file)
@@ -1,9 +1,10 @@
-name              "roundup"
+name              "php"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures a roundup server"
+description       "Installs and configures PHP"
 
 version           "1.0.0"
 supports          "ubuntu"
 depends           "apache"
+depends           "prometheus"
diff --git a/cookbooks/php/recipes/apache.rb b/cookbooks/php/recipes/apache.rb
new file mode 100644 (file)
index 0000000..dc60248
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Cookbook:: php
+# Recipe:: apache
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apache"
+include_recipe "php::fpm"
+
+apache_module "proxy"
+apache_module "proxy_fcgi"
+
+apache_module "php#{node[:php][:version]}" do
+  action :disable
+end
+
+apache_conf "php#{node[:php][:version]}-fpm" do
+  action :enable
+end
similarity index 83%
rename from cookbooks/roundup/recipes/default.rb
rename to cookbooks/php/recipes/default.rb
index 634019c3bff68b56e6911cd22570750d3814f802..3164006a42d4eac19bd1f03481e3ff637bf68204 100644 (file)
@@ -1,8 +1,8 @@
 #
-# Cookbook:: roundup
+# Cookbook:: php
 # Recipe:: default
 #
-# Copyright:: 2013, OpenStreetMap Foundation
+# Copyright:: 2020, OpenStreetMap Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,4 +16,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-include_recipe "apache"
+
+package %W[
+  php
+  php#{node[:php][:version]}-fpm
+]
diff --git a/cookbooks/php/recipes/fpm.rb b/cookbooks/php/recipes/fpm.rb
new file mode 100644 (file)
index 0000000..2bebc87
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# Cookbook:: php
+# Recipe:: fpm
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "php"
+include_recipe "prometheus"
+
+package "php-fpm"
+
+template "/etc/php/#{node[:php][:version]}/fpm/conf.d/99-chef.ini" do
+  source "php-fpm.ini.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  notifies :restart, "service[php#{node[:php][:version]}-fpm]"
+end
+
+service "php#{node[:php][:version]}-fpm" do
+  action [:enable, :start]
+end
diff --git a/cookbooks/php/resources/fpm.rb b/cookbooks/php/resources/fpm.rb
new file mode 100644 (file)
index 0000000..13c9735
--- /dev/null
@@ -0,0 +1,106 @@
+#
+# Cookbook:: php
+# Resource:: php_fpm
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unified_mode true
+
+default_action :create
+
+property :pool, :kind_of => String, :name_property => true
+property :port, :kind_of => Integer
+property :user, :kind_of => String, :default => "www-data"
+property :group, :kind_of => String, :default => "www-data"
+property :pm, :kind_of => String, :default => "dynamic"
+property :pm_max_children, :kind_of => Integer, :default => 10
+property :pm_start_servers, :kind_of => Integer, :default => 4
+property :pm_min_spare_servers, :kind_of => Integer, :default => 2
+property :pm_max_spare_servers, :kind_of => Integer, :default => 6
+property :pm_max_requests, :kind_of => Integer, :default => 1000
+property :request_terminate_timeout, :kind_of => Integer, :default => 1800
+property :environment, :kind_of => Hash, :default => {}
+property :php_values, :kind_of => Hash, :default => {}
+property :php_admin_values, :kind_of => Hash, :default => {}
+property :php_flags, :kind_of => Hash, :default => {}
+property :php_admin_flags, :kind_of => Hash, :default => {}
+property :reload_fpm, :kind_of => [TrueClass, FalseClass], :default => true
+property :prometheus_port, :kind_of => Integer
+
+action :create do
+  template conf_file do
+    cookbook "php"
+    source "pool.conf.erb"
+    owner "root"
+    group "root"
+    mode "644"
+    variables new_resource.to_hash.merge(:pool => new_resource.pool)
+  end
+
+  if new_resource.prometheus_port
+    prometheus_exporter "phpfpm" do
+      port new_resource.prometheus_port
+      restrict_address_families "AF_UNIX"
+      service service_name
+      group "www-data"
+      command "server"
+      options "--phpfpm.scrape-uri=#{scrape_uri} --phpfpm.fix-process-count"
+      labels "pool" => new_resource.pool
+    end
+  else
+    prometheus_exporter "phpfpm" do
+      action :delete
+      service service_name
+    end
+  end
+end
+
+action :delete do
+  file conf_file do
+    action :delete
+  end
+
+  prometheus_exporter "phpfpm" do
+    action :delete
+    service service_name
+  end
+end
+
+action_class do
+  def php_version
+    node[:php][:version]
+  end
+
+  def conf_file
+    "/etc/php/#{php_version}/fpm/pool.d/#{new_resource.pool}.conf"
+  end
+
+  def service_name
+    "phpfpm-#{new_resource.pool}"
+  end
+
+  def scrape_uri
+    if new_resource.port
+      "tcp://127.0.0.1:#{new_resource.port}/status"
+    else
+      "unix:///run/php/php-#{new_resource.pool}-fpm.sock;/status"
+    end
+  end
+end
+
+def after_created
+  notifies :reload, "service[php#{node[:php][:version]}-fpm]" if reload_fpm
+end
diff --git a/cookbooks/php/templates/default/php-fpm.ini.erb b/cookbooks/php/templates/default/php-fpm.ini.erb
new file mode 100644 (file)
index 0000000..da34ca3
--- /dev/null
@@ -0,0 +1,5 @@
+; DO NOT EDIT - This file is being maintained by Chef
+
+<% node[:php][:fpm][:options].sort.each do |key,value| -%>
+<%= key %>=<%= value %>
+<% end -%>
diff --git a/cookbooks/php/templates/default/pool.conf.erb b/cookbooks/php/templates/default/pool.conf.erb
new file mode 100644 (file)
index 0000000..cec611a
--- /dev/null
@@ -0,0 +1,46 @@
+; DO NOT EDIT - This file is being maintained by Chef
+
+[<%= @pool %>]
+<% if @port -%>
+listen = 127.0.0.1:<%= @port %>
+listen.backlog = 256
+<% else -%>
+listen = /run/php/php-<%= @pool %>-fpm.sock
+listen.owner = www-data
+listen.group = www-data
+<% end -%>
+
+user = <%= @user %>
+group = <%= @group %>
+
+pm = <%= @pm %>
+pm.max_children = <%= @pm_max_children %>
+pm.start_servers = <%= @pm_start_servers %>
+pm.min_spare_servers = <%= @pm_min_spare_servers %>
+pm.max_spare_servers = <%= @pm_max_spare_servers %>
+pm.max_requests = <%= @pm_max_requests %>
+pm.status_path = /status
+
+request_terminate_timeout = <%= @request_terminate_timeout %>
+
+security.limit_extensions = .php .phpx .phpj
+
+<% @environment.each do |name, value| -%>
+env[<%= name %>] = <%= value %>
+<% end -%>
+
+<% @php_values.each do |name, value| -%>
+php_value[<%= name %>] = <%= value %>
+<% end -%>
+
+<% @php_admin_values.each do |name, value| -%>
+php_admin_value[<%= name %>] = <%= value %>
+<% end -%>
+
+<% @php_flags.each do |name, value| -%>
+php_flag[<%= name %>] = <%= value %>
+<% end -%>
+
+<% @php_admin_flags.each do |name, value| -%>
+php_admin_flag[<%= name %>] = <%= value %>
+<% end -%>
diff --git a/cookbooks/piwik/README.md b/cookbooks/piwik/README.md
deleted file mode 100644 (file)
index a968336..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# Piwik Cookbook
-
-This cookbook installs and configures the Piwiki server-side software used for
-analytics on openstreetmap.org
diff --git a/cookbooks/piwik/attributes/default.rb b/cookbooks/piwik/attributes/default.rb
deleted file mode 100644 (file)
index 65c7091..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-default[:piwik][:version] = "3.13.0"
-default[:piwik][:plugins] = %w[
-  Actions Annotations API BulkTracking Contents CoreAdminHome CoreConsole
-  CoreHome CorePluginsAdmin CoreUpdater CoreVisualizations CustomPiwikJs
-  CustomVariables Dashboard DevicePlugins DevicesDetection Diagnostics Ecommerce
-  Events Feedback GeoIp2 Goals Heartbeat ImageGraph Insights Installation Intl
-  LanguagesManager Live Login Marketplace MobileMessaging Monolog Morpheus
-  MultiSites Overlay PrivacyManager ProfessionalServices Provider Proxy
-  Referrers Resolution RssWidget ScheduledReports SegmentEditor SEO SitesManager
-  Transitions UserCountry UserCountryMap UserId UserLanguage UsersManager
-  VisitFrequency VisitorInterest VisitsSummary VisitTime WebsiteMeasurable
-  Widgetize
-]
diff --git a/cookbooks/piwik/metadata.rb b/cookbooks/piwik/metadata.rb
deleted file mode 100644 (file)
index 1644aa9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-name              "piwik"
-maintainer        "OpenStreetMap Administrators"
-maintainer_email  "admins@openstreetmap.org"
-license           "Apache-2.0"
-description       "Installs and configures Piwik"
-
-version           "1.0.0"
-supports          "ubuntu"
-depends           "apache"
-depends           "mysql"
diff --git a/cookbooks/piwik/recipes/default.rb b/cookbooks/piwik/recipes/default.rb
deleted file mode 100644 (file)
index 2bd0b97..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-#
-# Cookbook:: piwik
-# Recipe:: default
-#
-# Copyright:: 2011, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-include_recipe "apache"
-include_recipe "mysql"
-
-passwords = data_bag_item("piwik", "passwords")
-
-package "php"
-package "php-cli"
-package "php-curl"
-package "php-mbstring"
-package "php-mysql"
-package "php-gd"
-package "php-xml"
-package "php-apcu"
-
-package "geoipupdate"
-
-apache_module "expires"
-apache_module "php7.2"
-apache_module "rewrite"
-
-version = node[:piwik][:version]
-
-directory "/opt/piwik-#{version}" do
-  owner "root"
-  group "root"
-  mode "0755"
-end
-
-remote_file "#{Chef::Config[:file_cache_path]}/piwik-#{version}.zip" do
-  source "https://builds.matomo.org/piwik-#{version}.zip"
-  not_if { File.exist?("/opt/piwik-#{version}/piwik") }
-end
-
-execute "unzip-piwik-#{version}" do
-  command "unzip -q #{Chef::Config[:file_cache_path]}/piwik-#{version}.zip"
-  cwd "/opt/piwik-#{version}"
-  user "root"
-  group "root"
-  not_if { File.exist?("/opt/piwik-#{version}/piwik") }
-end
-
-execute "/opt/piwik-#{version}/piwik/piwik.js" do
-  command "gzip -k -9 /opt/piwik-#{version}/piwik/piwik.js"
-  cwd "/opt/piwik-#{version}"
-  user "root"
-  group "root"
-  not_if { File.exist?("/opt/piwik-#{version}/piwik/piwik.js.gz") }
-end
-
-directory "/opt/piwik-#{version}/piwik/config" do
-  owner "www-data"
-  group "www-data"
-  mode "0755"
-end
-
-template "/opt/piwik-#{version}/piwik/config/config.ini.php" do
-  source "config.erb"
-  owner "root"
-  group "root"
-  mode "0644"
-  variables :passwords => passwords,
-            :directory => "/opt/piwik-#{version}/piwik",
-            :plugins => node[:piwik][:plugins]
-end
-
-directory "/opt/piwik-#{version}/piwik/tmp" do
-  owner "www-data"
-  group "www-data"
-  mode "0755"
-end
-
-link "/opt/piwik-#{version}/piwik/misc/GeoLite2-ASN.mmdb" do
-  to "/var/lib/GeoIP/GeoLite2-ASN.mmdb"
-end
-
-link "/opt/piwik-#{version}/piwik/misc/GeoLite2-City.mmdb" do
-  to "/var/lib/GeoIP/GeoLite2-City.mmdb"
-end
-
-link "/opt/piwik-#{version}/piwik/misc/GeoLite2-Country.mmdb" do
-  to "/var/lib/GeoIP/GeoLite2-Country.mmdb"
-end
-
-link "/srv/piwik.openstreetmap.org" do
-  to "/opt/piwik-#{version}/piwik"
-  notifies :restart, "service[apache2]"
-end
-
-mysql_user "piwik@localhost" do
-  password passwords["database"]
-end
-
-mysql_database "piwik" do
-  permissions "piwik@localhost" => :all
-end
-
-ssl_certificate "piwik.openstreetmap.org" do
-  domains ["piwik.openstreetmap.org", "piwik.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "piwik.openstreetmap.org" do
-  template "apache.erb"
-end
-
-template "/etc/cron.d/piwiki" do
-  source "cron.erb"
-  owner "root"
-  group "root"
-  mode "0644"
-end
diff --git a/cookbooks/piwik/templates/default/apache.erb b/cookbooks/piwik/templates/default/apache.erb
deleted file mode 100644 (file)
index 58703f4..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-       ServerName piwik.openstreetmap.org
-       ServerAlias piwik.osm.org
-       ServerAdmin webmaster@openstreetmap.org
-
-       SSLEngine on
-       SSLCertificateFile /etc/ssl/certs/piwik.openstreetmap.org.pem
-       SSLCertificateKeyFile /etc/ssl/private/piwik.openstreetmap.org.key
-
-       CustomLog /var/log/apache2/piwik.openstreetmap.org-access.log combined
-       ErrorLog /var/log/apache2/piwik.openstreetmap.org-error.log
-
-       Options -Indexes
-
-       DocumentRoot /srv/piwik.openstreetmap.org
-</VirtualHost>
-
-<VirtualHost *:80>
-       ServerName piwik.openstreetmap.org
-       ServerAlias piwik.osm.org
-       ServerAdmin webmaster@openstreetmap.org
-
-       CustomLog /var/log/apache2/piwik.openstreetmap.org-access.log combined
-       ErrorLog /var/log/apache2/piwik.openstreetmap.org-error.log
-
-       RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-       RedirectPermanent / https://piwik.openstreetmap.org/
-</VirtualHost>
-
-<Directory /srv/piwik.openstreetmap.org>
-       Require all granted
-
-       ExpiresActive On
-       RewriteEngine on
-
-       RewriteCond "%{HTTP:Accept-encoding}" "gzip"
-       RewriteCond "%{REQUEST_FILENAME}\.gz" -s
-       RewriteRule "^(.*)\.js" "$1\.js\.gz" [QSA]
-
-       RewriteRule "\.js\.gz$"  "-" [T=text/javascript,E=no-gzip:1]
-
-       <FilesMatch "\.js\.gz$">
-               Header append Content-Encoding gzip
-               Header append Vary Accept-Encoding
-       </FilesMatch>
-
-       <FilesMatch "(\.js|\.js\.gz)$">
-               ExpiresDefault "access plus 1 week"
-               Header set Cache-Control "max-age=604800"
-       </FilesMatch>
-</Directory>
diff --git a/cookbooks/piwik/templates/default/cron.erb b/cookbooks/piwik/templates/default/cron.erb
deleted file mode 100644 (file)
index 2637b2f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-5 * * * * www-data /usr/bin/php /srv/piwik.openstreetmap.org/console core:archive --quiet --url=https://piwik.openstreetmap.org/
index e888b56771753b07ffe0181df39dde1c45cd06a4..7c8a60466ae572bd12973a0a4b3bb592bf1be597 100644 (file)
@@ -1,6 +1,6 @@
+default[:accounts][:users][:planet][:status] = :role
+
 default[:planet][:dump][:xml_directory] = "/store/planet/planet"
 default[:planet][:dump][:xml_history_directory] = "/store/planet/planet/full-history"
 default[:planet][:dump][:pbf_directory] = "/store/planet/pbf"
 default[:planet][:dump][:pbf_history_directory] = "/store/planet/pbf/full-history"
-
-default[:planet][:current][:jobs] = {}
diff --git a/cookbooks/planet/files/default/ccbysa_cgi/HEADER.cgi b/cookbooks/planet/files/default/ccbysa_cgi/HEADER.cgi
new file mode 100644 (file)
index 0000000..9e68c94
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/python3
+
+print( """
+<html>
+ <head>
+  <title>OpenStreetMap historical CC BY-SA 2.0 licensed data</title>
+  <link href="/style.css" rel="stylesheet" type="text/css">
+ </head>
+ <body>
+<img id="logo" src="/logo.png" alt="OSM logo" width="128" height="128">
+<h1>planet.openstreetmap.org - cc by-sa</h1>
+<p>Licensed under the <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a></p>
+<p>&nbsp;</p>
+""")
index 25247379714faa433892abcfaaf899ff9b753b2c..b4a46ba9fffb89c5894f29ed36648f10bf87bbaa 100644 (file)
@@ -1,16 +1,16 @@
-#!/usr/bin/env python
+#!/usr/bin/python3
 
-print """
+print("""
 <html>
  <head>
   <title>OpenStreetMap historical CC BY-SA 2.0 licensed data</title>
-  <link href="/style.css" rel="stylesheet" type="text/css">
+  <link href="https://planet.openstreetmap.org/style.css" rel="stylesheet" type="text/css">
  </head>
  <body>
-<img id="logo" src="/logo.png" alt="OSM logo" width="128" height="128">
+<img id="logo" src="https://planet.openstreetmap.org/logo.png" alt="OSM logo" width="128" height="128">
 <h1>planet.openstreetmap.org - CC BY-SA experimental history files.</h1>
 <p>These files are the last experimental history files produced under the CC BY-SA license. More recent data under the ODbL license is <a href="/planet/full-history/">available here</a>.<p>
 <p>The <tt>full-planet-120401-final.osm.bz2</tt> file is the last dump of data before <a href="https://blog.osmfoundation.org/2012/07/26/automated-redactions-complete/">redactions were run to remove data which could not be released under ODbL</a>. The <tt>full-planet-120601-1150.osm.bz2</tt> is the last dump of data available under CC BY-SA, but after the redactions were run. This means it may have less data in some areas, although many redactions were quickly re-mapped.</p>
 <p>Licensed under the <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a></p>
 <p>&nbsp;</p>
-"""
+""")
index da7004ca10e0b7a58ff0ad60f95f44074e53e954..be9c3814c88923265f3bd14cf5473553eb1854fc 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python3
 
 from time import time
 from os import stat, environ
@@ -10,7 +10,7 @@ def nice_size(file):
     MB = 1024. * KB
     GB = 1024. * MB
     TB = 1024. * GB
-    
+
     if size < KB:
         size, suffix = size, ''
     elif size < MB:
@@ -21,7 +21,7 @@ def nice_size(file):
         size, suffix = size/GB, 'GB'
     else:
         size, suffix = size/TB, 'TB'
-    
+
     if size < 10:
         return '%.1f %s' % (round(size,1), suffix)
     else:
@@ -43,66 +43,60 @@ def nice_time(time):
 
     return '%d months' % (time / 2592000.)
 
-def file_info(file, name):
+def file_info(file, rss_file, name):
+    torrent_file = file + '.torrent'
     size = nice_size(file)
     hash = search(r'\w{32}', open(file+'.md5', 'r').read()).group(0)
     date = nice_time(time() - stat(file).st_mtime)
 
-    return '<b><a href="%(file)s">%(name)s</a></b><br><b>%(size)s</b>, created %(date)s ago.<br><small>md5: %(hash)s</small>.' % locals()
+    return '<b><a href="%(file)s">%(name)s</a> (<a href="%(torrent_file)s">torrent</a>) (<a href="%(rss_file)s">RSS</a>)</b><br><b>%(size)s</b>, created %(date)s ago.<br><small>md5: %(hash)s</small>.' % locals()
 
-planet_link = file_info('planet/planet-latest.osm.bz2', 'Latest Weekly Planet XML File')
-changesets_link = file_info('planet/changesets-latest.osm.bz2', 'Latest Weekly Changesets')
-planet_pbf_link = file_info('pbf/planet-latest.osm.pbf', 'Latest Weekly Planet PBF File')
+planet_link = file_info('planet/planet-latest.osm.bz2', 'planet/planet-bz2-rss.xml', 'Latest Weekly Planet XML File')
+changesets_link = file_info('planet/changesets-latest.osm.bz2', 'planet/changesets-bz2-rss.xml', 'Latest Weekly Changesets')
+planet_pbf_link = file_info('pbf/planet-latest.osm.pbf', 'pbf/planet-pbf-rss.xml', 'Latest Weekly Planet PBF File')
 
-print """
+print("""
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
 <html>
  <head>
-  <title>Index of /</title>
-  <link href="style.css" rel="stylesheet" type="text/css">
+  <title>Planet OSM</title>
+  <link href="https://planet.openstreetmap.org/style.css" rel="stylesheet" type="text/css">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
-<img id="logo" src="logo.png" alt="OSM logo" width="128" height="128">
+<img id="logo" src="https://planet.openstreetmap.org/logo.png" alt="OSM logo" width="128" height="128">
 <h1>Planet OSM</h1>
 
 <p>
-The files found here are regularly-updated, complete copies of the OpenStreetMap.org
-database, and those published before the 12 September 2012 are distributed under a Creative Commons Attribution-ShareAlike 2.0 license, those published after are  Open Data Commons Open Database License 1.0 licensed. For more information, <a href="https://wiki.openstreetmap.org/wiki/Planet.osm">see the project wiki</a>.
+The files found here are regularly-updated, complete copies of the <a href="https://openstreetmap.org">OpenStreetMap</a> database.
 </p>
-
-<table id="about">
-  <tr>
-    <th>
-        <h2>Complete OSM Data</h2>
-    </th>
-    <th>
-        <h2>Using The Data</h2>
-    </th>
-    <th>
-        <h2>Extracts &amp; Mirrors</h2>
-    </th>
-  </tr>
-  <tr>
-    <td>
-        <p>%(planet_link)s</p>
-        <p>%(changesets_link)s</p>
-        <p>%(planet_pbf_link)s</p>
-        <p>
-        Each week, a new and complete copy of all data in OpenStreetMap is made
-        available as both a compressed XML file and a custom PBF format file.
-        Also available is the <a href="planet/full-history">'history'</a> file
-        which contains not only up-to-date data but also older versions of data
-        and deleted data items.
-        <p>
-        </p>
-        A smaller file with complete metadata for all changes ('changesets') in
-        XML format is also available.
-        </p>
-    </td>
-    <td>
+<p>
+Files published before 12 September 2012 are distributed under a Creative Commons Attribution-ShareAlike 2.0 license, those
+published after are Open Data Commons Open Database License 1.0 licensed. For more information, <a href="https://wiki.openstreetmap.org/wiki/Planet.osm">see the project wiki</a>.
+</p>
+<div id="about">
+  <div>
+    <h2>Latest Exports</h2>
+      <p>%(planet_link)s</p>
+      <p>%(changesets_link)s</p>
+      <p>%(planet_pbf_link)s</p>
+      <p>
+      Each week, a new and complete copy of all data in OpenStreetMap is made
+      available as both a compressed XML file and a custom PBF format file.
+      Also available is the <a href="planet/full-history">'history'</a> file
+      which contains not only up-to-date data but also older versions of data
+      and deleted data items.
+      <p>
+      </p>
+      A smaller file with complete metadata for all changes ('changesets') in
+      XML format is also available.
+      </p>
+    </div>
+    <div>
+      <h2>Using the Data</h2>
         <p>
-        You are granted permission to use OpenStreetMap data by 
-        <a href="https://osm.org/copyright">the OpenStreetMap License</a>, which also describes 
+        You are granted permission to use OpenStreetMap data by
+        <a href="https://osm.org/copyright">the OpenStreetMap License</a>, which also describes
         your obligations.
         </p>
         <p>
@@ -113,12 +107,10 @@ database, and those published before the 12 September 2012 are distributed under
         is a tool for importing the data into a Postgis database for rendering maps.
         </p>
         <p>
-        <a href="https://wiki.openstreetmap.org/wiki/Coastline_error_checker">Processed coastline data</a>
-        derived from OSM data is also needed for rendering usable maps, and can be found in a
-        <a href="historical-shapefiles/processed_p.tar.bz2">single shapefile</a> (360MB).
+        <a href="https://osmdata.openstreetmap.de/">Processed coastline data</a>
+        derived from OSM data is also needed for rendering usable maps.
         </p>
-    </td>
-    <td>
+        <h3>Extracts &amp; Mirrors</h3>
         <p>
         The complete planet is very large, so you may prefer to use one of
         <a href="https://wiki.openstreetmap.org/wiki/Planet.osm#Downloading">several periodic extracts</a>
@@ -126,11 +118,32 @@ database, and those published before the 12 September 2012 are distributed under
         and <a href="https://download.bbbike.org/osm/">BBBike.org</a> are two providers
         of extracts with up-to-date worldwide coverage.
         </p>
-    </td>
-  </tr>
-</table>
+    </div>
+    <div>
+        <h2 id="supporting-osm">Supporting OSM</h2>
+        <p>OSM data is free to use, but is not free to make or host. The
+        stability and accuracy of OSM.org depends on its volunteers and
+        donations from its users. Please consider
+        <a href="https://supporting.openstreetmap.org">making an annual
+        recurring gift</a> to OSM to support the infrastructure,
+        tools, working groups, and other incentives needed to
+        create the map.</p>
+        <p>Donations can be made at <a href="https://supporting.openstreetmap.org/donate">supporting.openstreetmap.org/donate</a>.
+        Suggestions assume $US or equivalent.</p>
+        <ul>
+        <li>individual user, revenue &lt; $5k/yr, $50-$100</li>
+        <li>small organization, revenue $5-10k/yr, $250-$500</li>
+        <li>medium organization, revenue $10-100k/yr, $500-$1000</li>
+        </ul>
+        <p>Large businesses with revenue in the hundreds of thousands to
+        millions should <a
+        href="https://osmfoundation.org/wiki/Join_as_a_corporate_member">join as
+        corporate members</a> to receive additional benefits.</p>
+    </div>
+</div>
 
 <p>
 If you find data within OpenStreetMap that you believe is an infringement of someone else's copyright, then please make contact with the <a href="https://wiki.openstreetmap.org/wiki/Data_working_group">OpenStreetMap Data Working Group</a>.
 </p>
-""" % locals()
+<h2>Files</h2>
+""" % locals())
index 51ac8458141d10f6f9f77b9e4e38f92eda373698..4b64cfc6e7a3c682e243be698d46e115b1a8ea28 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python3
 
 from time import time
 from os import stat, environ
@@ -10,7 +10,7 @@ def nice_size(file):
     MB = 1024. * KB
     GB = 1024. * MB
     TB = 1024. * GB
-    
+
     if size < KB:
         size, suffix = size, ''
     elif size < MB:
@@ -21,7 +21,7 @@ def nice_size(file):
         size, suffix = size/GB, 'GB'
     else:
         size, suffix = size/TB, 'TB'
-    
+
     if size < 10:
         return '%.1f %s' % (round(size,1), suffix)
     else:
@@ -44,30 +44,31 @@ def nice_time(time):
     return '%d months' % (time / 2592000.)
 
 def file_info(file, name):
+    torrent_file = file + '.torrent'
     size = nice_size(file)
     hash = search(r'\w{32}', open(file+'.md5', 'r').read()).group(0)
     date = nice_time(time() - stat(file).st_mtime)
 
-    return '<b><a href="%(file)s">%(name)s</a></b><br><b>%(size)s</b>, created %(date)s ago.<br><small>md5: %(hash)s</small>.' % locals()
+    return '<b><a href="%(file)s">%(name)s</a> (<a href="%(torrent_file)s">torrent</a>)</b><br><b>%(size)s</b>, created %(date)s ago.<br><small>md5: %(hash)s</small>.' % locals()
 
 planet_link = file_info('history-latest.osm.bz2', 'Latest Full History Planet XML File')
 planet_pbf_link = file_info('../../pbf/full-history/history-latest.osm.pbf', 'Latest Full History Planet PBF File')
 
-print """
+print("""
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
 <html>
  <head>
   <title>Index of /planet/full-history</title>
-  <link href="../../style.css" rel="stylesheet" type="text/css">
+  <link href="https://planet.openstreetmap.org/style.css" rel="stylesheet" type="text/css">
  </head>
  <body>
-<img id="logo" src="../../logo.png" alt="OSM logo" width="128" height="128">
+<img id="logo" src="https://planet.openstreetmap.org/logo.png" alt="OSM logo" width="128" height="128">
 <h1>Planet OSM</h1>
 
 <p>
 The files found here are complete copies of the OpenStreetMap.org
-database, including editing history. These are published under an 
-Open Data Commons Open Database License 1.0 licensed. For more 
+database, including editing history. These are published under an
+Open Data Commons Open Database License 1.0 licensed. For more
 information, <a href="https://wiki.openstreetmap.org/wiki/Planet.osm/full">see the project wiki</a>.
 </p>
 
@@ -94,13 +95,13 @@ information, <a href="https://wiki.openstreetmap.org/wiki/Planet.osm/full">see t
     </td>
     <td>
         <p>
-        You are granted permission to use OpenStreetMap data by 
-        <a href="https://osm.org/copyright">the OpenStreetMap License</a>, which also describes 
+        You are granted permission to use OpenStreetMap data by
+        <a href="https://osm.org/copyright">the OpenStreetMap License</a>, which also describes
         your obligations.
         </p>
         <p>
         You can <a href="https://wiki.openstreetmap.org/wiki/Planet.osm/full#Processing">process the file</a>
-        or extracts with a variety of tools, although some tools for processing OSM data will 
+        or extracts with a variety of tools, although some tools for processing OSM data will
        only work on 'current' planets and will not process a 'history' planet available here.
         </p>
     </td>
@@ -108,7 +109,7 @@ information, <a href="https://wiki.openstreetmap.org/wiki/Planet.osm/full">see t
         <p>
         The complete history planet is extremely large, so you may prefer to use one of
         <a href="https://wiki.openstreetmap.org/wiki/Planet.osm/full#Extracts">the available extracts</a>
-        (individual countries or states) from third parties. 
+        (individual countries or states) from third parties.
         </p>
     </td>
   </tr>
@@ -117,4 +118,4 @@ information, <a href="https://wiki.openstreetmap.org/wiki/Planet.osm/full">see t
 <p>
 If you find data within OpenStreetMap that you believe is an infringement of someone else's copyright, then please make contact with the <a href="https://wiki.openstreetmap.org/wiki/Data_working_group">OpenStreetMap Data Working Group</a>.
 </p>
-""" % locals()
+""" % locals())
index 3f3940cbcc8cfa3b6cb627da9535eff99b9fb9bf..806b5ec1853752e627c00776700851f4c02fe04e 100644 (file)
@@ -1,8 +1,7 @@
-#No bz2 chomping bots please
+# No bz2 chomping bots please
 
 User-agent: wget
 Allow: /
 
 User-agent: *
 Disallow: /
-
index 0a7afa9d0b25020d3314d493298dc22d1339c970..26dfdb8b16afb24a34acde29b38d587da409dbb7 100644 (file)
@@ -1,22 +1,59 @@
-body,
-table#about tr *
-{
+body {
     font-family: sans-serif;
     line-height: 1.25em;
+    margin: 2em;
+    min-width: 350px;
+    max-width: 1100px;
 }
 
-body { margin: 2em; }
 img#logo { float: left; }
 img#logo, h1 { margin: 0 1em 0 0; }
-a { white-space: nowrap; }
 
 li { margin-bottom: 1em; }
-body>p { width: 42em; }
 
-table#about
-{
-    clear: left;
-    margin: 3em 0 2em 0;
+p, li {color: #333;}
+
+#about {
+  display: flex;
+  flex-direction: row;
+  width: 100%;
+}
+
+#about > div {
+  padding-right: 2em;
+  flex: 1;
+}
+
+@media(max-width: 900px) {
+  body {
+    margin: 20px 10px;
+  }
+
+  img#logo {
+    width: 64px;
+    height: 64px;
+  }
+
+  #about {
+    flex-direction: column;
+  }
+
+  #about > div {
+    padding-right: 0;
+  }
+
+  pre {
+    width: 100%;
+    overflow: scroll;
+  }
+}
+
+ul {
+  padding-left: 1em;
+}
+
+ul li {
+  margin-bottom: 0.3em;
 }
 
 table tr th { text-align: left; }
@@ -52,3 +89,13 @@ table#about tr td
     font-size: 100%;
     white-space: normal;
 }
+
+.alert {
+  clear: both;
+  padding: 20px;
+  background-color: #ff9800; /* Orange */
+  color: white;
+  margin: 15px auto;
+  max-width: 42em;
+  border-radius: 4px;
+}
index 29131b2edd27c2394fb5d83f76157912d90a58ec..0c53856d984f1aae58f754cc10a135ba8db27d83 100755 (executable)
@@ -128,10 +128,7 @@ end
 # to guarantee sync for newly created directories.
 def fdirsync(d)
   while d != "/"
-    Dir.open(d) do |dh|
-      io = IO.for_fd(dh.fileno)
-      io.fsync
-    end
+    fsync(d)
     d = File.dirname(d)
   end
 end
@@ -207,6 +204,10 @@ class Replicator
     @config["data_dir"] + format("/%03d/%03d/%03d", sequence / 1000000, (sequence / 1000) % 1000, (sequence % 1000))
   end
 
+  def s3_stem
+    @config["s3_dir"] + format("/%03d/%03d/%03d", sequence / 1000000, (sequence / 1000) % 1000, (sequence % 1000))
+  end
+
   def write_tmp_files!(changesets)
     data_file = data_stem + ".osm.gz"
     tmp_state = @config["state_file"] + ".tmp"
@@ -216,9 +217,7 @@ class Replicator
     Zlib::GzipWriter.open(tmp_data) do |fh|
       fh.write(changeset_dump(changesets))
     end
-    File.open(tmp_state, "w") do |fh|
-      fh.write(YAML.dump(@state))
-    end
+    File.write(tmp_state, YAML.dump(@state))
 
     # fsync the files in their old locations.
     fsync(tmp_data)
@@ -257,12 +256,27 @@ class Replicator
     # from the dirent and has been updated to account for any allocations.
     fdirsync(File.dirname(data_file))
     fdirsync(File.dirname(@config["state_file"]))
+
+    if @config["s3_dir"]
+      s3_file = s3_stem + ".osm.gz"
+      s3_state_file = s3_stem + ".state.txt"
+      s3_state_config_file = @config["s3_dir"] + "/state.yaml"
+
+      system("/opt/awscli/v2/current/bin/aws", "--profile=osm-pds-upload", "s3", "cp", "--storage-class=INTELLIGENT_TIERING", "--no-progress", data_file, s3_file)
+      system("/opt/awscli/v2/current/bin/aws", "--profile=osm-pds-upload", "s3", "cp", "--storage-class=INTELLIGENT_TIERING", "--no-progress", data_state_file, s3_state_file)
+      system("/opt/awscli/v2/current/bin/aws", "--profile=osm-pds-upload", "s3", "cp", "--storage-class=INTELLIGENT_TIERING", "--no-progress", @config["state_file"], s3_state_config_file)
+    end
   end
 
   # saves new state (including the changeset dump xml)
   def save!
-    File.open(@config["state_file"], "r") do |fl|
-      fl.flock(File::LOCK_EX)
+    File.open(@config["lock_file"], File::RDWR | File::CREAT, 0o600) do |fl|
+      # take the lock in non-blocking mode. if this process doesn't get the lock
+      # then another will be run from cron shortly. this prevents a whole bunch
+      # of processes queueing on the lock and causing weirdness if/when they
+      # get woken up in a random order.
+      got_lock = fl.flock(File::LOCK_EX | File::LOCK_NB)
+      break unless got_lock
 
       # try and write the files to tmp locations and then
       # move them into place later, to avoid in-progress
@@ -291,5 +305,8 @@ begin
   rep.save!
 rescue StandardError => e
   warn "ERROR: #{e.message}"
+  e.backtrace.each do |frame|
+    warn "ERROR: #{frame}"
+  end
   exit 1
 end
diff --git a/cookbooks/planet/files/default/replication-bin/replicate-cleanup b/cookbooks/planet/files/default/replication-bin/replicate-cleanup
new file mode 100755 (executable)
index 0000000..6049cc3
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -e
+
+find /var/lib/replication/minute -name *.done -mtime +14 -print0 | xargs -0r rm
diff --git a/cookbooks/planet/files/default/replication-bin/replicate-day b/cookbooks/planet/files/default/replication-bin/replicate-day
new file mode 100644 (file)
index 0000000..4e8fd34
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+set -e
+
+/usr/local/bin/osmosis -q --merge-replication-files workingDirectory=/var/lib/replication/day
+
+. /store/planet/replication/day/state.txt
+
+sequencePart1=$(($sequenceNumber / 1000000 % 1000))
+sequencePart2=$(($sequenceNumber / 1000 % 1000))
+sequencePart3=$(($sequenceNumber % 1000))
+diffPath=$(printf "%03d/%03d/%03d" $sequencePart1 $sequencePart2 $sequencePart3)
+
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/day/${diffPath}.osc.gz" "s3://osm-planet-eu-central-1/planet/replication/day/${diffPath}.osc.gz"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/day/${diffPath}.state.txt" "s3://osm-planet-eu-central-1/planet/replication/day/${diffPath}.state.txt"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/day/state.txt" "s3://osm-planet-eu-central-1/planet/replication/day/state.txt"
diff --git a/cookbooks/planet/files/default/replication-bin/replicate-hour b/cookbooks/planet/files/default/replication-bin/replicate-hour
new file mode 100644 (file)
index 0000000..184c4a3
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+set -e
+
+/usr/local/bin/osmosis -q --merge-replication-files workingDirectory=/var/lib/replication/hour
+
+. /store/planet/replication/hour/state.txt
+
+sequencePart1=$(($sequenceNumber / 1000000 % 1000))
+sequencePart2=$(($sequenceNumber / 1000 % 1000))
+sequencePart3=$(($sequenceNumber % 1000))
+diffPath=$(printf "%03d/%03d/%03d" $sequencePart1 $sequencePart2 $sequencePart3)
+
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/hour/${diffPath}.osc.gz" "s3://osm-planet-eu-central-1/planet/replication/hour/${diffPath}.osc.gz"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/hour/${diffPath}.state.txt" "s3://osm-planet-eu-central-1/planet/replication/hour/${diffPath}.state.txt"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/hour/state.txt" "s3://osm-planet-eu-central-1/planet/replication/hour/state.txt"
diff --git a/cookbooks/planet/files/default/replication-bin/replicate-minute b/cookbooks/planet/files/default/replication-bin/replicate-minute
new file mode 100755 (executable)
index 0000000..5e39bec
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+set -e
+
+cd /etc/replication
+
+osmdbt-catchup --quiet
+osmdbt-get-log --quiet
+
+/opt/awscli/v2/current/bin/aws --profile=osm-osmdbt-state-upload s3 sync --storage-class=INTELLIGENT_TIERING --no-progress --exclude='*' --include='osm-repl-*.log' /var/lib/replication/minute s3://openstreetmap-osmdbt-state
+
+osmdbt-catchup --quiet
+osmdbt-create-diff --quiet --with-comment --max-changes=50000
+
+. /store/planet/replication/minute/state.txt
+
+sequencePart1=$(($sequenceNumber / 1000000 % 1000))
+sequencePart2=$(($sequenceNumber / 1000 % 1000))
+sequencePart3=$(($sequenceNumber % 1000))
+diffPath=$(printf "%03d/%03d/%03d" $sequencePart1 $sequencePart2 $sequencePart3)
+
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/minute/${diffPath}.osc.gz" "s3://osm-planet-eu-central-1/planet/replication/minute/${diffPath}.osc.gz"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/minute/${diffPath}.state.txt" "s3://osm-planet-eu-central-1/planet/replication/minute/${diffPath}.state.txt"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "/store/planet/replication/minute/state.txt" "s3://osm-planet-eu-central-1/planet/replication/minute/state.txt"
diff --git a/cookbooks/planet/files/default/replication-bin/streaming-replicator b/cookbooks/planet/files/default/replication-bin/streaming-replicator
deleted file mode 100644 (file)
index 7b78ae4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-export TZ=UTC
-
-exec >> /var/log/replication/streaming-replicator 2>&1
-
-exec /usr/local/bin/osmosis -q \
-  --replicate-apidb iterations=0 minInterval=10000 maxInterval=60000 authFile=/etc/replication/auth.conf validateSchemaVersion=false \
-  --send-replication-sequence port=8081 \
-  --write-replication workingDirectory=/var/lib/replication/streaming
diff --git a/cookbooks/planet/files/default/replication-bin/streaming-server b/cookbooks/planet/files/default/replication-bin/streaming-server
deleted file mode 100644 (file)
index 11394ae..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-export TZ=UTC
-
-exec >> /var/log/replication/streaming-server 2>&1
-
-exec /usr/local/bin/osmosis -q \
-  --send-replication-data dataDirectory=/var/lib/replication/streaming port=8080 notificationPort=8081
index edde59d2774e94f6c6f005aaaeaeceed9899eee2..5e00a78e14d739c0e12a808345014bea9b178151 100644 (file)
@@ -1,14 +1,14 @@
-#!/usr/bin/env python
+#!/usr/bin/python3
 
-print """
+print("""
 <html>
  <head>
   <title>OpenStreetMap replication diffs</title>
-  <link href="/style.css" rel="stylesheet" type="text/css">
+  <link href="https://planet.openstreetmap.org/style.css" rel="stylesheet" type="text/css">
  </head>
  <body>
-<img id="logo" src="/logo.png" alt="OSM logo" width="128" height="128">
+<img id="logo" src="https://planet.openstreetmap.org/logo.png" alt="OSM logo" width="128" height="128">
 <h1>planet.openstreetmap.org - replication diffs</h1>
 <p>OpenStreetMap is <i>open data</i>, licensed under the <a href="https://opendatacommons.org/licenses/odbl/">Open Data Commons Open Database License</a> (ODbL)</p>
 <p>&nbsp;</p>
-"""
+""")
index 97cd99ffb8044a2c3b1f77af8a2fb262a33c0344..2e70109ee362bbb4ad33b93b78c46911baec272f 100644 (file)
@@ -6,8 +6,12 @@ description       "Installs and configures a planet server"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
+depends           "apt"
+depends           "awscli"
+depends           "geoipupdate"
 depends           "git"
+depends           "ruby"
 depends           "osmosis"
-depends           "incron"
-depends           "munin"
+depends           "systemd"
diff --git a/cookbooks/planet/recipes/aws.rb b/cookbooks/planet/recipes/aws.rb
new file mode 100644 (file)
index 0000000..cd44446
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# Cookbook:: planet
+# Recipe:: aws
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "accounts"
+include_recipe "awscli"
+
+aws_credentials = data_bag_item("planet", "aws")
+
+directory "/home/planet/.aws" do
+  owner "planet"
+  group "planet"
+  mode "0755"
+end
+
+template "/home/planet/.aws/config" do
+  source "aws-config.erb"
+  owner "planet"
+  group "planet"
+  mode "0644"
+end
+
+template "/home/planet/.aws/credentials" do
+  source "aws-credentials.erb"
+  owner "planet"
+  group "planet"
+  mode "0600"
+  variables :credentials => aws_credentials
+end
index 7e2e50f1d32a258604f65b8fb5b534929a7e6397..517123f5913219f97a73d9402c419e81415bdac7 100644 (file)
 # limitations under the License.
 #
 
+node.default[:accounts][:users][:planet][:status] = :role
+
+include_recipe "accounts"
+
 package %w[
   pyosmium
 ]
@@ -25,40 +29,29 @@ template "/usr/local/bin/planet-update" do
   source "planet-update.erb"
   owner "root"
   group "root"
-  mode 0o755
-end
-
-template "/usr/local/bin/planet-update-file" do
-  source "planet-update-file.erb"
-  owner "root"
-  group "root"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/lib/planet" do
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
 end
 
-remote_file "/var/lib/planet/planet.pbf" do
+remote_file "/var/lib/planet/planet.osh.pbf" do
   action :create_if_missing
-  source "https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf"
+  source "https://planet.openstreetmap.org/pbf/full-history/history-latest.osm.pbf"
   owner "planet"
   group "planet"
-  mode 0o644
+  mode "644"
+  not_if { kitchen? }
 end
 
-template "/etc/cron.d/planet-update" do
-  source "planet-update.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
-template "/etc/logrotate.d/planet-update" do
-  source "planet-update.logrotate.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+systemd_service "planet-update" do
+  description "Planet file update"
+  type "oneshot"
+  exec_start "/usr/local/bin/planet-update"
+  user "planet"
+  sandbox :enable_network => true
+  read_write_paths "/var/lib/planet"
 end
index 28b1abdb8d6f6bfb0790c196938257fd14930cf2..ad532f93e40eb49cdcce73323508924054ebf53d 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "apache"
+include_recipe "geoipupdate"
+include_recipe "planet::aws"
 
-package "perl"
-package "pbzip2"
-package "osmosis"
-
-package "php-cli"
-
-file "/etc/cron.d/planet" do
-  action :delete
-end
+package %w[
+  python3
+  python3-geoip2
+]
 
 remote_directory "/store/planet#html" do
   path "/store/planet"
@@ -37,7 +35,7 @@ remote_directory "/store/planet#html" do
   mode "0755"
   files_owner "root"
   files_group "root"
-  files_mode 0o644
+  files_mode "644"
 end
 
 remote_directory "/store/planet#cgi" do
@@ -45,58 +43,83 @@ remote_directory "/store/planet#cgi" do
   source "cgi"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o755
+  files_mode "755"
 end
 
 remote_directory node[:planet][:dump][:xml_history_directory] do
   source "history_cgi"
-  owner "www-data"
+  owner "planet"
+  group "planet"
+  mode "775"
+  files_owner "root"
+  files_group "root"
+  files_mode "755"
+end
+
+remote_directory "/store/planet/cc-by-sa" do
+  source "ccbysa_cgi"
+  owner "planet"
   group "planet"
-  mode 0o775
+  mode "775"
   files_owner "root"
   files_group "root"
-  files_mode 0o755
+  files_mode "755"
 end
 
 remote_directory "/store/planet/cc-by-sa/full-experimental" do
   source "ccbysa_history_cgi"
-  owner "www-data"
+  owner "planet"
   group "planet"
-  mode 0o775
+  mode "775"
   files_owner "root"
   files_group "root"
-  files_mode 0o755
+  files_mode "755"
 end
 
 [:xml_directory, :xml_history_directory,
  :pbf_directory, :pbf_history_directory].each do |dir|
   directory node[:planet][:dump][dir] do
-    owner "www-data"
+    owner "planet"
     group "planet"
-    mode 0o775
+    mode "775"
   end
 end
 
 directory "/store/planet/notes" do
-  owner "www-data"
+  owner "planet"
+  group "planet"
+  mode "775"
+end
+
+directory "/store/planet/statistics" do
+  owner "planet"
   group "planet"
-  mode 0o775
+  mode "775"
 end
 
 template "/usr/local/bin/apache-latest-planet-filename" do
   source "apache-latest-planet-filename.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
+  notifies :restart, "service[apache2]"
+end
+
+template "/usr/local/bin/apache-s3-ip2region" do
+  source "apache-s3-ip2region.erb"
+  owner "root"
+  group "root"
+  mode "755"
   notifies :restart, "service[apache2]"
 end
 
 apache_module "cgid"
 apache_module "rewrite"
 apache_module "proxy_http"
+apache_module "ratelimit"
 
 ssl_certificate "planet.openstreetmap.org" do
   domains ["planet.openstreetmap.org", "planet.osm.org"]
@@ -111,21 +134,32 @@ template "/etc/logrotate.d/apache2" do
   source "logrotate.apache.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
-munin_plugin "planet_age"
-
-template "/usr/local/bin/old-planet-file-cleanup" do
-  source "old-planet-file-cleanup.erb"
+template "/usr/local/bin/planet-file-cleanup" do
+  source "planet-file-cleanup.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
-template "/etc/cron.d/old-planet-file-cleanup" do
-  source "old-planet-file-cleanup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+systemd_service "planet-file-cleanup" do
+  description "Cleanup old planet files"
+  exec_start "/usr/local/bin/planet-file-cleanup --debug"
+  user "planet"
+  sandbox true
+  read_write_paths [
+    node[:planet][:dump][:xml_directory],
+    node[:planet][:dump][:pbf_directory]
+  ]
+end
+
+systemd_timer "planet-file-cleanup" do
+  description "Cleanup old planet files"
+  on_calendar "Mon *-*-1..7 03:44"
+end
+
+service "planet-file-cleanup.timer" do
+  action [:enable, :start]
 end
index 0b46a2c7bcdc65fc21eaea011bbde438d88c2e5a..d386eaa79ffb027d3adb27aa3c7a40e4b85bf0db 100644 (file)
 # limitations under the License.
 #
 
-node.default[:incron][:planetdump] = {
-  :user => "www-data",
-  :path => "/store/backup",
-  :events => %w[IN_CREATE IN_MOVED_TO],
-  :command => "/usr/local/bin/planetdump $#"
-}
-
+include_recipe "accounts"
 include_recipe "git"
-include_recipe "incron"
-
-package "gcc"
-package "make"
-package "autoconf"
-package "automake"
-package "libxml2-dev"
-package "libboost-dev"
-package "libboost-program-options-dev"
-package "libboost-date-time-dev"
-package "libboost-filesystem-dev"
-package "libboost-thread-dev"
-package "libboost-iostreams-dev"
-package "libosmpbf-dev"
-package "libprotobuf-dev"
-package "osmpbf-bin"
 
-# Add planet-mirror-redirect-update dependencies
-package "php-cli"
-package "php-curl"
+package %w[
+  gcc
+  g++
+  make
+  autoconf
+  automake
+  pkg-config
+  libxml2-dev
+  libboost-dev
+  libboost-program-options-dev
+  libboost-date-time-dev
+  libboost-filesystem-dev
+  libboost-thread-dev
+  libboost-iostreams-dev
+  libosmpbf-dev
+  libprotobuf-dev
+  osmpbf-bin
+  pbzip2
+  mktorrent
+  xmlstarlet
+  libxml2-utils
+  inotify-tools
+]
 
 directory "/opt/planet-dump-ng" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 git "/opt/planet-dump-ng" do
   action :sync
-  repository "git://github.com/zerebubuth/planet-dump-ng.git"
-  revision "v1.1.6"
+  repository "https://github.com/zerebubuth/planet-dump-ng.git"
+  revision "v1.2.7"
+  depth 1
   user "root"
   group "root"
 end
@@ -88,23 +87,47 @@ execute "/opt/planet-dump-ng/Makefile" do
 end
 
 directory "/store/planetdump" do
-  owner "www-data"
-  group "www-data"
-  mode 0o755
+  owner "planet"
+  group "planet"
+  mode "755"
+  recursive true
 end
 
-%w[planetdump planet-mirror-redirect-update].each do |program|
+%w[planetdump planetdump-trigger].each do |program|
   template "/usr/local/bin/#{program}" do
     source "#{program}.erb"
     owner "root"
     group "root"
-    mode 0o755
+    mode "755"
   end
 end
 
-template "/etc/cron.d/planet-dump-mirror" do
-  source "planet-dump-mirror-cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+systemd_service "planetdump@" do
+  description "Planet dump for %i"
+  user "planet"
+  exec_start "/usr/local/bin/planetdump %i"
+  memory_max "64G"
+  sandbox :enable_network => true
+  protect_home "tmpfs"
+  bind_paths "/home/planet"
+  read_write_paths [
+    "/store/planetdump",
+    "/store/planet/pbf",
+    "/store/planet/planet",
+    "/var/log/exim4",
+    "/var/spool/exim4"
+  ]
+end
+
+systemd_service "planetdump-trigger" do
+  description "Planet dump trigger"
+  user "root"
+  exec_start "/usr/local/bin/planetdump-trigger"
+  sandbox true
+  restrict_address_families "AF_UNIX"
+end
+
+service "planetdump-trigger" do
+  action [:enable, :start]
+  subscribes :restart, "template[/usr/local/bin/planetdump-trigger]"
 end
index 41303fe43e30dc6d2eea64abebcee685e2f0997f..e6329708190daa8201c81069a73dbbb2eade7f37 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "git"
+include_recipe "planet::aws"
 
 db_passwords = data_bag_item("db", "passwords")
 
-package "python-psycopg2"
-package "python-lxml"
+package %w[
+  pbzip2
+  python3
+  python3-psycopg2
+  python3-lxml
+]
 
 directory "/opt/planet-notes-dump" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 git "/opt/planet-notes-dump" do
   action :sync
-  repository "git://github.com/openstreetmap/planet-notes-dump.git"
+  repository "https://github.com/openstreetmap/planet-notes-dump.git"
+  depth 1
   user "root"
   group "root"
 end
@@ -41,13 +48,49 @@ template "/usr/local/bin/planet-notes-dump" do
   source "planet-notes-dump.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   variables :password => db_passwords["planetdump"]
 end
 
-template "/etc/cron.d/planet-notes-dump" do
-  source "planet-notes-dump.cron.erb"
+systemd_service "planet-notes-dump" do
+  description "Create notes dump"
+  exec_start "/usr/local/bin/planet-notes-dump"
+  user "planet"
+  sandbox :enable_network => true
+  protect_home "tmpfs"
+  bind_paths "/home/planet"
+  read_write_paths "/store/planet/notes"
+end
+
+systemd_timer "planet-notes-dump" do
+  description "Create notes dump"
+  on_calendar "03:00"
+end
+
+service "planet-notes-dump.timer" do
+  action [:enable, :start]
+end
+
+template "/usr/local/bin/planet-notes-cleanup" do
+  source "planet-notes-cleanup.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "755"
+end
+
+systemd_service "planet-notes-cleanup" do
+  description "Delete old notes dumps"
+  exec_start "/usr/local/bin/planet-notes-cleanup"
+  user "planet"
+  sandbox true
+  read_write_paths "/store/planet/notes"
+end
+
+systemd_timer "planet-notes-cleanup" do
+  description "Delete old notes dumps"
+  on_calendar "08:10"
+end
+
+service "planet-notes-cleanup.timer" do
+  action [:enable, :start]
 end
index 548ae871bdf920d20b8c99d9db5814951b529090..d719d11ae519c33800a36865f501f8f8c61ced1c 100644 (file)
 # limitations under the License.
 #
 
+require "yaml"
+
+include_recipe "accounts"
+include_recipe "apt"
 include_recipe "osmosis"
+include_recipe "planet::aws"
+include_recipe "ruby"
+include_recipe "tools"
 
 db_passwords = data_bag_item("db", "passwords")
 
-package "postgresql-client"
+## Install required packages
 
-package "ruby"
-package "ruby-dev"
-package "ruby-libxml"
+package %w[
+  postgresql-client
+  ruby-libxml
+  make
+  gcc
+  libc6-dev
+  libpq-dev
+  osmdbt
+]
 
-package "libpq-dev"
-gem_package "pg"
+gem_package "pg" do
+  gem_binary node[:ruby][:gem]
+end
 
-package "make"
-package "gcc"
+## Build preload library to flush files
 
 remote_directory "/opt/flush" do
   source "flush"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o755
+  files_mode "755"
 end
 
 execute "/opt/flush/Makefile" do
@@ -52,190 +65,391 @@ execute "/opt/flush/Makefile" do
   subscribes :run, "remote_directory[/opt/flush]"
 end
 
+## Install scripts
+
 remote_directory "/usr/local/bin" do
   source "replication-bin"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o755
+  files_mode "755"
 end
 
 template "/usr/local/bin/users-agreed" do
   source "users-agreed.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 template "/usr/local/bin/users-deleted" do
   source "users-deleted.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
+## Published deleted users directory
+
 remote_directory "/store/planet/users_deleted" do
   source "users_deleted"
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o644
+  files_mode "644"
 end
 
+## Published replication directory
+
 remote_directory "/store/planet/replication" do
   source "replication-cgi"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   files_owner "root"
   files_group "root"
-  files_mode 0o755
+  files_mode "755"
 end
 
-directory "/store/planet/replication/changesets" do
+## Configuration directory
+
+directory "/etc/replication" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+## Transient state directory
+
+systemd_tmpfile "/run/replication" do
+  type "d"
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
 end
 
-directory "/store/planet/replication/day" do
+## Persistent state directory
+
+directory "/var/lib/replication" do
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
 end
 
-directory "/store/planet/replication/hour" do
+## Temporary directory
+
+directory "/store/replication" do
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
 end
 
-directory "/store/planet/replication/minute" do
-  owner "planet"
+## Users replication
+
+template "/etc/replication/users-agreed.conf" do
+  source "users-agreed.conf.erb"
+  user "planet"
   group "planet"
-  mode 0o755
+  mode "600"
+  variables :password => db_passwords["planetdiff"]
 end
 
-directory "/etc/replication" do
-  owner "root"
-  group "root"
-  mode 0o755
+systemd_service "users-agreed" do
+  description "Update list of users accepting CTs"
+  user "planet"
+  exec_start "/usr/local/bin/users-agreed"
+  nice 10
+  sandbox :enable_network => true
+  read_write_paths "/store/planet/users_agreed"
 end
 
-template "/etc/replication/auth.conf" do
-  source "replication.auth.erb"
-  user "root"
+systemd_timer "users-agreed" do
+  description "Update list of users accepting CTs"
+  on_calendar "7:00"
+end
+
+systemd_service "users-deleted" do
+  description "Update list of deleted users"
+  user "planet"
+  exec_start "/usr/local/bin/users-deleted"
+  nice 10
+  sandbox :enable_network => true
+  read_write_paths "/store/planet/users_deleted"
+end
+
+systemd_timer "users-deleted" do
+  description "Update list of deleted users"
+  on_calendar "17:00"
+end
+
+## Changeset replication
+
+directory "/store/planet/replication/changesets" do
+  owner "planet"
   group "planet"
-  mode 0o640
-  variables :password => db_passwords["planetdiff"]
+  mode "755"
 end
 
 template "/etc/replication/changesets.conf" do
   source "changesets.conf.erb"
   user "root"
   group "planet"
-  mode 0o640
+  mode "640"
   variables :password => db_passwords["planetdiff"]
 end
 
-template "/etc/replication/users-agreed.conf" do
-  source "users-agreed.conf.erb"
+systemd_service "replication-changesets" do
+  description "Changesets replication"
   user "planet"
+  exec_start "/usr/local/bin/replicate-changesets /etc/replication/changesets.conf"
+  sandbox :enable_network => true
+  protect_home "tmpfs"
+  bind_paths "/home/planet"
+  read_write_paths [
+    "/run/replication",
+    "/store/planet/replication/changesets"
+  ]
+end
+
+systemd_timer "replication-changesets" do
+  description "Changesets replication"
+  on_boot_sec 60
+  on_unit_active_sec 60
+  accuracy_sec 5
+end
+
+## Minutely replication
+
+directory "/store/planet/replication/minute" do
+  owner "planet"
   group "planet"
-  mode 0o600
-  variables :password => db_passwords["planetdiff"]
+  mode "755"
 end
 
-directory "/var/lib/replication" do
+directory "/var/lib/replication/minute" do
+  owner "planet"
+  group "planet"
+  mode "755"
+end
+
+directory "/store/replication/minute" do
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
+end
+
+osmdbt_config = {
+  "database" => {
+    "host" => node[:web][:database_host],
+    "dbname" => "openstreetmap",
+    "user" => "planetdiff",
+    "password" => db_passwords["planetdiff"],
+    "replication_slot" => "osmdbt"
+  },
+  "log_dir" => "/var/lib/replication/minute",
+  "changes_dir" => "/store/planet/replication/minute",
+  "tmp_dir" => "/store/replication/minute",
+  "run_dir" => "/run/replication"
+}
+
+file "/etc/replication/osmdbt-config.yaml" do
+  user "root"
+  group "planet"
+  mode "640"
+  content YAML.dump(osmdbt_config)
+end
+
+systemd_service "replication-minutely" do
+  description "Minutely replication"
+  user "planet"
+  working_directory "/etc/replication"
+  exec_start "/usr/local/bin/replicate-minute"
+  sandbox :enable_network => true
+  protect_home "tmpfs"
+  bind_paths "/home/planet"
+  read_write_paths [
+    "/run/replication",
+    "/store",
+    "/var/lib/replication/minute"
+  ]
+end
+
+systemd_timer "replication-minutely" do
+  description "Minutely replication"
+  on_boot_sec 60
+  on_unit_active_sec 60
+  accuracy_sec 5
+end
+
+## Hourly replication
+
+directory "/store/planet/replication/hour" do
+  owner "planet"
+  group "planet"
+  mode "755"
 end
 
 directory "/var/lib/replication/hour" do
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
+end
+
+link "/var/lib/replication/hour/data" do
+  to "/store/planet/replication/hour"
 end
 
 template "/var/lib/replication/hour/configuration.txt" do
   source "replication.config.erb"
   owner "planet"
   group "planet"
-  mode 0o644
+  mode "644"
   variables :base => "minute", :interval => 3600
 end
 
-link "/var/lib/replication/hour/data" do
-  to "/store/planet/replication/hour"
+systemd_service "replication-hourly" do
+  description "Hourly replication"
+  user "planet"
+  exec_start "/usr/local/bin/replicate-hour"
+  environment "LD_PRELOAD" => "/opt/flush/flush.so"
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  protect_home "tmpfs"
+  bind_paths "/home/planet"
+  read_write_paths [
+    "/store/planet/replication/hour",
+    "/var/lib/replication/hour"
+  ]
+end
+
+systemd_timer "replication-hourly" do
+  description "Hourly replication"
+  on_calendar "*-*-* *:02/15:00"
+end
+
+## Daily replication
+
+directory "/store/planet/replication/day" do
+  owner "planet"
+  group "planet"
+  mode "755"
 end
 
 directory "/var/lib/replication/day" do
   owner "planet"
   group "planet"
-  mode 0o755
+  mode "755"
+end
+
+link "/var/lib/replication/day/data" do
+  to "/store/planet/replication/day"
 end
 
 template "/var/lib/replication/day/configuration.txt" do
   source "replication.config.erb"
   owner "planet"
   group "planet"
-  mode 0o644
+  mode "644"
   variables :base => "hour", :interval => 86400
 end
 
-link "/var/lib/replication/day/data" do
-  to "/store/planet/replication/day"
+systemd_service "replication-daily" do
+  description "Daily replication"
+  user "planet"
+  exec_start "/usr/local/bin/replicate-day"
+  environment "LD_PRELOAD" => "/opt/flush/flush.so"
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  protect_home "tmpfs"
+  bind_paths "/home/planet"
+  read_write_paths [
+    "/store/planet/replication/day",
+    "/var/lib/replication/day"
+  ]
+end
+
+systemd_timer "replication-daily" do
+  description "Daily replication"
+  on_calendar "*-*-* *:02/15:00"
 end
 
+## Replication cleanup
+
+systemd_service "replication-cleanup" do
+  description "Cleanup replication"
+  user "planet"
+  exec_start "/usr/local/bin/replicate-cleanup"
+  sandbox true
+  read_write_paths "/var/lib/replication"
+end
+
+systemd_timer "replication-cleanup" do
+  description "Cleanup replication"
+  on_boot_sec 60
+  on_unit_active_sec 86400
+  accuracy_sec 1800
+end
+
+## Enable/disable feeds
+
 if node[:planet][:replication] == "enabled"
-  template "/etc/cron.d/replication" do
-    source "replication.cron.erb"
-    owner "root"
-    group "root"
-    mode 0o644
+  service "users-agreed.timer" do
+    action [:enable, :start]
+  end
+
+  service "users-deleted.timer" do
+    action [:enable, :start]
+  end
+
+  service "replication-changesets.timer" do
+    action [:enable, :start]
+  end
+
+  service "replication-minutely.timer" do
+    action [:enable, :start]
+  end
+
+  service "replication-hourly.timer" do
+    action [:enable, :start]
+  end
+
+  service "replication-daily.timer" do
+    action [:enable, :start]
+  end
+
+  service "replication-cleanup.timer" do
+    action [:enable, :start]
   end
 else
-  file "/etc/cron.d/replication" do
-    action :delete
+  service "users-agreed.timer" do
+    action [:stop, :disable]
   end
-end
 
-# directory "/var/lib/replication/streaming" do
-#   owner "planet"
-#   group "planet"
-#   mode 0o755
-# end
-#
-# directory "/var/log/replication" do
-#   owner "planet"
-#   group "planet"
-#   mode 0o755
-# end
-#
-# ["streaming-replicator", "streaming-server"].each do |name|
-#   template "/etc/init.d/#{name}" do
-#     source "streaming.init.erb"
-#     owner "root"
-#     group "root"
-#     mode 0o755
-#     variables :service => name
-#   end
-#
-#   if node[:planet][:replication] == "enabled"
-#     service name do
-#       action [:enable, :start]
-#       supports :restart => true, :status => true
-#       subscribes :restart, "template[/etc/init.d/#{name}]"
-#     end
-#   else
-#     service name do
-#       action [:disable, :stop]
-#       supports :restart => true, :status => true
-#     end
-#   end
-# end
+  service "users-deleted.timer" do
+    action [:stop, :disable]
+  end
+
+  service "replication-changesets.timer" do
+    action [:stop, :disable]
+  end
+
+  service "replication-minutely.timer" do
+    action [:stop, :disable]
+  end
+
+  service "replication-hourly.timer" do
+    action [:stop, :disable]
+  end
+
+  service "replication-daily.timer" do
+    action [:stop, :disable]
+  end
+
+  service "replication-cleanup.timer" do
+    action [:stop, :disable]
+  end
+end
index 9107436b3d38cbfddfcd0114393c5a059791a222..283e0d5a8cce8b7d52416e43ce5201a3ff0c2fcb 100644 (file)
@@ -1,26 +1,28 @@
-#!/usr/bin/perl
+#!/usr/bin/python3
 
 # DO NOT EDIT - This file is being maintained by Chef
 
-use strict;
-use warnings;
+import os
+import sys
 
-use Cwd qw(abs_path);
+def main():
+    for line in sys.stdin:
+        path = line.strip()
 
-$| = 1;
+        # Construct the file path and resolve its real path,
+        # which will consider any symbolic links
+        file = os.path.realpath(f"/store/planet{path}")
 
-while (my $path = <STDIN>)
-{
-    chomp $path;
+        # Check if the constructed file path starts with '/store/planet'
+        # and if the file actually exists
+        if file.startswith('/store/planet') and os.path.isfile(file):
+            # Print the portion of the path after '/store/planet'
+            # and immediately flush the output
+            print(file[len('/store/planet'):], flush=True)
+        else:
+            # If the file does not exist or the path does not start with
+            # the expected prefix, print "NULL" and flush the output
+            print("NULL", flush=True)
 
-    my $file = abs_path("/store/planet${path}");
-
-    if ($file && $file =~ m|^/store/planet(/.*)$| && -f $file)
-    {
-        print "$1\n";
-    }
-    else
-    {
-        print "NULL\n";
-    }
-}
+if __name__ == "__main__":
+    main()
diff --git a/cookbooks/planet/templates/default/apache-s3-ip2region.erb b/cookbooks/planet/templates/default/apache-s3-ip2region.erb
new file mode 100644 (file)
index 0000000..92f438b
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import geoip2.database
+import ipaddress
+
+# Constants
+DB_PATH = "<%= node[:geoipupdate][:directory] %>/GeoLite2-Country.mmdb"
+
+# Default region when continent doesn't match any in the dictionary
+DEFAULT_REGION = "eu-central-1"
+
+# Mapping of continents to AWS regions
+CONTINENT_TO_AWS_REGION = {
+    "NA": "us-west-2", # North America
+    "OC": "us-west-2", # Oceania
+    "SA": "us-west-2", # South America
+}
+
+# Global to store last known modification time and database reader
+last_mod_time = None
+reader = None
+
+def is_valid_ip(ip_str):
+    """Check if a string is a valid IPv4 or IPv6 address."""
+    try:
+        ipaddress.ip_address(ip_str)
+        return True
+    except ValueError:
+        return False
+
+def get_reader():
+    """Get the geoip2 database reader. Reload if the DB file has changed."""
+    global last_mod_time
+    global reader
+
+    if not os.path.exists(DB_PATH):
+      return None  # Database file missing
+
+    current_mod_time = os.path.getmtime(DB_PATH)
+
+    # If file has changed or reader isn't initialized, reload it
+    if reader is None or current_mod_time != last_mod_time:
+        if reader:
+            reader.close()  # Close the existing reader before reinitializing
+        reader = geoip2.database.Reader(DB_PATH)
+        last_mod_time = current_mod_time
+
+    return reader
+
+def get_continent_from_ip(ip_address):
+    """Return the continent for a given IP address."""
+    if not is_valid_ip(ip_address):
+        return None
+    reader = get_reader()
+    if reader is None:
+      return None  # No continent as DB is missing
+    try:
+        response = reader.country(ip_address)
+        return response.continent.code
+    except:
+        return None  # Indicates invalid IP address or other issues
+
+def determine_aws_region(continent_code):
+    """Determine AWS region based on the continent code using a dictionary."""
+    return CONTINENT_TO_AWS_REGION.get(continent_code, DEFAULT_REGION)
+
+def main():
+    """Main function to process IP addresses from stdin and return AWS regions."""
+    for line in sys.stdin:
+        ip_address = line.strip()
+
+        continent_code = get_continent_from_ip(ip_address)
+        aws_region = determine_aws_region(continent_code)
+
+        sys.stdout.write(f"{aws_region}\n")
+        sys.stdout.flush()
+
+if __name__ == "__main__":
+    main()
index a67189a0dbb9df8065442de41823c9d2a7a4604f..867d1c6fec29bba65366e5059910d7d0dfad22b4 100644 (file)
@@ -5,7 +5,7 @@
         ServerAlias planet.osm.org
         ServerAdmin webmaster@openstreetmap.org
 
-        CustomLog /var/log/apache2/planet.openstreetmap.org-access.log combined
+        CustomLog /var/log/apache2/planet.openstreetmap.org-access.log combined_extended
         ErrorLog /var/log/apache2/planet.openstreetmap.org-error.log
 
         SSLEngine on
                 Require all granted
         </Directory>
 
-        ProxyPass /replication/streaming http://127.0.0.1:8080
-
-        <Location /replication/steaming>
-                Require all granted
-        </Location>
-
         Redirect /pbf-experimental/    /pbf/
 
         <IfModule mod_headers.c>
-                Header set Access-Control-Allow-Origin "*"
+                Header always set Access-Control-Allow-Origin "*"
         </IfModule>
 
         RewriteEngine on
         RewriteMap latestplanet prg:/usr/local/bin/apache-latest-planet-filename
+        RewriteMap ip2region prg:/usr/local/bin/apache-s3-ip2region
 
-        #Direct, no redirect for the following
-        RewriteCond %{REMOTE_ADDR}  ^127\.                          [OR]
-        RewriteCond %{REMOTE_ADDR}  ^10\.                             [OR]
-        RewriteCond %{REMOTE_ADDR}  ^193\.60\.       [OR]
-        RewriteCond %{REMOTE_ADDR}  ^193\.61\.       [OR]
-        RewriteCond %{REMOTE_ADDR}  ^193\.62\.       [OR]
-        RewriteCond %{REMOTE_ADDR}  ^193\.63\.       [OR]
+        # Direct, no redirect for the following
+        RewriteCond %{REMOTE_ADDR} ^(127\.|10\.|192\.168\.)
         RewriteCond %{QUERY_STRING} nomirror
-        RewriteRule    .*      - [L]
+        RewriteRule    .* - [L]
 
-        RewriteRule ^(/planet/planet\-latest\.osm\.bz2)$                ${latestplanet:$1} [R,L]
-        RewriteRule ^(/planet/full\-history/history\-latest\.osm\.bz2)$ ${latestplanet:$1} [R,L]
-        RewriteRule ^(/planet/changesets\-latest\.osm\.bz2)$            ${latestplanet:$1} [R,L]
-        RewriteRule ^(/planet/discussions\-latest\.osm\.bz2)$           ${latestplanet:$1} [R,L]
+        # Use RewriteMap latestplanet to redirect -latest symlink to resolved file eg: planet-latest.osm.bz2 -> 2023/planet-230918.osm.bz2
+        RewriteRule ^(/planet/planet\-latest\.osm\.bz2(\.torrent)?)$                ${latestplanet:$1} [R,L]
+        RewriteRule ^(/planet/full\-history/history\-latest\.osm\.bz2(\.torrent)?)$ ${latestplanet:$1} [R,L]
+        RewriteRule ^(/planet/changesets\-latest\.osm\.bz2(\.torrent)?)$            ${latestplanet:$1} [R,L]
+        RewriteRule ^(/planet/discussions\-latest\.osm\.bz2(\.torrent)?)$           ${latestplanet:$1} [R,L]
 
-        RewriteRule ^(/pbf/planet\-latest\.osm\.pbf)$                   ${latestplanet:$1} [R,L]
-        RewriteRule ^(/pbf/full\-history/history\-latest\.osm\.pbf)$    ${latestplanet:$1} [R,L]
+        RewriteRule ^(/pbf/planet\-latest\.osm\.pbf(\.torrent)?)$                   ${latestplanet:$1} [R,L]
+        RewriteRule ^(/pbf/full\-history/history\-latest\.osm\.pbf(\.torrent)?)$    ${latestplanet:$1} [R,L]
 
         RewriteRule ^(/cc\-by\-sa/pbf/planet\-latest\.osm\.pbf)$        ${latestplanet:$1} [R,L]
         RewriteRule ^(/cc\-by\-sa/planet\-latest\.osm\.bz2)$            ${latestplanet:$1} [R,L]
         RewriteRule ^(/cc\-by\-sa/changesets\-latest\.osm\.bz2)$        ${latestplanet:$1} [R,L]
         RewriteRule ^(/cc\-by\-sa/relations\-latest\.osm\.bz2)$         ${latestplanet:$1} [R,L]
 
+        RewriteRule ^(/notes/planet\-notes\-latest\.osn\.bz2)$         ${latestplanet:$1} [R,L]
+
+        # Redirect minute/hour/day replication files to AWS S3 eu-central-1 bucket
+        RewriteRule ^/replication/((minute|hour|day)/state\.txt)$                    https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/$1 [R,L]
+        RewriteRule ^/replication/((minute|hour|day)/\d{3}/\d{3}/\d{3}\.state\.txt)$ https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/$1 [R,L]
+        RewriteRule ^/replication/((minute|hour|day)/\d{3}/\d{3}/\d{3}\.osc\.gz)$    https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/$1 [R,L]
+
+        # Redirect changeset replication files to AWS S3 eu-central-1 bucket
+        RewriteRule ^/replication/changesets/(state\.yaml)$                   https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/changesets/replication/minute/$1 [R,L]
+        RewriteRule ^/replication/changesets/(\d{3}/\d{3}/\d{3}\.state\.txt)$ https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/changesets/replication/minute/$1 [R,L]
+        RewriteRule ^/replication/changesets/(\d{3}/\d{3}/\d{3}\.osm\.gz)$    https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/changesets/replication/minute/$1 [R,L]
+
+        # Set ENV:REGION to AWS region closest to the user
+        RewriteRule .* - [E=REGION:${ip2region:%{REMOTE_ADDR}|eu-central-1}]
+
+        <% start_year = 2008 %>
+        <% current_year = Time.now.year %>
+        <% (start_year..current_year).each do |year| %>
+        <% year_two = sprintf('%02d', year % 100) %>
+        RewriteRule ^/pbf/(planet\-<%= year_two %>[0-1][0-9][0-3][0-9]\.osm\.pbf(\.torrent|\.md5)?)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/planet/pbf/<%= year %>/$1 [R,L]
+        RewriteRule ^/pbf/full\-history/(history\-<%= year_two %>[0-1][0-9][0-3][0-9]\.osm\.pbf(\.torrent|\.md5)?)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/planet-full-history/pbf/<%= year %>/$1 [R,L]
+        RewriteRule ^/planet/<%= year %>/(planet\-<%= year_two %>[0-1][0-9][0-3][0-9]\.osm\.bz2(\.torrent|\.md5)?)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/planet/osm/<%= year %>/$1 [R,L]
+        RewriteRule ^/planet/<%= year %>/(changesets\-<%= year_two %>[0-1][0-9][0-3][0-9]\.osm\.bz2(\.torrent|\.md5)?)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/changesets/osm/<%= year %>/$1 [R,L]
+        RewriteRule ^/planet/<%= year %>/(discussions\-<%= year_two %>[0-1][0-9][0-3][0-9]\.osm\.bz2(\.torrent|\.md5)?)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/discussions/osm/<%= year %>/$1 [R,L]
+        RewriteRule ^/planet/full\-history/<%= year %>/(history\-<%= year_two %>[0-1][0-9][0-3][0-9]\.osm\.bz2(\.torrent|\.md5)?)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/planet-full-history/osm/<%= year %>/$1 [R,L]
+        RewriteRule ^/notes/<%= year %>/(planet\-notes\-<%= year_two %>[0-1][0-9][0-3][0-9]\.osn\.bz2(\.md5)?)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/notes/osn/<%= year %>/$1 [R,L]
+        RewriteRule ^/tile_logs/(hosts\-<%= year %>\-[01][0-9]\-[0-3][0-9]\.csv)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/tile_logs/standard_layer/hosts/<%= year %>/$1 [R,L]
+        RewriteRule ^/tile_logs/(countries\-<%= year %>\-[01][0-9]\-[0-3][0-9]\.csv)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/tile_logs/standard_layer/countries/<%= year %>/$1 [R,L]
+        RewriteRule ^/tile_logs/(apps\-<%= year %>\-[01][0-9]\-[0-3][0-9]\.csv)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/tile_logs/standard_layer/apps/<%= year %>/$1 [R,L]
+        RewriteRule ^/tile_logs/(tiles\-<%= year %>\-[01][0-9]\-[0-3][0-9]\.txt\.xz)$ https://osm-planet-%{ENV:REGION}.s3.dualstack.%{ENV:REGION}.amazonaws.com/tile_logs/standard_layer/tiles/<%= year %>/$1 [R,L]
+        <% end %>
 </VirtualHost>
 
 <VirtualHost *:80>
@@ -71,7 +93,7 @@
         ServerAlias planet.osm.org
         ServerAdmin webmaster@openstreetmap.org
 
-        CustomLog /var/log/apache2/planet.openstreetmap.org-access.log combined
+        CustomLog /var/log/apache2/planet.openstreetmap.org-access.log combined_extended
         ErrorLog /var/log/apache2/planet.openstreetmap.org-error.log
 
         RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
diff --git a/cookbooks/planet/templates/default/aws-config.erb b/cookbooks/planet/templates/default/aws-config.erb
new file mode 100644 (file)
index 0000000..a499431
--- /dev/null
@@ -0,0 +1,17 @@
+[profile osm-pds]
+region = eu-central-1
+
+[profile osm-pds-upload]
+region = eu-central-1
+s3 =
+    max_bandwidth = 150MB/s
+    max_concurrent_requests = 256
+
+[profile osm-osmdbt-state]
+region = eu-west-1
+
+[profile osm-osmdbt-state-upload]
+region = eu-west-1
+s3 =
+    max_bandwidth = 100MB/s
+    max_concurrent_requests = 256
diff --git a/cookbooks/planet/templates/default/aws-credentials.erb b/cookbooks/planet/templates/default/aws-credentials.erb
new file mode 100644 (file)
index 0000000..2475b9a
--- /dev/null
@@ -0,0 +1,15 @@
+[osm-pds]
+aws_access_key_id = AKIAZFVRMSDZE2DANIFS
+aws_secret_access_key = <%= @credentials["osm-pds"] %>
+
+[osm-pds-upload]
+role_arn=arn:aws:iam::630658470130:role/osm-pds-upload-role
+source_profile=osm-pds
+
+[osm-osmdbt-state]
+aws_access_key_id = AKIASQUXHPE7BNEKJFRQ
+aws_secret_access_key = <%= @credentials["osm-osmdbt-state"] %>
+
+[osm-osmdbt-state-upload]
+role_arn=arn:aws:iam::173189593406:role/osm-osmdbt-state-upload-role
+source_profile=osm-osmdbt-state
index 309f253b49638720077e3f01bfba988567a8fd1c..752b2156635ef7591a3aa9551561b0f328e646b7 100644 (file)
@@ -1,3 +1,5 @@
 state_file: /store/planet/replication/changesets/state.yaml
 db: host=<%= node[:web][:database_host] %> dbname=openstreetmap user=planetdiff password=<%= @password %>
 data_dir: /store/planet/replication/changesets
+s3_dir: s3://osm-planet-eu-central-1/changesets/replication/minute
+lock_file: /run/replication/changesets.lock
diff --git a/cookbooks/planet/templates/default/old-planet-file-cleanup.cron.erb b/cookbooks/planet/templates/default/old-planet-file-cleanup.cron.erb
deleted file mode 100644 (file)
index 4c880b4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-MAILTO=zerebubuth@gmail.com
-# run this on the first monday of the month at 3:44am
-44 3 1-7 * * www-data test $(date +\%u) -eq 1 && /usr/local/bin/old-planet-file-cleanup --debug
diff --git a/cookbooks/planet/templates/default/planet-dump-mirror-cron.erb b/cookbooks/planet/templates/default/planet-dump-mirror-cron.erb
deleted file mode 100644 (file)
index 3feec3f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-MAILTO=horntail-www-data-cron@firefishy.com
-20 */2 * * * www-data /usr/local/bin/planet-mirror-redirect-update
diff --git a/cookbooks/planet/templates/default/planet-mirror-redirect-update.erb b/cookbooks/planet/templates/default/planet-mirror-redirect-update.erb
deleted file mode 100644 (file)
index 81c9f2a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/php
-<?php
-/*
-       DO NOT EDIT - This file is being maintained by Chef
-
-       planet-mirror-redirect
-       Check if planet file exists on mirror and link if not yet linked
-       Modifies .htaccess
-*/
-$_YEAR = date('Y');
-$_PLANET_FOLDER = '<%= node[:planet][:dump][:xml_directory] %>/'.$_YEAR.'/';
-$_PLANET_REGEX = "/^(planet|changesets)\-\d{6}(\-nolt)?\.osm\.(bz2|gz)$/";
-$_MIRROR = 'https://ftp5.gwdg.de/pub/misc/openstreetmap/planet.openstreetmap.org/planet/'.$_YEAR.'/';
-$_PLANET_HTACCESS = realpath('<%= node[:planet][:dump][:xml_directory] %>/..').'/.htaccess';
-
-function _MIRROR_FILE_SIZE($url) {
-       $ch = @curl_init();
-       curl_setopt($ch, CURLOPT_URL, $url);
-       curl_setopt($ch, CURLOPT_NOBODY, TRUE);
-       curl_setopt($ch, CURLOPT_VERBOSE, FALSE);
-       $curl_response = @curl_exec($ch);
-       $curl_result = curl_getinfo($ch);
-       if ($curl_result['http_code']!='200') return FALSE;
-       return ($curl_result['download_content_length']);
-}
-
-if (!is_writable($_PLANET_HTACCESS)) die('File '.$_PLANET_HTACCESS.' is not writable by current user.'."\n");
-
-if (is_dir($_PLANET_FOLDER)) {
-       $htaccess_contents = file_get_contents($_PLANET_HTACCESS);
-       $htaccess_handle = fopen($_PLANET_HTACCESS, 'a');
-       if ($dh = opendir($_PLANET_FOLDER)) {
-               while (($file = readdir($dh)) !== false ) {
-                       if (preg_match($_PLANET_REGEX,$file)) {
-                               $file_slashed = 'planet/'.$_YEAR.'/'.str_replace(array('.','-'), array('\.','\-'), $file);
-                               if (strpos($htaccess_contents,$file_slashed) === false) {
-                                       $file_size = filesize($_PLANET_FOLDER.$file);
-                                       sleep(rand(2,5));
-                                       $file_mirror_size = _MIRROR_FILE_SIZE($_MIRROR.$file);
-                                       if ($file_size==$file_mirror_size) {
-                                                       echo 'Adding: '.$file."\n";
-                                                       fwrite($htaccess_handle,        'RewriteRule'."\t".
-                                                                                       '^('.$file_slashed.')$'."\t".
-                                                                                       'https://ftp5.gwdg.de/pub/misc/openstreetmap/planet.openstreetmap.org/$1'."\t".
-                                                                                       '[R,L]'."\n");
-                                       }
-                               }
-                       }
-               }
-               closedir($dh);
-               fclose($htaccess_handle);
-       }
-}
diff --git a/cookbooks/planet/templates/default/planet-notes-cleanup.erb b/cookbooks/planet/templates/default/planet-notes-cleanup.erb
new file mode 100644 (file)
index 0000000..6c248c2
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+exec find /store/planet/notes/20?? -maxdepth 1 -type f -iname 'planet-notes-??????.osn*' -printf '%T@ %p\n' | \
+  sort -k 1nr | \
+  sed 's/^[^ ]* //' | \
+  tail -n +17 | \
+  xargs -r rm -f
diff --git a/cookbooks/planet/templates/default/planet-notes-dump.cron.erb b/cookbooks/planet/templates/default/planet-notes-dump.cron.erb
deleted file mode 100644 (file)
index 3c5709a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-MAILTO=grant-smaug@firefishy.com
-0 3 * * * www-data /usr/local/bin/planet-notes-dump
-
-#Delete Planet Notes dump files older than 8 days
-10 8 * * * www-data find /store/planet/notes/20??/ -maxdepth 1 -type f -iname 'planet-notes-??????.osn*' -printf '\%T@ \%p\n' | sort -k 1nr | sed 's/^[^ ]* //' | tail -n +17 | xargs -r rm -f
index 92ca8b3758ec1313c4f366a515c14d77d5c8b105..ebfb9db13bfa3256a54088cb24edb26499a0f595 100644 (file)
@@ -17,43 +17,45 @@ fi
 echo $$ > /tmp/planet-notes-dump.lock
 
 
-cur_date=`date +%y%m%d`
-cur_year=`date +%Y`
-cur_planet_notes=planet-notes-${cur_date}.osn
+cur_date=$(date +%y%m%d)
+cur_year=$(date +%Y)
+cur_planet_notes="planet-notes-${cur_date}.osn"
 planet_dir=/store/planet/
 
 export PATH='/usr/local/bin:/usr/bin:/bin:/usr/bin/X11'
 
 
-if [ \! -d ${planet_dir}/notes/ ]
+if [ \! -d "${planet_dir}/notes/" ]
        then
-               echo ${planet_dir}notes/ does not exist
+               echo "${planet_dir}notes/ does not exist"
                exit 1
        fi
-if [ \! -d ${planet_dir}/notes/${cur_year}/ ]; then mkdir ${planet_dir}/notes/${cur_year}/; fi
-cd ${planet_dir}/notes/${cur_year}/
+if [ \! -d "${planet_dir}/notes/${cur_year}/" ]; then mkdir "${planet_dir}/notes/${cur_year}/"; fi
+cd "${planet_dir}/notes/${cur_year}/"
 
-/usr/bin/python /opt/planet-notes-dump/dump.py --quiet --database openstreetmap --host <%= node[:web][:readonly_database_host] %> --user planetdump --password '<%= @password %>' .${cur_planet_notes}
-pbzip2 -p6 -9 .${cur_planet_notes}
+/usr/bin/python3 /opt/planet-notes-dump/dump.py --quiet --database openstreetmap --host <%= node[:web][:readonly_database_host] %> --user planetdump --password '<%= @password %>' ".${cur_planet_notes}"
+pbzip2 -p6 -9 ".${cur_planet_notes}"
 
-planet_notes_size=$(du -sb .${cur_planet_notes}.bz2 | awk '{ print $1 }')
+planet_notes_size=$(du -sb ".${cur_planet_notes}.bz2" | awk '{ print $1 }')
 if ((planet_notes_size<12000000)); then
-       echo Planet .${cur_planet_notes}.bz2 too small
+       echo "Planet .${cur_planet_notes}.bz2 too small"
        exit 1
 fi
 
-mv .${cur_planet_notes}.bz2 ${cur_planet_notes}.bz2
-md5sum ${cur_planet_notes}.bz2 > ${cur_planet_notes}.bz2.md5
+mv ".${cur_planet_notes}.bz2" "${cur_planet_notes}.bz2"
+md5sum "${cur_planet_notes}.bz2" > "${cur_planet_notes}.bz2.md5"
 
 #link planet latest to the new file
-cd ${planet_dir}/notes/
+cd "${planet_dir}/notes/"
 
-ln -fs ${cur_year}/${cur_planet_notes}.bz2 planet-notes-latest.osn.bz2
+ln -fs "${cur_year}/${cur_planet_notes}.bz2" planet-notes-latest.osn.bz2
 
 # mangle md5 files for 'latest' ones
 rm -f planet-notes-latest.osn.bz2.md5
 
-sed -e "s/${cur_planet_notes}.bz2/planet-notes-latest.osn.bz2/" ${cur_year}/${cur_planet_notes}.bz2.md5 > planet-notes-latest.osn.bz2.md5
+sed -e "s/${cur_planet_notes}.bz2/planet-notes-latest.osn.bz2/" "${cur_year}/${cur_planet_notes}.bz2.md5" > planet-notes-latest.osn.bz2.md5
 
-rm /tmp/planet-notes-dump.lock
+/opt/awscli/v2/current/bin/aws --profile osm-pds-upload s3 cp --storage-class INTELLIGENT_TIERING  --no-progress "${cur_year}/${cur_planet_notes}.bz2.md5" "s3://osm-planet-eu-central-1/notes/osn/${cur_year}/${cur_planet_notes}.bz2.md5"
+/opt/awscli/v2/current/bin/aws --profile osm-pds-upload s3 cp --storage-class INTELLIGENT_TIERING  --no-progress "${cur_year}/${cur_planet_notes}.bz2" "s3://osm-planet-eu-central-1/notes/osn/${cur_year}/${cur_planet_notes}.bz2"
 
+rm /tmp/planet-notes-dump.lock
diff --git a/cookbooks/planet/templates/default/planet-update-file.erb b/cookbooks/planet/templates/default/planet-update-file.erb
deleted file mode 100644 (file)
index 36786e2..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-# setup
-
-PLANETDIR="/var/lib/planet"
-PLANETPREV="${PLANETDIR}/planet-previous.pbf"
-PLANETCURR="${PLANETDIR}/planet.pbf"
-PLANETNEW="${PLANETDIR}/planet-new.pbf"
-PLANETTMP="${PLANETDIR}/planet-tmp.pbf"
-
-pyosmium-up-to-date -v -o "$PLANETNEW" "$PLANETCURR"
-retval=$?
-
-while [ $retval -eq 1 ]; do
-    mv "$PLANETNEW" "$PLANETTMP"
-    pyosmium-up-to-date -v -o "$PLANETNEW" "$PLANETTMP"
-    retval=$?
-    rm "$PLANETTMP"
-done
-
-if [ $retval -ne 0 ]; then
-    exit $retval
-fi
-
-# cleanup
-
-mv "$PLANETCURR" "$PLANETPREV"
-mv "$PLANETNEW" "$PLANETCURR"
diff --git a/cookbooks/planet/templates/default/planet-update.cron.erb b/cookbooks/planet/templates/default/planet-update.cron.erb
deleted file mode 100644 (file)
index 5a9f6f7..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-17 1 * * * root /usr/local/bin/planet-update
index 3f6f0a6db62930544311fceecebb8ea5982ebe4e..73a778bbaaa812c9bd33455683f0e05b0b41d3d7 100644 (file)
@@ -2,18 +2,30 @@
 
 # DO NOT EDIT - This file is being maintained by Chef
 
-exec > /var/log/planet-update.log 2>&1
+# setup
 
-echo "Updating planet file..."
+SUFFIX="osh.pbf"
 
-/sbin/runuser -u planet -- /usr/local/bin/planet-update-file
+PLANETDIR="/var/lib/planet"
+PLANETPREV="${PLANETDIR}/planet-previous.${SUFFIX}"
+PLANETCURR="${PLANETDIR}/planet.${SUFFIX}"
+PLANETNEW="${PLANETDIR}/planet-new.${SUFFIX}"
 
-echo "Running jobs..."
-<% node[:planet][:current][:jobs].each_value do |job| -%>
+pyosmium-up-to-date -vvv -o "$PLANETNEW" "$PLANETCURR"
+retval=$?
 
-echo "Running '<%= job[:command] %>' as user '<%= job[:user] %>'..."
+while [ $retval -eq 1 ]; do
+    mv "$PLANETCURR" "$PLANETPREV"
+    mv "$PLANETNEW" "$PLANETCURR"
+    pyosmium-up-to-date -vvv -o "$PLANETNEW" "$PLANETCURR"
+    retval=$?
+done
 
-/sbin/runuser -u "<%= job[:user] %>" -- "<%= job[:command] %>"
-<% end -%>
+if [ $retval -ne 0 ]; then
+    exit $retval
+fi
 
-echo "Done."
+# cleanup
+
+mv "$PLANETCURR" "$PLANETPREV"
+mv "$PLANETNEW" "$PLANETCURR"
diff --git a/cookbooks/planet/templates/default/planet-update.logrotate.erb b/cookbooks/planet/templates/default/planet-update.logrotate.erb
deleted file mode 100644 (file)
index a3ca8ac..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/var/log/planet-update.log {
-       compress
-       notifempty
-       missingok
-}
diff --git a/cookbooks/planet/templates/default/planetdump-trigger.erb b/cookbooks/planet/templates/default/planetdump-trigger.erb
new file mode 100644 (file)
index 0000000..b24197f
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+inotifywait --quiet --monitor --event CREATE --event MOVED_TO --include "/osm-[0-9]{4}-[0-9]{2}-[0-9]{2}\\.dmp\$" --format %f /store/backup | \
+  xargs -I %file% systemctl start planetdump@%file%.service
index 15a0051910152841cb635e898e8e7294b5e4d111..5c0d380459d76a25d4a9107504c1addcbc1d2073 100644 (file)
@@ -26,13 +26,6 @@ if [ -f /tmp/planetdump.lock ]; then
     fi
 fi
 
-# Redirect this shell's output to a file. This is so that it
-# can be emailed later, since this script is run from incron
-# and incron doesn't yet support MAILTO like cron does. The
-# command below appears to work in bash as well as dash.
-logfile="/tmp/planetdump.log.$$"
-exec > "${logfile}" 2>&1
-
 # Create lock file
 echo $$ > /tmp/planetdump.lock
 
@@ -40,16 +33,6 @@ echo $$ > /tmp/planetdump.lock
 function cleanup {
     # Remove the lock file
     rm /tmp/planetdump.lock
-
-    # Send an email with the output, since incron doesn't yet
-    # support doing this in the incrontab
-    if [[ -s "$logfile" ]]
-    then
-        mailx -s "Planet dump output: ${file}" zerebubuth@gmail.com < "${logfile}"
-    fi
-
-    # Remove the log file
-    rm -f "${logfile}"
 }
 
 # Remove lock on exit
@@ -67,36 +50,155 @@ rm -rf relations relation_tags relation_members
 
 # Run the dump
 time nice -n 19 /opt/planet-dump-ng/planet-dump-ng \
+     --max-concurrency=4 \
      -c "pbzip2 -c" -f "/store/backup/${file}" --dense-nodes=1 \
      -C "changesets-${date}.osm.bz2" \
      -D "discussions-${date}.osm.bz2" \
      -x "planet-${date}.osm.bz2" -X "history-${date}.osm.bz2" \
      -p "planet-${date}.osm.pbf" -P "history-${date}.osm.pbf"
 
+# Function to create bittorrent files
+function mk_torrent {
+  local type="$1"
+  local format="$2"
+  local dir="$3"
+  local s3path="$4"
+  local s_year="$5"
+  local web_dir="${dir}${s_year}"
+  local name="${type}-${date}.osm.${format}"
+  local web_path="${web_dir}/${name}"
+  local s3_web_path="${s3path}/${name}"
+  local rss_web_dir="https://planet.openstreetmap.org/${dir}"
+  local rss_file="${type}-${format}-rss.xml"
+  local torrent_file="${name}.torrent"
+  local torrent_url="${rss_web_dir}${s_year}/${torrent_file}"
+
+  # create .torrent file
+  mktorrent -l 22 "${name}" \
+     -a udp://tracker.opentrackr.org:1337 \
+     -a udp://tracker.datacenterlight.ch:6969/announce,http://tracker.datacenterlight.ch:6969/announce \
+     -a udp://tracker.torrent.eu.org:451 \
+     -a udp://tracker-udp.gbitt.info:80/announce,http://tracker.gbitt.info/announce,https://tracker.gbitt.info/announce \
+     -a http://retracker.local/announce \
+     -w "https://planet.openstreetmap.org/${web_path}" \
+     -w "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/${s3_web_path}" \
+     -w "https://osm-planet-us-west-2.s3.dualstack.us-west-2.amazonaws.com/${s3_web_path}" \
+     -w "https://ftp5.gwdg.de/pub/misc/openstreetmap/planet.openstreetmap.org/${web_path}" \
+     -w "https://ftpmirror.your.org/pub/openstreetmap/${web_path}" \
+     -w "https://mirror.init7.net/openstreetmap/${web_path}" \
+     -w "https://ftp.fau.de/osm-planet/${web_path}" \
+     -w "https://ftp.spline.de/pub/openstreetmap/${web_path}" \
+     -w "https://downloads.opencagedata.com/planet/${name}" \
+     -w "https://planet.osm-hr.org/${web_path}" \
+     -w "https://planet.maps.mail.ru/${web_path}" \
+     -c "OpenStreetMap ${type} data export, licensed under https://opendatacommons.org/licenses/odbl/ by OpenStreetMap contributors" \
+     -o "${torrent_file}" > /dev/null
+
+  # create .xml global RSS headers if missing
+  torrent_time_rfc="$(date -R -r ${torrent_file})"
+  test -f "${rss_file}" || echo "<x/>" | xmlstarlet select --xml-decl --indent \
+       -N "atom=http://www.w3.org/2005/Atom" \
+       -N "dcterms=http://purl.org/dc/terms/" \
+       -N "content=http://purl.org/rss/1.0/modules/content/" \
+       --encode "UTF-8" \
+       --template \
+       --match / \
+       --elem "rss" \
+               --attr "version" --output "2.0" --break \
+               --attr "atom:DUMMY" --break \
+       --elem "channel" \
+       --elem "title" --output "OpenStreetMap ${type} ${format} torrent RSS" --break \
+       --elem "link"  --output "${rss_web_dir}" --break \
+       --elem "atom:link" \
+               --attr "href" --output "${rss_web_dir}/${rss_file}" --break \
+               --attr "rel" --output "self" --break \
+               --attr "type" --output "application/rss+xml" --break \
+               --break \
+       --elem "description" --output "${type}.osm.${format}.torrent RSS feed" --break \
+       --elem "copyright" --output "Source: OpenStreetMap contributors, under ODbL 1.0 licence" --break \
+       --elem "generator" --output "OpenStreetMap xmlstarlet powered shell script v1.0" --break \
+       --elem "language" --output "en" --break \
+       --elem "lastBuildDate" --output "${torrent_time_rfc}" \
+       > "${rss_file}"
+
+  # add newly created .torrent file as new entry to .xml RSS feed, removing excess entries
+  torrent_size="$(stat --format="%s" ${torrent_file})"
+  xmlstarlet edit --inplace \
+       -a "//lastBuildDate" -t elem -n item -v ""  \
+       -s "//item[1]" -t elem -n "title" -v "${torrent_file}" \
+       -s "//item[1]" -t elem -n "guid" -v "${torrent_url}" \
+       -s "//item[1]" -t elem -n "link" -v "${torrent_url}" \
+       -s "//item[1]" -t elem -n "pubDate" -v "${torrent_time_rfc}" \
+       -s "//item[1]" -t elem -n "category" -v "OpenStreetMap data" \
+       -s "//item[1]" -t elem -n "enclosure" \
+               -s "//item[1]"/enclosure -t attr -n "type" -v "application/x-bittorrent" \
+               -s "//item[1]"/enclosure -t attr -n "length" -v "${torrent_size}" \
+               -s "//item[1]"/enclosure -t attr -n "url" -v "${torrent_url}" \
+       -s "//item[1]" -t elem -n "description" -v "OpenStreetMap torrent ${torrent_file}" \
+       -u /rss/channel/lastBuildDate -v "${torrent_time_rfc}" \
+       -d /rss/@atom:DUMMY \
+       -d "//item[position()>5]" \
+       "${rss_file}"
+}
+
+function replication_status_wait {
+  local s3_url="$1"
+  for i in {1..3600}; do
+    local replication_status=$(curl -sI --location "${s3_url}" | grep -F 'x-amz-replication-status' | awk '{print $2}' |  tr -d '\r' )
+
+    if [[ "${replication_status}" == "COMPLETED" ]]; then
+      return 0 # success
+    fi
+
+    sleep 1
+  done
+  echo "Timeout waiting for ${s3_url} to complete replication status: ${replication_status}"
+}
+
 # Function to install a dump in place
 function install_dump {
-  type="$1"
-  format="$2"
-  dir="$3"
-  year="$4"
-  name="${type}-${date}.osm.${format}"
-  latest="${type}-latest.osm.${format}"
+  local type="$1"
+  local format="$2"
+  local dir="$3"
+  local s3dir="$4"
+  local year="$5"
+  local name="${type}-${date}.osm.${format}"
+  local latest="${type}-latest.osm.${format}"
+  local rss_file="${type}-${format}-rss.xml"
 
   md5sum "${name}" > "${name}.md5"
+
+  # Upload all files to S3
+  /opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "${name}.md5" "s3://osm-planet-eu-central-1/${s3dir}/${name}.md5"
+  /opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "${name}.torrent" "s3://osm-planet-eu-central-1/${s3dir}/${name}.torrent"
+  /opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "${name}" "s3://osm-planet-eu-central-1/${s3dir}/${name}"
+
+  # Waiting for S3 replication to complete
+  replication_status_wait "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/${s3dir}/${name}.md5"
+  replication_status_wait "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/${s3dir}/${name}.torrent"
+  replication_status_wait "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/${s3dir}/${name}"
+
   mkdir -p "${dir}/${year}"
   mv "${name}" "${name}.md5" "${dir}/${year}"
   ln -sf "${year:-.}/${name}" "${dir}/${latest}"
+  test -f "${name}.torrent" && mv "${name}.torrent" "${dir}/${year}" && ln -sf "${year:-.}/${name}.torrent" "${dir}/${latest}.torrent"
+  test -f "${rss_file}" && xmllint --noout "${rss_file}" && cp -f "${rss_file}" "${dir}"
   rm -f "${dir}/${latest}.md5"
   sed -e "s/${name}/${latest}/" "${dir}/${year}/${name}.md5" > "${dir}/${latest}.md5"
 }
 
+# Create *.torrent files
+mk_torrent "changesets" "bz2" "planet" "changesets/osm/${year}" "/${year}"
+mk_torrent "discussions" "bz2" "planet" "discussions/osm/${year}" "/${year}"
+mk_torrent "planet" "bz2" "planet" "planet/osm/${year}" "/${year}"
+mk_torrent "history" "bz2" "planet/full-history" "planet-full-history/osm/${year}" "/${year}"
+mk_torrent "planet" "pbf" "pbf" "planet/pbf/${year}"
+mk_torrent "history" "pbf" "pbf/full-history" "planet-full-history/pbf/${year}"
+
 # Move dumps into place
-install_dump "changesets" "bz2" "<%= node[:planet][:dump][:xml_directory] %>" "${year}"
-install_dump "discussions" "bz2" "<%= node[:planet][:dump][:xml_directory] %>" "${year}"
-install_dump "planet" "bz2" "<%= node[:planet][:dump][:xml_directory] %>" "${year}"
-install_dump "history" "bz2" "<%= node[:planet][:dump][:xml_history_directory] %>" "${year}"
-install_dump "planet" "pbf" "<%= node[:planet][:dump][:pbf_directory] %>"
-install_dump "history" "pbf" "<%= node[:planet][:dump][:pbf_history_directory] %>"
-
-# Remove pbf dumps older than 90 days
-find "<%= node[:planet][:dump][:pbf_directory] %>" "<%= node[:planet][:dump][:pbf_history_directory] %>" -maxdepth 1 -mindepth 1 -type f -mtime +90 \( -iname 'planet-*.pbf' -o -iname 'history-*.pbf' -o -iname 'planet-*.pbf.md5' -o -iname 'history-*.pbf.md5' \) -delete
+install_dump "changesets" "bz2" "<%= node[:planet][:dump][:xml_directory] %>" "changesets/osm/${year}" "${year}"
+install_dump "discussions" "bz2" "<%= node[:planet][:dump][:xml_directory] %>" "discussions/osm/${year}" "${year}"
+install_dump "planet" "bz2" "<%= node[:planet][:dump][:xml_directory] %>" "planet/osm/${year}" "${year}"
+install_dump "history" "bz2" "<%= node[:planet][:dump][:xml_history_directory] %>" "planet-full-history/osm/${year}" "${year}"
+install_dump "planet" "pbf" "<%= node[:planet][:dump][:pbf_directory] %>" "planet/pbf/${year}"
+install_dump "history" "pbf" "<%= node[:planet][:dump][:pbf_history_directory] %>" "planet-full-history/pbf/${year}"
diff --git a/cookbooks/planet/templates/default/replication.cron.erb b/cookbooks/planet/templates/default/replication.cron.erb
deleted file mode 100644 (file)
index 0ccffdd..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-TZ=UTC
-
-MAILTO=zerebubuth@gmail.com
-
-0 7 * * * planet /usr/local/bin/users-agreed
-0 17 * * * planet /usr/local/bin/users-deleted
-* * * * * planet /usr/local/bin/replicate-changesets /etc/replication/changesets.conf
-
-MAILTO=brett@bretth.com
-LD_PRELOAD=/opt/flush/flush.so
-
-* * * * * planet /usr/local/bin/osmosis -q --replicate-apidb authFile=/etc/replication/auth.conf validateSchemaVersion=false --write-replication workingDirectory=/store/planet/replication/minute
-2,7,12,17 * * * * planet /home/bretth/bin/osmosis -q --merge-replication-files workingDirectory=/var/lib/replication/hour
-5,10,15,20 * * * * planet /home/bretth/bin/osmosis -q --merge-replication-files workingDirectory=/var/lib/replication/day
diff --git a/cookbooks/planet/templates/default/streaming.init.erb b/cookbooks/planet/templates/default/streaming.init.erb
deleted file mode 100644 (file)
index 85ed3ef..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-start() {
-  start-stop-daemon --start --chuid planet --background --make-pidfile --pidfile /var/run/<%= @service %>.pid --exec /usr/local/bin/<%= @service %>
-}
-
-stop() {
-  start-stop-daemon --stop --retry 300 --pidfile /var/run/<%= @service %>.pid
-}
-
-status() {
-  start-stop-daemon --status --pidfile /var/run/<%= @service %>.pid
-}
-
-case "$1" in
-  start)
-    start
-    ;;
-  stop)
-    stop
-    ;;
-  restart)
-    stop || exit $?
-    start
-    ;;
-  status)
-    status
-    ;;
-esac
index 707a65bfd94cd955d17a98b0cbbcdad21ee7401d..f88800a6160487db62ff0f80b4122c31bf41aff6 100644 (file)
@@ -6,22 +6,22 @@ T=$(mktemp -d -t -p /var/tmp users.XXXXXXXXXX)
 
 export PGPASSFILE=/etc/replication/users-agreed.conf
 
-echo "# user IDs < 286582 who have agreed to the contributor terms. " > $T/users_agreed
-echo "# any active user IDs >= 286582 would have agreed as part of the sign-up process." >> $T/users_agreed
-psql -h <%= node[:web][:readonly_database_host] %> -U planetdiff -t -c "select id from users where id < 286582 and terms_agreed is not null order by id asc" openstreetmap >> $T/users_agreed
+echo "# user IDs < 286582 who have agreed to the contributor terms. " > "$T/users_agreed"
+echo "# any active user IDs >= 286582 would have agreed as part of the sign-up process." >> "$T/users_agreed"
+psql -h <%= node[:web][:readonly_database_host] %> -U planetdiff -t -c "select id from users where id < 286582 and terms_agreed is not null order by id asc" openstreetmap >> "$T/users_agreed"
 
-psql -h <%= node[:web][:readonly_database_host] %> -U planetdiff -t -c "select id from users where terms_seen and terms_agreed is null order by id asc" openstreetmap > $T/users_disagreed
+psql -h <%= node[:web][:readonly_database_host] %> -U planetdiff -t -c "select id from users where terms_seen and terms_agreed is null order by id asc" openstreetmap > "$T/users_disagreed"
 
 if cmp -s "${T}/users_agreed" "/store/planet/users_agreed/users_agreed.txt"; then
   : # do nothing
 else
-  cp $T/users_agreed /store/planet/users_agreed/users_agreed.txt
+  cp "$T/users_agreed" /store/planet/users_agreed/users_agreed.txt
 fi
 
 if cmp -s "${T}/users_disagreed" "/store/planet/users_agreed/users_disagreed.txt"; then
   : #  do nothing
 else
-  cp $T/users_disagreed /store/planet/users_agreed/users_disagreed.txt
+  cp "$T/users_disagreed" /store/planet/users_agreed/users_disagreed.txt
 fi
 
-rm -rf $T
+rm -rf "$T"
diff --git a/cookbooks/podman/attributes/default.rb b/cookbooks/podman/attributes/default.rb
new file mode 100644 (file)
index 0000000..0d4f407
--- /dev/null
@@ -0,0 +1 @@
+default[:podman][:ports] = {}
similarity index 66%
rename from cookbooks/squid/metadata.rb
rename to cookbooks/podman/metadata.rb
index 6f9dcc7239acad363cdf43598a515873cef500a2..d44ad30bdd3ef9af6ca6dd90b33b14aac43e6a05 100644 (file)
@@ -1,9 +1,10 @@
-name              "squid"
+name              "podman"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures squid"
+description       "Installs and configures podman"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "apache"
 depends           "systemd"
diff --git a/cookbooks/podman/recipes/apache.rb b/cookbooks/podman/recipes/apache.rb
new file mode 100644 (file)
index 0000000..b63bfe4
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Cookbook:: podman
+# Recipe:: apache
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "podman"
+include_recipe "apache"
+
+apache_module "proxy_http"
diff --git a/cookbooks/podman/recipes/default.rb b/cookbooks/podman/recipes/default.rb
new file mode 100644 (file)
index 0000000..b29769c
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# Cookbook:: podman
+# Recipe:: default
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+package %w[
+  podman
+  slirp4netns
+  uidmap
+  fuse-overlayfs
+]
+
+ruby_block "subuid-containers" do
+  block do
+    File.open("/etc/subuid", "a") do |file|
+      file.puts("containers:2147483647:2147483648")
+    end
+  end
+  not_if "grep -q '^containers:' /etc/subuid"
+end
+
+ruby_block "subgid-containers" do
+  block do
+    File.open("/etc/subgid", "a") do |file|
+      file.puts("containers:2147483647:2147483648")
+    end
+  end
+  not_if "grep -q '^containers:' /etc/subgid"
+end
+
+systemd_timer "podman-auto-update-frequency" do
+  timer "podman-auto-update"
+  dropin "frequency"
+  on_boot_sec "5m"
+  on_unit_inactive_sec "20m"
+  randomized_delay_sec "5m"
+end
+
+service "podman-auto-update.timer" do
+  action [:enable, :start]
+end
diff --git a/cookbooks/podman/resources/service.rb b/cookbooks/podman/resources/service.rb
new file mode 100644 (file)
index 0000000..5b64f78
--- /dev/null
@@ -0,0 +1,90 @@
+#
+# Cookbook:: podman
+# Resource:: podman_service
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unified_mode true
+
+default_action :create
+
+property :service, String, :name_property => true
+property :description, String, :required => true
+property :image, String, :required => true
+property :ports, Hash
+property :environment, Hash, :default => {}
+property :volume, Hash, :default => {}
+
+action :create do
+  systemd_service new_resource.service do
+    description new_resource.description
+    type "notify"
+    notify_access "all"
+    environment "PODMAN_SYSTEMD_UNIT" => "%n"
+    exec_start_pre "/bin/rm --force %t/%n.ctr-id"
+    exec_start "/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --userns=auto --label=io.containers.autoupdate=registry --pids-limit=-1 #{publish_options} #{environment_options} #{volume_options} --rm --sdnotify=conmon --detach --replace --name=%N #{new_resource.image}"
+    exec_stop "/usr/bin/podman stop --ignore --time=10 --cidfile=%t/%n.ctr-id"
+    exec_stop_post "/usr/bin/podman rm --force --ignore --cidfile=%t/%n.ctr-id"
+    timeout_start_sec 180
+    timeout_stop_sec 70
+    restart "on-failure"
+  end
+
+  # No action :start here to avoid a start and then immediate :restart, due to subscribe, on first run
+  # FIXME: Ubuntu 22.04 podman/crun bug workaround "retries"
+  service new_resource.service do
+    action :enable
+    subscribes :restart, "systemd_service[#{new_resource.service}]", :immediately
+    retries 4 # Workaround https://github.com/containers/podman/issues/9752
+    retry_delay 5
+  end
+
+  # Ensure the service is started if not running, replies on status of service resource
+  notify_group new_resource.service do
+    action :run
+    notifies :start, "service[#{new_resource.service}]", :immediately
+  end
+end
+
+action :delete do
+  service new_resource.service do
+    action [:disable, :stop]
+  end
+
+  systemd_service new_resource.service do
+    action :delete
+  end
+end
+
+action_class do
+  def publish_options
+    new_resource.ports.collect do |host, guest|
+      "--publish=127.0.0.1:#{host}:#{guest}"
+    end.join(" ")
+  end
+
+  def environment_options
+    new_resource.environment.collect do |key, value|
+      "-e '#{key}=#{value}'"
+    end.join(" ")
+  end
+
+  def volume_options
+    new_resource.volume.collect do |key, value|
+      "-v '#{key}:#{value}'"
+    end.join(" ")
+  end
+end
diff --git a/cookbooks/podman/resources/site.rb b/cookbooks/podman/resources/site.rb
new file mode 100644 (file)
index 0000000..7cab5a5
--- /dev/null
@@ -0,0 +1,93 @@
+#
+# Cookbook:: podman
+# Resource:: podman_site
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "yaml"
+
+unified_mode true
+
+default_action :create
+
+property :site, String, :name_property => true
+property :image, String, :required => true
+property :port, Integer, :default => 8080
+property :aliases, :kind_of => Array, :default => []
+property :environment, Hash, :default => {}
+
+action :create do
+  podman_service new_resource.site do
+    description "Container service for #{new_resource.site}"
+    image new_resource.image
+    ports external_port => new_resource.port
+    environment new_resource.environment
+  end
+
+  ssl_certificate new_resource.site do
+    domains Array(new_resource.site) + new_resource.aliases
+  end
+
+  apache_site new_resource.site do
+    cookbook "podman"
+    template "apache.erb"
+    variables :port => external_port, :aliases => new_resource.aliases
+  end
+end
+
+action :delete do
+  apache_site new_resource.site do
+    action [:disable, :delete]
+  end
+
+  podman_service new_resource.site do
+    action :delete
+  end
+
+  node.rm_normal(:podman, :ports, new_resource.site)
+end
+
+action_class do
+  def ports_file
+    "#{Chef::Config[:file_cache_path]}/podman-ports.yml"
+  end
+
+  def ports
+    @ports ||= if ::File.exist?(ports_file)
+                 YAML.safe_load(::File.read(ports_file))
+               else
+                 {}
+               end
+  end
+
+  def external_port
+    unless ports.include?(new_resource.site)
+      port = 40000
+
+      port += 1 while ports.values.include?(port)
+
+      ports[new_resource.site] = port
+
+      ::File.write(ports_file, YAML.dump(ports))
+    end
+
+    ports[new_resource.site]
+  end
+end
+
+def after_created
+  notifies :reload, "service[apache2]"
+end
similarity index 76%
rename from cookbooks/dmca/templates/default/apache.erb
rename to cookbooks/podman/templates/default/apache.erb
index bf53e2d2e41b4449a0e198ab6a3f8476a61a1911..92ca2f4c5537ca44bd9a37ab7b604cc0275557d4 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
   SSLEngine on
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
   RedirectPermanent / https://<%= @name %>/
 </VirtualHost>
 <% end -%>
   ServerName <%= @name %>
   ServerAdmin webmaster@openstreetmap.org
 
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
   SSLEngine on
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  DocumentRoot <%= @directory %>/html
+  RequestHeader set X-Forwarded-Proto "https"
+  RequestHeader set X-Forwarded-Port "443"
 
-  Options -Indexes
+  ProxyPass / http://localhost:<%= @port %>/
+  ProxyPreserveHost on
 </VirtualHost>
-
-<Directory <%= @directory %>/html>
-  Require all granted
-</Directory>
index b23cd2bc670cb1454339170a298565962fee7922..4aea35d5422e51fb870522a1949afccd894c6d3a 100644 (file)
@@ -6,7 +6,6 @@ defines a number of providers that can be used in other cookbooks:
 * database: For managing databases.
 * execute: For running commands against the database.
 * extension: For installing extensions.
-* munin: For configuring munin plugins for a given database name.
 * table: For managing database tables.
 * user: For managing database users.
 * tablespace: For managing tablespaces.
index dce61724fdf3ee97979813a2e3f26a9b1a8a44ed..aa3e4b8ac503dec270aa25e710f0fe168aa1e5e7 100644 (file)
@@ -1,36 +1,52 @@
 default[:postgresql][:versions] = []
 default[:postgresql][:clusters] = {}
+default[:postgresql][:monitor_database] = "postgres"
+default[:postgresql][:monitor_queries] = false
 default[:postgresql][:settings][:defaults][:port] = "5432"
 default[:postgresql][:settings][:defaults][:max_connections] = "100"
-default[:postgresql][:settings][:defaults][:shared_buffers] = "32MB"
+default[:postgresql][:settings][:defaults][:ssl] = "true"
+default[:postgresql][:settings][:defaults][:shared_buffers] = "128MB"
 default[:postgresql][:settings][:defaults][:temp_buffers] = "8MB"
-default[:postgresql][:settings][:defaults][:work_mem] = "1MB"
-default[:postgresql][:settings][:defaults][:maintenance_work_mem] = "16MB"
+default[:postgresql][:settings][:defaults][:work_mem] = "4MB"
+default[:postgresql][:settings][:defaults][:maintenance_work_mem] = "64MB"
 default[:postgresql][:settings][:defaults][:max_stack_depth] = "2MB"
-default[:postgresql][:settings][:defaults][:effective_io_concurrency] = "1"
-default[:postgresql][:settings][:defaults][:wal_level] = "minimal"
+default[:postgresql][:settings][:defaults][:effective_io_concurrency] = "256"
+default[:postgresql][:settings][:defaults][:max_worker_processes] = "8"
+default[:postgresql][:settings][:defaults][:max_parallel_workers_per_gather] = "2"
+default[:postgresql][:settings][:defaults][:max_parallel_workers] = "8"
+default[:postgresql][:settings][:defaults][:wal_level] = "replica"
 default[:postgresql][:settings][:defaults][:fsync] = "on"
 default[:postgresql][:settings][:defaults][:synchronous_commit] = "on"
 default[:postgresql][:settings][:defaults][:wal_buffers] = "-1"
 default[:postgresql][:settings][:defaults][:wal_writer_delay] = "200ms"
 default[:postgresql][:settings][:defaults][:commit_delay] = "0"
-default[:postgresql][:settings][:defaults][:checkpoint_segments] = "3"
 default[:postgresql][:settings][:defaults][:checkpoint_timeout] = "5min"
+default[:postgresql][:settings][:defaults][:checkpoint_completion_target] = "0.9"
 default[:postgresql][:settings][:defaults][:max_wal_size] = "1GB"
 default[:postgresql][:settings][:defaults][:min_wal_size] = "80MB"
-default[:postgresql][:settings][:defaults][:checkpoint_completion_target] = "0.5"
 default[:postgresql][:settings][:defaults][:archive_mode] = "off"
-default[:postgresql][:settings][:defaults][:max_wal_senders] = "0"
-default[:postgresql][:settings][:defaults][:hot_standby] = "off"
+default[:postgresql][:settings][:defaults][:max_wal_senders] = "10"
+default[:postgresql][:settings][:defaults][:max_replication_slots] = "10"
+default[:postgresql][:settings][:defaults][:wal_keep_size] = "0"
+default[:postgresql][:settings][:defaults][:hot_standby] = "on"
 default[:postgresql][:settings][:defaults][:hot_standby_feedback] = "off"
-default[:postgresql][:settings][:defaults][:random_page_cost] = "4.0"
+default[:postgresql][:settings][:defaults][:seq_page_cost] = "1.0"
+default[:postgresql][:settings][:defaults][:random_page_cost] = "1.1"
 default[:postgresql][:settings][:defaults][:cpu_tuple_cost] = "0.01"
-default[:postgresql][:settings][:defaults][:effective_cache_size] = "128MB"
+default[:postgresql][:settings][:defaults][:effective_cache_size] = "4GB"
+default[:postgresql][:settings][:defaults][:default_statistics_target] = "100"
+default[:postgresql][:settings][:defaults][:jit] = "on"
 default[:postgresql][:settings][:defaults][:log_min_duration_statement] = "-1"
+default[:postgresql][:settings][:defaults][:log_autovacuum_min_duration] = "-1"
 default[:postgresql][:settings][:defaults][:track_activity_query_size] = "1024"
 default[:postgresql][:settings][:defaults][:autovacuum_max_workers] = "3"
+default[:postgresql][:settings][:defaults][:autovacuum_naptime] = "1min"
 default[:postgresql][:settings][:defaults][:autovacuum_vacuum_scale_factor] = "0.2"
 default[:postgresql][:settings][:defaults][:autovacuum_analyze_scale_factor] = "0.1"
+default[:postgresql][:settings][:defaults][:autovacuum_freeze_max_age] = "200000000"
+default[:postgresql][:settings][:defaults][:autovacuum_multixact_freeze_max_age] = "400000000"
+default[:postgresql][:settings][:defaults][:shared_preload_libraries] = []
+default[:postgresql][:settings][:defaults][:max_locks_per_transaction] = "64"
 default[:postgresql][:settings][:defaults][:user_name_maps] = {}
 default[:postgresql][:settings][:defaults][:early_authentication_rules] = []
 default[:postgresql][:settings][:defaults][:late_authentication_rules] = []
index feaa508b9c9ff5bccb5854e5694aba36bfa6085c..1a39da25a146bc6426ee9d694e1cc0f714da989c 100644 (file)
@@ -8,10 +8,18 @@ module OpenStreetMap
       :select, :insert, :update, :delete, :truncate, :references, :trigger
     ].freeze
 
+    SEQUENCE_PRIVILEGES = [
+      :usage, :select, :update
+    ].freeze
+
     def initialize(cluster)
       @cluster = cluster
     end
 
+    def version
+      @cluster.split("/").first.to_f
+    end
+
     def execute(options)
       # Create argument array
       args = []
@@ -68,12 +76,13 @@ module OpenStreetMap
     end
 
     def users
-      @users ||= query("SELECT * FROM pg_user").each_with_object({}) do |user, users|
+      @users ||= query("SELECT *, ARRAY(SELECT groname FROM pg_group WHERE usesysid = ANY(grolist)) AS roles FROM pg_user").each_with_object({}) do |user, users|
         users[user[:usename]] = {
           :superuser => user[:usesuper] == "t",
           :createdb => user[:usercreatedb] == "t",
           :createrole => user[:usecatupd] == "t",
-          :replication => user[:userepl] == "t"
+          :replication => user[:userepl] == "t",
+          :roles => parse_array(user[:roles] || "{}")
         }
       end
     end
@@ -108,7 +117,7 @@ module OpenStreetMap
 
     def tables(database)
       @tables ||= {}
-      @tables[database] ||= query("SELECT n.nspname, c.relname, u.usename, c.relacl FROM pg_class AS c INNER JOIN pg_user AS u ON c.relowner = u.usesysid INNER JOIN pg_namespace AS n ON c.relnamespace = n.oid", :database => database).each_with_object({}) do |table, tables|
+      @tables[database] ||= query("SELECT n.nspname, c.relname, u.usename, c.relacl FROM pg_class AS c INNER JOIN pg_user AS u ON c.relowner = u.usesysid INNER JOIN pg_namespace AS n ON c.relnamespace = n.oid WHERE n.nspname NOT IN ('pg_catalog', 'information_schema') AND c.relkind = 'r'", :database => database).each_with_object({}) do |table, tables|
         name = "#{table[:nspname]}.#{table[:relname]}"
 
         tables[name] = {
@@ -118,10 +127,26 @@ module OpenStreetMap
       end
     end
 
+    def sequences(database)
+      @sequences ||= {}
+      @sequences[database] ||= query("SELECT n.nspname, c.relname, u.usename, c.relacl FROM pg_class AS c INNER JOIN pg_user AS u ON c.relowner = u.usesysid INNER JOIN pg_namespace AS n ON c.relnamespace = n.oid WHERE n.nspname NOT IN ('pg_catalog', 'information_schema') AND c.relkind = 'S'", :database => database).each_with_object({}) do |sequence, sequences|
+        name = "#{sequence[:nspname]}.#{sequence[:relname]}"
+
+        sequences[name] = {
+          :owner => sequence[:usename],
+          :permissions => parse_acl(sequence[:relacl] || "{}")
+        }
+      end
+    end
+
     private
 
+    def parse_array(array)
+      array.sub(/^\{(.*)\}$/, "\\1").split(",")
+    end
+
     def parse_acl(acl)
-      acl.sub(/^\{(.*)\}$/, "\\1").split(",").each_with_object({}) do |entry, permissions|
+      parse_array(acl).each_with_object({}) do |entry, permissions|
         entry = entry.sub(/^"(.*)"$/) { Regexp.last_match[1].gsub(/\\"/, '"') }.sub(%r{/.*$}, "")
         user, privileges = entry.split("=")
 
@@ -129,8 +154,10 @@ module OpenStreetMap
         user = "public" if user == ""
 
         permissions[user] = {
-          "a" => :insert, "r" => :select, "w" => :update, "d" => :delete,
-          "D" => :truncate, "x" => :references, "t" => :trigger
+          "r" => :select, "a" => :insert, "w" => :update, "d" => :delete,
+          "D" => :truncate, "x" => :references, "t" => :trigger,
+          "C" => :create, "c" => :connect, "T" => :temporary,
+          "X" => :execute, "U" => :usage, "s" => :set, "A" => :alter_system
         }.values_at(*privileges.chars).compact
       end
     end
index 47927729ea7b834fa8a051e40e6a84590c27a282..909b123dfae77c680aa41cf809670223bc02af10 100644 (file)
@@ -6,4 +6,6 @@ description       "Installs and configures postgresql"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "apt"
 depends           "ohai"
+depends           "prometheus"
index 3a3c63de108fc2413aac45d60843255ace3a3fc8..eae492f16c99cf4f49a5ca1a9a966c6631dbd841 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "apt::postgresql"
+include_recipe "prometheus"
+
+package "locales-all"
 package "postgresql-common"
 
 node[:postgresql][:versions].each do |version|
@@ -28,67 +32,68 @@ node[:postgresql][:versions].each do |version|
   defaults = node[:postgresql][:settings][:defaults] || {}
   settings = node[:postgresql][:settings][version] || {}
 
+  standby_mode = settings[:standby_mode] || defaults[:standby_mode]
+  primary_conninfo = settings[:primary_conninfo] || defaults[:primary_conninfo]
+
+  passwords = if primary_conninfo
+                data_bag_item(primary_conninfo[:passwords][:bag],
+                              primary_conninfo[:passwords][:item])
+              end
+
   template "/etc/postgresql/#{version}/main/postgresql.conf" do
     source "postgresql.conf.erb"
     owner "postgres"
     group "postgres"
-    mode 0o644
-    variables :version => version, :defaults => defaults, :settings => settings
+    mode "644"
+    variables :version => version,
+              :defaults => defaults,
+              :settings => settings,
+              :primary_conninfo => primary_conninfo,
+              :passwords => passwords
     notifies :reload, "service[postgresql]"
+    only_if { ::Dir.exist?("/etc/postgresql/#{version}/main") }
   end
 
   template "/etc/postgresql/#{version}/main/pg_hba.conf" do
     source "pg_hba.conf.erb"
     owner "postgres"
     group "postgres"
-    mode 0o640
+    mode "640"
     variables :early_rules => settings[:early_authentication_rules] || defaults[:early_authentication_rules],
               :late_rules => settings[:late_authentication_rules] || defaults[:late_authentication_rules]
     notifies :reload, "service[postgresql]"
+    only_if { ::Dir.exist?("/etc/postgresql/#{version}/main") }
   end
 
   template "/etc/postgresql/#{version}/main/pg_ident.conf" do
     source "pg_ident.conf.erb"
     owner "postgres"
     group "postgres"
-    mode 0o640
+    mode "640"
     variables :maps => settings[:user_name_maps] || defaults[:user_name_maps]
     notifies :reload, "service[postgresql]"
+    only_if { ::Dir.exist?("/etc/postgresql/#{version}/main") }
   end
 
   link "/var/lib/postgresql/#{version}/main/server.crt" do
     to "/etc/ssl/certs/ssl-cert-snakeoil.pem"
+    only_if { ::Dir.exist?("/var/lib/postgresql/#{version}/main") }
   end
 
   link "/var/lib/postgresql/#{version}/main/server.key" do
     to "/etc/ssl/private/ssl-cert-snakeoil.key"
+    only_if { ::Dir.exist?("/var/lib/postgresql/#{version}/main") }
   end
 
-  standby_mode = settings[:standby_mode] || defaults[:standby_mode]
-  primary_conninfo = settings[:primary_conninfo] || defaults[:primary_conninfo]
-  restore_command = settings[:restore_command] || defaults[:restore_command]
-
-  if restore_command || standby_mode == "on"
-    passwords = if primary_conninfo
-                  data_bag_item(primary_conninfo[:passwords][:bag],
-                                primary_conninfo[:passwords][:item])
-                end
-
-    template "/var/lib/postgresql/#{version}/main/recovery.conf" do
-      source "recovery.conf.erb"
+  if standby_mode == "on"
+    file "/var/lib/postgresql/#{version}/main/standby.signal" do
       owner "postgres"
       group "postgres"
-      mode 0o640
-      variables :standby_mode => standby_mode,
-                :primary_conninfo => primary_conninfo,
-                :restore_command => restore_command,
-                :passwords => passwords
-      notifies :reload, "service[postgresql]"
+      mode "640"
     end
   else
-    template "/var/lib/postgresql/#{version}/main/recovery.conf" do
+    file "/var/lib/postgresql/#{version}/main/standby.signal" do
       action :delete
-      notifies :reload, "service[postgresql]"
     end
   end
 end
@@ -102,49 +107,69 @@ ohai_plugin "postgresql" do
   template "ohai.rb.erb"
 end
 
-package "ptop"
+package "pgtop"
 package "libdbd-pg-perl"
 
 clusters = node[:postgresql][:clusters] || []
+passwords = data_bag_item("postgresql", "passwords")
 
 clusters.each do |name, details|
-  suffix = name.tr("/", ":")
-
-  munin_plugin "postgres_bgwriter_#{suffix}" do
-    target "postgres_bgwriter"
-    conf "munin.erb"
-    conf_variables :port => details[:port]
-  end
-
-  munin_plugin "postgres_checkpoints_#{suffix}" do
-    target "postgres_checkpoints"
-    conf "munin.erb"
-    conf_variables :port => details[:port]
-  end
-
-  munin_plugin "postgres_connections_db_#{suffix}" do
-    target "postgres_connections_db"
-    conf "munin.erb"
-    conf_variables :port => details[:port]
+  prometheus_suffix = name.tr("/", "-")
+  prometheus_database = node[:postgresql][:monitor_database]
+
+  postgresql_user "prometheus" do
+    cluster name
+    password passwords["prometheus"]
+    roles "pg_monitor"
+    not_if { ::File.exist?("/var/lib/postgresql/#{name}/standby.signal") }
   end
 
-  munin_plugin "postgres_users_#{suffix}" do
-    target "postgres_users"
-    conf "munin.erb"
-    conf_variables :port => details[:port]
+  prometheus_exporter "postgres" do
+    port 10000 + details[:port].to_i
+    service "postgres-#{prometheus_suffix}"
+    labels "cluster" => name
+    scrape_interval "1m"
+    scrape_timeout "1m"
+    options %w[
+      --collector.database_wraparound
+      --collector.long_running_transactions
+      --collector.process_idle
+      --collector.stat_activity_autovacuum
+      --collector.stat_wal_receiver
+      --collector.statio_user_indexes
+    ]
+    environment "DATA_SOURCE_NAME" => "postgres:///#{prometheus_database}?host=/run/postgresql&port=#{details[:port]}&user=prometheus&password=#{passwords['prometheus']}"
+    restrict_address_families "AF_UNIX"
+    subscribes :restart, "template[/etc/prometheus/exporters/postgres_queries.yml]"
   end
 
-  munin_plugin "postgres_xlog_#{suffix}" do
-    target "postgres_xlog"
-    conf "munin.erb"
-    conf_variables :port => details[:port]
-  end
+  if node[:postgresql][:monitor_queries]
+    template "/etc/prometheus/exporters/sql_exporter.yml" do
+      source "sql_exporter.yml.erb"
+      owner "root"
+      group "root"
+      mode "644"
+    end
 
-  next unless File.exist?("/var/lib/postgresql/#{details[:version]}/main/recovery.conf")
+    prometheus_exporter "sql" do
+      port 20000 + details[:port].to_i
+      service "sql-#{prometheus_suffix}"
+      labels "cluster" => name
+      scrape_interval "1m"
+      scrape_timeout "1m"
+      options "--config.file=/etc/prometheus/exporters/sql_exporter.yml"
+      environment "SQLEXPORTER_TARGET_DSN" => "postgres://prometheus:#{passwords['prometheus']}@/run/postgresql:#{details[:port]}/#{prometheus_database}"
+      restrict_address_families "AF_UNIX"
+      subscribes :restart, "template[/etc/prometheus/exporters/sql_exporter.yml]"
+    end
+  else
+    prometheus_exporter "sql" do
+      action :delete
+      service "sql-#{prometheus_suffix}"
+    end
 
-  munin_plugin "postgres_replication_#{suffix}" do
-    target "postgres_replication"
-    conf "munin.erb"
-    conf_variables :port => details[:port]
+    file "/etc/prometheus/exporters/sql_exporter.yml" do
+      action :delete
+    end
   end
 end
index 9cc4f1e0e39b75270c7ff1ca905a9f75601700cb..cd2d4c7644f27f9bcac74ac326ab64dbcd2a8730 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :database, :kind_of => String, :name_attribute => true
+property :database, :kind_of => String, :name_property => true
 property :cluster, :kind_of => String, :required => true
-property :owner, :kind_of => String, :required => true
+property :owner, :kind_of => String, :required => [:create]
 property :encoding, :kind_of => String, :default => "UTF8"
 property :collation, :kind_of => String, :default => "en_GB.UTF8"
 property :ctype, :kind_of => String, :default => "en_GB.UTF8"
@@ -41,7 +43,11 @@ end
 action :drop do
   if cluster.databases.include?(new_resource.database)
     converge_by "drop database #{new_resource.database}" do
-      cluster.execute(:command => "DROP DATABASE \"#{new_resource.database}\"")
+      if cluster.version >= 13
+        cluster.execute(:command => "DROP DATABASE \"#{new_resource.database}\" WITH (FORCE)")
+      else
+        cluster.execute(:command => "DROP DATABASE \"#{new_resource.database}\"")
+      end
     end
   end
 end
index 463a80edbb71e275fbff22d9e8f445a2facc771a..4f7217ec850a82fe81f08d16083412f0b45a1406 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :run
 
-property :command, :kind_of => String, :name_attribute => true
+property :command, :kind_of => String, :name_property => true
 property :cluster, :kind_of => String, :required => true
 property :database, :kind_of => String, :required => true
-property :user, :default => "postgres"
-property :group, :default => "postgres"
+property :user, :kind_of => String, :default => "postgres"
+property :group, :kind_of => String, :default => "postgres"
 
 action :run do
   options = { :database => new_resource.database, :user => new_resource.user, :group => new_resource.group }
index 24df6c568c46b39f0d6070c500c0fb4c11eecf50..ec60fb9752aace2bcb9b5069abb4740fa1f25254 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :extension, :kind_of => String, :name_attribute => true
+property :extension, :kind_of => String, :name_property => true
 property :cluster, :kind_of => String, :required => true
 property :database, :kind_of => String, :required => true
 
diff --git a/cookbooks/postgresql/resources/munin.rb b/cookbooks/postgresql/resources/munin.rb
deleted file mode 100644 (file)
index e069a87..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# Cookbook:: postgresql
-# Resource:: postgresql_munin
-#
-# Copyright:: 2015, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-default_action :create
-
-property :munin, :kind_of => String, :name_attribute => true
-property :cluster, :kind_of => String, :required => true
-property :database, :kind_of => String, :required => true
-
-action :create do
-  cluster = node[:postgresql][:clusters] && node[:postgresql][:clusters][new_resource.cluster]
-  database = new_resource.database
-
-  if cluster
-    %w[cache connections locks querylength scans size transactions tuples].each do |plugin|
-      munin_plugin "postgres_#{plugin}_#{database}:#{suffix}" do
-        target "postgres_#{plugin}_"
-        conf "munin.erb"
-        conf_cookbook "postgresql"
-        conf_variables :port => cluster[:port]
-        restart_munin false
-      end
-    end
-  else
-    Chef::Log.info "Postgres cluster #{new_resource.cluster} not found"
-  end
-end
-
-action :delete do
-  database = new_resource.database
-
-  %w[cache connections locks querylength scans size transactions tuples].each do |plugin|
-    munin_plugin "postgres_#{plugin}_#{database}:#{suffix}" do
-      action :delete
-      restart_munin false
-    end
-  end
-end
-
-action_class do
-  def suffix
-    new_resource.cluster.tr("/", ":")
-  end
-end
-
-def after_created
-  notifies :restart, "service[munin-node]"
-end
diff --git a/cookbooks/postgresql/resources/sequence.rb b/cookbooks/postgresql/resources/sequence.rb
new file mode 100644 (file)
index 0000000..dae657c
--- /dev/null
@@ -0,0 +1,97 @@
+#
+# Cookbook:: postgresql
+# Resource:: postgresql_sequence
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unified_mode true
+
+default_action :create
+
+property :sequence, :kind_of => String, :name_property => true
+property :cluster, :kind_of => String, :required => true
+property :database, :kind_of => String, :required => true
+property :schema, :kind_of => String, :default => "public"
+property :owner, :kind_of => String, :required => [:create]
+property :permissions, :kind_of => Hash, :default => {}
+
+action :create do
+  if sequences.include?(qualified_name)
+    if new_resource.owner != sequences[qualified_name][:owner]
+      converge_by("set owner for #{new_resource} to #{new_resource.owner}") do
+        Chef::Log.info("Setting owner for #{new_resource} to #{new_resource.owner}")
+        cluster.execute(:command => "ALTER SEQUENCE #{qualified_name} OWNER TO \"#{new_resource.owner}\"", :database => new_resource.database)
+      end
+    end
+
+    sequences[qualified_name][:permissions].each_key do |user|
+      next if new_resource.permissions[user]
+
+      converge_by("revoke all for #{user} on #{new_resource}") do
+        Chef::Log.info("Revoking all for #{user} on #{new_resource}")
+        cluster.execute(:command => "REVOKE ALL ON TABLE #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
+      end
+    end
+
+    new_resource.permissions.each do |user, new_privileges|
+      current_privileges = sequences[qualified_name][:permissions][user] || {}
+      new_privileges = Array(new_privileges)
+
+      if new_privileges.include?(:all)
+        new_privileges |= OpenStreetMap::PostgreSQL::SEQUENCE_PRIVILEGES
+      end
+
+      OpenStreetMap::PostgreSQL::SEQUENCE_PRIVILEGES.each do |privilege|
+        if new_privileges.include?(privilege)
+          unless current_privileges.include?(privilege)
+            converge_by("grant #{privilege} for #{user} on #{new_resource}") do
+              Chef::Log.info("Granting #{privilege} for #{user} on #{new_resource}")
+              cluster.execute(:command => "GRANT #{privilege.to_s.upcase} ON SEQUENCE #{qualified_name} TO \"#{user}\"", :database => new_resource.database)
+            end
+          end
+        elsif current_privileges.include?(privilege)
+          converge_by("revoke #{privilege} for #{user} on #{new_resource}") do
+            Chef::Log.info("Revoking #{privilege} for #{user} on #{new_resource}")
+            cluster.execute(:command => "REVOKE #{privilege.to_s.upcase} ON SEQUENCE #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
+          end
+        end
+      end
+    end
+  end
+end
+
+action :drop do
+  if sequences.include?(qualified_name)
+    converge_by("drop #{new_resource}") do
+      Chef::Log.info("Dropping #{new_resource}")
+      cluster.execute(:command => "DROP SEQUENCE #{qualified_name}", :database => new_resource.database)
+    end
+  end
+end
+
+action_class do
+  def cluster
+    @cluster ||= OpenStreetMap::PostgreSQL.new(new_resource.cluster)
+  end
+
+  def sequences
+    @sequences ||= cluster.sequences(new_resource.database)
+  end
+
+  def qualified_name
+    "#{new_resource.schema}.#{new_resource.name}"
+  end
+end
index 75df2f60ca7c5f579590b0ede5e97aea49d98d4e..5970f4e0aba8c5fed1be808867c64b5d69eda1c3 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :table, :kind_of => String, :name_attribute => true
+property :table, :kind_of => String, :name_property => true
 property :cluster, :kind_of => String, :required => true
 property :database, :kind_of => String, :required => true
 property :schema, :kind_of => String, :default => "public"
-property :owner, :kind_of => String, :required => true
+property :owner, :kind_of => String, :required => [:create]
 property :permissions, :kind_of => Hash, :default => {}
 
 action :create do
@@ -40,7 +42,7 @@ action :create do
 
       converge_by("revoke all for #{user} on #{new_resource}") do
         Chef::Log.info("Revoking all for #{user} on #{new_resource}")
-        cluster.execute(:command => "REVOKE ALL ON #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
+        cluster.execute(:command => "REVOKE ALL ON TABLE #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
       end
     end
 
@@ -57,13 +59,13 @@ action :create do
           unless current_privileges.include?(privilege)
             converge_by("grant #{privilege} for #{user} on #{new_resource}") do
               Chef::Log.info("Granting #{privilege} for #{user} on #{new_resource}")
-              cluster.execute(:command => "GRANT #{privilege.to_s.upcase} ON #{qualified_name} TO \"#{user}\"", :database => new_resource.database)
+              cluster.execute(:command => "GRANT #{privilege.to_s.upcase} ON TABLE #{qualified_name} TO \"#{user}\"", :database => new_resource.database)
             end
           end
         elsif current_privileges.include?(privilege)
           converge_by("revoke #{privilege} for #{user} on #{new_resource}") do
             Chef::Log.info("Revoking #{privilege} for #{user} on #{new_resource}")
-            cluster.execute(:command => "REVOKE #{privilege.to_s.upcase} ON #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
+            cluster.execute(:command => "REVOKE #{privilege.to_s.upcase} ON TABLE #{qualified_name} FROM \"#{user}\"", :database => new_resource.database)
           end
         end
       end
index 0fa05cafcf857da87827eb0f1678eee9a0524918..bfa0c4b8cd361ace35d030ae28f470c84314a609 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :tablespace, :kind_of => String, :name_attribute => true
+property :tablespace, :kind_of => String, :name_property => true
 property :cluster, :kind_of => String, :required => true
-property :location, :kind_of => String, :required => true
+property :location, :kind_of => String, :required => [:create]
 
 action :create do
   unless cluster.tablespaces.include?(new_resource.tablespace)
index 072b18424700326d9165276369be2a1387e74547..6d0e07e4794299fcd627f40f8d6d48012824251c 100644 (file)
 
 require "shellwords"
 
+unified_mode true
+
 default_action :create
 
-property :user, :kind_of => String, :name_attribute => true
+property :user, :kind_of => String, :name_property => true
 property :cluster, :kind_of => String, :required => true
 property :password, :kind_of => String
-property :superuser, :default => false
-property :createdb, :default => false
-property :createrole, :default => false
-property :replication, :default => false
+property :superuser, :kind_of => [TrueClass, FalseClass], :default => false
+property :createdb, :kind_of => [TrueClass, FalseClass], :default => false
+property :createrole, :kind_of => [TrueClass, FalseClass], :default => false
+property :replication, :kind_of => [TrueClass, FalseClass], :default => false
+property :roles, :kind_of => [String, Array]
 
 action :create do
   password = new_resource.password ? "ENCRYPTED PASSWORD '#{new_resource.password.shellescape}'" : ""
@@ -40,6 +43,12 @@ action :create do
     converge_by "create role #{new_resource.user}" do
       cluster.execute(:command => "CREATE ROLE \"#{new_resource.user}\" LOGIN #{password} #{superuser} #{createdb} #{createrole}")
     end
+
+    Array(new_resource.roles).each do |role|
+      converge_by "grant #{role} to #{new_resource.user}" do
+        cluster.execute(:command => "GRANT \"#{role}\" TO \"#{new_resource.user}\"")
+      end
+    end
   else
     current_user = cluster.users[new_resource.user]
 
@@ -68,6 +77,24 @@ action :create do
         end
       end
     end
+
+    roles = Array(new_resource.roles)
+
+    roles.each do |role|
+      next if current_user[:roles].include?(role)
+
+      converge_by "grant #{role} to #{new_resource.user}" do
+        cluster.execute(:command => "GRANT \"#{role}\" TO \"#{new_resource.user}\"")
+      end
+    end
+
+    current_user[:roles].each do |role|
+      next if roles.include?(role)
+
+      converge_by "revoke #{role} from #{new_resource.user}" do
+        cluster.execute(:command => "REVOKE \"#{role}\" FROM \"#{new_resource.user}\"")
+      end
+    end
   end
 end
 
diff --git a/cookbooks/postgresql/templates/default/munin.erb b/cookbooks/postgresql/templates/default/munin.erb
deleted file mode 100644 (file)
index fd08870..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[<%= @name %>]
-user postgres
-env.PGUSER postgres
-env.PGPORT <%= @port %>
index 18b490c03c1de3b02ceb672087099483e7dd6f32..cb561691f9061f3f5f6be0bc638f6ba7535caf30 100644 (file)
@@ -4,6 +4,7 @@
 <% @early_rules.each do |rule| -%>
 <%= rule[:type] || "host" %>   <%= rule[:database] || "all" %>         <%= rule[:user] || "all" %>             <%= rule[:address] %>           <%= rule[:method] || "md5" %> <%= (rule[:options] || {}).collect { |k,v| "#{k}=#{v}" }.join(" ") %>
 <% end -%>
+local  all             prometheus                              md5
 local  all             all                                     peer
 host   all             all             127.0.0.1/32            md5
 host   all             all             ::1/128                 md5
index 6e9e29d6fb9a87ad6206f547e4390db6249428ea..b43afa7834a167dd4cf31ae4eab4c70a5ef7ba2d 100644 (file)
@@ -20,15 +20,11 @@ listen_addresses = '<%= @settings[:listen_addresses] || @defaults[:listen_addres
 <% end -%>
 port = <%= @settings[:port] || @defaults[:port] %>
 max_connections = <%= @settings[:max_connections] || @defaults[:max_connections] %>
-<% if @version.to_f >= 9.3 %>
 unix_socket_directories = '/var/run/postgresql'
-<% else -%>
-unix_socket_directory = '/var/run/postgresql'
-<% end -%>
 
 # - Security and Authentication -
 
-ssl = true
+ssl = <%= @settings[:ssl] || @defaults[:ssl] %>
 ssl_renegotiation_limit = 0
 
 #------------------------------------------------------------------------------
@@ -46,6 +42,9 @@ max_stack_depth = <%= @settings[:max_stack_depth] || @defaults[:max_stack_depth]
 # - Asynchronous Behavior -
 
 effective_io_concurrency = <%= @settings[:effective_io_concurrency] || @defaults[:effective_io_concurrency] %>
+max_worker_processes = <%= @settings[:max_worker_processes] || @defaults[:max_worker_processes] %>
+max_parallel_workers_per_gather = <%= @settings[:max_parallel_workers_per_gather] || @defaults[:max_parallel_workers_per_gather] %>
+max_parallel_workers = <%= @settings[:max_parallel_workers] || @defaults[:max_parallel_workers] %>
 
 #------------------------------------------------------------------------------
 # WRITE AHEAD LOG
@@ -62,15 +61,10 @@ commit_delay = <%= @settings[:commit_delay] || @defaults[:commit_delay] %>
 
 # - Checkpoints -
 
-<% if @version.to_f < 9.5 -%>
-checkpoint_segments = <%= @settings[:checkpoint_segments] || @defaults[:checkpoint_segments] %>
-<% end -%>
 checkpoint_timeout = <%= @settings[:checkpoint_timeout] || @defaults[:checkpoint_timeout] %>
-<% if @version.to_f >= 9.5 -%>
+checkpoint_completion_target = <%= @settings[:checkpoint_completion_target] || @defaults[:checkpoint_completion_target] %>
 max_wal_size = <%= @settings[:max_wal_size] || @defaults[:max_wal_size] %>
 min_wal_size = <%= @settings[:min_wal_size] || @defaults[:min_wal_size] %>
-<% end -%>
-checkpoint_completion_target = <%= @settings[:checkpoint_completion_target] || @defaults[:checkpoint_completion_target] %>
 
 # - Archiving -
 
@@ -79,6 +73,14 @@ archive_mode = <%= @settings[:archive_mode] || @defaults[:archive_mode] %>
 archive_command = '<%= @settings[:archive_command] || @defaults[:archive_command] %>'
 <% end -%>
 
+# - Archive Recovery -
+
+# These are only used in recovery mode.
+
+<% if @settings[:restore_command] || @defaults[:restore_command] -%>
+restore_command = '<%= @settings[:restore_command] || @defaults[:restore_command] %>'
+<% end -%>
+
 #------------------------------------------------------------------------------
 # REPLICATION
 #------------------------------------------------------------------------------
@@ -86,9 +88,14 @@ archive_command = '<%= @settings[:archive_command] || @defaults[:archive_command
 # - Sending Server(s) -
 
 max_wal_senders = <%= @settings[:max_wal_senders] || @defaults[:max_wal_senders] %>
+max_replication_slots = <%= @settings[:max_replication_slots] || @defaults[:max_replication_slots] %>
+wal_keep_size = <%= @settings[:wal_keep_size] || @defaults[:wal_keep_size] %>
 
 # - Standby Servers -
 
+<% if @primary_conninfo -%>
+primary_conninfo = 'host=<%= @primary_conninfo[:host] %> port=<%= @primary_conninfo[:port] %> user=<%= @primary_conninfo[:user] %> password=<%= @passwords[@primary_conninfo[:user]] %>'
+<% end -%>
 hot_standby = <%= @settings[:hot_standby] || @defaults[:hot_standby] %>
 hot_standby_feedback = <%= @settings[:hot_standby_feedback] || @defaults[:hot_standby_feedback] %>
 
@@ -98,12 +105,18 @@ hot_standby_feedback = <%= @settings[:hot_standby_feedback] || @defaults[:hot_st
 
 # - Planner Cost Constants -
 
+seq_page_cost = <%= @settings[:seq_page_cost] || @defaults[:seq_page_cost] %>
 random_page_cost = <%= @settings[:random_page_cost] || @defaults[:random_page_cost] %>
 cpu_tuple_cost = <%= @settings[:cpu_tuple_cost] || @defaults[:cpu_tuple_cost] %>
 effective_cache_size = <%= @settings[:effective_cache_size] || @defaults[:effective_cache_size] %>
 
+# - Other Planner Options -
+
+default_statistics_target = <%= @settings[:default_statistics_target] || @defaults[:default_statistics_target] %>
+jit = <%= @settings[:jit] || @defaults[:jit] %>
+
 #------------------------------------------------------------------------------
-# ERROR REPORTING AND LOGGING
+# REPORTING AND LOGGING
 #------------------------------------------------------------------------------
 
 # - When to Log -
@@ -112,6 +125,7 @@ log_min_duration_statement = <%= @settings[:log_min_duration_statement] || @defa
 
 # - What to Log -
 
+log_autovacuum_min_duration = <%= @settings[:log_autovacuum_min_duration] || @defaults[:log_autovacuum_min_duration] %>
 log_line_prefix = '%t '
 
 #------------------------------------------------------------------------------
@@ -121,14 +135,20 @@ log_line_prefix = '%t '
 # - Query/Index Statistics Collector -
 
 track_activity_query_size = <%= @settings[:track_activity_query_size] || @defaults[:track_activity_query_size] %>
+<% if @version.to_f < 15 -%>
+stats_temp_directory = '/run/postgresql/<%= @version %>-main.pg_stat_tmp'
+<% end -%>
 
 #------------------------------------------------------------------------------
 # AUTOVACUUM PARAMETERS
 #------------------------------------------------------------------------------
 
 autovacuum_max_workers = <%= @settings[:autovacuum_max_workers] || @defaults[:autovacuum_max_workers] %>
+autovacuum_naptime = <%= @settings[:autovacuum_naptime] || @defaults[:autovacuum_naptime] %>
 autovacuum_vacuum_scale_factor = <%= @settings[:autovacuum_vacuum_scale_factor] || @defaults[:autovacuum_vacuum_scale_factor] %>
 autovacuum_analyze_scale_factor = <%= @settings[:autovacuum_analyze_scale_factor] || @defaults[:autovacuum_analyze_scale_factor] %>
+autovacuum_freeze_max_age = <%= @settings[:autovacuum_freeze_max_age] || @defaults[:autovacuum_freeze_max_age] %>
+autovacuum_multixact_freeze_max_age = <%= @settings[:autovacuum_multixact_freeze_max_age] || @defaults[:autovacuum_multixact_freeze_max_age] %>
 
 #------------------------------------------------------------------------------
 # CLIENT CONNECTION DEFAULTS
@@ -142,3 +162,21 @@ lc_monetary = 'en_GB.UTF-8'
 lc_numeric = 'en_GB.UTF-8'
 lc_time = 'en_GB.UTF-8'
 default_text_search_config = 'pg_catalog.english'
+
+# - Shared Library Preloading -
+
+shared_preload_libraries = '<%= (@settings[:shared_preload_libraries] || @defaults[:shared_preload_libraries]).sort.join(",") %>'
+
+#------------------------------------------------------------------------------
+# LOCK MANAGEMENT
+#------------------------------------------------------------------------------
+
+max_locks_per_transaction = <%= @settings[:max_locks_per_transaction] || @defaults[:max_locks_per_transaction] %>
+
+#------------------------------------------------------------------------------
+# CUSTOMIZED OPTIONS
+#------------------------------------------------------------------------------
+
+<% Hash(@settings[:customized_options]).sort.each do |name, value| -%>
+<%= name %> = <%= value %>
+<% end -%>
diff --git a/cookbooks/postgresql/templates/default/sql_exporter.yml.erb b/cookbooks/postgresql/templates/default/sql_exporter.yml.erb
new file mode 100644 (file)
index 0000000..94e9477
--- /dev/null
@@ -0,0 +1,32 @@
+# Global defaults.
+global:
+  # If scrape_timeout <= 0, no timeout is set unless Prometheus provides one. The default is 10s.
+  scrape_timeout: 10s
+  # Subtracted from Prometheus' scrape_timeout to give us some headroom and prevent Prometheus from timing out first.
+  scrape_timeout_offset: 500ms
+  # Minimum interval between collector runs: by default (0s) collectors are executed on every scrape.
+  min_interval: 0s
+  # Maximum number of open connections to any one target. Metric queries will run concurrently on multiple connections,
+  # as will concurrent scrapes.
+  max_connections: 3
+  # Maximum number of idle connections to any one target. Unless you use very long collection intervals, this should
+  # always be the same as max_connections.
+  max_idle_connections: 3
+  # Maximum number of maximum amount of time a connection may be reused. Expired connections may be closed lazily before reuse.
+  # If 0, connections are not closed due to a connection's age.
+  max_connection_lifetime: 5m
+
+# The target to monitor and the collectors to execute on it.
+target:
+  # Data source name always has a URI schema that matches the driver name. In some cases (e.g. MySQL)
+  # the schema gets dropped or replaced to match the driver expected DSN format.
+  data_source_name: postgres
+
+  # Collectors (referenced by name) to execute on the target.
+  # Glob patterns are supported (see <https://pkg.go.dev/path/filepath#Match> for syntax).
+  collectors: [sql_*]
+
+# Collector files specifies a list of globs. One collector definition is read from each matching file.
+# Glob patterns are supported (see <https://pkg.go.dev/path/filepath#Match> for syntax).
+collector_files:
+  - "sql_*.collector.yml"
diff --git a/cookbooks/prometheus/README.md b/cookbooks/prometheus/README.md
new file mode 100644 (file)
index 0000000..25feafa
--- /dev/null
@@ -0,0 +1,12 @@
+# Prometheus Cookbook
+
+This cookbook configures prometheus, which we use for server monitoring at
+[prometheus.openstreetmap.org](https://prometheus.openstreetmap.org). The
+cookbook contains two recipes:
+
+* default - installs and configures basic prometheus exporters on each machine
+* server - configures the central prometheus server
+
+Additionally two providers are defined - prometheus_exporter and
+prometheus_textfile_exporter, for configuring individual prometheus
+exporters.
diff --git a/cookbooks/prometheus/attributes/default.rb b/cookbooks/prometheus/attributes/default.rb
new file mode 100644 (file)
index 0000000..0fe8089
--- /dev/null
@@ -0,0 +1,6 @@
+default[:prometheus][:addresses] = {}
+default[:prometheus][:exporters] = {}
+default[:prometheus][:junos] = {}
+default[:prometheus][:snmp] = {}
+default[:prometheus][:metrics] = {}
+default[:prometheus][:files] = []
diff --git a/cookbooks/prometheus/files/default/id_rsa.pub b/cookbooks/prometheus/files/default/id_rsa.pub
new file mode 100644 (file)
index 0000000..41565df
--- /dev/null
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCwBRhz6gJsBcf5xf1WWEdhm6DjOnVlB5CHn48qEDYk4Gy5j62ZsKq+pBmHIJ1SeoR2ezlsMgKyPouzRkIQgh3Mc1qcy0fmr/szsDwhswKjODyk7vfnkEH5bK70W2/WrrBmBi1RGp03hCnJqWFG5uLaYiO2MjkyihTSoLM4XWj71aohbmOhIQiHB8td24JS+3tsGqNe+UhtKWjk2BJ0lqIhDvpOmuLjxGPMVGzBaC4a18jMYFxZs1AxXf/veLP5cduxA7KxT5nWnun2QsW/P0AThBGkhTny/a2GdmQ/aKAmYftFwnBUtgJtGuo/GXkd5Up8BienJzbZ16HhKFl23cXAuFIV7EJwu8bClzCJQtMUE+7rhAX9StDris1P9e1ldjalUSFBMzPHkhf3nHAju3E14URH8DrnfA8kNrnYvYwCgeH3mAu+yht/6mzZWkoaF94AkJVCQ8KRxsuUO9tZO/hLONMuG5FCao1dofnNtvc797XYWS4X6pjBMW5BpANrFrk= prometheus@openstreetmap.org
diff --git a/cookbooks/prometheus/metadata.rb b/cookbooks/prometheus/metadata.rb
new file mode 100644 (file)
index 0000000..6148979
--- /dev/null
@@ -0,0 +1,14 @@
+name              "prometheus"
+maintainer        "OpenStreetMap Administrators"
+maintainer_email  "admins@openstreetmap.org"
+license           "Apache-2.0"
+description       "Installs and configures prometheus"
+
+version           "1.0.0"
+supports          "ubuntu"
+depends           "apache"
+depends           "apt"
+depends           "awscli"
+depends           "git"
+depends           "hardware"
+depends           "networking"
diff --git a/cookbooks/prometheus/recipes/default.rb b/cookbooks/prometheus/recipes/default.rb
new file mode 100644 (file)
index 0000000..df3ec2e
--- /dev/null
@@ -0,0 +1,167 @@
+#
+# Cookbook:: prometheus
+# Recipe:: default
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "git"
+include_recipe "networking"
+
+package "ruby"
+
+if node.internal_ipaddress
+  node.default[:prometheus][:mode] = "internal"
+  node.default[:prometheus][:address] = node.internal_ipaddress
+elsif node[:networking][:wireguard][:enabled]
+  node.default[:prometheus][:mode] = "wireguard"
+  node.default[:prometheus][:address] = node[:networking][:wireguard][:address]
+
+  search(:node, "roles:prometheus") do |server|
+    node.default[:networking][:wireguard][:peers] << {
+      :public_key => server[:networking][:wireguard][:public_key],
+      :allowed_ips => server[:networking][:wireguard][:address],
+      :endpoint => "#{server.name}:51820"
+    }
+  end
+else
+  node.default[:prometheus][:mode] = "external"
+  node.default[:prometheus][:address] = node.external_ipaddress(:family => :inet)
+end
+
+directory "/opt/prometheus" do
+  action :delete
+  recursive true
+end
+
+git "/opt/prometheus-exporters" do
+  action :sync
+  repository "https://github.com/openstreetmap/prometheus-exporters.git"
+  revision "main"
+  depth 1
+  user "root"
+  group "root"
+end
+
+directory "/etc/prometheus/collectors" do
+  owner "root"
+  group "root"
+  mode "755"
+  recursive true
+end
+
+directory "/etc/prometheus/exporters" do
+  owner "root"
+  group "root"
+  mode "755"
+  recursive true
+end
+
+directory "/var/lib/prometheus/node-exporter" do
+  owner "root"
+  group "adm"
+  mode "775"
+  recursive true
+end
+
+template "/var/lib/prometheus/node-exporter/chef.prom" do
+  source "chef.prom.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+metric_relabel = []
+
+node[:hardware][:hwmon].each do |chip, details|
+  next unless details[:ignore]
+
+  sensors = details[:ignore].join("|")
+
+  metric_relabel << {
+    :source_labels => "chip,sensor",
+    :regex => "#{chip};(#{sensors})",
+    :action => "drop"
+  }
+end
+
+prometheus_exporter "node" do
+  port 9100
+  user "root"
+  proc_subset "all"
+  protect_clock false
+  restrict_address_families %w[AF_UNIX AF_NETLINK]
+  system_call_filter ["@system-service", "@clock"]
+  options %w[
+    --collector.textfile.directory=/var/lib/prometheus/node-exporter
+    --collector.interrupts
+    --collector.processes
+    --collector.rapl.enable-zone-label
+    --collector.systemd
+    --collector.tcpstat
+  ]
+  metric_relabel metric_relabel
+end
+
+unless node[:prometheus][:junos].empty?
+  targets = node[:prometheus][:junos].collect { |_, details| details[:address] }.sort.join(",")
+
+  prometheus_exporter "junos" do
+    port 9326
+    options %W[
+      --ssh.user=prometheus
+      --ssh.keyfile=/var/lib/prometheus/junos-exporter/id_rsa
+      --ssh.targets=#{targets}
+      --bgp.enabled=false
+      --lacp.enabled=true
+      --ldp.enabled=false
+      --ospf.enabled=false
+      --power.enabled=false
+    ]
+    ssh true
+    register_target false
+  end
+end
+
+unless node[:prometheus][:snmp].empty?
+  prometheus_exporter "snmp" do
+    port 9116
+    options "--config.file=/opt/prometheus-exporters/exporters/snmp/snmp.yml"
+    register_target false
+  end
+end
+
+if node[:prometheus][:files].empty?
+  prometheus_exporter "filestat" do
+    action :delete
+  end
+
+  file "/etc/prometheus/filestat.yml" do
+    action :delete
+  end
+else
+  template "/etc/prometheus/filestat.yml" do
+    source "filestat.yml.erb"
+    owner "root"
+    group "root"
+    mode "644"
+  end
+
+  prometheus_exporter "filestat" do
+    port 9943
+    options "--config.file=/etc/prometheus/filestat.yml"
+    subscribes :restart, "template[/etc/prometheus/filestat.yml]"
+  end
+end
diff --git a/cookbooks/prometheus/recipes/server.rb b/cookbooks/prometheus/recipes/server.rb
new file mode 100644 (file)
index 0000000..4b9058c
--- /dev/null
@@ -0,0 +1,426 @@
+#
+# Cookbook:: prometheus
+# Recipe:: server
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "apache"
+include_recipe "apt::grafana"
+include_recipe "awscli"
+include_recipe "networking"
+
+passwords = data_bag_item("prometheus", "passwords")
+tokens = data_bag_item("prometheus", "tokens")
+admins = data_bag_item("apache", "admins")
+
+prometheus_exporter "fastly" do
+  port 8080
+  listen_switch "listen"
+  environment "FASTLY_API_TOKEN" => tokens["fastly"]
+end
+
+prometheus_exporter "fastly_healthcheck" do
+  port 9696
+  scrape_interval "1m"
+  environment "FASTLY_API_TOKEN" => tokens["fastly"]
+end
+
+prometheus_exporter "statuscake" do
+  port 9595
+  scrape_interval "5m"
+  scrape_timeout "2m"
+  environment "STATUSCAKE_APIKEY" => tokens["statuscake"]
+end
+
+template "/etc/prometheus/cloudwatch.yml" do
+  source "cloudwatch.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+prometheus_exporter "cloudwatch" do
+  address "127.0.0.1"
+  port 5000
+  listen_switch "listen-address"
+  options %w[
+    --config.file=/etc/prometheus/cloudwatch.yml
+    --enable-feature=aws-sdk-v2
+    --enable-feature=always-return-info-metrics
+  ]
+  environment "AWS_ACCESS_KEY_ID" => "AKIASQUXHPE7JHG37EA6",
+              "AWS_SECRET_ACCESS_KEY" => tokens["cloudwatch"]
+  subscribes :restart, "template[/etc/prometheus/cloudwatch.yml]"
+end
+
+cache_dir = Chef::Config[:file_cache_path]
+
+prometheus_version = "2.45.0"
+alertmanager_version = "0.25.0"
+karma_version = "0.114"
+
+directory "/opt/prometheus-server" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+prometheus_arch = if arm?
+                    "arm64"
+                  else
+                    "amd64"
+                  end
+
+remote_file "#{cache_dir}/prometheus.linux.tar.gz" do
+  source "https://github.com/prometheus/prometheus/releases/download/v#{prometheus_version}/prometheus-#{prometheus_version}.linux-#{prometheus_arch}.tar.gz"
+  owner "root"
+  group "root"
+  mode "644"
+  backup false
+end
+
+archive_file "#{cache_dir}/prometheus.linux.tar.gz" do
+  action :nothing
+  destination "/opt/prometheus-server/prometheus"
+  overwrite true
+  strip_components 1
+  owner "root"
+  group "root"
+  subscribes :extract, "remote_file[#{cache_dir}/prometheus.linux.tar.gz]", :immediately
+end
+
+remote_file "#{cache_dir}/alertmanager.linux.tar.gz" do
+  source "https://github.com/prometheus/alertmanager/releases/download/v#{alertmanager_version}/alertmanager-#{alertmanager_version}.linux-#{prometheus_arch}.tar.gz"
+  owner "root"
+  group "root"
+  mode "644"
+  backup false
+end
+
+archive_file "#{cache_dir}/alertmanager.linux.tar.gz" do
+  action :nothing
+  destination "/opt/prometheus-server/alertmanager"
+  overwrite true
+  strip_components 1
+  owner "root"
+  group "root"
+  subscribes :extract, "remote_file[#{cache_dir}/alertmanager.linux.tar.gz]", :immediately
+end
+
+remote_file "#{cache_dir}/karma-linux.tar.gz" do
+  source "https://github.com/prymitive/karma/releases/download/v#{karma_version}/karma-linux-#{prometheus_arch}.tar.gz"
+  owner "root"
+  group "root"
+  mode "644"
+  backup false
+end
+
+archive_file "#{cache_dir}/karma-linux.tar.gz" do
+  action :nothing
+  destination "/opt/prometheus-server/karma"
+  overwrite true
+  owner "root"
+  group "root"
+  subscribes :extract, "remote_file[#{cache_dir}/karma-linux.tar.gz]", :immediately
+end
+
+search(:node, "roles:gateway") do |gateway|
+  allowed_ips = gateway.ipaddresses(:role => :internal).map(&:subnet)
+
+  node.default[:networking][:wireguard][:peers] << {
+    :public_key => gateway[:networking][:wireguard][:public_key],
+    :allowed_ips => allowed_ips,
+    :endpoint => "#{gateway.name}:51820"
+  }
+end
+
+jobs = {}
+junos_targets = []
+snmp_targets = []
+
+search(:node, "recipes:prometheus\\:\\:default").sort_by(&:name).each do |client|
+  if client[:prometheus][:mode] == "wireguard"
+    node.default[:networking][:wireguard][:peers] << {
+      :public_key => client[:networking][:wireguard][:public_key],
+      :allowed_ips => client[:networking][:wireguard][:address],
+      :endpoint => "#{client.name}:51820"
+    }
+  end
+
+  client[:prometheus][:exporters].each do |key, exporter|
+    if exporter.is_a?(Hash)
+      name = exporter[:name]
+      address = exporter[:address]
+      sni = exporter[:sni]
+      labels = Array(exporter[:labels])
+      scrape_interval = exporter[:scrape_interval]
+      scrape_timeout = exporter[:scrape_timeout]
+      metric_relabel = exporter[:metric_relabel] || []
+    else
+      name = key
+      address = exporter
+      sni = nil
+      labels = []
+      scrape_interval = nil
+      scrape_timeout = nil
+      metric_relabel = []
+    end
+
+    jobs[name] ||= []
+    jobs[name] << {
+      :address => address,
+      :sni => sni,
+      :instance => client.name.split(".").first,
+      :labels => labels,
+      :scrape_interval => scrape_interval,
+      :scrape_timeout => scrape_timeout,
+      :metric_relabel => metric_relabel
+    }
+  end
+
+  Hash(client[:prometheus][:junos]).each do |instance, details|
+    junos_targets << {
+      :instance => instance,
+      :target => details[:address],
+      :address => client[:prometheus][:addresses]["junos"],
+      :labels => Array(details[:labels])
+    }
+  end
+
+  Hash(client[:prometheus][:snmp]).each do |instance, details|
+    snmp_targets << {
+      :instance => instance,
+      :target => details[:address],
+      :modules => details[:modules],
+      :address => client[:prometheus][:addresses]["snmp"],
+      :labels => Array(details[:labels])
+    }
+  end
+end
+
+certificates = search(:node, "letsencrypt:certificates").each_with_object({}) do |n, c|
+  n[:letsencrypt][:certificates].each do |name, details|
+    c[name] ||= details.merge(:nodes => [])
+
+    c[name][:nodes] << {
+      :name => n[:fqdn],
+      :address => n.external_ipaddress || n.internal_ipaddress
+    }
+  end
+end
+
+template "/etc/prometheus/ssl.yml" do
+  source "ssl.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  variables :certificates => certificates
+end
+
+prometheus_exporter "ssl" do
+  address "127.0.0.1"
+  port 9219
+  options "--config.file=/etc/prometheus/ssl.yml"
+  register_target false
+end
+
+package "prometheus"
+
+systemd_service "prometheus-executable" do
+  service "prometheus"
+  dropin "executable"
+  exec_start "/opt/prometheus-server/prometheus/prometheus --config.file=/etc/prometheus/prometheus.yml --web.enable-admin-api --web.external-url=https://prometheus.openstreetmap.org/prometheus --storage.tsdb.path=/var/lib/prometheus/metrics2 --storage.tsdb.retention.time=540d"
+  timeout_stop_sec 300
+  notifies :restart, "service[prometheus]"
+end
+
+template "/etc/prometheus/prometheus.yml" do
+  source "prometheus.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  variables :jobs => jobs, :junos_targets => junos_targets, :snmp_targets => snmp_targets, :certificates => certificates
+end
+
+template "/etc/prometheus/alert_rules.yml" do
+  source "alert_rules.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+service "prometheus" do
+  action [:enable, :start]
+  subscribes :reload, "template[/etc/prometheus/prometheus.yml]"
+  subscribes :reload, "template[/etc/prometheus/alert_rules.yml]"
+  subscribes :restart, "archive_file[#{cache_dir}/prometheus.linux.tar.gz]"
+end
+
+systemd_service "prometheus-alertmanager" do
+  description "Prometheus alert manager"
+  type "simple"
+  user "prometheus"
+  exec_start "/opt/prometheus-server/alertmanager/alertmanager --config.file=/etc/prometheus/alertmanager.yml --storage.path=/var/lib/prometheus/alertmanager --web.external-url=https://prometheus.openstreetmap.org/alertmanager"
+  exec_reload "/bin/kill -HUP $MAINPID"
+  timeout_stop_sec 20
+  restart "on-failure"
+  notifies :restart, "service[prometheus-alertmanager]"
+end
+
+link "/usr/local/bin/promtool" do
+  to "/opt/prometheus-server/prometheus/promtool"
+end
+
+template "/etc/prometheus/alertmanager.yml" do
+  source "alertmanager.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+directory "/var/lib/prometheus/alertmanager" do
+  owner "prometheus"
+  group "prometheus"
+  mode "755"
+end
+
+service "prometheus-alertmanager" do
+  action [:enable, :start]
+  subscribes :reload, "template[/etc/prometheus/alertmanager.yml]"
+  subscribes :restart, "systemd_service[prometheus-alertmanager]"
+  subscribes :restart, "archive_file[#{cache_dir}/alertmanager.linux.tar.gz]"
+end
+
+directory "/etc/amtool" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+template "/etc/amtool/config.yml" do
+  source "amtool.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+link "/usr/local/bin/amtool" do
+  to "/opt/prometheus-server/alertmanager/amtool"
+end
+
+template "/etc/prometheus/karma.yml" do
+  source "karma.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
+
+systemd_service "prometheus-karma" do
+  description "Alert dashboard for Prometheus Alertmanager"
+  user "prometheus"
+  exec_start "/opt/prometheus-server/karma/karma-linux-#{prometheus_arch} --config.file=/etc/prometheus/karma.yml"
+  sandbox :enable_network => true
+  restart "on-failure"
+end
+
+service "prometheus-karma" do
+  action [:enable, :start]
+  subscribes :restart, "template[/etc/prometheus/karma.yml]"
+  subscribes :restart, "archive_file[#{cache_dir}/karma-linux.tar.gz]"
+  subscribes :restart, "systemd_service[prometheus-karma]"
+end
+
+package "grafana-enterprise"
+
+template "/etc/grafana/grafana.ini" do
+  source "grafana.ini.erb"
+  owner "root"
+  group "grafana"
+  mode "640"
+  variables :passwords => passwords
+end
+
+service "grafana-server" do
+  action [:enable, :start]
+  subscribes :restart, "template[/etc/grafana/grafana.ini]"
+end
+
+apache_module "alias"
+apache_module "proxy_http"
+apache_module "proxy_wstunnel"
+
+ssl_certificate "prometheus.openstreetmap.org" do
+  domains ["prometheus.openstreetmap.org", "prometheus.osm.org", "munin.openstreetmap.org", "munin.osm.org"]
+  notifies :reload, "service[apache2]"
+end
+
+apache_site "prometheus.openstreetmap.org" do
+  template "apache.erb"
+  variables :admin_hosts => admins["hosts"]
+end
+
+template "/etc/cron.daily/prometheus-backup" do
+  source "backup.cron.erb"
+  owner "root"
+  group "root"
+  mode "750"
+end
+
+package %w[
+  curl
+  jq
+]
+
+directory "/var/lib/prometheus/.aws" do
+  user "prometheus"
+  group "prometheus"
+  mode "755"
+end
+
+template "/var/lib/prometheus/.aws/credentials" do
+  source "aws-credentials.erb"
+  user "prometheus"
+  group "prometheus"
+  mode "600"
+  variables :passwords => passwords
+end
+
+template "/usr/local/bin/prometheus-backup-data" do
+  source "backup-data.erb"
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+systemd_service "prometheus-backup-data" do
+  description "Backup prometheus data to S3"
+  user "prometheus"
+  exec_start "/usr/local/bin/prometheus-backup-data"
+  read_write_paths %w[
+    /var/lib/prometheus/.aws
+    /var/lib/prometheus/metrics2/snapshots
+  ]
+  sandbox :enable_network => true
+end
+
+systemd_timer "prometheus-backup-data" do
+  description "Backup prometheus data to S3"
+  on_calendar "03:11"
+end
+
+service "prometheus-backup-data.timer" do
+  action [:enable, :start]
+end
diff --git a/cookbooks/prometheus/recipes/smokeping.rb b/cookbooks/prometheus/recipes/smokeping.rb
new file mode 100644 (file)
index 0000000..27b0c6d
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# Cookbook:: prometheus
+# Recipe:: smokeping
+#
+# Copyright:: 2023, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "prometheus"
+
+ip4_hosts = []
+ip6_hosts = []
+
+search(:node, "networking:interfaces") do |host|
+  next if host.name == node.name
+
+  ip4_hosts << host[:fqdn] unless host.ipaddresses(:role => :external, :family => :inet).empty?
+  ip6_hosts << host[:fqdn] unless host.ipaddresses(:role => :external, :family => :inet6).empty?
+end
+
+template "/etc/prometheus/exporters/smokeping.yml" do
+  source "smokeping.yml.erb"
+  owner "root"
+  group "root"
+  mode "644"
+  variables :ip4_hosts => ip4_hosts, :ip6_hosts => ip6_hosts
+end
+
+prometheus_exporter "smokeping" do
+  port 9374
+  options "--config.file=/etc/prometheus/exporters/smokeping.yml"
+  capability_bounding_set "CAP_NET_RAW"
+  ambient_capabilities "CAP_NET_RAW"
+  private_users false
+  subscribes :restart, "template[/etc/prometheus/exporters/smokeping.yml]"
+end
diff --git a/cookbooks/prometheus/resources/collector.rb b/cookbooks/prometheus/resources/collector.rb
new file mode 100644 (file)
index 0000000..ce68a7e
--- /dev/null
@@ -0,0 +1,101 @@
+#
+# Cookbook:: prometheus
+# Resource:: prometheus_collector
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unified_mode true
+
+default_action :create
+
+property :collector, :kind_of => String, :name_property => true
+property :interval, :kind_of => [Integer, String], :required => [:create]
+property :user, :kind_of => String
+property :path, :kind_of => String
+property :options, :kind_of => [String, Array]
+property :environment, :kind_of => Hash, :default => {}
+property :proc_subset, String
+property :capability_bounding_set, [String, Array]
+property :private_devices, [true, false]
+property :private_users, [true, false]
+property :protect_clock, [true, false]
+property :protect_kernel_modules, [true, false]
+
+action :create do
+  systemd_service service_name do
+    description "Prometheus #{new_resource.collector} collector"
+    type "oneshot"
+    user new_resource.user
+    dynamic_user new_resource.user.nil?
+    group "adm"
+    environment new_resource.environment
+    standard_output "file:/var/lib/prometheus/node-exporter/#{new_resource.collector}.new"
+    standard_error "journal"
+    exec_start "#{executable_path} #{executable_options}"
+    exec_start_post "/bin/mv /var/lib/prometheus/node-exporter/#{new_resource.collector}.new /var/lib/prometheus/node-exporter/#{new_resource.collector}.prom"
+    sandbox true
+    proc_subset new_resource.proc_subset if new_resource.property_is_set?(:proc_subset)
+    capability_bounding_set new_resource.capability_bounding_set if new_resource.property_is_set?(:capability_bounding_set)
+    private_devices new_resource.private_devices if new_resource.property_is_set?(:private_devices)
+    private_users new_resource.private_users if new_resource.property_is_set?(:private_users)
+    protect_clock new_resource.protect_clock if new_resource.property_is_set?(:protect_clock)
+    protect_kernel_modules new_resource.protect_kernel_modules if new_resource.property_is_set?(:protect_kernel_modules)
+    read_write_paths ["/var/lib/prometheus/node-exporter", "/var/lock", "/var/log"]
+  end
+
+  systemd_timer service_name do
+    description "Prometheus #{new_resource.collector} collector"
+    on_boot_sec 60
+    on_unit_active_sec new_resource.interval
+  end
+
+  service "#{service_name}.timer" do
+    action [:enable, :start]
+    subscribes :restart, "systemd_timer[#{service_name}]"
+  end
+end
+
+action :delete do
+  service "#{service_name}.timer" do
+    action [:disable, :stop]
+  end
+
+  systemd_timer service_name do
+    action :delete
+  end
+
+  systemd_service service_name do
+    action :delete
+  end
+
+  file "/var/lib/prometheus/node-exporter/#{new_resource.collector}.prom" do
+    action :delete
+  end
+end
+
+action_class do
+  def service_name
+    "prometheus-#{new_resource.collector}-collector"
+  end
+
+  def executable_path
+    new_resource.path || "/opt/prometheus-exporters/collectors/#{new_resource.collector}/#{new_resource.collector}_collector"
+  end
+
+  def executable_options
+    Array(new_resource.options).join(" ")
+  end
+end
diff --git a/cookbooks/prometheus/resources/exporter.rb b/cookbooks/prometheus/resources/exporter.rb
new file mode 100644 (file)
index 0000000..5075c5d
--- /dev/null
@@ -0,0 +1,197 @@
+#
+# Cookbook:: prometheus
+# Resource:: prometheus_exporter
+#
+# Copyright:: 2020, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unified_mode true
+
+default_action :create
+
+property :exporter, :kind_of => String, :name_property => true
+property :address, :kind_of => String
+property :port, :kind_of => Integer, :required => [:create]
+property :listen_switch, :kind_of => String, :default => "web.listen-address"
+property :listen_type, :kind_of => String, :default => "address"
+property :user, :kind_of => String
+property :group, :kind_of => String
+property :command, :kind_of => String
+property :options, :kind_of => [String, Array]
+property :environment, :kind_of => Hash, :default => {}
+property :protect_proc, String
+property :proc_subset, String
+property :capability_bounding_set, [String, Array]
+property :ambient_capabilities, [String, Array]
+property :private_devices, [true, false]
+property :private_users, [true, false]
+property :protect_clock, [true, false]
+property :restrict_address_families, [String, Array]
+property :remove_ipc, [true, false]
+property :system_call_filter, [String, Array]
+property :service, :kind_of => String
+property :labels, :kind_of => Hash, :default => {}
+property :scrape_interval, :kind_of => String
+property :scrape_timeout, :kind_of => String
+property :metric_relabel, :kind_of => Array
+property :register_target, :kind_of => [TrueClass, FalseClass], :default => true
+property :ssh, [true, false]
+
+action :create do
+  if new_resource.ssh && new_resource.user.nil?
+    keys = data_bag_item("prometheus", "keys")
+
+    directory "/var/lib/private/prometheus/#{new_resource.exporter}-exporter" do
+      mode "700"
+      recursive true
+    end
+
+    file "/var/lib/private/prometheus/#{new_resource.exporter}-exporter/id_rsa" do
+      content keys["ssh"].join("\n")
+      mode "400"
+    end
+
+    cookbook_file "/var/lib/private/prometheus/#{new_resource.exporter}-exporter/id_rsa.pub" do
+      mode "644"
+    end
+  end
+
+  systemd_service service_name do
+    after "network-online.target"
+    wants "network-online.target"
+    description "Prometheus #{new_resource.exporter} exporter"
+    type "simple"
+    user new_resource.user
+    dynamic_user new_resource.user.nil?
+    group new_resource.group
+    environment new_resource.environment
+    exec_start "#{executable_path} #{new_resource.command} #{executable_options}"
+    sandbox :enable_network => true
+    state_directory "prometheus/#{new_resource.exporter}-exporter" if new_resource.ssh && new_resource.user.nil?
+    protect_proc new_resource.protect_proc if new_resource.property_is_set?(:protect_proc)
+    proc_subset new_resource.proc_subset if new_resource.property_is_set?(:proc_subset)
+    capability_bounding_set new_resource.capability_bounding_set if new_resource.property_is_set?(:capability_bounding_set)
+    ambient_capabilities new_resource.ambient_capabilities if new_resource.property_is_set?(:ambient_capabilities)
+    private_devices new_resource.private_devices if new_resource.property_is_set?(:private_devices)
+    private_users new_resource.private_users if new_resource.property_is_set?(:private_users)
+    protect_clock new_resource.protect_clock if new_resource.property_is_set?(:protect_clock)
+    restrict_address_families new_resource.restrict_address_families if new_resource.property_is_set?(:restrict_address_families)
+    remove_ipc new_resource.remove_ipc if new_resource.property_is_set?(:remove_ipc)
+    system_call_filter new_resource.system_call_filter if new_resource.property_is_set?(:system_call_filter)
+  end
+
+  service service_name do
+    action [:enable, :start]
+    subscribes :restart, "systemd_service[#{service_name}]"
+  end
+
+  firewall_rule "accept-prometheus-#{new_resource.exporter}" do
+    action :accept
+    context :incoming
+    protocol :tcp
+    source :osm
+    dest_ports new_resource.port
+    only_if { node[:prometheus][:mode] == "external" }
+  end
+
+  node.default[:prometheus][:addresses][new_resource.exporter] = listen_address
+
+  if new_resource.register_target
+    node.default[:prometheus][:exporters][new_resource.port] = {
+      :name => new_resource.exporter,
+      :address => listen_address,
+      :labels => new_resource.labels,
+      :scrape_interval => new_resource.scrape_interval,
+      :scrape_timeout => new_resource.scrape_timeout,
+      :metric_relabel => new_resource.metric_relabel
+    }
+  end
+end
+
+action :delete do
+  service service_name do
+    action [:disable, :stop]
+  end
+
+  systemd_service service_name do
+    action :delete
+  end
+end
+
+action :restart do
+  service service_name do
+    action :restart
+    only_if { service_exists? }
+  end
+end
+
+action_class do
+  def service_name
+    if new_resource.service
+      "prometheus-#{new_resource.service}-exporter"
+    else
+      "prometheus-#{new_resource.exporter}-exporter"
+    end
+  end
+
+  def service_exists?
+    ::File.exist?("/etc/systemd/system/#{service_name}.service")
+  end
+
+  def executable_path
+    if ::File.exist?("#{executable_directory}/#{executable_name}_#{executable_architecture}")
+      "#{executable_directory}/#{executable_name}_#{executable_architecture}"
+    else
+      "#{executable_directory}/#{executable_name}"
+    end
+  end
+
+  def executable_directory
+    "/opt/prometheus-exporters/exporters/#{new_resource.exporter}"
+  end
+
+  def executable_name
+    "#{new_resource.exporter}_exporter"
+  end
+
+  def executable_architecture
+    node[:kernel][:machine]
+  end
+
+  def executable_options
+    "--#{new_resource.listen_switch}=#{listen_argument} #{Array(new_resource.options).join(' ')}"
+  end
+
+  def listen_argument
+    case new_resource.listen_type
+    when "address" then listen_address
+    when "url" then "http://#{listen_address}/metrics"
+    end
+  end
+
+  def listen_address
+    if new_resource.address
+      "#{new_resource.address}:#{new_resource.port}"
+    elsif node[:prometheus][:mode] == "wireguard"
+      "[#{node[:prometheus][:address]}]:#{new_resource.port}"
+    else
+      "#{node[:prometheus][:address]}:#{new_resource.port}"
+    end
+  end
+end
+
+def after_created
+  subscribes :restart, "git[/opt/prometheus-exporters]"
+end
diff --git a/cookbooks/prometheus/templates/default/alert_rules.yml.erb b/cookbooks/prometheus/templates/default/alert_rules.yml.erb
new file mode 100644 (file)
index 0000000..a0cea57
--- /dev/null
@@ -0,0 +1,808 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+groups:
+  - name: amsterdam
+    rules:
+      - alert: uplink
+        expr: junos_interface_up{site="amsterdam",name=~"ge-[01]/2/2"} != 1
+        for: 6m
+        labels:
+          alertgroup: "amsterdam"
+        annotations:
+          status: "{{ $value }}"
+      - alert: pdu current draw
+        expr: rPDU2PhaseStatusCurrent{site="amsterdam",rPDU2PhaseStatusIndex="1"} / 10 > 28
+        for: 6m
+        labels:
+          alertgroup: "amsterdam"
+        annotations:
+          current: "{{ $value | humanize }}A"
+      - alert: site power
+        expr: sum(avg_over_time(rPDU2PhaseStatusApparentPower{site="amsterdam",rPDU2PhaseStatusIndex="1"}[1h]) / 100) > 3.5
+        for: 6m
+        labels:
+          alertgroup: "amsterdam"
+        annotations:
+          current: "{{ $value | humanize }}kVA"
+      - alert: site temperature
+        expr: min(rPDU2SensorTempHumidityStatusTempC{site="amsterdam"}) / 10 < 15 or min(rPDU2SensorTempHumidityStatusTempC{site="amsterdam"}) / 10 > 32
+        for: 6m
+        labels:
+          alertgroup: "amsterdam"
+        annotations:
+          temperature: "{{ $value | humanize }}C"
+      - alert: site humidity
+        expr: max(rPDU2SensorTempHumidityStatusRelativeHumidity{site="amsterdam"}) / 100 < 0.08 or max(rPDU2SensorTempHumidityStatusRelativeHumidity{site="amsterdam"}) / 100 > 0.8
+        for: 6m
+        labels:
+          alertgroup: "amsterdam"
+        annotations:
+          humidity: "{{ $value | humanizePercentage }}"
+  - name: apache
+    rules:
+      - alert: apache down
+        expr: apache_up == 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: apache workers busy
+        expr: sum(apache_workers{state="busy"}) by (instance) / sum(apache_scoreboard) by (instance) > 0.8
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          busy_workers: "{{ $value | humanizePercentage }}"
+      - alert: apache connection limit
+        expr: (apache_connections{state="total"} - on (instance) apache_connections{state="closing"}) / on (instance) (apache_server_limit * on (instance) (apache_threads_per_child + on (instance) (apache_async_request_worker_factor * on (instance) apache_workers{state="idle"} / on(instance) apache_processes{state="all"}))) > 0.8
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          connections: "{{ $value | humanizePercentage }}"
+  - name: chef
+    rules:
+      - alert: chef client not running
+        expr: time() - node_systemd_timer_last_trigger_seconds{name="chef-client.timer"} > 3600
+        for: 12h
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          down_time: "{{ $value | humanizeDuration }}"
+  - name: cisco
+    rules:
+      - alert: cisco fan alarm
+        expr: rlPhdUnitEnvParamFan1Status{rlPhdUnitEnvParamFan1Status!="normal"} > 0 or rlPhdUnitEnvParamFan2Status{rlPhdUnitEnvParamFan2Status!="normal"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+        annotations:
+          fan_rpm: "{{ with printf \"rlPhdUnitEnvParamFan1Speed{site='%s',instance='%s',rlPhdUnitEnvParamStackUnit='%s'}\" $labels.site $labels.instance $labels.rlPhdUnitEnvParamStackUnit | query }}{{ . | first | value | humanize }}rpm{{end}}"
+      - alert: cisco temperature alarm
+        expr: rlPhdUnitEnvParamTempSensorStatus{rlPhdUnitEnvParamTempSensorStatus!="ok"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+        annotations:
+          temp_celsius: "{{ with printf \"rlPhdUnitEnvParamTempSensorValue{site='%s',instance='%s',rlPhdUnitEnvParamStackUnit='%s'}\" $labels.site $labels.instance $labels.rlPhdUnitEnvParamStackUnit | query }}{{ . | first | value | humanize }}C{{end}}"
+      - alert: cisco main power alarm
+        expr: rlPhdUnitEnvParamMainPSStatus{rlPhdUnitEnvParamMainPSStatus!="normal"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+      - alert: cisco redundant power alarm
+        expr: rlPhdUnitEnvParamRedundantPSStatus{rlPhdUnitEnvParamRedundantPSStatus!="normal"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+  - name: cpu
+    rules:
+      - alert: cpu pressure
+        expr: rate(node_pressure_cpu_waiting_seconds_total[5m]) > 0.75
+        for: 60m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          pressure: "{{ $value | humanizePercentage }}"
+  - name: database
+    rules:
+      - alert: active rails queries
+        expr: sum(pg_stat_activity_count{datname="openstreetmap",usename="rails",state="active"}) by (instance) > 50 and on (instance) chef_role{name="db-master"}
+        for: 5m
+        labels:
+          alertgroup: database
+        annotations:
+          queries: "{{ $value }}"
+      - alert: active cgimap queries
+        expr: sum(pg_stat_activity_count{datname="openstreetmap",usename="cgimap",state="active"}) by (instance) > 30 and on (instance) chef_role{name="db-master"}
+        for: 5m
+        labels:
+          alertgroup: database
+        annotations:
+          delay: "{{ $value }}"
+  - name: discourse
+    rules:
+      - alert: discourse job failure rate
+        expr: rate(discourse_job_failures[5m]) > 0
+        for: 5m
+        labels:
+          alertgroup: discourse
+        annotations:
+          failure_rate: "{{ $value }} jobs/s"
+  - name: dublin
+    rules:
+      - alert: uplink
+        expr: junos_interface_up{site="dublin",name=~"ge-[01]/2/2"} != 1
+        for: 6m
+        labels:
+          alertgroup: "dublin"
+        annotations:
+          status: "{{ $value }}"
+      - alert: pdu current draw
+        expr: rPDU2PhaseStatusCurrent{site="dublin",rPDU2PhaseStatusIndex="1"} / 10 > 28
+        for: 6m
+        labels:
+          alertgroup: "dublin"
+        annotations:
+          current: "{{ $value | humanize }}A"
+      - alert: site power
+        expr: sum(avg_over_time(rPDU2PhaseStatusApparentPower{site="dublin",rPDU2PhaseStatusIndex="1"}[1h]) / 100) > 4
+        for: 6m
+        labels:
+          alertgroup: "dublin"
+        annotations:
+          current: "{{ $value | humanize }}kVA"
+      - alert: site temperature
+        expr: min(rPDU2SensorTempHumidityStatusTempC{site="dublin"}) / 10 < 18 or min(rPDU2SensorTempHumidityStatusTempC{site="dublin"}) / 10 > 26
+        for: 6m
+        labels:
+          alertgroup: "dublin"
+        annotations:
+          temperature: "{{ $value | humanize }}C"
+      - alert: site humidity
+        expr: max(rPDU2SensorTempHumidityStatusRelativeHumidity{site="dublin"}) / 100 < 0.25 or max(rPDU2SensorTempHumidityStatusRelativeHumidity{site="dublin"}) / 100 > 0.65
+        for: 6m
+        labels:
+          alertgroup: "dublin"
+        annotations:
+          humidity: "{{ $value | humanizePercentage }}"
+  - name: fastly
+    rules:
+      - alert: fastly error rate
+        expr: sum(rate(fastly_rt_status_group_total{status_group="5xx"}[5m])) by (service_name, datacenter) / sum(rate(fastly_rt_status_group_total[5m])) by (service_name, datacenter) > 0.005
+        for: 15m
+        labels:
+          alertgroup: fastly
+        annotations:
+          error_rate: "{{ $value | humanizePercentage }}"
+      - alert: fastly frontend healthcheck warning
+        expr: count(fastly_healthcheck_status == 0) by (service, datacenter) > 2
+        for: 15m
+        labels:
+          alertgroup: fastly
+      - alert: fastly frontend healthcheck critical
+        expr: count(fastly_healthcheck_status == 0) by (service, datacenter) == count(fastly_healthcheck_status) by (service, datacenter)
+        for: 5m
+        labels:
+          alertgroup: fastly
+      - alert: fastly backend healthcheck warning
+        expr: count(fastly_healthcheck_status == 0) by (service, backend) > 10
+        for: 15m
+        labels:
+          alertgroup: fastly
+      - alert: fastly backend healthcheck critical
+        expr: count(fastly_healthcheck_status == 0) by (service, backend) == count(fastly_healthcheck_status) by (service, backend)
+        for: 5m
+        labels:
+          alertgroup: fastly
+  - name: filesystem
+    rules:
+      - alert: readonly filesystem
+        expr: node_filesystem_readonly > min_over_time(node_filesystem_readonly[7d])
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: filesystem low on space
+        expr: node_filesystem_avail_bytes / node_filesystem_size_bytes < 0.05
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          percentage_free: "{{ $value | humanizePercentage }}"
+          free_bytes: "{{ with printf \"node_filesystem_avail_bytes{instance='%s',mountpoint='%s'}\" $labels.instance $labels.mountpoint | query }}{{ . | first | value | humanize1024 }}bytes{{end}}"
+          total_total: "{{ with printf \"node_filesystem_size_bytes{instance='%s',mountpoint='%s'}\" $labels.instance $labels.mountpoint | query }}{{ . | first | value | humanize1024 }}bytes{{end}}"
+      - alert: filesystem low on inodes
+        expr: node_filesystem_files_free / node_filesystem_files < 0.1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          percentage_free: "{{ $value | humanizePercentage }}"
+          free_inodes: "{{ with printf \"node_filesystem_files_free{instance='%s',mountpoint='%s'}\" $labels.instance $labels.mountpoint | query }}{{ . | first | value }}{{end}}"
+          total_inodes: "{{ with printf \"node_filesystem_files{instance='%s',mountpoint='%s'}\" $labels.instance $labels.mountpoint | query }}{{ . | first | value }}{{end}}"
+  - name: hwmon
+    rules:
+      - alert: hwmon fan alarm
+        expr: node_hwmon_fan_alarm == 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          fan_rpm: "{{ with printf \"node_hwmon_fan_rpm{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}rpm{{end}}"
+          fan_min_rpm: "{{ with printf \"node_hwmon_fan_min_rpm{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}rpm{{end}}"
+      - alert: hwmon temperature alarm
+        expr: node_hwmon_temp_alarm == 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          temp_celsius: "{{ with printf \"node_hwmon_temp_celsius{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}C{{end}}"
+          temp_max_celsius: "{{ with printf \"node_hwmon_temp_max_celsius{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}C{{end}}"
+          temp_crit_celsius: "{{ with printf \"node_hwmon_temp_crit_celsius{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}C{{end}}"
+      - alert: hwmon voltage alarm
+        expr: node_hwmon_in_alarm == 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          in_volts: "{{ with printf \"node_hwmon_in_volts{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}V{{end}}"
+          in_min_volts: "{{ with printf \"node_hwmon_in_min_volts{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}V{{end}}"
+          in_max_volts: "{{ with printf \"node_hwmon_in_max_volts{instance='%s',chip='%s',sensor='%s'}\" $labels.instance $labels.chip $labels.sensor | query }}{{ . | first | value | humanize }}V{{end}}"
+  - name: io
+    rules:
+      - alert: io pressure
+        expr: rate(node_pressure_io_waiting_seconds_total[5m]) > 0.6
+        for: 60m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          pressure: "{{ $value | humanizePercentage }}"
+  - name: ipmi
+    rules:
+      - alert: ipmi fan alarm
+        expr: ipmi_fan_speed_state > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          fan_speed_rpm: "{{ with printf \"ipmi_fan_speed_rpm{instance='%s',id='%s'}\" $labels.instance $labels.id | query }}{{ . | first | value | humanize }}rpm{{end}}"
+      - alert: ipmi temperature alarm
+        expr: ipmi_temperature_state > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          temperature_celsius: "{{ with printf \"ipmi_temperature_celsius{instance='%s',id='%s'}\" $labels.instance $labels.id | query }}{{ . | first | value | humanize }}C{{end}}"
+      - alert: ipmi voltage alarm
+        expr: ipmi_voltage_state > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          voltage_volts: "{{ with printf \"ipmi_voltage_volts{instance='%s',id='%s'}\" $labels.instance $labels.id | query }}{{ . | first | value | humanize }}V{{end}}"
+      - alert: ipmi power alarm
+        expr: ipmi_power_state > 0 or ipmi_sensor_state{type=~"Power .*"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+  - name: juniper
+    rules:
+      - alert: juniper red alarms
+        expr: juniper_alarms_red_count > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+        annotations:
+          alarm_count: "{{ $value }} alarms"
+      - alert: juniper yellow alarms
+        expr: juniper_alarms_yellow_count > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+        annotations:
+          alarm_count: "{{ $value }} alarms"
+      - alert: juniper cpu alarm
+        expr: junos_route_engine_load_average_five / 2 > 0.5
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+        annotations:
+          load_average: "{{ $value | humanizePercentage }}"
+      - alert: juniper fan alarm
+        expr: junos_environment_fan_up != 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+      - alert: juniper power alarm
+        expr: junos_environment_power_up != 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+      - alert: juniper laser receive power
+        expr: junos_interface_diagnostics_laser_rx_dbm < -12 and on (site, instance, name) junos_interface_admin_up == 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+        annotations:
+          power: "{{ $value }} dBm"
+      - alert: juniper laser transmit power
+        expr: junos_interface_diagnostics_laser_output_dbm < -8 and on (site, instance, name) junos_interface_admin_up == 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.site }}"
+        annotations:
+          power: "{{ $value }} dBm"
+  - name: mail
+    rules:
+      - alert: exim down
+        expr: exim_up == 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: exim queue length
+        expr: exim_queue > ignoring(job) exim_queue_limit
+        for: 60m
+        labels:
+          alertgroup: mail
+        annotations:
+          queue_length: "{{ $value }}"
+      - alert: mailman queue length
+        expr: mailman_queue_length > 200
+        for: 60m
+        labels:
+          alertgroup: mail
+        annotations:
+          queue_length: "{{ $value }}"
+  - name: mdadm
+    rules:
+      - alert: mdadm array inactive
+        expr: node_md_state{state="inactive"} > 0
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          required: "{{ with printf \"node_md_disks_required{instance='%s',device='%s'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          active: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='active'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          failed: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='failed'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          spare: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='spare'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+      - alert: mdadm array degraded
+        expr: sum (node_md_disks{state="active"}) without (state) < node_md_disks_required
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          required: "{{ with printf \"node_md_disks_required{instance='%s',device='%s'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          active: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='active'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          failed: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='failed'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          spare: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='spare'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+      - alert: mdadm disk failed
+        expr: node_md_disks{state="failed"} > 0
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          required: "{{ with printf \"node_md_disks_required{instance='%s',device='%s'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          active: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='active'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          failed: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='failed'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+          spare: "{{ with printf \"node_md_disks{instance='%s',device='%s',state='spare'}\" $labels.instance $labels.device | query }}{{ . | first | value | humanize }} disks{{end}}"
+  - name: memory
+    rules:
+      - alert: low memory
+        expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.1
+        for: 15m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          memory_free: "{{ $value | humanizePercentage }}"
+      - alert: memory pressure
+        expr: rate(node_pressure_memory_waiting_seconds_total[5m]) > 0.6
+        for: 60m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          pressure: "{{ $value | humanizePercentage }}"
+      - alert: oom kill detected
+        expr: increase(node_vmstat_oom_kill[1m]) > 0
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          new_oom_kills: "{{ $value }}"
+  - name: mysql
+    rules:
+      - alert: mysql down
+        expr: mysql_up == 0
+        for: 1m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: mysql connection limit
+        expr: mysql_global_status_max_used_connections / mysql_global_variables_max_connections > 0.8
+        for: 1m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          connections_used: "{{ $value | humanizePercentage }}"
+      - alert: mysql connection errors
+        expr: increase(mysql_global_status_connection_errors_total[1m]) > 0
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          error_count: "{{ $value }}"
+  - name: network
+    rules:
+      - alert: interface redundancy lost
+        expr: node_bonding_active < 2 and on (instance, master) label_replace(chef_network_interface{bond_mode="802.3ad"}, "master", "$1", "name", "(.*)")
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          link_count: "{{ $value }}"
+      - alert: interface transmit rate
+        expr: rate(node_network_transmit_bytes_total[1m]) / node_network_speed_bytes > 0.99
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          bandwidth_used: "{{ $value | humanizePercentage }}"
+      - alert: interface receive rate
+        expr: rate(node_network_receive_bytes_total[1m]) / node_network_speed_bytes > 0.99
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          bandwidth_used: "{{ $value | humanizePercentage }}"
+      - alert: interface transmit errors
+        expr: rate(node_network_transmit_errs_total{device!~"wg.*"}[1m]) / rate(node_network_transmit_packets_total{device!~"wg.*"}[1m]) > 0.01
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          error_rate: "{{ $value | humanizePercentage }}"
+      - alert: wireguard interface transmit errors
+        expr: rate(node_network_transmit_errs_total{device=~"wg.*"}[1m]) / rate(node_network_transmit_packets_total{device=~"wg.*"}[1m]) > 0.05
+        for: 1h
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          error_rate: "{{ $value | humanizePercentage }}"
+      - alert: interface receive errors
+        expr: rate(node_network_receive_errs_total[1m]) / rate(node_network_receive_packets_total[1m]) > 0.01
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          error_rate: "{{ $value | humanizePercentage }}"
+      - alert: conntrack entries
+        expr: node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          entries_used: "{{ $value | humanizePercentage }}"
+  - name: nominatim
+    rules:
+      - alert: nominatim replication delay
+        expr: nominatim_replication_delay > 10800
+        for: 1h
+        labels:
+          alertgroup: nominatim
+        annotations:
+          delay: "{{ $value | humanizeDuration }}"
+  - name: overpass
+    rules:
+      - alert: overpass osm database age
+        expr: overpass_database_age_seconds{database="osm"} > 3600
+        for: 1h
+        labels:
+          alertgroup: overpass
+        annotations:
+          age: "{{ $value | humanizeDuration }}"
+      - alert: overpass area database age
+        expr: overpass_database_age_seconds{database="area"} > 86400
+        for: 1h
+        labels:
+          alertgroup: overpass
+        annotations:
+          age: "{{ $value | humanizeDuration }}"
+  - name: passenger
+    rules:
+      - alert: passenger down
+        expr: passenger_up == 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: passenger queuing
+        expr: passenger_top_level_request_queue > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: passenger application queuing
+        expr: passenger_app_request_queue > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+  - name: planet
+    rules:
+      - alert: planet dump overdue
+        expr: time() - file_stat_modif_time_seconds{path=~"/store/planet/(pbf|planet)/.*"} > 7 * 86400 and ignoring (job, name, path) chef_role{name="planetdump"} == 1
+        for: 24h
+        labels:
+          alertgroup: planet
+        annotations:
+          overdue_by: "{{ $value | humanizeDuration }}"
+      - alert: notes dump overdue
+        expr: time() - file_stat_modif_time_seconds{path=~"/store/planet/notes/.*"} > 86400 and ignoring (job, name, path) chef_role{name="planetdump"} == 1
+        for: 6h
+        labels:
+          alertgroup: planet
+        annotations:
+          overdue_by: "{{ $value | humanizeDuration }}"
+      - alert: daily replication feed delayed
+        expr: time() - file_stat_modif_time_seconds{path=~"/store/planet/replication/day/.*"} > 86400 and ignoring (job, name, path) chef_role{name="planetdump"} == 1
+        for: 3h
+        labels:
+          alertgroup: planet
+        annotations:
+          delayed_by: "{{ $value | humanizeDuration }}"
+      - alert: hourly replication feed delayed
+        expr: time() - file_stat_modif_time_seconds{path=~"/store/planet/replication/hour/.*"} > 3600 and ignoring (job, name, path) chef_role{name="planetdump"} == 1
+        for: 30m
+        labels:
+          alertgroup: planet
+        annotations:
+          delayed_by: "{{ $value | humanizeDuration }}"
+      - alert: minutely replication feed delayed
+        expr: time() - file_stat_modif_time_seconds{path=~"/store/planet/replication/minute/.*"} > 60 and ignoring (job, name, path) chef_role{name="planetdump"} == 1
+        for: 5m
+        labels:
+          alertgroup: planet
+        annotations:
+          delayed_by: "{{ $value | humanizeDuration }}"
+      - alert: changeset replication feed delayed
+        expr: time() - file_stat_modif_time_seconds{path=~"/store/planet/replication/changesets/.*"} > 60 and ignoring (job, name, path) chef_role{name="planetdump"} == 1
+        for: 5m
+        labels:
+          alertgroup: planet
+        annotations:
+          delayed_by: "{{ $value | humanizeDuration }}"
+  - name: postgresql
+    rules:
+      - alert: postgresql down
+        expr: pg_up == 0
+        for: 1m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: postgresql replication delay
+        expr: pg_replication_lag_seconds > 30
+        for: 15m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          delay: "{{ $value | humanizeDuration }}"
+      - alert: postgresql connection limit
+        expr: sum (pg_stat_activity_count) by (instance, server) / sum (pg_settings_max_connections) by (instance, server) > 0.8
+        for: 1m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          connections_used: "{{ $value | humanizePercentage }}"
+      - alert: postgresql deadlocks
+        expr: increase(pg_stat_database_deadlocks{datname!="nominatim"}[1m]) > 5
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          new_deadlocks: "{{ $value }}"
+      - alert: postgresql idle transactions
+        expr: sum(pg_process_idle_seconds_count{state="idle in transaction"}) by (instance, server) > sum(pg_process_idle_seconds_bucket{state="idle in transaction",le="300"}) by (instance, server)
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          queries: "{{ $value }}"
+  - name: prometheus
+    rules:
+      - alert: prometheus configuration error
+        expr: prometheus_config_last_reload_successful == 0
+        for: 10m
+        labels:
+          alertgroup: "prometheus"
+      - alert: prometheus target missing
+        expr: up == 0
+        for: 10m
+        labels:
+          alertgroup: "prometheus"
+      - alert: node exporter text file scrape error
+        expr: node_textfile_scrape_error > 0
+        for: 10m
+        labels:
+          alertgroup: "prometheus"
+  - name: raid
+    rules:
+      - alert: raid controller battery failed
+        expr: ohai_controller_info{battery_status="failed"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: raid controller battery recharging
+        expr: ohai_controller_info{battery_status="recharging"} > 0
+        for: 4h
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: raid array degraded
+        expr: ohai_array_info{status="degraded"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: raid disk failed
+        expr: ohai_disk_info{status="failed"} > 0
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+  - name: rasdaemon
+    rules:
+      - alert: memory controller errors
+        expr: increase(rasdaemon_mc_events_total[1m]) > 0
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          new_errors: "{{ $value }}"
+      - alert: pcie aer errors
+        expr: increase(rasdaemon_aer_events_total[1m]) > 0
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          new_errors: "{{ $value }}"
+  - name: smart
+    rules:
+      - alert: smart failure
+        expr: smart_health_status == 0
+        for: 60m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: smart ssd wearout approaching
+        expr: smart_percentage_used / 100 >= 0.8
+        for: 60m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          percentage_used: "{{ $value | humanizePercentage }}"
+  - name: smokeping
+    rules:
+      - alert: packet loss
+        expr: 1 - (rate(smokeping_response_duration_seconds_count[5m]) / rate(smokeping_requests_total[5m])) > 0.02
+        for: 10m
+        labels:
+          alertgroup: smokeping
+        annotations:
+          loss_rate: "{{ $value | humanizePercentage }}"
+  - name: snmp
+    rules:
+      - alert: snmp pdus missing
+        expr: max_over_time(snmp_scrape_pdus_returned[1d]) - snmp_scrape_pdus_returned > 0
+        for: 15m
+        labels:
+          alertgroup: snmp
+        annotations:
+          missing_pdus: "{{ $value }}"
+  - name: ssl
+    rules:
+      - alert: ssl certificate probe failed
+        expr: ssl_probe_success == 0
+        for: 60m
+        labels:
+          alertgroup: ssl
+      - alert: ssl certificate expiry
+        expr: ssl_verified_cert_not_after{chain_no="0"} - time() < 86400 * 14
+        for: 0m
+        labels:
+          alertgroup: ssl
+        annotations:
+          expires_in: "{{ $value | humanizeDuration }}"
+      - alert: ssl certificate revoked
+        expr: ssl_ocsp_response_status == 1
+        for: 0m
+        labels:
+          alertgroup: ssl
+      - alert: ocsp status unknown
+        expr: ssl_ocsp_response_status == 1
+        for: 0m
+        labels:
+          alertgroup: ssl
+  - name: statuscake
+    rules:
+      - alert: statuscake uptime check failing
+        expr: statuscake_paused == 0 and statuscake_up == 0
+        for: 10m
+        labels:
+          alertgroup: statuscake
+  - name: systemd
+    rules:
+      - alert: systemd failed service
+        expr: node_systemd_unit_state{state="failed",name!="chef-client.service"} == 1
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: systemd failed chef client service
+        expr: sum_over_time(node_systemd_unit_state{state="inactive",name="chef-client.service"}[6h]) == 0
+        for: 0m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+  - name: taginfo
+    rules:
+      - alert: taginfo planet age
+        expr: time() - taginfo_data_from_seconds > 129600 and on (instance) chef_role{name="taginfo"}
+        for: 0m
+        labels:
+          alertgroup: taginfo
+        annotations:
+          age: "{{ $value | humanizeDuration }}"
+      - alert: taginfo database age
+        expr: time() - taginfo_database_update_finish_seconds > 129600 and on (instance) chef_role{name="taginfo"}
+        for: 0m
+        labels:
+          alertgroup: taginfo
+        annotations:
+          age: "{{ $value | humanizeDuration }}"
+      - alert: taginfo database size
+        expr: abs(delta(taginfo_database_size_bytes[30m])) / taginfo_database_size_bytes > 0.1
+        for: 30m
+        labels:
+          alertgroup: taginfo
+        annotations:
+          size_change: "{{ $value | humanizePercentage }}"
+  - name: tile
+    rules:
+      - alert: renderd replication delay
+        expr: renderd_replication_delay > 120
+        for: 15m
+        labels:
+          alertgroup: tile
+        annotations:
+          delay: "{{ $value | humanizeDuration }}"
+      - alert: missed tile rate
+        expr: sum(rate(modtile_http_response_total{code="404"}[5m])) by (instance) / sum(rate(modtile_http_response_total[5m])) by (instance) > 0.05
+        for: 5m
+        labels:
+          alertgroup: tile
+        annotations:
+          miss_rate: "{{ $value | humanizePercentage }}"
+      - alert: tile render rate
+        expr: sum(rate(renderd_zoom_metatiles_total[5m])) by (instance) == 0
+        for: 15m
+        labels:
+          alertgroup: tile
+        annotations:
+          render_rate: "{{ $value }} tiles/s"
+  - name: time
+    rules:
+      - alert: clock not synchronising
+        expr: min_over_time(node_timex_sync_status[1m]) == 0 and node_timex_maxerror_seconds >= 16
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+      - alert: clock skew detected
+        expr: (node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or (node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)
+        for: 5m
+        labels:
+          alertgroup: "{{ $labels.instance }}"
+        annotations:
+          skew: "{{ with printf \"node_timex_offset_seconds{instance='%s'}\" $labels.instance | query }} {{ . | humanizeDuration }}{{ end }}"
+  - name: web
+    rules:
+      - alert: web error rate
+        expr: sum(rate(api_call_count_total{status=~"50[0-8]|5[1-9][0-9]"}[5m])) by (instance) / sum(rate(api_call_count_total[5m])) by (instance) > 0.002
+        for: 5m
+        labels:
+          alertgroup: web
+        annotations:
+          error_rate: "{{ $value | humanizePercentage }}"
+      - alert: job processing rate
+        expr: rate(pg_stat_user_tables_n_tup_del{datname="openstreetmap",relname="delayed_jobs"}[1h]) / rate(pg_stat_user_tables_n_tup_ins{datname="openstreetmap",relname="delayed_jobs"}[1h]) < 0.9 and ignoring(job, name, datname, relname, schemaname, server) chef_role{name="db-master"} == 1
+        for: 1h
+        labels:
+          alertgroup: web
+        annotations:
+          job_processing_rate: "{{ $value | humanizePercentage }}"
diff --git a/cookbooks/prometheus/templates/default/alertmanager.yml.erb b/cookbooks/prometheus/templates/default/alertmanager.yml.erb
new file mode 100644 (file)
index 0000000..7433f99
--- /dev/null
@@ -0,0 +1,25 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+global:
+  smtp_smarthost: localhost:25
+  smtp_from: prometheus@openstreetmap.org
+  smtp_require_tls: false
+
+templates:
+  - /etc/prometheus/alertmanager_templates/*.tmpl
+
+route:
+  group_by:
+    - alertgroup
+  group_wait: 30s
+  group_interval: 5m
+  repeat_interval: 3h
+  receiver: admins-email
+
+inhibit_rules:
+
+receivers:
+  - name: admins-email
+    email_configs:
+      - send_resolved: true
+        to: admins@openstreetmap.org
diff --git a/cookbooks/prometheus/templates/default/amtool.yml.erb b/cookbooks/prometheus/templates/default/amtool.yml.erb
new file mode 100644 (file)
index 0000000..2bd4656
--- /dev/null
@@ -0,0 +1,3 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+alertmanager.url: http://localhost:9093/alertmanager
diff --git a/cookbooks/prometheus/templates/default/apache.erb b/cookbooks/prometheus/templates/default/apache.erb
new file mode 100644 (file)
index 0000000..f03cf10
--- /dev/null
@@ -0,0 +1,75 @@
+# DO NOT EDIT - This file is being maintained by Prometheus
+
+<VirtualHost *:80>
+       ServerName prometheus.openstreetmap.org
+       ServerAlias prometheus.osm.org
+       ServerAdmin webmaster@openstreetmap.org
+
+       CustomLog /var/log/apache2/prometheus.openstreetmap.org-access.log combined_extended
+       ErrorLog /var/log/apache2/prometheus.openstreetmap.org-error.log
+
+       RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
+       Redirect permanent / https://prometheus.openstreetmap.org/
+</VirtualHost>
+
+<VirtualHost *:443>
+       ServerName prometheus.openstreetmap.org
+       ServerAdmin webmaster@openstreetmap.org
+
+       CustomLog /var/log/apache2/prometheus.openstreetmap.org-access.log combined_extended
+       ErrorLog /var/log/apache2/prometheus.openstreetmap.org-error.log
+
+       SSLEngine on
+       SSLCertificateFile /etc/ssl/certs/prometheus.openstreetmap.org.pem
+       SSLCertificateKeyFile /etc/ssl/private/prometheus.openstreetmap.org.key
+
+       ProxyPass /prometheus http://localhost:9090/prometheus
+       ProxyPass /alertmanager http://localhost:9093/alertmanager
+       ProxyPass /karma http://localhost:8081/karma
+       ProxyPass /api/live/ws ws://localhost:3000/api/live/ws
+       ProxyPass / http://localhost:3000/
+       ProxyPreserveHost on
+
+       <Location /prometheus/api/v1/admin>
+               Require all denied
+       </Location>
+
+       <Location /alertmanager>
+<% @admin_hosts.each do |host| -%>
+               Require ip <%= host %>
+<% end -%>
+       </Location>
+
+       <Location /karma>
+<% @admin_hosts.each do |host| -%>
+               Require ip <%= host %>
+<% end -%>
+       </Location>
+</VirtualHost>
+
+<VirtualHost *:80>
+  ServerName munin.openstreetmap.org
+  ServerAlias munin.osm.org
+  ServerAdmin webmaster@openstreetmap.org
+
+  CustomLog /var/log/apache2/munin.openstreetmap.org-access.log combined_extended
+  ErrorLog /var/log/apache2/munin.openstreetmap.org-error.log
+
+  RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
+  Redirect permanent / https://prometheus.openstreetmap.org/
+</VirtualHost>
+
+<VirtualHost *:443>
+  ServerName munin.openstreetmap.org
+  ServerAlias munin.osm.org
+  ServerAdmin webmaster@openstreetmap.org
+
+  CustomLog /var/log/apache2/munin.openstreetmap.org-access.log combined_extended
+  ErrorLog /var/log/apache2/munin.openstreetmap.org-error.log
+
+  SSLEngine on
+  SSLCertificateFile /etc/ssl/certs/prometheus.openstreetmap.org.pem
+  SSLCertificateKeyFile /etc/ssl/private/prometheus.openstreetmap.org.key
+
+  Redirect permanent / https://prometheus.openstreetmap.org/
+</VirtualHost>
diff --git a/cookbooks/prometheus/templates/default/aws-credentials.erb b/cookbooks/prometheus/templates/default/aws-credentials.erb
new file mode 100644 (file)
index 0000000..9ee21b8
--- /dev/null
@@ -0,0 +1,7 @@
+[osm-prometheus-data]
+aws_access_key_id = AKIASQUXHPE7KAYP364J
+aws_secret_access_key = <%= @passwords["aws_prometheus_data"] %>
+
+[osm-prometheus-data-upload]
+role_arn=arn:aws:iam::173189593406:role/osm-prometheus-data-upload-role
+source_profile=osm-prometheus-data
diff --git a/cookbooks/prometheus/templates/default/backup-data.erb b/cookbooks/prometheus/templates/default/backup-data.erb
new file mode 100644 (file)
index 0000000..93786a1
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+set -e
+
+SNAPSHOT=$(curl -s -XPOST http://localhost:9090/prometheus/api/v1/admin/tsdb/snapshot | jq -r .data.name)
+
+/opt/awscli/v2/current/bin/aws --profile osm-prometheus-data-upload s3 sync --storage-class=INTELLIGENT_TIERING --no-progress /var/lib/prometheus/metrics2/snapshots/${SNAPSHOT} s3://openstreetmap-prometheus-data
+
+rm -rf /var/lib/prometheus/metrics2/snapshots/${SNAPSHOT}
diff --git a/cookbooks/prometheus/templates/default/backup.cron.erb b/cookbooks/prometheus/templates/default/backup.cron.erb
new file mode 100644 (file)
index 0000000..3273aac
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+T=$(mktemp -d -t -p /var/tmp prometheus.XXXXXXXXXX)
+D=$(date +%Y-%m-%d)
+B=prometheus-$D.tar.gz
+
+mkdir $T/prometheus-$D
+
+ln -s /var/lib/prometheus/alertmanager $T/prometheus-$D/alertmanager
+ln -s /var/lib/grafana $T/prometheus-$D/grafana
+
+export RSYNC_RSH="ssh -ax"
+
+nice tar --create --dereference --directory=$T prometheus-$D | nice gzip --rsyncable -9 > $T/$B
+nice rsync --preallocate --fuzzy $T/$B backup::backup
+
+rm -rf $T
diff --git a/cookbooks/prometheus/templates/default/chef.prom.erb b/cookbooks/prometheus/templates/default/chef.prom.erb
new file mode 100644 (file)
index 0000000..58235e3
--- /dev/null
@@ -0,0 +1,19 @@
+# HELP chef_network_interface Information about network interfaces
+# TYPE chef_network_interface gauge
+<% node.interfaces.each do |interface| -%>
+<% if interface[:interface] =~ /^bond\d+$/ -%>
+chef_network_interface{name="<%= interface[:interface] %>",role="<%= interface[:role].to_s %>",bond_mode="<%= interface[:bond][:mode] || 'active-backup' %>"} 1
+<% else -%>
+chef_network_interface{name="<%= interface[:interface] %>",role="<%= interface[:role].to_s %>"} 1
+<% end -%>
+<% end -%>
+# HELP chef_role Information about chef roles
+# TYPE chef_role gauge
+<% node[:roles].sort.each do |role| -%>
+chef_role{name="<%= role %>"} 1
+<% end -%>
+<% node[:prometheus][:metrics].sort.each do |name, details| -%>
+# HELP <%= name %> <%= details[:help] %>
+# TYPE <%= name %> gauge
+<%= name %>{<%= Hash(details[:labels]).map { |k,v| "#{k}=\"#{v}\"" }.join(",") %>} <%= details[:metric] || 1 %>
+<% end -%>
diff --git a/cookbooks/prometheus/templates/default/cloudwatch.yml.erb b/cookbooks/prometheus/templates/default/cloudwatch.yml.erb
new file mode 100644 (file)
index 0000000..bab5559
--- /dev/null
@@ -0,0 +1,314 @@
+apiVersion: v1alpha1
+sts-region: eu-west-1
+discovery:
+  jobs:
+    - type: AWS/S3
+      regions:
+        - eu-west-1
+        - eu-west-2
+      roles:
+        - roleArn: "arn:aws:iam::173189593406:role/osm-cloudwatch-export-role" # osm-main
+      period: 86400
+      length: 86400
+      metrics:
+        - name: BucketSizeBytes
+          statistics: [Average]
+        - name: NumberOfObjects
+          statistics: [Average]
+    - type: AWS/S3
+      regions:
+        - eu-west-1
+        - eu-west-2
+      roles:
+        - roleArn: "arn:aws:iam::173189593406:role/osm-cloudwatch-export-role" # osm-main
+      period: 300
+      length: 300
+      metrics:
+        - name: AllRequests
+          statistics: [Sum]
+        - name: GetRequests
+          statistics: [Sum]
+        - name: PutRequests
+          statistics: [Sum]
+        - name: DeleteRequests
+          statistics: [Sum]
+        - name: HeadRequests
+          statistics: [Sum]
+        - name: PostRequests
+          statistics: [Sum]
+        - name: ListRequests
+          statistics: [Sum]
+        - name: BytesDownloaded
+          statistics: [Sum]
+        - name: BytesUploaded
+          statistics: [Sum]
+        - name: 4xxErrors
+          statistics: [Sum]
+        - name: 5xxErrors
+          statistics: [Sum]
+        - name: FirstByteLatency
+          statistics: [Minimum, Maximum, Average]
+        - name: TotalRequestLatency
+          statistics: [Minimum, Maximum, Average]
+        - name: ReplicationLatency
+          statistics: [Maximum]
+        - name: BytesPendingReplication
+          statistics: [Maximum]
+        - name: OperationsPendingReplication
+          statistics: [Maximum]
+        - name: OperationsFailedReplication
+          statistics: [Sum]
+    - type: AWS/S3
+      regions:
+        - eu-central-1
+        - us-west-2
+      roles:
+        - roleArn: "arn:aws:iam::630658470130:role/osm-cloudwatch-export-role" # osm-planet (pds)
+      period: 86400
+      length: 86400
+      metrics:
+        - name: BucketSizeBytes
+          statistics: [Average]
+        - name: NumberOfObjects
+          statistics: [Average]
+    - type: AWS/S3
+      regions:
+        - eu-central-1
+        - us-west-2
+      roles:
+        - roleArn: "arn:aws:iam::630658470130:role/osm-cloudwatch-export-role" # osm-planet (pds)
+      period: 300
+      length: 300
+      metrics:
+        - name: AllRequests
+          statistics: [Sum]
+        - name: GetRequests
+          statistics: [Sum]
+        - name: PutRequests
+          statistics: [Sum]
+        - name: DeleteRequests
+          statistics: [Sum]
+        - name: HeadRequests
+          statistics: [Sum]
+        - name: PostRequests
+          statistics: [Sum]
+        - name: ListRequests
+          statistics: [Sum]
+        - name: BytesDownloaded
+          statistics: [Sum]
+        - name: BytesUploaded
+          statistics: [Sum]
+        - name: 4xxErrors
+          statistics: [Sum]
+        - name: 5xxErrors
+          statistics: [Sum]
+        - name: FirstByteLatency
+          statistics: [Minimum, Maximum, Average]
+        - name: TotalRequestLatency
+          statistics: [Minimum, Maximum, Average]
+        - name: ReplicationLatency
+          statistics: [Maximum]
+        - name: BytesPendingReplication
+          statistics: [Maximum]
+        - name: OperationsPendingReplication
+          statistics: [Maximum]
+        - name: OperationsFailedReplication
+          statistics: [Sum]
+    - type: AWS/S3
+      regions:
+        - eu-north-1
+      roles:
+        - roleArn: "arn:aws:iam::674083635870:role/osm-cloudwatch-export-role" # osm-backup
+      period: 86400
+      length: 86400
+      metrics:
+        - name: BucketSizeBytes
+          statistics: [Average]
+        - name: NumberOfObjects
+          statistics: [Average]
+    - type: AWS/S3
+      regions:
+        - eu-north-1
+      roles:
+        - roleArn: "arn:aws:iam::674083635870:role/osm-cloudwatch-export-role" # osm-backup
+      period: 300
+      length: 300
+      metrics:
+        - name: AllRequests
+          statistics: [Sum]
+        - name: GetRequests
+          statistics: [Sum]
+        - name: PutRequests
+          statistics: [Sum]
+        - name: DeleteRequests
+          statistics: [Sum]
+        - name: HeadRequests
+          statistics: [Sum]
+        - name: PostRequests
+          statistics: [Sum]
+        - name: ListRequests
+          statistics: [Sum]
+        - name: BytesDownloaded
+          statistics: [Sum]
+        - name: BytesUploaded
+          statistics: [Sum]
+        - name: 4xxErrors
+          statistics: [Sum]
+        - name: 5xxErrors
+          statistics: [Sum]
+        - name: FirstByteLatency
+          statistics: [Minimum, Maximum, Average]
+        - name: TotalRequestLatency
+          statistics: [Minimum, Maximum, Average]
+        - name: ReplicationLatency
+          statistics: [Maximum]
+        - name: BytesPendingReplication
+          statistics: [Maximum]
+        - name: OperationsPendingReplication
+          statistics: [Maximum]
+        - name: OperationsFailedReplication
+          statistics: [Sum]
+    - type: AWS/EC2
+      regions:
+        - us-east-2
+      roles:
+        - roleArn: "arn:aws:iam::683740446523:role/osm-cloudwatch-export-role" # osm-render
+      period: 300
+      length: 300
+      metrics:
+        - name: CPUUtilization
+          statistics: [Average]
+        - name: DiskReadOps
+          statistics: [Sum]
+        - name: DiskWriteOps
+          statistics: [Sum]
+        - name: DiskReadBytes
+          statistics: [Sum]
+        - name: DiskWriteBytes
+          statistics: [Sum]
+        - name: NetworkIn
+          statistics: [Sum]
+        - name: NetworkOut
+          statistics: [Sum]
+        - name: NetworkPacketsIn
+          statistics: [Sum]
+        - name: NetworkPacketsOut
+          statistics: [Sum]
+    - type: AWS/Billing
+      regions:
+        - us-east-1
+      roles:
+        - roleArn: "arn:aws:iam::173189593406:role/osm-cloudwatch-export-role" # osm-main
+        - roleArn: "arn:aws:iam::674083635870:role/osm-cloudwatch-export-role" # osm-backup
+        - roleArn: "arn:aws:iam::683740446523:role/osm-cloudwatch-export-role" # osm-render
+        # Note osm-planet is billed direct to AWS Open Data Program
+      period: 21600
+      length: 21600
+      metrics:
+        - name: EstimatedCharges
+          statistics: [Sum]
+static:
+  - namespace: AWS/S3
+    name: gps-images-replication
+    regions:
+      - eu-north-1
+    roles:
+      - roleArn: "arn:aws:iam::173189593406:role/osm-cloudwatch-export-role" # osm-main
+    dimensions:
+      - name: RuleId
+        value: full-bucket-replication
+      - name: SourceBucket
+        value: openstreetmap-gps-images
+      - name: DestinationBucket
+        value: openstreetmap-gps-images-replicate
+    metrics:
+      - name: ReplicationLatency
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: BytesPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: OperationsPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
+  - namespace: AWS/S3
+    name: gps-traces-replication
+    regions:
+      - eu-north-1
+    roles:
+      - roleArn: "arn:aws:iam::173189593406:role/osm-cloudwatch-export-role" # osm-main
+    dimensions:
+      - name: RuleId
+        value: full-bucket-replication
+      - name: SourceBucket
+        value: openstreetmap-gps-traces
+      - name: DestinationBucket
+        value: openstreetmap-gps-traces-replicate
+    metrics:
+      - name: ReplicationLatency
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: BytesPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: OperationsPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
+  - namespace: AWS/S3
+    name: user-avatars-replication
+    regions:
+      - eu-north-1
+    roles:
+      - roleArn: "arn:aws:iam::173189593406:role/osm-cloudwatch-export-role" # osm-main
+    dimensions:
+      - name: RuleId
+        value: full-bucket-replication
+      - name: SourceBucket
+        value: openstreetmap-user-avatars
+      - name: DestinationBucket
+        value: openstreetmap-user-avatars-replicate
+    metrics:
+      - name: ReplicationLatency
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: BytesPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: OperationsPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
+  - namespace: AWS/S3
+    name: aws-cloudtrail-replication
+    regions:
+      - eu-north-1
+    roles:
+      - roleArn: "arn:aws:iam::173189593406:role/osm-cloudwatch-export-role" # osm-main
+    dimensions:
+      - name: RuleId
+        value: full-bucket-replication
+      - name: SourceBucket
+        value: openstreetmap-aws-cloudtrail
+      - name: DestinationBucket
+        value: openstreetmap-aws-cloudtrail-replicate
+    metrics:
+      - name: ReplicationLatency
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: BytesPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
+      - name: OperationsPendingReplication
+        statistics: [Maximum]
+        period: 300
+        length: 300
diff --git a/cookbooks/prometheus/templates/default/filestat.yml.erb b/cookbooks/prometheus/templates/default/filestat.yml.erb
new file mode 100644 (file)
index 0000000..f77ecab
--- /dev/null
@@ -0,0 +1,6 @@
+exporter:
+  files:
+    - patterns:
+<% node[:prometheus][:files].each do |file| -%>
+        - <%= file %>
+<% end -%>
diff --git a/cookbooks/prometheus/templates/default/grafana.ini.erb b/cookbooks/prometheus/templates/default/grafana.ini.erb
new file mode 100644 (file)
index 0000000..ffd8f97
--- /dev/null
@@ -0,0 +1,24 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+instance_name = prometheus.openstreetmap.org
+
+[server]
+root_url = https://prometheus.openstreetmap.org/
+
+[security]
+admin_user = admin
+admin_password = <%= @passwords[:grafana_admin] %>
+disable_gravatar = true
+cookie_secure = true
+
+[smtp]
+enabled = true
+host = localhost:25
+skip_verify = true
+from_address = admins@openstreetmap.org
+from_name = Prometheus
+
+[auth.anonymous]
+enabled = true
+org_name = OpenStreetMap
+org_role = Viewer
diff --git a/cookbooks/prometheus/templates/default/karma.yml.erb b/cookbooks/prometheus/templates/default/karma.yml.erb
new file mode 100644 (file)
index 0000000..cc61c6e
--- /dev/null
@@ -0,0 +1,21 @@
+karma:
+  name: OpenStreetMap
+alertmanager:
+  interval: 1m
+  servers:
+    - name: openstreetmap
+      uri: http://127.0.0.1:9093/alertmanager/
+      external_uri: https://prometheus.openstreetmap.org/alertmanager/
+      proxy: true
+listen:
+  port: 8081
+  prefix: /karma/
+filters:
+  default:
+    - "@state=active"
+labels:
+  color:
+    static:
+      - instance
+  strip:
+    - "@cluster"
diff --git a/cookbooks/prometheus/templates/default/prometheus.yml.erb b/cookbooks/prometheus/templates/default/prometheus.yml.erb
new file mode 100644 (file)
index 0000000..02ade7d
--- /dev/null
@@ -0,0 +1,136 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+global:
+  scrape_interval: 15s
+  evaluation_interval: 15s
+
+alerting:
+  alertmanagers:
+    - path_prefix: /alertmanager
+      static_configs:
+        - targets:
+            - localhost:9093
+
+rule_files:
+  - /etc/prometheus/*_rules.yml
+
+scrape_configs:
+  - job_name: prometheus
+    scrape_interval: 5s
+    scrape_timeout: 5s
+    metrics_path: /prometheus/metrics
+    static_configs:
+      - targets:
+          - localhost:9090
+  - job_name: alertmanager
+    metrics_path: /alertmanager/metrics
+    static_configs:
+      - targets:
+          - localhost:9093
+  - job_name: ssl
+    scrape_interval: 15m
+    metrics_path: /probe
+    static_configs:
+<% @certificates.values.sort_by { |c| c[:domains].first }.each do |certificate| -%>
+      - targets:
+<% certificate[:nodes].sort_by { |h| h[:name] }.each do |host| -%>
+          - <%= certificate[:domains].first %>/<%= host[:name] %>:443
+<% end -%>
+        labels:
+          domain: <%= certificate[:domains].first %>
+<% end -%>
+    relabel_configs:
+      - source_labels: [__address__]
+        regex: "([^/]+)/.*"
+        target_label: __param_module
+      - source_labels: [__address__]
+        regex: "[^/]+/(.*)"
+        target_label: __param_target
+      - source_labels: [__param_target]
+        regex: "([^.]+)\\..*"
+        target_label: instance
+      - target_label: __address__
+        replacement: 127.0.0.1:9219
+<% @jobs.sort.each do |name, targets| -%>
+  - job_name: <%= name %>
+<% if targets.first[:scrape_interval] -%>
+    scrape_interval: <%= targets.first[:scrape_interval] %>
+<% end -%>
+<% if targets.first[:scrape_timeout] -%>
+    scrape_timeout: <%= targets.first[:scrape_timeout] %>
+<% end -%>
+<% if targets.first[:sni] -%>
+    tls_config:
+      server_name: <%= targets.first[:sni] %>
+    relabel_configs:
+      - target_label: __scheme__
+        replacement: https
+<% end -%>
+    static_configs:
+<% targets.each do |target| -%>
+      - targets:
+          - "<%= target[:address] %>"
+        labels:
+          instance: <%= target[:instance] %>
+<% target[:labels].sort.each do |name, value| -%>
+          <%= name %>: <%= value %>
+<% end -%>
+<% end -%>
+    metric_relabel_configs:
+<% targets.each do |target| -%>
+<% target[:metric_relabel].each do |relabel| -%>
+      - source_labels: [instance,<%= relabel[:source_labels] %>]
+        regex: "<%= target[:instance] %>;<%= relabel[:regex] %>"
+        action: <%= relabel[:action] %>
+<% end -%>
+<% end -%>
+<% end -%>
+  - job_name: junos
+    scrape_interval: 5m
+    scrape_timeout: 4m
+    static_configs:
+<% @junos_targets.sort_by { |t| t[:instance] }.each do |target| -%>
+      - targets:
+          - "<%= target[:target] %>/<%= target[:address] %>"
+        labels:
+          instance: <%= target[:instance] %>
+<% target[:labels].sort.each do |name, value| -%>
+          <%= name %>: <%= value %>
+<% end -%>
+<% end -%>
+    relabel_configs:
+      - source_labels: [__address__]
+        regex: "([^/]+)/.*"
+        target_label: __param_target
+      - source_labels: [__address__]
+        regex: "[^/]+/(.*)"
+        target_label: __address__
+  - job_name: snmp
+    scrape_interval: 5m
+    scrape_timeout: 2m
+    metrics_path: /snmp
+    static_configs:
+<% @snmp_targets.sort_by { |t| t[:instance] }.each do |target| -%>
+      - targets:
+<% target[:modules].each do |module_name| -%>
+          - "<%= target[:target] %>/<%= module_name %>/<%= target[:address] %>"
+<% end -%>
+        labels:
+          instance: <%= target[:instance] %>
+<% target[:labels].sort.each do |name, value| -%>
+          <%= name %>: <%= value %>
+<% end -%>
+<% end -%>
+    relabel_configs:
+      - source_labels: [__address__]
+        regex: "([^/]+)/[^/]+/.*"
+        target_label: __param_target
+      - source_labels: [__address__]
+        regex: "[^/]+/([^/]+)/.*"
+        target_label: __param_module
+      - source_labels: [__address__]
+        regex: "[^/]+/([^/]+)/.*"
+        target_label: module
+      - source_labels: [__address__]
+        regex: "[^/]+/[^/]+/(.*)"
+        target_label: __address__
diff --git a/cookbooks/prometheus/templates/default/smokeping.yml.erb b/cookbooks/prometheus/templates/default/smokeping.yml.erb
new file mode 100644 (file)
index 0000000..7618e64
--- /dev/null
@@ -0,0 +1,16 @@
+---
+targets:
+- hosts:
+<% @ip4_hosts.sort.each do |host| -%>
+  - <%= host %>
+<% end -%>
+  interval: 5s
+  network: ip4
+  size: 24
+- hosts:
+<% @ip6_hosts.sort.each do |host| -%>
+  - <%= host %>
+<% end -%>
+  interval: 5s
+  network: ip6
+  size: 24
diff --git a/cookbooks/prometheus/templates/default/ssl.yml.erb b/cookbooks/prometheus/templates/default/ssl.yml.erb
new file mode 100644 (file)
index 0000000..be622f4
--- /dev/null
@@ -0,0 +1,7 @@
+modules:
+<% @certificates.values.sort_by { |c| c[:domains].first }.each do |certificate| -%>
+  <%= certificate[:domains].first %>:
+    prober: tcp
+    tls_config:
+      server_name: <%= certificate[:domains].first %>
+<% end -%>
index 53dc4c59ab29de609ab792bffd52891667c59599..8abefc794a78781ffd572b93947a43c611265d08 100644 (file)
 # limitations under the License.
 #
 
-package "python"
-package "python-pip"
-
 package "python3"
 package "python3-pip"
 
-package "python-virtualenv"
+package "virtualenv"
index 0679e87e34f7b75030610c1d79be94a7e6a17643..c838690afebe9e21d4284b0a3e5ca3bdf8da9df4 100644 (file)
@@ -17,6 +17,8 @@
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :install
 
 property :package_name, :kind_of => String, :name_property => true
@@ -38,6 +40,20 @@ action :install do
   end
 end
 
+action :upgrade do
+  if new_resource.version.nil?
+    execute "pip-upgrade-#{new_resource.package_name}" do
+      command "#{pip_command} install --upgrade #{new_resource.package_name}"
+      only_if "#{pip_command} list --outdated | fgrep -q #{new_resource.package_name}"
+    end
+  else
+    execute "pip-upgrade-#{new_resource.package_name}" do
+      command "#{pip_command} install --upgrade #{new_resource.package_name}==#{new_resource.version}"
+      not_if "#{pip_command} show #{new_resource.package_name} | fgrep -q #{new_resource.version}"
+    end
+  end
+end
+
 action :remove do
   execute "pip-uninstall-#{new_resource.package_name}" do
     command "#{pip_command} uninstall #{new_resource.package_name}"
index cb372f4c3bb1c1730027d4ae8eed2a1dece99e23..8b13917614daadcdb2ce9d4f4d7fbedd77d0693f 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
 property :virtualenv_directory, :kind_of => String, :name_property => true
+property :interpreter, :kind_of => String, :default => "/usr/bin/python"
 
 action :create do
   execute "virtualenv-#{new_resource.virtualenv_directory}" do
-    command "virtualenv #{new_resource.virtualenv_directory}"
+    command "virtualenv --python=#{new_resource.interpreter} #{new_resource.virtualenv_directory}"
     not_if { ::File.exist?(new_resource.virtualenv_directory) }
   end
 end
diff --git a/cookbooks/roundup/README.md b/cookbooks/roundup/README.md
deleted file mode 100644 (file)
index a40f953..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# Roundup Cookbook
-
-This is a placeholder cookbook, intended for use with the Roundup Issue Tracker.
index e32c2b7edfd038a7b74b129ed8fb6ca40b27b8a8..38e70fe78a6c2ffdc83735dafe7ca6eb92a2a178 100644 (file)
@@ -7,3 +7,4 @@ description       "Configures rsyncd"
 version           "1.0.0"
 supports          "ubuntu"
 depends           "networking"
+depends           "systemd"
index 7a93fc021fa20cbccb26a3fc67ae13da470da711..89ee459091705e5e057647b191921fe0beb393ad 100644 (file)
 
 include_recipe "networking"
 
+writable_paths = []
 hosts_allow = {}
 hosts_deny = {}
 
 node[:rsyncd][:modules].each do |name, details|
+  writable_paths << details[:path] if details[:write_only]
+
   hosts_allow[name] = details[:hosts_allow] || []
 
   if details[:nodes_allow]
@@ -42,6 +45,15 @@ end
 
 package "rsync"
 
+systemd_service "rsync-override" do
+  service "rsync"
+  dropin "override"
+  exec_start "/usr/bin/rsync --daemon --no-detach"
+  nice 10
+  read_write_paths writable_paths.sort
+  notifies :restart, "service[rsync]"
+end
+
 service "rsync" do
   action [:enable, :start]
   supports :status => true, :restart => true
@@ -51,7 +63,7 @@ template "/etc/default/rsync" do
   source "rsync.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :restart, "service[rsync]"
 end
 
@@ -59,15 +71,14 @@ template "/etc/rsyncd.conf" do
   source "rsyncd.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   variables :hosts_allow => hosts_allow, :hosts_deny => hosts_deny
 end
 
 firewall_rule "accept-rsync" do
   action :accept
-  source "net"
-  dest "fw"
-  proto "tcp:syn"
+  context :incoming
+  protocol :tcp
   dest_ports "rsync"
-  source_ports "1024:"
+  source_ports "1024-65535"
 end
diff --git a/cookbooks/ruby/README.md b/cookbooks/ruby/README.md
new file mode 100644 (file)
index 0000000..d7f1641
--- /dev/null
@@ -0,0 +1,3 @@
+# Ruby Cookbook
+
+Installs and configures ruby.
diff --git a/cookbooks/ruby/attributes/default.rb b/cookbooks/ruby/attributes/default.rb
new file mode 100644 (file)
index 0000000..eefaf22
--- /dev/null
@@ -0,0 +1,9 @@
+default[:ruby][:version] = if platform?("debian")
+                             "3.1"
+                           elsif node[:lsb][:release].to_f < 22.04
+                             "2.7"
+                           else
+                             "3.0"
+                           end
+default[:ruby][:gem] = "/usr/bin/gem#{node[:ruby][:version]}"
+default[:ruby][:bundle] = "/usr/bin/bundle#{node[:ruby][:version]}"
similarity index 70%
rename from cookbooks/nfs/metadata.rb
rename to cookbooks/ruby/metadata.rb
index e83da596a4cf2f0afabd95ac4e26d1d37e95cbb4..d8f2eac0edf453d840c89c85c86031d21200ffef 100644 (file)
@@ -1,8 +1,8 @@
-name              "nfs"
+name              "ruby"
 maintainer        "OpenStreetMap Administrators"
 maintainer_email  "admins@openstreetmap.org"
 license           "Apache-2.0"
-description       "Installs and configures nfs"
+description       "Installs and configures ruby"
 
 version           "1.0.0"
 supports          "ubuntu"
diff --git a/cookbooks/ruby/recipes/default.rb b/cookbooks/ruby/recipes/default.rb
new file mode 100644 (file)
index 0000000..a2833ae
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# Cookbook:: ruby
+# Recipe:: default
+#
+# Copyright:: 2022, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+ruby_version = node[:ruby][:version]
+
+package %W[
+  ruby
+  ruby#{ruby_version}
+  ruby
+  ruby#{ruby_version}-dev
+]
+
+gem_package "bundler#{ruby_version}-1" do
+  package_name "bundler"
+  version "~> 1.17.3"
+  gem_binary node[:ruby][:gem]
+  options "--format-executable"
+end
+
+gem_package "bundler#{ruby_version}-2" do
+  package_name "bundler"
+  version "~> 2.3.16"
+  gem_binary node[:ruby][:gem]
+  options "--format-executable"
+end
diff --git a/cookbooks/ruby/resources/bundle_exec.rb b/cookbooks/ruby/resources/bundle_exec.rb
new file mode 100644 (file)
index 0000000..e4150f6
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# Cookbook:: ruby
+# Resource:: bundle_exec
+#
+# Copyright:: 2022, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+resource_name :bundle_exec
+provides :bundle_exec
+
+unified_mode true
+
+default_action :run
+
+property :directory, :kind_of => String, :name_property => true
+property :command, :kind_of => String
+property :user, :kind_of => String
+property :group, :kind_of => String
+property :environment, :kind_of => Hash
+
+action :run do
+  execute "#{new_resource.directory}/Gemfile" do
+    command "#{bundle_command} exec #{new_resource.command}"
+    cwd new_resource.directory
+    user new_resource.user
+    group new_resource.group
+    environment new_resource.environment
+  end
+end
+
+action_class do
+  def bundle_command
+    node[:ruby][:bundle]
+  end
+end
diff --git a/cookbooks/ruby/resources/bundle_install.rb b/cookbooks/ruby/resources/bundle_install.rb
new file mode 100644 (file)
index 0000000..897bde5
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# Cookbook:: ruby
+# Resource:: bundle_install
+#
+# Copyright:: 2022, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+resource_name :bundle_install
+provides :bundle_install
+
+unified_mode true
+
+default_action :run
+
+property :directory, :kind_of => String, :name_property => true
+property :options, :kind_of => String
+property :user, :kind_of => String
+property :group, :kind_of => String
+property :environment, :kind_of => Hash
+
+action :run do
+  execute "#{new_resource.directory}/Gemfile" do
+    command "#{bundle_command} install #{new_resource.options}"
+    cwd new_resource.directory
+    user new_resource.user
+    group new_resource.group
+    environment new_resource.environment
+  end
+end
+
+action_class do
+  def bundle_command
+    node[:ruby][:bundle]
+  end
+end
+
+def after_created
+  subscribes :run, "gem_package[bundler#{node[:ruby][:version]}-1]"
+  subscribes :run, "gem_package[bundler#{node[:ruby][:version]}-2]"
+end
index 64239b18f6d93da650b7ee088992128e5bafe9d3..3f18f255e5d2c798727b2cc361842ab1e4caaeab 100644 (file)
@@ -2,4 +2,4 @@
 
 This cookbook configures the hardware details website found at
 [hardware.openstreetmap.org](https://hardware.openstreetmap.org). The code for
-the website itself is available at [github.com/gravitystorm/osmf-server-info](https://github.com/gravitystorm/osmf-server-info).
+the website itself is available at [github.com/osmfoundation/osmf-server-info](https://github.com/osmfoundation/osmf-server-info).
index 73a4b3895f3cf0631d3989bcf91b254b9ca47c0a..55d69f066a86c04d0e34089187d1410f87e39fea 100644 (file)
@@ -8,3 +8,4 @@ version           "1.0.0"
 supports          "ubuntu"
 depends           "apache"
 depends           "git"
+depends           "ruby"
index 92bd5703deb481f81ab5614e080934bd0aef6baf..2bbc31e5b0d70d406ac702b3021e0ce6b67c4af4 100644 (file)
 
 include_recipe "apache"
 include_recipe "git"
+include_recipe "ruby"
 
 package %w[
-  ruby
-  ruby-dev
+  gcc
+  g++
+  make
+  libssl-dev
   zlib1g-dev
+  pkg-config
 ]
 
-gem_package "bundler" do
-  version "1.17.3"
-end
-
 git "/srv/hardware.openstreetmap.org" do
   action :sync
-  repository "git://github.com/gravitystorm/osmf-server-info.git"
+  repository "https://github.com/osmfoundation/osmf-server-info.git"
+  depth 1
   user "root"
   group "root"
-  notifies :run, "execute[/srv/hardware.openstreetmap.org/Gemfile]"
+  notifies :run, "bundle_install[/srv/hardware.openstreetmap.org]"
 end
 
 nodes = { :rows => search(:node, "*:*") }
@@ -43,58 +44,62 @@ roles = { :rows => search(:role, "*:*") }
 
 file "/srv/hardware.openstreetmap.org/_data/nodes.json" do
   content nodes.to_json
-  mode 0o644
+  mode "644"
   owner "root"
   group "root"
-  notifies :run, "execute[/srv/hardware.openstreetmap.org]"
+  notifies :run, "bundle_exec[/srv/hardware.openstreetmap.org]"
 end
 
 file "/srv/hardware.openstreetmap.org/_data/roles.json" do
   content roles.to_json
-  mode 0o644
+  mode "644"
   owner "root"
   group "root"
-  notifies :run, "execute[/srv/hardware.openstreetmap.org]"
+  notifies :run, "bundle_exec[/srv/hardware.openstreetmap.org]"
 end
 
 directory "/srv/hardware.openstreetmap.org/_site" do
-  mode 0o755
+  mode "755"
   owner "nobody"
   group "nogroup"
 end
 
-# Workaround https://github.com/jekyll/jekyll/issues/7804
-# by creating a .jekyll-cache folder
-directory "/srv/hardware.openstreetmap.org/.jekyll-cache" do
-  mode 0o755
+directory "/srv/hardware.openstreetmap.org/vendor" do
+  action :create
   owner "nobody"
   group "nogroup"
+  notifies :run, "bundle_install[/srv/hardware.openstreetmap.org]", :immediately
 end
 
-execute "/srv/hardware.openstreetmap.org/Gemfile" do
+bundle_install "/srv/hardware.openstreetmap.org" do
   action :nothing
-  command "bundle install --deployment"
-  cwd "/srv/hardware.openstreetmap.org"
-  user "root"
-  group "root"
-  notifies :run, "execute[/srv/hardware.openstreetmap.org]"
+  user "nobody"
+  group "nogroup"
+  environment "BUNDLE_FROZEN" => "true",
+              "BUNDLE_WITHOUT" => "development:test",
+              "BUNDLE_PATH" => "vendor/bundle",
+              "BUNDLE_DEPLOYMENT" => "1",
+              "BUNDLE_JOBS" => node.cpu_cores.to_s
+  notifies :run, "bundle_exec[/srv/hardware.openstreetmap.org]"
 end
 
-execute "/srv/hardware.openstreetmap.org" do
+bundle_exec "/srv/hardware.openstreetmap.org" do
   action :nothing
-  command "bundle exec jekyll build --trace --baseurl=https://hardware.openstreetmap.org"
-  cwd "/srv/hardware.openstreetmap.org"
+  command "jekyll build --trace --disable-disk-cache --baseurl=https://hardware.openstreetmap.org"
   user "nobody"
   group "nogroup"
+  environment "LANG" => "C.UTF-8",
+              "BUNDLE_PATH" => "vendor/bundle",
+              "BUNDLE_DEPLOYMENT" => "1"
 end
 
 ssl_certificate "hardware.openstreetmap.org" do
-  domains ["hardware.openstreetmap.org", "hardware.osm.org"]
+  domains ["hardware.openstreetmap.org", "hardware.osm.org", "hardware.osmfoundation.org"]
   notifies :reload, "service[apache2]"
 end
 
 apache_site "hardware.openstreetmap.org" do
   template "apache.erb"
   directory "/srv/hardware.openstreetmap.org/_site"
-  variables :aliases => ["hardware.osm.org"]
+  variables :aliases => ["hardware.osm.org", "hardware.osmfoundation.org"]
 end
index 309f59550aaee9fb562264e2e9144c3678485665..3f4416aa06bb703642187b6258a02300268ef190 100644 (file)
@@ -7,7 +7,7 @@
 <% end -%>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
@@ -26,7 +26,7 @@
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent / https://<%= @name %>/
@@ -37,7 +37,7 @@
   ServerName <%= @name %>
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   SSLEngine on
index 0cba387e1899db761de28619d10a93a1c854b613..3e7c1d1c42db9e38a14180e1aae10a953c2cc2a2 100644 (file)
@@ -1 +1 @@
-default[:rsyncd][:modules] = []
+default[:snmpd][:clients] = []
index ccafc831cc98bd1a6f37aea7f608fd822514f134..f4a57fef2851d72d81ae9b8e456f3a5203378e6c 100644 (file)
@@ -23,40 +23,25 @@ communities = data_bag_item("snmpd", "communities")
 
 package "snmpd"
 
-service "snmpd" do
-  action [:enable, :start]
-  supports :status => true, :restart => true
-end
-
 template "/etc/snmp/snmpd.conf" do
   source "snmpd.conf.erb"
   owner "root"
   group "root"
-  mode 0o600
+  mode "600"
   variables :communities => communities
   notifies :restart, "service[snmpd]"
 end
 
-if node[:snmpd][:clients]
-  node[:snmpd][:clients].each do |address|
-    firewall_rule "accept-snmp" do
-      action :accept
-      family "inet"
-      source "net:#{address}"
-      dest "fw"
-      proto "udp"
-      dest_ports "snmp"
-      source_ports "1024:"
-    end
-  end
-else
-  firewall_rule "accept-snmp" do
-    action :accept
-    family "inet"
-    source "net"
-    dest "fw"
-    proto "udp"
-    dest_ports "snmp"
-    source_ports "1024:"
-  end
+service "snmpd" do
+  action [:enable, :start]
+  supports :status => true, :restart => true
+end
+
+firewall_rule "accept-snmp" do
+  action :accept
+  context :incoming
+  protocol :udp
+  source node[:snmpd][:clients] if node[:snmpd][:clients]
+  dest_ports "snmp"
+  source_ports "1024-65535"
 end
index 9239fbd309aaa7a90836264e51edd436578b0521..3b79ad1f8a65e4b73fd9530248483573e1fe399c 100644 (file)
@@ -1,6 +1,9 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
-rocommunity     <%= @communities[node[:snmpd][:community]] %>
+<% Array(@communities[node[:snmpd][:community]]).each do |community| -%>  
+rocommunity     <%= community %>
+rocommunity6    <%= community %>
+<% end -%>
 syslocation     <%= node[:snmpd][:location] %>
 <% if node[:snmpd][:contact] -%>
 syscontact      <%= node[:snmpd][:contact] %>
index 470463eafce467cb3d9a9dac59f8df88f0478a9d..acd564bf7a62c52d8cd0045f6de3ba96a7773007 100644 (file)
@@ -6,3 +6,4 @@ description       "Installs and configures spamassassin"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "exim"
index 49b15a583da44975fd1232d3381b5bdd9b81eece..db498b75f4bf7bd52681734664301f3caae08098 100644 (file)
 
 package "spamassassin"
 
-service "spamassassin" do
+service_name = if platform?("debian")
+                 "spamd"
+               else
+                 "spamassassin"
+               end
+
+service service_name do
   action [:enable, :start]
   supports :status => true, :restart => true, :reload => true
 end
@@ -27,15 +33,15 @@ end
 directory "/var/spool/spamassassin" do
   owner "debian-spamd"
   group "debian-spamd"
-  mode 0o755
+  mode "755"
 end
 
 template "/etc/default/spamassassin" do
   source "spamassassin.erb"
   owner "root"
   group "root"
-  mode 0o644
-  notifies :restart, "service[spamassassin]"
+  mode "644"
+  notifies :restart, "service[#{service_name}]"
 end
 
 trusted_networks = node[:exim][:relay_from_hosts]
@@ -52,7 +58,7 @@ template "/etc/spamassassin/local.cf" do
   source "local.cf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   variables :trusted_networks => trusted_networks.sort
-  notifies :restart, "service[spamassassin]"
+  notifies :restart, "service[#{service_name}]"
 end
index 286d1feeb9bd5a0e091083d9baf36d371438f459..1f5769d502c42462a8f4a42ec476160c85255506 100644 (file)
@@ -10,7 +10,7 @@ ENABLED=1
 # make sure --max-children is not set to anything higher than 5,
 # unless you know what you're doing.
 
-OPTIONS="--username debian-spamd --nouser-config"
+OPTIONS="--username debian-spamd --nouser-config --max-children=20 --max-spare=5"
 
 # Pid file
 # Where should spamd write its PID to file? If you use the -u or
diff --git a/cookbooks/squid/README.md b/cookbooks/squid/README.md
deleted file mode 100644 (file)
index 4946af4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# Squid cookbook
-
-This cookbook installs the Squid caching proxy service and configures it for use
-as a tile cache.
diff --git a/cookbooks/squid/attributes/default.rb b/cookbooks/squid/attributes/default.rb
deleted file mode 100644 (file)
index 7b7333d..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-default[:squid][:version] = 4
-default[:squid][:cache_mem] = "256 MB"
-default[:squid][:cache_dir] = "ufs /var/spool/squid 256 16 256"
-default[:squid][:access_log] = "/var/log/squid/access.log openstreetmap"
-
-default[:apt][:sources] = node[:apt][:sources] | ["squid#{node[:squid][:version]}"]
diff --git a/cookbooks/squid/recipes/default.rb b/cookbooks/squid/recipes/default.rb
deleted file mode 100644 (file)
index fcc5f33..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#
-# Cookbook:: squid
-# Recipe:: default
-#
-# Copyright:: 2011, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-if node[:squid][:version] >= 3
-  apt_package "squid" do
-    action :unlock
-  end
-
-  apt_package "squid-common" do
-    action :unlock
-  end
-
-  apt_package "squid" do
-    action :purge
-    only_if "dpkg-query -W squid | fgrep -q 2."
-  end
-
-  apt_package "squid-common" do
-    action :purge
-    only_if "dpkg-query -W squid-common | fgrep -q 2."
-  end
-
-  file "/store/squid/coss-01" do
-    action :delete
-    backup false
-  end
-
-  package "squidclient" do
-    action :upgrade
-  end
-end
-
-package "squid"
-package "squidclient"
-
-template "/etc/squid/squid.conf" do
-  source "squid.conf.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
-directory "/etc/squid/squid.conf.d" do
-  owner "root"
-  group "root"
-  mode 0o755
-end
-
-Array(node[:squid][:cache_dir]).each do |cache_dir|
-  if cache_dir =~ /^coss (\S+) /
-    cache_dir = File.dirname(Regexp.last_match(1))
-  elsif cache_dir =~ /^\S+ (\S+) /
-    cache_dir = Regexp.last_match(1)
-  end
-
-  directory cache_dir do
-    owner "proxy"
-    group "proxy"
-    mode 0o750
-    recursive true
-    notifies :restart, "service[squid]"
-  end
-end
-
-systemd_tmpfile "/var/run/squid" do
-  type "d"
-  owner "proxy"
-  group "proxy"
-  mode "0755"
-end
-
-address_families = %w[AF_UNIX AF_INET AF_INET6]
-
-systemd_service "squid" do
-  description "Squid caching proxy"
-  after ["network.target", "nss-lookup.target"]
-  type "forking"
-  limit_nofile 98304
-  exec_start_pre "/usr/sbin/squid --foreground -z"
-  exec_start "/usr/sbin/squid -YC"
-  exec_reload "/bin/kill -HUP $MAINPID"
-  pid_file "/var/run/squid.pid"
-  private_tmp true
-  private_devices true
-  protect_system "full"
-  protect_home true
-  restrict_address_families address_families
-  restart "always"
-  kill_mode "mixed"
-end
-
-service "squid" do
-  action [:enable, :start]
-  subscribes :restart, "systemd_service[squid]"
-  subscribes :restart, "template[/etc/squid/squid.conf]"
-  subscribes :reload, "template[/etc/resolv.conf]"
-end
-
-log "squid-restart" do
-  message "Restarting squid due to counter wraparound"
-  notifies :restart, "service[squid]"
-  only_if do
-    IO.popen(["squidclient", "--host=127.0.0.1", "--port=3128", "mgr:counters"]) do |io|
-      io.each.grep(/^[a-z][a-z_.]+ = -[0-9]+$/).count.positive?
-    end
-  end
-end
-
-munin_plugin "squid_cache"
-munin_plugin "squid_times"
-munin_plugin "squid_icp"
-munin_plugin "squid_objectsize"
-munin_plugin "squid_requests"
-munin_plugin "squid_traffic"
-
-munin_plugin "squid_delay_pools" do
-  action :delete
-end
-
-munin_plugin "squid_delay_pools_noreferer" do
-  action :delete
-end
diff --git a/cookbooks/squid/resources/fragment.rb b/cookbooks/squid/resources/fragment.rb
deleted file mode 100644 (file)
index d3778c4..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# Cookbook:: squid
-# Resource:: squid_fragment
-#
-# Copyright:: 2015, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-default_action :create
-
-property :fragment, :kind_of => String, :name_attribute => true
-property :template, :kind_of => String, :required => true
-property :variables, :kind_of => Hash, :default => {}
-
-action :create do
-  declare_resource :template, fragment_path do
-    source new_resource.template
-    owner "root"
-    group "root"
-    mode 0o644
-    variables new_resource.variables
-  end
-end
-
-action :delete do
-  file fragment_path do
-    action :delete
-  end
-end
-
-action_class do
-  def fragment_path
-    "/etc/squid/squid.conf.d/#{new_resource.fragment}.conf"
-  end
-end
-
-def after_created
-  notifies :create, "template[/etc/squid/squid.conf]"
-end
diff --git a/cookbooks/squid/templates/default/squid.conf.erb b/cookbooks/squid/templates/default/squid.conf.erb
deleted file mode 100644 (file)
index ede39ef..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# configure host name
-visible_hostname <%= node.name %>
-
-cache_mem  <%= node[:squid][:cache_mem] %>
-<% if node[:squid][:version] > 2 -%>
-
-workers <%= [ node[:cpu][:total] - 2, 1 ].max.ceil %>
-cpu_affinity_map process_numbers=<%= (1..[ node[:cpu][:total] - 2, 1 ].max.ceil).to_a.join(',') %> cores=<%=(1..[ node[:cpu][:total] - 2, 1 ].max.ceil).to_a.join(',') %>
-
-# Set short clean shutdown interval
-shutdown_lifetime 10 seconds
-
-error_log_languages off
-<% end -%>
-
-max_filedescriptors 98304
-
-<% if node[:squid][:version] > 3 -%>
-# Use RFC6891 recommended max size
-dns_packet_max 4096 bytes
-# Use low initial retry interval (backoff start)
-dns_retransmit_interval 2 seconds
-# Set low timeout
-dns_timeout 15 seconds
-<% end -%>
-
-# used by squidclient / munin
-http_port 3128
-# HTCP
-htcp_port 4827
-# ICP
-icp_port 3130
-log_icp_queries off
-
-<% if node[:squid][:version] < 3 -%>
-http_port 80 accel defaultsite=tile.openstreetmap.org tcpkeepalive=60,10,6 http11
-<% else -%>
-http_port 80 accel no-vhost defaultsite=tile.openstreetmap.org tcpkeepalive=60,10,6
-http_port 8080 accel no-vhost defaultsite=tile.openstreetmap.org tcpkeepalive=60,10,6
-<% end -%>
-
-cache_effective_user proxy
-cache_effective_group proxy
-
-<% Array(node[:squid][:cache_dir]).each do |cache_dir| -%>
-cache_dir <%= cache_dir %>
-<% end -%>
-
-<% if node[:squid][:version] < 3 -%>
-cache_swap_log /var/spool/squid/%s
-<% end -%>
-
-cache_mgr webmaster@openstreetmap.org
-
-quick_abort_min 0 KB
-quick_abort_max 0 KB
-
-read_ahead_gap 64 KB
-
-maximum_object_size 256 KB
-maximum_object_size_in_memory 64 KB
-
-cache_replacement_policy heap LFUDA
-memory_replacement_policy heap GDSF
-
-server_persistent_connections on
-<% if node[:squid][:version] < 3 -%>
-persistent_request_timeout 1 minutes
-<% else -%>
-client_idle_pconn_timeout 1 minutes
-<% end -%>
-<% if node[:squid][:version] > 3 -%>
-pconn_lifetime 5 minutes
-<% end -%>
-
-negative_ttl 15 seconds
-<% if node[:squid][:version] < 3 -%>
-pipeline_prefetch on
-<% end -%>
-
-read_timeout 90 seconds
-request_timeout 90 seconds
-connect_timeout 20 seconds
-client_lifetime 1 hours
-
-<% if node[:squid][:version] < 3 -%>
-refresh_stale_hit 300 seconds
-<% end -%>
-
-# Recommended minimum configuration:
-# ----------------------------------
-<% if node[:squid][:version] < 3 -%>
-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
-<% end -%>
-acl SSL_ports port 443
-acl Safe_ports port 80          # http
-acl Safe_ports port 21          # ftp
-acl Safe_ports port 443         # https
-acl Safe_ports port 70          # gopher
-acl Safe_ports port 210         # wais
-acl Safe_ports port 1025-65535  # unregistered ports
-acl Safe_ports port 280         # http-mgmt
-acl Safe_ports port 488         # gss-http
-acl Safe_ports port 591         # filemaker
-acl Safe_ports port 777         # multiling http
-acl CONNECT method CONNECT
-http_access allow manager localhost
-
-http_access allow manager
-
-http_access deny manager
-http_access deny !Safe_ports
-http_access deny CONNECT !SSL_ports
-# ----------------------------------
-
-acl purge_hosts src 127.0.0.0/8
-acl PURGE method purge
-http_access allow purge purge_hosts
-http_access deny purge
-
-forwarded_for on
-follow_x_forwarded_for allow localhost
-
-<% if node[:squid][:version] < 3 -%>
-logformat openstreetmap %ts.%03tu %tr %>a %Ss/%03Hs %<st %rm %rp %Sh/%<A %mt "%{Referer}>h" "%{User-Agent}>h"
-access_log <%= node[:squid][:access_log] %>
-<% else -%>
-logformat openstreetmap %ts.%03tu %tr %>a %Ss/%03>Hs %<st %rm %>rp %Sh/%<A %mt "%{Referer}>h" "%{User-Agent}>h"
-access_log daemon:<%= node[:squid][:access_log] %>
-<% end -%>
-cache_log /var/log/squid/cache.log
-cache_store_log none
-
-client_db off
-strip_query_terms off
-<% if node[:squid][:version] > 2 -%>
-# Work around bug in squid 3 that causes log_fqdn to be
-# turned on by some of the (unused by us) default formats:
-# http://lists.squid-cache.org/pipermail/squid-users/2016-February/thread.html#8999
-url_rewrite_extras "%>a %un %>rm myip=%la myport=%lp"
-store_id_extras "%>a %un %>rm myip=%la myport=%lp"
-<% end -%>
-
-digest_generation on
-
-refresh_pattern .              0       50%     20160
-refresh_pattern -i tile.openstreetmap.org 60 80% 20160 reload-into-ims
-
-# ZERO required for logrotate to work properly
-logfile_rotate 0
-
-<% Dir.glob("/etc/squid/squid.conf.d/*.conf") do |file| -%>
-<%= File.read(file) %>
-<% end -%>
-
-# MUST BE LAST ACL
-# --------------
-http_access deny all
-htcp_access deny all
-icp_access deny all
-# --------------
index 55c7ebee5479cb9a2465c63ab235c05a895ac0b7..b1785343efa6288e081405985270d2358e9f4506 100644 (file)
@@ -1,3 +1,4 @@
 default[:ssl][:openssl_ciphers] = "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS"
-default[:ssl][:gnutls_ciphers] = "NONE:+AEAD:+SHA256:+SHA1:+SHA384:+SHA512:+CURVE-X25519:+CURVE-SECP256R1:+CURVE-SECP384R1:+CURVE-SECP521R1:+SIGN-ALL:-SIGN-RSA-MD5:-SIGN-DSA-SHA1:-SIGN-DSA-SHA224:-SIGN-DSA-SHA256:-SIGN-DSA-SHA384:-SIGN-DSA-SHA512:+AES-256-GCM:+AES-256-CCM:+CHACHA20-POLY1305:+CAMELLIA-256-GCM:+AES-256-CBC:+CAMELLIA-256-CBC:+AES-128-GCM:+AES-128-CCM:+CAMELLIA-128-GCM:+AES-128-CBC:+CAMELLIA-128-CBC:+ECDHE-RSA:+ECDHE-ECDSA:+RSA:+DHE-RSA:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-DTLS1.2:+VERS-DTLS1.0:+COMP-NULL:%PROFILE_LOW"
+default[:ssl][:gnutls_ciphers] = "NONE:+AEAD:+SHA256:+SHA1:+SHA384:+SHA512:+CURVE-X25519:+CURVE-SECP256R1:+CURVE-SECP384R1:+CURVE-SECP521R1:+SIGN-ALL:-SIGN-RSA-MD5:-SIGN-DSA-SHA1:-SIGN-DSA-SHA224:-SIGN-DSA-SHA256:-SIGN-DSA-SHA384:-SIGN-DSA-SHA512:+AES-256-GCM:+AES-256-CCM:+CHACHA20-POLY1305:+CAMELLIA-256-GCM:+AES-256-CBC:+CAMELLIA-256-CBC:+AES-128-GCM:+AES-128-CCM:+CAMELLIA-128-GCM:+AES-128-CBC:+CAMELLIA-128-CBC:+ECDHE-RSA:+ECDHE-ECDSA:+RSA:+DHE-RSA:+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-DTLS1.2:+VERS-DTLS1.0:+COMP-NULL:%PROFILE_LOW"
 default[:ssl][:strict_transport_security] = "max-age=31536000; includeSubDomains; preload"
+default[:ssl][:ct_report_uri] = "https://openstreetmap.report-uri.com/r/d/ct/reportOnly"
diff --git a/cookbooks/ssl/files/default/dhparam.pem b/cookbooks/ssl/files/default/dhparam.pem
new file mode 100644 (file)
index 0000000..9b182b7
--- /dev/null
@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
+87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
+YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
+7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
+ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
+-----END DH PARAMETERS-----
diff --git a/cookbooks/ssl/files/default/letsencrypt.pem b/cookbooks/ssl/files/default/letsencrypt.pem
deleted file mode 100644 (file)
index 0002462..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
-MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
-DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
-SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
-GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
-q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
-SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
-Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
-a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
-/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
-AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
-CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
-bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
-c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
-VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
-ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
-MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
-Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
-AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
-uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
-wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
-X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
-PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
-KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
------END CERTIFICATE-----
index 674c8768d24f897f95199939a5e6e4ac65209d3b..17bb6339ecf4bf2e4aa5324a6c5c518ee85598da 100644 (file)
 package "openssl"
 package "ssl-cert"
 
-cookbook_file "/etc/ssl/certs/letsencrypt.pem" do
+cookbook_file "/etc/ssl/certs/dhparam.pem" do
   owner "root"
   group "root"
-  mode 0o444
+  mode "444"
   backup false
 end
-
-openssl_dhparam "/etc/ssl/certs/dhparam.pem" do
-  owner "root"
-  group "root"
-  mode 0o444
-end
index fdbcf2b526404f4ee82d79196979abbdf6b3ad8c..f2fb4784c35219d6281d5ffb62f00d86c840c80e 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
 property :certificate, String, :name_property => true
-property :domains, [String, Array], :required => true
+property :domains, [String, Array], :required => [:create]
 
 action :create do
   node.default[:letsencrypt][:certificates][new_resource.certificate] = {
-    :domains => Array(new_resource.domains)
+    :domains => domains
   }
 
   if letsencrypt
@@ -36,7 +38,7 @@ action :create do
     file "/etc/ssl/certs/#{new_resource.certificate}.pem" do
       owner "root"
       group "root"
-      mode 0o444
+      mode "444"
       content certificate
       backup false
       manage_symlink_source false
@@ -46,23 +48,23 @@ action :create do
     file "/etc/ssl/private/#{new_resource.certificate}.key" do
       owner "root"
       group "ssl-cert"
-      mode 0o440
+      mode "440"
       content key
       backup false
       manage_symlink_source false
       force_unlink true
     end
   else
-    alt_names = new_resource.domains.collect { |domain| "DNS:#{domain}" }
+    alt_names = domains.collect { |domain| "DNS:#{domain}" }
 
     openssl_x509_certificate "/etc/ssl/certs/#{new_resource.certificate}.pem" do
       key_file "/etc/ssl/private/#{new_resource.certificate}.key"
       owner "root"
       group "ssl-cert"
-      mode 0o640
+      mode "640"
       org "OpenStreetMap"
       email "operations@osmfoundation.org"
-      common_name new_resource.domains.first
+      common_name domains.first
       subject_alt_name alt_names
       extensions "keyUsage" => { "values" => %w[digitalSignature keyEncipherment], "critical" => true },
                  "extendedKeyUsage" => { "values" => %w[serverAuth clientAuth], "critical" => true }
@@ -84,4 +86,8 @@ action_class do
   def letsencrypt
     @letsencrypt ||= search(:letsencrypt, "id:#{new_resource.certificate}").first
   end
+
+  def domains
+    Array(new_resource.domains)
+  end
 end
index 63481503df6e6ee5d6e1000d77095a3b32d64e46..139ba825e79c3df42576e82ad93dd58b660efdc6 100644 (file)
@@ -6,4 +6,6 @@ description       "Installs and configures State of the Map services"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "apache"
+depends           "podman"
 depends           "wordpress"
diff --git a/cookbooks/stateofthemap/recipes/container.rb b/cookbooks/stateofthemap/recipes/container.rb
new file mode 100644 (file)
index 0000000..16cb780
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Cookbook:: stateofthemap
+# Recipe:: container
+#
+# Copyright:: 2022, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "podman::apache"
+
+podman_site "stateofthemap.org" do
+  image "ghcr.io/openstreetmap/stateofthemap-website:latest"
+  aliases ["www.stateofthemap.org", "stateofthemap.com", "www.stateofthemap.com", "sotm.org", "www.sotm.org"]
+end
+
+%w[2013 2016 2017 2018 2019 2020 2021 2022 2024].each do |year|
+  podman_site "#{year}.stateofthemap.org" do
+    image "ghcr.io/openstreetmap/stateofthemap-#{year}:latest"
+    aliases ["#{year}.stateofthemap.com", "#{year}.sotm.org"]
+  end
+end
index 162c1002f68c8f39c31a5a0832dfa1571909b2da..3047f77a84f98c73dc6bafa8690d2b84688fbcf8 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-include_recipe "wordpress"
-
-passwords = data_bag_item("stateofthemap", "passwords")
-
-git "/srv/stateofthemap.org" do
-  action :sync
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "chooser"
-  user "root"
-  group "root"
-end
-
-ssl_certificate "stateofthemap.org" do
-  domains ["stateofthemap.org", "www.stateofthemap.org",
-           "stateofthemap.com", "www.stateofthemap.com",
-           "sotm.org", "www.sotm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "stateofthemap.org" do
-  template "apache.erb"
-  directory "/srv/stateofthemap.org"
-end
-
-directory "/srv/2007.stateofthemap.org" do
-  owner "wordpress"
-  group "wordpress"
-  mode 0o755
-end
-
-wordpress_site "2007.stateofthemap.org" do
-  aliases "2007.stateofthemap.com"
-  directory "/srv/2007.stateofthemap.org/wp"
-  database_name "sotm2007"
-  database_user "sotm2007"
-  database_password passwords["sotm2007"]
-  database_prefix "wp_sotm_"
-end
-
-wordpress_theme "2007.stateofthemap.org-refreshwp-11" do
-  theme "refreshwp-11"
-  site "2007.stateofthemap.org"
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "theme-2007"
-end
-
-wordpress_plugin "2007.stateofthemap.org-geopress" do
-  plugin "geopress"
-  site "2007.stateofthemap.org"
-end
-
-directory "/srv/2008.stateofthemap.org" do
-  owner "wordpress"
-  group "wordpress"
-  mode 0o755
-end
-
-wordpress_site "2008.stateofthemap.org" do
-  aliases "2008.stateofthemap.com"
-  directory "/srv/2008.stateofthemap.org/wp"
-  database_name "sotm2008"
-  database_user "sotm2008"
-  database_password passwords["sotm2008"]
-  database_prefix "wp_sotm08_"
-end
-
-wordpress_theme "2008.stateofthemap.org-refreshwp-11" do
-  theme "refreshwp-11"
-  site "2008.stateofthemap.org"
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "theme-2008"
-end
-
-wordpress_plugin "2008.stateofthemap.org-geopress" do
-  plugin "geopress"
-  site "2008.stateofthemap.org"
-end
-
-directory "/srv/2009.stateofthemap.org" do
-  owner "wordpress"
-  group "wordpress"
-  mode 0o755
-end
-
-git "/srv/2009.stateofthemap.org" do
-  action :sync
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "resources-2009"
-  user "wordpress"
-  group "wordpress"
-end
-
-wordpress_site "2009.stateofthemap.org" do
-  aliases "2009.stateofthemap.com"
-  directory "/srv/2009.stateofthemap.org/wp"
-  database_name "sotm2009"
-  database_user "sotm2009"
-  database_password passwords["sotm2009"]
-  urls "/register" => "/srv/2009.stateofthemap.org/register",
-       "/register-pro-user" => "/srv/2009.stateofthemap.org/register-pro-user",
-       "/podcasts" => "/srv/2009.stateofthemap.org/podcasts"
-end
-
-wordpress_theme "2009.stateofthemap.org-aerodrome" do
-  theme "aerodrome"
-  site "2009.stateofthemap.org"
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "theme-2009"
-end
-
-wordpress_plugin "2009.stateofthemap.org-wp-sticky" do
-  plugin "wp-sticky"
-  site "2009.stateofthemap.org"
-end
-
-directory "/srv/2010.stateofthemap.org" do
-  owner "wordpress"
-  group "wordpress"
-  mode 0o755
-end
-
-git "/srv/2010.stateofthemap.org" do
-  action :sync
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "resources-2010"
-  user "wordpress"
-  group "wordpress"
-end
-
-wordpress_site "2010.stateofthemap.org" do
-  aliases "2010.stateofthemap.com"
-  directory "/srv/2010.stateofthemap.org/wp"
-  database_name "sotm2010"
-  database_user "sotm2010"
-  database_password passwords["sotm2010"]
-  urls "/register" => "/srv/2010.stateofthemap.org/register"
-end
-
-wordpress_theme "2010.stateofthemap.org-aerodrome" do
-  theme "aerodrome"
-  site "2010.stateofthemap.org"
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "theme-2010"
-end
-
-wordpress_plugin "2010.stateofthemap.org-sitepress-multilingual-cms" do
-  plugin "sitepress-multilingual-cms"
-  site "2010.stateofthemap.org"
-  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
-end
-
-wordpress_plugin "2010.stateofthemap.org-wp-sticky" do
-  plugin "wp-sticky"
-  site "2010.stateofthemap.org"
-end
-
-directory "/srv/2011.stateofthemap.org" do
-  owner "wordpress"
-  group "wordpress"
-  mode 0o755
-end
-
-git "/srv/2011.stateofthemap.org" do
-  action :sync
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "resources-2011"
-  user "wordpress"
-  group "wordpress"
-end
-
-wordpress_site "2011.stateofthemap.org" do
-  aliases "2011.stateofthemap.com"
-  directory "/srv/2011.stateofthemap.org/wp"
-  database_name "sotm2011"
-  database_user "sotm2011"
-  database_password passwords["sotm2011"]
-  urls "/register" => "/srv/2011.stateofthemap.org/register"
-end
-
-wordpress_theme "2011.stateofthemap.org-aerodrome" do
-  theme "aerodrome"
-  site "2011.stateofthemap.org"
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "theme-2011"
-end
-
-wordpress_plugin "2011.stateofthemap.org-sitepress-multilingual-cms" do
-  plugin "sitepress-multilingual-cms"
-  site "2011.stateofthemap.org"
-  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
-end
-
-wordpress_plugin "2011.stateofthemap.org-wp-sticky" do
-  plugin "wp-sticky"
-  site "2011.stateofthemap.org"
-end
-
-directory "/srv/2012.stateofthemap.org" do
-  owner "wordpress"
-  group "wordpress"
-  mode 0o755
-end
-
-git "/srv/2012.stateofthemap.org" do
-  action :sync
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "resources-2012"
-  user "wordpress"
-  group "wordpress"
-end
-
-wordpress_site "2012.stateofthemap.org" do
-  aliases "2012.stateofthemap.com"
-  directory "/srv/2012.stateofthemap.org/wp"
-  database_name "sotm2012"
-  database_user "sotm2012"
-  database_password passwords["sotm2012"]
-  urls "/register" => "/srv/2012.stateofthemap.org/register"
-end
-
-wordpress_theme "2012.stateofthemap.org-aerodrome" do
-  theme "aerodrome"
-  site "2012.stateofthemap.org"
-  repository "https://git.openstreetmap.org/public/stateofthemap.git"
-  revision "theme-2012"
-end
-
-wordpress_plugin "2012.stateofthemap.org-leaflet-maps-marker" do
-  plugin "leaflet-maps-marker"
-  site "2012.stateofthemap.org"
-end
-
-wordpress_plugin "2012.stateofthemap.org-sitepress-multilingual-cms" do
-  plugin "sitepress-multilingual-cms"
-  site "2012.stateofthemap.org"
-  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
-end
-
-wordpress_plugin "2012.stateofthemap.org-wp-sticky" do
-  plugin "wp-sticky"
-  site "2012.stateofthemap.org"
-end
-
-%w[2013].each do |year|
-  git "/srv/#{year}.stateofthemap.org" do
-    action :sync
-    repository "https://git.openstreetmap.org/public/stateofthemap.git"
-    revision "site-#{year}"
-    user "root"
-    group "root"
-  end
-
-  ssl_certificate "#{year}.stateofthemap.org" do
-    domains ["#{year}.stateofthemap.org", "#{year}.stateofthemap.com", "#{year}.sotm.org"]
-    notifies :reload, "service[apache2]"
-  end
-
-  apache_site "#{year}.stateofthemap.org" do
-    template "apache.static.erb"
-    directory "/srv/#{year}.stateofthemap.org"
-    variables :year => year
-  end
-end
-
-package %w[
-  ruby
-  ruby-dev
-  zlib1g-dev
-]
-
-gem_package "bundler" do
-  version "1.17.3"
-end
-
-%w[2016 2017 2018 2019 2020].each do |year|
-  git "/srv/#{year}.stateofthemap.org" do
-    action :sync
-    repository "git://github.com/openstreetmap/stateofthemap-#{year}.git"
-    user "root"
-    group "root"
-    notifies :run, "execute[/srv/#{year}.stateofthemap.org/Gemfile]"
-  end
-
-  directory "/srv/#{year}.stateofthemap.org/_site" do
-    mode 0o755
-    owner "nobody"
-    group "nogroup"
-  end
-
-  # Workaround https://github.com/jekyll/jekyll/issues/7804
-  # by creating a .jekyll-cache folder
-  directory "/srv/#{year}.stateofthemap.org/.jekyll-cache" do
-    mode 0o755
-    owner "nobody"
-    group "nogroup"
-  end
-
-  execute "/srv/#{year}.stateofthemap.org/Gemfile" do
-    action :nothing
-    command "bundle install --deployment"
-    cwd "/srv/#{year}.stateofthemap.org"
-    user "root"
-    group "root"
-    notifies :run, "execute[/srv/#{year}.stateofthemap.org]"
-    only_if { ::File.exist?("/srv/#{year}.stateofthemap.org/Gemfile") }
-  end
-
-  execute "/srv/#{year}.stateofthemap.org" do
-    action :nothing
-    command "bundle exec jekyll build --trace --baseurl=https://#{year}.stateofthemap.org"
-    cwd "/srv/#{year}.stateofthemap.org"
-    user "nobody"
-    group "nogroup"
-  end
-
-  ssl_certificate "#{year}.stateofthemap.org" do
-    domains ["#{year}.stateofthemap.org", "#{year}.stateofthemap.com", "#{year}.sotm.org"]
-    notifies :reload, "service[apache2]"
-  end
-
-  apache_site "#{year}.stateofthemap.org" do
-    template "apache.jekyll.erb"
-    directory "/srv/#{year}.stateofthemap.org/_site"
-    variables :year => year
-  end
-end
-
-template "/etc/cron.daily/sotm-backup" do
-  source "backup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o750
-  variables :passwords => passwords
-end
diff --git a/cookbooks/stateofthemap/recipes/wordpress.rb b/cookbooks/stateofthemap/recipes/wordpress.rb
new file mode 100644 (file)
index 0000000..61f22c1
--- /dev/null
@@ -0,0 +1,277 @@
+#
+# Cookbook:: stateofthemap
+# Recipe:: wordpress
+#
+# Copyright:: 2022, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include_recipe "stateofthemap"
+include_recipe "wordpress"
+
+passwords = data_bag_item("stateofthemap", "passwords")
+wp2fa_encrypt_keys = data_bag_item("stateofthemap", "wp2fa_encrypt_keys")
+
+directory "/srv/2007.stateofthemap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+wordpress_site "2007.stateofthemap.org" do
+  aliases ["2007.stateofthemap.com", "2007.sotm.org"]
+  directory "/srv/2007.stateofthemap.org/wp"
+  database_name "sotm2007"
+  database_user "sotm2007"
+  database_password passwords["sotm2007"]
+  database_prefix "wp_sotm_"
+  wp2fa_encrypt_key wp2fa_encrypt_keys["sotm2007"]
+  fpm_prometheus_port 12007
+end
+
+wordpress_theme "2007.stateofthemap.org-refreshwp-11" do
+  theme "refreshwp-11"
+  site "2007.stateofthemap.org"
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "theme-2007"
+end
+
+# Remove broken geopress plugin
+wordpress_plugin "2007.stateofthemap.org-geopress" do
+  action :delete
+  plugin "geopress"
+  site "2007.stateofthemap.org"
+end
+
+directory "/srv/2008.stateofthemap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+wordpress_site "2008.stateofthemap.org" do
+  aliases ["2008.stateofthemap.com", "2008.sotm.org"]
+  directory "/srv/2008.stateofthemap.org/wp"
+  database_name "sotm2008"
+  database_user "sotm2008"
+  database_password passwords["sotm2008"]
+  database_prefix "wp_sotm08_"
+  wp2fa_encrypt_key wp2fa_encrypt_keys["sotm2008"]
+  fpm_prometheus_port 12008
+end
+
+wordpress_theme "2008.stateofthemap.org-refreshwp-11" do
+  theme "refreshwp-11"
+  site "2008.stateofthemap.org"
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "theme-2008"
+end
+
+# Remove broken geopress plugin
+wordpress_plugin "2008.stateofthemap.org-geopress" do
+  action :delete
+  plugin "geopress"
+  site "2008.stateofthemap.org"
+end
+
+directory "/srv/2009.stateofthemap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+git "/srv/2009.stateofthemap.org" do
+  action :sync
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "resources-2009"
+  depth 1
+  user "wordpress"
+  group "wordpress"
+end
+
+wordpress_site "2009.stateofthemap.org" do
+  aliases ["2009.stateofthemap.com", "2009.sotm.org"]
+  directory "/srv/2009.stateofthemap.org/wp"
+  database_name "sotm2009"
+  database_user "sotm2009"
+  database_password passwords["sotm2009"]
+  wp2fa_encrypt_key wp2fa_encrypt_keys["sotm2009"]
+  urls "/register" => "/srv/2009.stateofthemap.org/register",
+       "/register-pro-user" => "/srv/2009.stateofthemap.org/register-pro-user",
+       "/podcasts" => "/srv/2009.stateofthemap.org/podcasts"
+  fpm_prometheus_port 12009
+end
+
+wordpress_theme "2009.stateofthemap.org-aerodrome" do
+  theme "aerodrome"
+  site "2009.stateofthemap.org"
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "theme-2009"
+end
+
+# wordpress_plugin "2009.stateofthemap.org-wp-sticky" do
+#   plugin "wp-sticky"
+#   site "2009.stateofthemap.org"
+# end
+
+directory "/srv/2010.stateofthemap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+git "/srv/2010.stateofthemap.org" do
+  action :sync
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "resources-2010"
+  depth 1
+  user "wordpress"
+  group "wordpress"
+end
+
+wordpress_site "2010.stateofthemap.org" do
+  aliases ["2010.stateofthemap.com", "2010.sotm.org"]
+  directory "/srv/2010.stateofthemap.org/wp"
+  database_name "sotm2010"
+  database_user "sotm2010"
+  database_password passwords["sotm2010"]
+  wp2fa_encrypt_key wp2fa_encrypt_keys["sotm2010"]
+  urls "/register" => "/srv/2010.stateofthemap.org/register"
+  fpm_prometheus_port 12010
+end
+
+wordpress_theme "2010.stateofthemap.org-aerodrome" do
+  theme "aerodrome"
+  site "2010.stateofthemap.org"
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "theme-2010"
+end
+
+wordpress_plugin "2010.stateofthemap.org-sitepress-multilingual-cms" do
+  plugin "sitepress-multilingual-cms"
+  site "2010.stateofthemap.org"
+  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
+  revision "master"
+  not_if { kitchen? }
+end
+
+# wordpress_plugin "2010.stateofthemap.org-wp-sticky" do
+#   plugin "wp-sticky"
+#   site "2010.stateofthemap.org"
+# end
+
+directory "/srv/2011.stateofthemap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+git "/srv/2011.stateofthemap.org" do
+  action :sync
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "resources-2011"
+  depth 1
+  user "wordpress"
+  group "wordpress"
+end
+
+wordpress_site "2011.stateofthemap.org" do
+  aliases ["2011.stateofthemap.com", "2011.sotm.org"]
+  directory "/srv/2011.stateofthemap.org/wp"
+  database_name "sotm2011"
+  database_user "sotm2011"
+  database_password passwords["sotm2011"]
+  wp2fa_encrypt_key wp2fa_encrypt_keys["sotm2011"]
+  urls "/register" => "/srv/2011.stateofthemap.org/register"
+  fpm_prometheus_port 12011
+end
+
+wordpress_theme "2011.stateofthemap.org-aerodrome" do
+  theme "aerodrome"
+  site "2011.stateofthemap.org"
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "theme-2011"
+end
+
+wordpress_plugin "2011.stateofthemap.org-sitepress-multilingual-cms" do
+  plugin "sitepress-multilingual-cms"
+  site "2011.stateofthemap.org"
+  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
+  revision "master"
+  not_if { kitchen? }
+end
+
+# wordpress_plugin "2011.stateofthemap.org-wp-sticky" do
+#   plugin "wp-sticky"
+#   site "2011.stateofthemap.org"
+# end
+
+directory "/srv/2012.stateofthemap.org" do
+  owner "wordpress"
+  group "wordpress"
+  mode "755"
+end
+
+git "/srv/2012.stateofthemap.org" do
+  action :sync
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "resources-2012"
+  depth 1
+  user "wordpress"
+  group "wordpress"
+end
+
+wordpress_site "2012.stateofthemap.org" do
+  aliases ["2012.stateofthemap.com", "2012.sotm.org"]
+  directory "/srv/2012.stateofthemap.org/wp"
+  database_name "sotm2012"
+  database_user "sotm2012"
+  database_password passwords["sotm2012"]
+  wp2fa_encrypt_key wp2fa_encrypt_keys["sotm2012"]
+  urls "/register" => "/srv/2012.stateofthemap.org/register"
+  fpm_prometheus_port 12012
+end
+
+wordpress_theme "2012.stateofthemap.org-aerodrome" do
+  theme "aerodrome"
+  site "2012.stateofthemap.org"
+  repository "https://git.openstreetmap.org/public/stateofthemap.git"
+  revision "theme-2012"
+end
+
+wordpress_plugin "2012.stateofthemap.org-leaflet-maps-marker" do
+  plugin "leaflet-maps-marker"
+  site "2012.stateofthemap.org"
+end
+
+wordpress_plugin "2012.stateofthemap.org-sitepress-multilingual-cms" do
+  plugin "sitepress-multilingual-cms"
+  site "2012.stateofthemap.org"
+  repository "https://git.openstreetmap.org/private/sitepress-multilingual-cms.git"
+  revision "master"
+  not_if { kitchen? }
+end
+
+# wordpress_plugin "2012.stateofthemap.org-wp-sticky" do
+#   plugin "wp-sticky"
+#   site "2012.stateofthemap.org"
+# end
+
+template "/etc/cron.daily/sotm-backup" do
+  source "backup.cron.erb"
+  owner "root"
+  group "root"
+  mode "750"
+  variables :passwords => passwords
+end
diff --git a/cookbooks/stateofthemap/templates/default/apache.erb b/cookbooks/stateofthemap/templates/default/apache.erb
deleted file mode 100644 (file)
index 7cea946..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:80>
-        ServerName stateofthemap.org
-        ServerAlias stateofthemap.com
-        ServerAlias sotm.org
-        ServerAlias www.stateofthemap.org
-        ServerAlias www.stateofthemap.com
-        ServerAlias www.sotm.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/stateofthemap.org-error.log
-
-        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-        RedirectPermanent / https://stateofthemap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-        ServerName stateofthemap.com
-        ServerAlias sotm.org
-        ServerAlias www.stateofthemap.org
-        ServerAlias www.stateofthemap.com
-        ServerAlias www.sotm.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/stateofthemap.org-error.log
-
-        SSLEngine on
-        SSLCertificateFile /etc/ssl/certs/stateofthemap.org.pem
-        SSLCertificateKeyFile /etc/ssl/private/stateofthemap.org.key
-
-        RedirectPermanent / https://stateofthemap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-        ServerName stateofthemap.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/stateofthemap.org-error.log
-
-        SSLEngine on
-        SSLCertificateFile /etc/ssl/certs/stateofthemap.org.pem
-        SSLCertificateKeyFile /etc/ssl/private/stateofthemap.org.key
-
-        DocumentRoot /srv/stateofthemap.org/html
-</VirtualHost>
-
-<Directory /srv/stateofthemap.org/html>
-        Require all granted
-</Directory>
diff --git a/cookbooks/stateofthemap/templates/default/apache.jekyll.erb b/cookbooks/stateofthemap/templates/default/apache.jekyll.erb
deleted file mode 100644 (file)
index 005996b..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:80>
-        ServerName <%= @year %>.stateofthemap.org
-        ServerAlias <%= @year %>.stateofthemap.com <%= @year %>.sotm.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/<%= @year %>.stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/<%= @year %>.stateofthemap.org-error.log
-
-        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-        RedirectPermanent / https://<%= @year %>.stateofthemap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-        ServerName <%= @year %>.stateofthemap.com
-        ServerAlias <%= @year %>.sotm.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/<%= @year %>.stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/<%= @year %>.stateofthemap.org-error.log
-
-        SSLEngine on
-        SSLCertificateFile /etc/ssl/certs/<%= @year %>.stateofthemap.org.pem
-        SSLCertificateKeyFile /etc/ssl/private/<%= @year %>.stateofthemap.org.key
-
-        RedirectPermanent / https://<%= @year %>.stateofthemap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-        ServerName <%= @year %>.stateofthemap.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/<%= @year %>.stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/<%= @year %>.stateofthemap.org-error.log
-
-        SSLEngine on
-        SSLCertificateFile /etc/ssl/certs/<%= @year %>.stateofthemap.org.pem
-        SSLCertificateKeyFile /etc/ssl/private/<%= @year %>.stateofthemap.org.key
-
-        DocumentRoot /srv/<%= @year %>.stateofthemap.org/_site
-</VirtualHost>
-
-<Directory /srv/<%= @year %>.stateofthemap.org/_site>
-        Require all granted
-</Directory>
diff --git a/cookbooks/stateofthemap/templates/default/apache.static.erb b/cookbooks/stateofthemap/templates/default/apache.static.erb
deleted file mode 100644 (file)
index db543bb..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:80>
-        ServerName <%= @year %>.stateofthemap.org
-        ServerAlias <%= @year %>.stateofthemap.com <%= @year %>.sotm.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/<%= @year %>.stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/<%= @year %>.stateofthemap.org-error.log
-
-        RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-        RedirectPermanent / https://<%= @year %>.stateofthemap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-        ServerName <%= @year %>.stateofthemap.com
-        ServerAlias <%= @year %>.sotm.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/<%= @year %>.stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/<%= @year %>.stateofthemap.org-error.log
-
-        SSLEngine on
-        SSLCertificateFile /etc/ssl/certs/<%= @year %>.stateofthemap.org.pem
-        SSLCertificateKeyFile /etc/ssl/private/<%= @year %>.stateofthemap.org.key
-
-        RedirectPermanent / https://<%= @year %>.stateofthemap.org/
-</VirtualHost>
-
-<VirtualHost *:443>
-        ServerName <%= @year %>.stateofthemap.org
-        ServerAdmin webmaster@openstreetmap.org
-
-        CustomLog /var/log/apache2/<%= @year %>.stateofthemap.org-access.log combined
-        ErrorLog /var/log/apache2/<%= @year %>.stateofthemap.org-error.log
-
-        SSLEngine on
-        SSLCertificateFile /etc/ssl/certs/<%= @year %>.stateofthemap.org.pem
-        SSLCertificateKeyFile /etc/ssl/private/<%= @year %>.stateofthemap.org.key
-
-        DocumentRoot /srv/<%= @year %>.stateofthemap.org
-</VirtualHost>
-
-<Directory /srv/<%= @year %>.stateofthemap.org>
-        Require all granted
-</Directory>
index cb7171b6f5dd82464c922b70849c0f69b93c15bd..e0f4d87bae534bd939006b8ea9a75460e9a879aa 100644 (file)
@@ -8,11 +8,11 @@ B=sotm-$D.tar.gz
 
 mkdir $T/sotm-$D
 
-<% %w(2007 2008 2009 2010 2011 2012 2016).each do |year| -%>
+<% %w(2007 2008 2009 2010 2011 2012).each do |year| -%>
 echo '[mysqldump]' > $T/mysqldump.opts
 echo 'user=sotm<%= year %>' >> $T/mysqldump.opts
 echo 'password=<%= @passwords["sotm#{year}"] %>' >> $T/mysqldump.opts
-mysqldump --defaults-file=$T/mysqldump.opts --opt sotm<%= year %> > $T/sotm-$D/sotm<%= year %>.sql
+mysqldump --defaults-file=$T/mysqldump.opts --opt --no-tablespaces sotm<%= year %> > $T/sotm-$D/sotm<%= year %>.sql
 <% end -%>
 
 ln -s /srv/2007.stateofthemap.org $T/sotm-$D/www2007
@@ -21,12 +21,10 @@ ln -s /srv/2009.stateofthemap.org $T/sotm-$D/www2009
 ln -s /srv/2010.stateofthemap.org $T/sotm-$D/www2010
 ln -s /srv/2011.stateofthemap.org $T/sotm-$D/www2011
 ln -s /srv/2012.stateofthemap.org $T/sotm-$D/www2012
-ln -s /srv/2016.stateofthemap.org $T/sotm-$D/www2016
 
-export GZIP="--rsyncable -9"
 export RSYNC_RSH="ssh -ax"
 
-nice tar --create --gzip --dereference --directory=$T --file=$T/$B sotm-$D
+nice tar --create --dereference --directory=$T sotm-$D | nice gzip --rsyncable -9 > $T/$B
 nice rsync --preallocate --fuzzy $T/$B backup::backup
 
 rm -rf $T
diff --git a/cookbooks/subversion/files/default/hooks/post-commit b/cookbooks/subversion/files/default/hooks/post-commit
deleted file mode 100644 (file)
index a8de2af..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-/usr/bin/sudo -u trac /usr/bin/trac-admin /var/lib/trac changeset added "$1" "$2"
diff --git a/cookbooks/subversion/files/default/hooks/post-revprop-change b/cookbooks/subversion/files/default/hooks/post-revprop-change
deleted file mode 100644 (file)
index 31843a0..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-/usr/bin/sudo -u trac /usr/bin/trac-admin /var/lib/trac changeset modified "$1" "$2"
index d40690a4e37202bb10aed8974e17dcc2190dd768..1d376481c0127aee792673bc1340ca773009fdea 100644 (file)
@@ -6,4 +6,4 @@ description       "Installs and configures subversion servers"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "apache"
+depends           "podman"
index 7014c2d5fa5f74e9735121b0e43f2f3c40e1c262..3ce35840bfcb7f758bef9154768fa593b2cfbb33 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "apache"
+include_recipe "podman::apache"
 
-package "subversion"
-
-repository_directory = "/var/lib/subversion/repos/openstreetmap"
-
-remote_directory "#{repository_directory}/hooks" do
-  source "hooks"
-  owner "www-data"
-  group "www-data"
-  mode 0o755
-  files_owner "www-data"
-  files_group "www-data"
-  files_mode 0o755
-  purge false
-end
-
-apache_module "dav" do
-  package "apache2"
-end
-
-apache_module "dav_fs" do
-  package "apache2"
-end
-
-apache_module "dav_svn" do
-  package "libapache2-svn"
-end
-
-apache_module "authz_svn" do
-  package "libapache2-svn"
-end
-
-ssl_certificate "svn.openstreetmap.org" do
-  domains ["svn.openstreetmap.org", "svn.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "svn.openstreetmap.org" do
-  template "apache.erb"
-  directory repository_directory
-  variables :realm => "Subversion Repository", :password_file => "/etc/apache2/svn.passwd", :aliases => ["svn.osm.org"]
-end
-
-template "/etc/cron.daily/svn-backup" do
-  source "backup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o755
+podman_site "svn.openstreetmap.org" do
+  image "ghcr.io/openstreetmap/svn-website:latest"
+  aliases ["svn.osm.org"]
 end
diff --git a/cookbooks/subversion/templates/default/apache.erb b/cookbooks/subversion/templates/default/apache.erb
deleted file mode 100644 (file)
index 42e4592..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-  ServerName <%= @name %>
-  ServerAdmin webmaster@openstreetmap.org
-
-  Protocols http/1.1
-
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  CustomLog /var/log/apache2/<%= @name %>-svn-access.log "%h %t %u %{SVN-ACTION}e" env=SVN-ACTION
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  <Location />
-    DAV svn
-    SVNPath <%= @directory %>
-    SVNIndexXSLT /svnindex.xsl
-
-    AuthType Basic
-    AuthName "<%= @realm %>"
-    AuthUserFile <%= @password_file %>
-
-    LimitXMLRequestBody 0
-    LimitRequestBody 0
-
-    <Limit GET PROPFIND OPTIONS REPORT>
-      Require all granted
-    </Limit>
-
-    <LimitExcept GET PROPFIND OPTIONS REPORT>
-      Require valid-user
-    </LimitExcept>
-  </Location>
-</VirtualHost>
-<% unless @aliases.empty? -%>
-
-<VirtualHost *:443>
-  ServerName <%= @aliases.first %>
-<% @aliases.drop(1).each do |alias_name| -%>
-  ServerAlias <%= alias_name %>
-<% end -%>
-  ServerAdmin webmaster@openstreetmap.org
-
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
-<% end -%>
-
-<VirtualHost *:80>
-  ServerName <%= @name %>
-<% @aliases.each do |alias_name| -%>
-  ServerAlias <%= alias_name %>
-<% end -%>
-
-  ServerAdmin webmaster@openstreetmap.org
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-  RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
diff --git a/cookbooks/subversion/templates/default/backup.cron.erb b/cookbooks/subversion/templates/default/backup.cron.erb
deleted file mode 100644 (file)
index df7b4fe..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-T=$(mktemp -d -t -p /var/tmp svn.XXXXXXXXXX)
-D=$(date +%Y-%m-%d)
-B=svn-$D.tar.gz
-
-nice svnadmin hotcopy /var/lib/subversion/repos/openstreetmap $T/svn-$D > /dev/null
-
-export GZIP="--rsyncable -9"
-export RSYNC_RSH="ssh -ax"
-
-nice tar --create --gzip --directory=$T --file=$T/$B svn-$D
-nice rsync --preallocate --fuzzy $T/$B backup::backup
-
-rm -rf $T
diff --git a/cookbooks/supybot/attributes/default.rb b/cookbooks/supybot/attributes/default.rb
new file mode 100644 (file)
index 0000000..1e8be78
--- /dev/null
@@ -0,0 +1 @@
+default[:accounts][:users][:supybot][:status] = :role
index 1b372ae221fa91f82bcbb36961a609657ebdcdf7..76dbe20f28c1a589eef21a178f18ec87b8617f57 100644 (file)
@@ -6,4 +6,5 @@ description       "Installs and configures supybot"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "systemd"
index d1c1ea32d8f9e17b1ece07f0fcfb5f9a374120de..7545ff331767bd814742ac281c72f176bf5e7b40 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
+
 users = data_bag_item("supybot", "users")
 passwords = data_bag_item("supybot", "passwords")
 
-package "supybot"
-package "python-git"
+package "limnoria"
+package "python3-git"
 
 directory "/etc/supybot" do
   owner "supybot"
   group "supybot"
-  mode 0o755
+  mode "755"
 end
 
 template "/etc/supybot/supybot.conf" do
   source "supybot.conf.erb"
   owner "supybot"
   group "supybot"
-  mode 0o644
+  mode "644"
   variables :passwords => passwords
 end
 
@@ -41,84 +43,85 @@ template "/etc/supybot/channels.conf" do
   source "channels.conf.erb"
   owner "supybot"
   group "supybot"
-  mode 0o644
+  mode "644"
 end
 
 template "/etc/supybot/git.conf" do
   source "git.conf.erb"
   owner "supybot"
   group "supybot"
-  mode 0o644
+  mode "644"
 end
 
 template "/etc/supybot/ignores.conf" do
   source "ignores.conf.erb"
   owner "supybot"
   group "supybot"
-  mode 0o644
+  mode "644"
 end
 
 template "/etc/supybot/userdata.conf" do
   source "userdata.conf.erb"
   owner "supybot"
   group "supybot"
-  mode 0o644
+  mode "644"
 end
 
 template "/etc/supybot/users.conf" do
   source "users.conf.erb"
   owner "supybot"
   group "supybot"
-  mode 0o644
+  mode "644"
   variables :passwords => users
 end
 
 directory "/var/lib/supybot" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/lib/supybot/data" do
   owner "supybot"
   group "supybot"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/lib/supybot/backup" do
   owner "supybot"
   group "supybot"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/lib/supybot/git" do
   owner "supybot"
   group "supybot"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/log/supybot" do
   owner "supybot"
   group "supybot"
-  mode 0o755
+  mode "755"
 end
 
 directory "/usr/local/lib/supybot" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 directory "/usr/local/lib/supybot/plugins" do
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 git "/usr/local/lib/supybot/plugins/Git" do
   action :sync
-  repository "git://github.com/openstreetmap/supybot-git"
+  repository "https://github.com/openstreetmap/supybot-git"
   revision "master"
+  depth 1
   user "root"
   group "root"
 end
@@ -128,11 +131,8 @@ systemd_service "supybot" do
   after "network.target"
   user "supybot"
   exec_start "/usr/bin/supybot /etc/supybot/supybot.conf"
-  private_tmp true
-  private_devices true
-  protect_system true
-  protect_home true
-  no_new_privileges true
+  sandbox :enable_network => true
+  read_write_paths ["/etc/supybot", "/var/lib/supybot", "/var/log/supybot"]
   restart "on-failure"
 end
 
index 7c9d54465a8142cceb85952c7850998391aff112..c1711dbcc366f032e5671540f2ca3ec3326430a3 100644 (file)
@@ -1,16 +1,16 @@
-channel #osm-dev-test
+channel #osm-dev
   lobotomized False
   defaultAllow True
-  capability -halfop
   capability -protected
   capability -op
   capability -voice
+  capability -halfop
 
-channel #osm-dev
+channel #osm-dev-test
   lobotomized False
   defaultAllow True
-  capability -halfop
   capability -protected
   capability -op
   capability -voice
+  capability -halfop
 
index 63bc8be12507b1535e73bd3f7e92974c610bdcbf..5d19c0095adc9ce3b4a006468b6ab48ead9c574d 100644 (file)
@@ -1,5 +1,4 @@
 # DO NOT EDIT - This file is being maintained by Chef
-# Note use git:// protocol instead of ssh based to avoid host key verification issue
 
 [osm-website]
 short name = osm-website
@@ -25,9 +24,9 @@ commit message = [%s|%b|%a] %m %l
 
 [osm-cgimap]
 short name = osm-cgimap
-url = https://git.openstreetmap.org/public/cgimap.git
+url = https://github.com/zerebubuth/openstreetmap-cgimap.git
 branch = master
-commit link = https://github.com/openstreetmap/cgimap/commit/%c
+commit link = https://github.com/zerebubuth/openstreetmap-cgimap/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
@@ -39,22 +38,6 @@ commit link = https://github.com/openstreetmap/dns/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
-[osm-potlatch2]
-short name = osm-potlatch2
-url = https://git.openstreetmap.org/public/potlatch2.git
-branch = master
-commit link = https://github.com/openstreetmap/potlatch2/commit/%c
-channels = #osm-dev
-commit message = [%s|%b|%a] %m %l
-
-[osm-gpx-import]
-short name = osm-gpx-import
-url = https://git.openstreetmap.org/public/gpx-import.git
-branch = master
-commit link = https://git.osm.org/gpx-import.git/commitdiff/%c
-channels = #osm-dev
-commit message = [%s|%b|%a] %m %l
-
 [osm-nominatim]
 short name = osm-nominatim
 url = https://git.openstreetmap.org/public/nominatim.git
@@ -63,65 +46,33 @@ commit link = https://git.osm.org/nominatim.git/commitdiff/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
-[osm-planetdump]
-short name = osm-planetdump
-url = https://git.openstreetmap.org/public/planetdump.git
+[osm-planetdump-ng]
+short name = osm-planetdump-ng
+url = https://github.com/zerebubuth/planet-dump-ng.git
 branch = master
-commit link = https://git.osm.org/planetdump.git/commitdiff/%c
+commit link = https://github.com/zerebubuth/planet-dump-ng-commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
 [osm-carto]
 short name = osm-carto
-url = git://github.com/gravitystorm/openstreetmap-carto.git
+url = https://github.com/gravitystorm/openstreetmap-carto.git
 branch = master
 commit link = https://github.com/gravitystorm/openstreetmap-carto/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
-[osm-carto-schema]
-short name = osm-carto-schema
-url = git://github.com/gravitystorm/openstreetmap-carto.git
-branch = schema_changes
-commit link = https://github.com/gravitystorm/openstreetmap-carto/commit/%c
-channels = #osm-dev
-commit message = [%s|%b|%a] %m %l
-
 [osm-osm2pgsql]
 short name = osm-osm2pgsql
-url = git://github.com/openstreetmap/osm2pgsql.git
+url = https://github.com/openstreetmap/osm2pgsql.git
 branch = master
 commit link = https://github.com/openstreetmap/osm2pgsql/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
-[osm-osm2pgsql-0.92.x]
-short name = osm-osm2pgsql-0.92.x
-url = git://github.com/openstreetmap/osm2pgsql.git
-branch = 0.92.x
-commit link = https://github.com/openstreetmap/osm2pgsql/commit/%c
-channels = #osm-dev
-commit message = [%s|%b|%a] %m %l
-
-[osm-osm2pgsql-0.90.x]
-short name = osm-osm2pgsql-0.90.x
-url = git://github.com/openstreetmap/osm2pgsql.git
-branch = 0.90.x
-commit link = https://github.com/openstreetmap/osm2pgsql/commit/%c
-channels = #osm-dev
-commit message = [%s|%b|%a] %m %l
-
-[osm-osm2pgsql-0.88.x]
-short name = osm-osm2pgsql-0.88.x
-url = git://github.com/openstreetmap/osm2pgsql.git
-branch = 0.88.x
-commit link = https://github.com/openstreetmap/osm2pgsql/commit/%c
-channels = #osm-dev
-commit message = [%s|%b|%a] %m %l
-
 [osm-mod_tile]
 short name = osm-mod_tile
-url = git://github.com/openstreetmap/mod_tile.git
+url = https://github.com/openstreetmap/mod_tile.git
 branch = master
 commit link = https://github.com/openstreetmap/mod_tile/commit/%c
 channels = #osm-dev
@@ -129,7 +80,7 @@ commit message = [%s|%b|%a] %m %l
 
 [osm-planet-gpx-dump]
 short name = osm-planet-gpx-dump
-url = git://github.com/iandees/planet-gpx-dump.git
+url = https://github.com/iandees/planet-gpx-dump.git
 branch = master
 commit link = https://github.com/iandees/planet-gpx-dump/commit/%c
 channels = #osm-dev
@@ -137,15 +88,15 @@ commit message = [%s|%b|%a] %m %l
 
 [osm-id]
 short name = osm-id
-url = git://github.com/openstreetmap/iD.git
-branch = master
+url = https://github.com/openstreetmap/iD.git
+branch = develop
 commit link = https://github.com/openstreetmap/iD/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
 [osm-maproulette]
 short name = osm-maproulette
-url = git://github.com/osmlab/maproulette.git
+url = https://github.com/osmlab/maproulette.git
 branch = master
 commit link = https://github.com/osmlab/maproulette/commit/%c
 channels = #osm-dev
@@ -153,7 +104,7 @@ commit message = [%s|%b|%a] %m %l
 
 [osm-supybot]
 short name = osm-supybot
-url = git://github.com/iandees/supybot-plugin-osm.git
+url = https://github.com/iandees/supybot-plugin-osm.git
 commit link = https://github.com/iandees/supybot-plugin-osm/commit/%c
 branch = master
 channels = #osm-dev
@@ -161,7 +112,7 @@ commit message = [%s|%b|%a] %m %l
 
 [osm-taginfo]
 short name = osm-taginfo
-url = git://github.com/joto/taginfo.git
+url = https://github.com/joto/taginfo.git
 commit link = https://github.com/joto/taginfo/commit/%c
 branch = master
 channels = #osm-dev
@@ -169,23 +120,15 @@ commit message = [%s|%b|%a] %m %l
 
 [osmf-server-info]
 short name = osmf-server-info
-url = git://github.com/gravitystorm/osmf-server-info.git
+url = https://github.com/osmfoundation/osmf-server-info.git
 branch = master
-commit link = https://github.com/gravitystorm/osmf-server-info/commit/%c
-channels = #osm-dev
-commit message = [%s|%b|%a] %m %l
-
-[osm-forum]
-short name = osm-forum
-url = git://github.com/openstreetmap/openstreetmap-forum.git
-branch = openstreetmap-1.5.10
-commit link = https://github.com/openstreetmap/openstreetmap-forum/commit/%c
+commit link = https://github.com/osmfoundation/osmf-server-info/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
 [osm-osmosis]
 short name = osm-osmosis
-url = git://github.com/openstreetmap/osmosis.git
+url = https://github.com/openstreetmap/osmosis.git
 branch = master
 commit link = https://github.com/openstreetmap/osmosis/commit/%c
 channels = #osm-dev
@@ -193,23 +136,31 @@ commit message = [%s|%b|%a] %m %l
 
 [owg-website]
 short name = owg-website
-url = git://github.com/openstreetmap/owg-website.git
+url = https://github.com/openstreetmap/owg-website.git
 branch = gh-pages
 commit link = https://github.com/openstreetmap/owg-website/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
+[osm-tilelog]
+short name = osm-tilelog
+url = https://github.com/openstreetmap/tilelog.git
+branch = main
+commit link = https://github.com/openstreetmap/tilelog/commit/%c
+channels = #osm-dev
+commit message = [%s|%b|%a] %m %l
+
 [osm-josm]
 short name = osm-josm
-url = git://github.com/openstreetmap/josm.git
+url = https://github.com/JOSM/josm.git
 branch = master
-commit link = https://github.com/openstreetmap/josm/commit/%c
+commit link = https://github.com/JOSM/josm/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
 [osmlab-editor-layer-index]
 short name = osmlab-editor-layer-index
-url = git://github.com/osmlab/editor-layer-index.git
+url = https://github.com/osmlab/editor-layer-index.git
 branch = gh-pages
 commit link = https://github.com/osmlab/editor-layer-index/commit/%c
 channels = #osm-dev
@@ -217,24 +168,32 @@ commit message = [%s|%b|%a] %m %l
 
 [osmlab-osm-community-index]
 short name = osmlab-osm-community-index
-url = git://github.com/osmlab/osm-community-index.git
-branch = master
+url = https://github.com/osmlab/osm-community-index.git
+branch = main
 commit link = https://github.com/osmlab/osm-community-index/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
 [vespucci]
 short name = vespucci
-url = git://github.com/MarcusWolschon/osmeditor4android.git
+url = https://github.com/MarcusWolschon/osmeditor4android.git
 branch = master
-commit link = https://github.com//MarcusWolschon/osmeditor4android/commit/%c
+commit link = https://github.com/MarcusWolschon/osmeditor4android/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
 
 [switch2osm]
 short name = switch2osm
-url = git://github.com/switch2osm/switch2osm.github.io.git
+url = https://github.com/switch2osm/switch2osm.github.io.git
 branch = master
 commit link = https://github.com/switch2osm/switch2osm.github.io/commit/%c
 channels = #osm-dev
 commit message = [%s|%b|%a] %m %l
+
+[simon-openinghoursparser]
+short name = simon-openinghoursparser
+url = https://github.com/simonpoole/OpeningHoursParser.git
+branch = master
+commit link = https://github.com/simonpoole/OpeningHoursParser/commit/%c
+channels = #osm-dev
+commit message = [%s|%b|%a] %m %l
index fe3c63eb6d2b23a545450497e49cb1ac8e734292..bf7cd709dde36e61a1e239437c81df1583cb7b83 100644 (file)
@@ -58,7 +58,7 @@ supybot.networks.oftc.password:
 #
 # Default value: 
 ###
-supybot.networks.oftc.servers: irc.oftc.net:6667
+supybot.networks.oftc.servers: irc.oftc.net:6697
 
 ###
 # Determines what channels the bot will join only on oftc.
@@ -80,7 +80,7 @@ supybot.networks.oftc.channels.key:
 #
 # Default value: False
 ###
-supybot.networks.oftc.ssl: False
+supybot.networks.oftc.ssl: True
 
 ###
 # Determines how timestamps printed for human reading should be
@@ -637,6 +637,13 @@ supybot.directories.data: /var/lib/supybot/data
 ###
 supybot.directories.data.tmp: /var/lib/supybot/data/tmp
 
+###
+# Determines what directory files of the web server (templates, custom images, ...) are put into.
+#
+# Default value: web
+###
+supybot.directories.data.web: /var/lib/supybot/data/web
+
 ###
 # Determines what directory backup data is put into.
 #
@@ -887,7 +894,6 @@ supybot.plugins.Services.NickServ: NickServ
 #
 # Default value: 
 ###
-supybot.plugins.Services.NickServ.password: <%= @passwords["nickserv"] %>
 supybot.plugins.Services.NickServ.password.osmbot: <%= @passwords["nickserv"] %>
 
 ###
@@ -1062,6 +1068,15 @@ supybot.databases.types.cdb: True
 ###
 supybot.databases.types.cdb.maximumModifications: 0.5
 
+###
+# Determines whether server certificates will be verified, which
+# checks whether the server certificate is signed by a known certificate
+# authority, and aborts the connection if it is not.
+#
+# Default value: False
+###
+supybot.protocols.ssl.verifyCertificates: True
+
 ###
 # Determines what will be used as the default banmask style.
 #
index 3a380b93fa2e2368ce7e57f3ad9a3b6512cca1dc..40f3aa308e2c8d6576571a5a416df35b9ee3984c 100644 (file)
@@ -6,4 +6,4 @@ description       "Installs and configures servers for switch2osm"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "wordpress"
+depends           "podman"
index 8ddaf5101c7f1cac0a45bcd1956b4da4fcf730b1..d4eb9eeecdeb0b30224f36311e9a03642ea14b6c 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-include_recipe "apache"
-include_recipe "git"
 
-package %w[
-  ruby
-  ruby-dev
-  zlib1g-dev
-]
+include_recipe "podman::apache"
 
-gem_package "bundler" do
-  version "1.17.3"
-end
-
-git "/srv/switch2osm.org" do
-  action :sync
-  repository "https://github.com/switch2osm/switch2osm.github.io.git"
-  user "root"
-  group "root"
-  notifies :run, "execute[/srv/switch2osm.org/Gemfile]"
-end
-
-directory "/srv/switch2osm.org/_site" do
-  mode 0o755
-  owner "nobody"
-  group "nogroup"
-end
-
-# Workaround https://github.com/jekyll/jekyll/issues/7804
-# by creating a .jekyll-cache folder
-directory "/srv/switch2osm.org/.jekyll-cache" do
-  mode 0o755
-  owner "nobody"
-  group "nogroup"
-end
-
-execute "/srv/switch2osm.org/Gemfile" do
-  action :nothing
-  command "bundle install --deployment"
-  cwd "/srv/switch2osm.org"
-  user "root"
-  group "root"
-  notifies :run, "execute[/srv/switch2osm.org]"
-end
-
-execute "/srv/switch2osm.org" do
-  action :nothing
-  command "bundle exec jekyll build --trace --config _config.yml,_config_osm.yml"
-  cwd "/srv/switch2osm.org"
-  user "nobody"
-  group "nogroup"
-end
-
-ssl_certificate "switch2osm.org" do
-  domains ["switch2osm.org",
-           "www.switch2osm.org", "switch2osm.com", "www.switch2osm.com"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site "switch2osm.org" do
-  template "apache.erb"
-  directory "/srv/switch2osm.org/_site"
+podman_site "switch2osm.org" do
+  image "ghcr.io/switch2osm/switch2osm:latest"
+  aliases ["www.switch2osm.org", "switch2osm.com", "www.switch2osm.com"]
 end
diff --git a/cookbooks/switch2osm/templates/default/apache.erb b/cookbooks/switch2osm/templates/default/apache.erb
deleted file mode 100644 (file)
index 7d73ca6..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-   ServerName <%= @name %>
-   ServerAlias www.switch2osm.org
-   ServerAlias switch2osm.com
-   ServerAlias www.switch2osm.com
-   ServerAdmin webmaster@openstreetmap.org
-
-   CustomLog /var/log/apache2/<%= @name %>-access.log combined
-   ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-   SSLEngine on
-   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-   DocumentRoot <%= @directory %>
-
-   ErrorDocument 404 /404.html
-</VirtualHost>
-
-<VirtualHost *:80>
-   ServerName <%= @name %>
-   ServerAlias www.switch2osm.org
-   ServerAlias switch2osm.com
-   ServerAlias www.switch2osm.com
-   ServerAdmin webmaster@openstreetmap.org
-
-   CustomLog /var/log/apache2/<%= @name %>-access.log combined
-   ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-   RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
-
-<Directory <%= @directory %>>
-   Require all granted
-</Directory>
diff --git a/cookbooks/sysctl/attributes/default.rb b/cookbooks/sysctl/attributes/default.rb
new file mode 100644 (file)
index 0000000..5c16360
--- /dev/null
@@ -0,0 +1 @@
+default[:sysctl] = {}
index 14295b37726baba083b2479cdc5f4b4c5f73955a..f16537c5185c277d12897f8424bf8b6cf58575d9 100644 (file)
 # limitations under the License.
 #
 
-if node[:virtualization][:role] == "guest" &&
-   node[:virtualization][:system] == "lxd"
-  file "/etc/sysctl.d/60-chef.conf" do
-    action :delete
-  end
-else
-  package "procps"
+file "/etc/sysctl.d/60-chef.conf" do
+  action :delete
+end
 
-  directory "/etc/sysctl.d" do
-    owner "root"
-    group "root"
-    mode 0o755
-  end
+if node[:virtualization][:role] != "guest" ||
+   (node[:virtualization][:system] != "lxc" &&
+    node[:virtualization][:system] != "lxd" &&
+    node[:virtualization][:system] != "openvz")
+  keys = []
 
-  execute "sysctl" do
-    action :nothing
-    command "/sbin/sysctl -p /etc/sysctl.d/60-chef.conf"
-  end
+  Dir.new("/etc/sysctl.d").each_entry do |file|
+    next unless file =~ /^99-chef-(.*)\.conf$/
 
-  template "/etc/sysctl.d/60-chef.conf" do
-    source "chef.conf.erb"
-    owner "root"
-    group "root"
-    mode 0o644
-    notifies :run, "execute[sysctl]"
+    keys.push(Regexp.last_match(1))
   end
 
   node[:sysctl].each_value do |group|
     group[:parameters].each do |key, value|
-      sysctl_file = "/proc/sys/#{key.tr('.', '/')}"
-
-      file sysctl_file do
-        content "#{value}\n"
-        atomic_update false
-        ignore_failure true
+      sysctl key do
+        value value
+        # comment group[:comment]
       end
+
+      keys.delete(key)
+    end
+  end
+
+  keys.each do |key|
+    sysctl key do
+      action :remove
     end
   end
 end
diff --git a/cookbooks/sysctl/templates/default/chef.conf.erb b/cookbooks/sysctl/templates/default/chef.conf.erb
deleted file mode 100644 (file)
index 991664f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-<% node[:sysctl].each do |name,group| -%>
-
-# <%= group[:comment] %>
-<% group[:parameters].each do |key,value| -%>
-<%= key %> = <%= value %>
-<% end -%>
-<% end -%>
index c34a16989baafb79d769a6d5f92e708ab75b6a98..6e2dac1f5ba0dcf011bcaaa03861865fa0da1e01 100644 (file)
@@ -30,11 +30,11 @@ else
     supports :status => false, :restart => true, :reload => false
   end
 
-  template "/etc/sysfs.conf" do
+  template "/etc/sysfs.d/99-chef.conf" do
     source "sysfs.conf.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     notifies :restart, "service[sysfsutils]"
   end
 
index 139f4b8db6cbdad2e7176f236c35e20cca2ae954..52f5576c6a86fa4f979505f4e8c5f71045bdcbbd 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
 property :path, String, :name_property => true
-property :description, String, :required => true
+property :description, String, :required => [:create]
 property :after, [String, Array]
 property :wants, [String, Array]
 property :path_exists, [String, Array]
@@ -29,7 +31,7 @@ property :path_changed, [String, Array]
 property :path_modified, [String, Array]
 property :directory_not_empty, [String, Array]
 property :unit, String
-property :make_directory, [TrueClass, FalseClass]
+property :make_directory, [true, false]
 property :directory_mode, Integer
 
 action :create do
@@ -40,7 +42,7 @@ action :create do
     source "path.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables path_variables
   end
 
index dfb6864c5acf180bcaae39bfb18a8fb467609abe..3a9f0b893e2d19337b755dc29dac4d821039d898 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
 property :service, String, :name_property => true
 property :dropin, String
 property :description, String
+property :condition_path_exists, [String, Array]
+property :condition_path_exists_glob, [String, Array]
 property :after, [String, Array]
+property :conflicts, [String, Array]
 property :wants, [String, Array]
+property :requires, [String, Array]
+property :joins_namespace_of, [String, Array]
 property :type, String, :is => %w[simple forking oneshot dbus notify idle]
+property :notify_access, String, :is => %w[none main exec all]
 property :limit_nofile, Integer
 property :limit_as, [Integer, String]
 property :limit_cpu, [Integer, String]
@@ -35,14 +43,27 @@ property :environment, Hash, :default => {}
 property :environment_file, [String, Hash]
 property :user, String
 property :group, String
+property :dynamic_user, [true, false]
 property :working_directory, String
-property :exec_start_pre, String
-property :exec_start, String
-property :exec_start_post, String
-property :exec_stop, String
+property :umask, String
+property :exec_start_pre, [String, Array]
+property :exec_start, [String, Array]
+property :exec_start_post, [String, Array]
+property :exec_stop, [String, Array]
+property :exec_stop_post, [String, Array]
 property :exec_reload, String
+property :runtime_max_sec, Integer
 property :runtime_directory, String
 property :runtime_directory_mode, Integer
+property :runtime_directory_preserve, [true, false, String]
+property :state_directory, String
+property :state_directory_mode, Integer
+property :cache_directory, String
+property :cache_directory_mode, Integer
+property :logs_directory, String
+property :logs_directory_mode, Integer
+property :configuration_directory, String
+property :configuration_directory_mode, Integer
 property :standard_input, String,
          :is => %w[null tty tty-force tty-fail socket]
 property :standard_output, String,
@@ -52,14 +73,45 @@ property :standard_error, String,
 property :success_exit_status, [Integer, String, Array]
 property :restart, String,
          :is => %w[on-success on-failure on-abnormal on-watchdog on-abort always]
-property :private_tmp, [TrueClass, FalseClass]
-property :private_devices, [TrueClass, FalseClass]
-property :private_network, [TrueClass, FalseClass]
-property :protect_system, [TrueClass, FalseClass, String]
-property :protect_home, [TrueClass, FalseClass, String]
+property :restart_sec, [Integer, String]
+property :protect_proc, String,
+         :is => %w[noaccess invisible ptraceable default]
+property :proc_subset, String,
+         :is => %w[all pid]
+property :bind_paths, [String, Array]
+property :bind_read_only_paths, [String, Array]
+property :capability_bounding_set, [String, Array]
+property :ambient_capabilities, [String, Array]
+property :no_new_privileges, [true, false]
+property :protect_system, [true, false, String]
+property :protect_home, [true, false, String]
+property :read_write_paths, [String, Array]
+property :read_only_paths, [String, Array]
+property :inaccessible_paths, [String, Array]
+property :private_tmp, [true, false]
+property :private_devices, [true, false]
+property :private_network, [true, false]
+property :private_ipc, [true, false]
+property :private_users, [true, false]
+property :protect_hostname, [true, false]
+property :protect_clock, [true, false]
+property :protect_kernel_tunables, [true, false]
+property :protect_kernel_modules, [true, false]
+property :protect_kernel_logs, [true, false]
+property :protect_control_groups, [true, false]
 property :restrict_address_families, [String, Array]
-property :no_new_privileges, [TrueClass, FalseClass]
+property :restrict_namespaces, [true, false, String, Array]
+property :lock_personality, [true, false]
+property :memory_deny_write_execute, [true, false]
+property :restrict_realtime, [true, false]
+property :restrict_suid_sgid, [true, false]
+property :remove_ipc, [true, false]
+property :system_call_filter, [String, Array]
+property :system_call_architectures, [String, Array]
 property :tasks_max, Integer
+property :timeout_start_sec, Integer
+property :timeout_stop_sec, Integer
+property :timeout_abort_sec, Integer
 property :timeout_sec, Integer
 property :pid_file, String
 property :nice, Integer
@@ -67,6 +119,7 @@ property :io_scheduling_class, [Integer, String]
 property :io_scheduling_priority, Integer
 property :kill_mode, String,
          :is => %w[control-group process mixed none]
+property :sandbox, [true, false, Hash]
 
 action :create do
   service_variables = new_resource.to_hash
@@ -75,13 +128,48 @@ action :create do
     service_variables[:type] ||= "simple"
   end
 
+  if new_resource.sandbox
+    service_variables[:protect_proc] = "invisible" unless property_is_set?(:protect_proc)
+    service_variables[:proc_subset] = "pid" unless property_is_set?(:proc_subset)
+    service_variables[:capability_bounding_set] = [] unless property_is_set?(:capability_bounding_set)
+    service_variables[:ambient_capabilities] = [] unless property_is_set?(:ambient_capabilities)
+    service_variables[:no_new_privileges] = true unless property_is_set?(:no_new_privileges)
+    service_variables[:protect_system] = "strict" unless property_is_set?(:protect_system)
+    service_variables[:protect_home] = true unless property_is_set?(:protect_home)
+    service_variables[:private_tmp] = true unless property_is_set?(:private_tmp)
+    service_variables[:private_devices] = true unless property_is_set?(:private_devices)
+    service_variables[:private_network] = true unless property_is_set?(:private_network)
+    service_variables[:private_ipc] = true unless property_is_set?(:private_ipc)
+    service_variables[:private_users] = true unless property_is_set?(:private_users)
+    service_variables[:protect_hostname] = true unless property_is_set?(:protect_hostname)
+    service_variables[:protect_clock] = true unless property_is_set?(:protect_clock)
+    service_variables[:protect_kernel_tunables] = true unless property_is_set?(:protect_kernel_tunables)
+    service_variables[:protect_kernel_modules] = true unless property_is_set?(:protect_kernel_modules)
+    service_variables[:protect_kernel_logs] = true unless property_is_set?(:protect_kernel_logs)
+    service_variables[:protect_control_groups] = true unless property_is_set?(:protect_control_groups)
+    service_variables[:restrict_address_families] = [] unless property_is_set?(:restrict_address_families)
+    service_variables[:restrict_namespaces] = true unless property_is_set?(:restrict_namespaces)
+    service_variables[:lock_personality] = true unless property_is_set?(:lock_personality)
+    service_variables[:memory_deny_write_execute] = true unless property_is_set?(:memory_deny_write_execute)
+    service_variables[:restrict_realtime] = true unless property_is_set?(:restrict_realtime)
+    service_variables[:restrict_suid_sgid] = true unless property_is_set?(:restrict_suid_sgid)
+    service_variables[:remove_ipc] = true unless property_is_set?(:remove_ipc)
+    service_variables[:system_call_filter] = "@system-service" unless property_is_set?(:system_call_filter)
+    service_variables[:system_call_architectures] = "native" unless property_is_set?(:system_call_architectures)
+
+    if sandbox_option(:enable_network)
+      service_variables[:private_network] = false
+      service_variables[:restrict_address_families] = Array(service_variables[:restrict_address_families]).append("AF_INET", "AF_INET6").reject { |f| f == "none" }
+    end
+  end
+
   if new_resource.environment_file.is_a?(Hash)
     template "/etc/default/#{new_resource.service}" do
       cookbook "systemd"
       source "environment.erb"
       owner "root"
       group "root"
-      mode 0o640
+      mode "640"
       variables :environment => new_resource.environment_file
     end
 
@@ -92,7 +180,7 @@ action :create do
     directory dropin_directory do
       owner "root"
       group "root"
-      mode 0o755
+      mode "755"
     end
   end
 
@@ -101,7 +189,7 @@ action :create do
     source "service.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables service_variables
     notifies :run, "execute[systemctl-reload]"
   end
@@ -134,6 +222,10 @@ action :delete do
 end
 
 action_class do
+  def sandbox_option(option)
+    new_resource.sandbox[option] if new_resource.sandbox.is_a?(Hash)
+  end
+
   def dropin_directory
     "/etc/systemd/system/#{new_resource.service}.service.d"
   end
diff --git a/cookbooks/systemd/resources/socket.rb b/cookbooks/systemd/resources/socket.rb
new file mode 100644 (file)
index 0000000..beb44fe
--- /dev/null
@@ -0,0 +1,115 @@
+#
+# Cookbook:: systemd
+# Resource:: systemd_socket
+#
+# Copyright:: 2021, OpenStreetMap Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+unified_mode true
+
+default_action :create
+
+property :socket, String, :name_property => true
+property :description, String, :required => [:create]
+property :after, [String, Array]
+property :wants, [String, Array]
+property :listen_stream, [String, Array]
+property :listen_datagram, [String, Array]
+property :listen_sequential_packet, [String, Array]
+property :listen_fifo, [String, Array]
+property :listen_special, [String, Array]
+property :listen_netlink, [String, Array]
+property :listen_message_queue, [String, Array]
+property :listen_usb_function, [String, Array]
+property :socket_protocol, String
+property :bind_ipv6_only, String
+property :backlog, Integer
+property :bind_to_device, String
+property :socket_user, String
+property :socket_group, String
+property :socket_mode, Integer
+property :directory_mode, Integer
+property :accept, [true, false]
+property :writable, [true, false]
+property :max_connections, Integer
+property :max_connections_per_source, Integer
+property :keep_alive, [true, false]
+property :keep_alive_time_sec, Integer
+property :keep_alive_interval_sec, Integer
+property :keep_alive_probes, Integer
+property :no_delay, [true, false]
+property :priority, Integer
+property :defer_accept_sec, Integer
+property :receive_buffer, Integer
+property :send_buffer, Integer
+property :ip_tos, Integer
+property :ip_ttl, Integer
+property :mark, Integer
+property :reuse_port, [true, false]
+property :pipe_size, Integer
+property :message_queue_max_messages, Integer
+property :message_queue_message_size, Integer
+property :free_bind, [true, false]
+property :transparent, [true, false]
+property :broadcast, [true, false]
+property :pass_credentials, [true, false]
+property :pass_security, [true, false]
+property :tcp_congestion, String
+property :exec_start_pre, [String, Array]
+property :exec_start, [String, Array]
+property :exec_start_post, [String, Array]
+property :exec_stop, [String, Array]
+property :timeout_sec, [Integer, String]
+property :service, String
+property :remove_on_stop, [true, false]
+property :symlinks, [String, Array]
+property :file_descriptor_name, String
+property :trigger_limit_interval_sec, [Integer, String]
+property :trigger_limit_burst, Integer
+
+action :create do
+  socket_variables = new_resource.to_hash
+
+  template "/etc/systemd/system/#{new_resource.socket}.socket" do
+    cookbook "systemd"
+    source "socket.erb"
+    owner "root"
+    group "root"
+    mode "644"
+    variables socket_variables
+  end
+
+  execute "systemctl-reload-#{new_resource.socket}.socket" do
+    action :nothing
+    command "systemctl daemon-reload"
+    user "root"
+    group "root"
+    subscribes :run, "template[/etc/systemd/system/#{new_resource.socket}.socket]"
+  end
+end
+
+action :delete do
+  file "/etc/systemd/system/#{new_resource.socket}.socket" do
+    action :delete
+  end
+
+  execute "systemctl-reload-#{new_resource.socket}.socket" do
+    action :nothing
+    command "systemctl daemon-reload"
+    user "root"
+    group "root"
+    subscribes :run, "file[/etc/systemd/system/#{new_resource.socket}.socket]"
+  end
+end
index b33cff2d0b84d2581af5ab3f2f250658023853cb..f3f324ea035cd2fbf3f95cf86804bb1db96bd4ca 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
 property :timer, String, :name_property => true
-property :description, String, :required => true
+property :dropin, String
+property :description, String
 property :after, [String, Array]
 property :wants, [String, Array]
 property :on_active_sec, [Integer, String]
@@ -32,33 +35,41 @@ property :on_calendar, String
 property :accuracy_sec, [Integer, String]
 property :randomized_delay_sec, [Integer, String]
 property :unit, String
-property :persistent, [TrueClass, FalseClass]
-property :wake_system, [TrueClass, FalseClass]
-property :remain_after_elapse, [TrueClass, FalseClass]
+property :persistent, [true, false]
+property :wake_system, [true, false]
+property :remain_after_elapse, [true, false]
 
 action :create do
   timer_variables = new_resource.to_hash
 
-  template "/etc/systemd/system/#{new_resource.timer}.timer" do
+  if new_resource.dropin
+    directory dropin_directory do
+      owner "root"
+      group "root"
+      mode "755"
+    end
+  end
+
+  template config_name do
     cookbook "systemd"
     source "timer.erb"
     owner "root"
     group "root"
-    mode 0o644
+    mode "644"
     variables timer_variables
+    notifies :run, "execute[systemctl-reload]"
   end
 
-  execute "systemctl-reload-#{new_resource.timer}.timer" do
+  execute "systemctl-reload" do
     action :nothing
     command "systemctl daemon-reload"
     user "root"
     group "root"
-    subscribes :run, "template[/etc/systemd/system/#{new_resource.timer}.timer]"
   end
 end
 
 action :delete do
-  file "/etc/systemd/system/#{new_resource.timer}.timer" do
+  file config_name do
     action :delete
   end
 
@@ -70,3 +81,17 @@ action :delete do
     subscribes :run, "file[/etc/systemd/system/#{new_resource.timer}.timer]"
   end
 end
+
+action_class do
+  def dropin_directory
+    "/etc/systemd/system/#{new_resource.timer}.timer.d"
+  end
+
+  def config_name
+    if new_resource.dropin
+      "#{dropin_directory}/#{new_resource.dropin}.conf"
+    else
+      "/etc/systemd/system/#{new_resource.timer}.timer"
+    end
+  end
+end
index 8c21b6b6ff3462a79f2ae0c386627946cde88309..07c39d3a9ccc62908428777f4aa6a5488831e3a4 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :type, String, :required => true
+property :type, String, :required => [:create]
 property :path, String, :name_property => true
 property :mode, String, :default => "-"
 property :owner, String, :default => "-"
@@ -33,8 +35,8 @@ action :create do
     source "tmpfile.erb"
     owner "root"
     group "root"
-    mode 0o644
-    variables new_resource.to_hash
+    mode "644"
+    variables new_resource.to_hash.merge(:path => new_resource.path)
   end
 
   execute "systemd-tmpfiles" do
index 0d4abbcefe493eedab4a3679a9829bcb78f82a2e..197d8bddf80dd6972be5d9eb550f69f6d6d8ff79 100644 (file)
@@ -4,17 +4,35 @@
 <% if @description -%>
 Description=<%= @description %>
 <% end -%>
+<% if @condition_path_exists -%>
+ConditionPathExists=<%= Array(@condition_path_exists).join(" ") %>
+<% end -%>
+<% if @condition_path_exists_glob -%>
+ConditionPathExistsGlob=<%= Array(@condition_path_exists_glob).join(" ") %>
+<% end -%>
 <% if @after -%>
 After=<%= Array(@after).join(" ") %>
 <% end -%>
+<% if @conflicts -%>
+Conflicts=<%= Array(@conflicts).join(" ") %>
+<% end -%>
 <% if @wants -%>
 Wants=<%= Array(@wants).join(" ") %>
 <% end -%>
+<% if @requires -%>
+Requires=<%= Array(@requires).join(" ") %>
+<% end -%>
+<% if @joins_namespace_of -%>
+JoinsNamespaceOf=<%= Array(@joins_namespace_of).join(" ") %>
+<% end -%>
 
 [Service]
 <% if @type -%>
 Type=<%= @type %>
 <% end -%>
+<% if @notify_access -%>
+NotifyAccess=<%= @notify_access %>
+<% end -%>
 <% if @limit_nofile -%>
 LimitNOFILE=<%= @limit_nofile %>
 <% end -%>
@@ -45,30 +63,97 @@ User=<%= @user %>
 <% if @group -%>
 Group=<%= @group %>
 <% end -%>
+<% if @dynamic_user -%>
+DynamicUser=<%= @dynamic_user %>
+<% end -%>
 <% if @working_directory -%>
 WorkingDirectory=<%= @working_directory %>
 <% end -%>
+<% if @umask -%>
+UMask=<%= @umask %>
+<% end -%>
 <% if @exec_start_pre -%>
-ExecStartPre=<%= @exec_start_pre %>
+<% if @dropin -%>
+ExecStartPre=
+<% end -%>
+<% Array(@exec_start_pre).each do |exec_start_pre| -%>
+ExecStartPre=<%= exec_start_pre %>
+<% end -%>
 <% end -%>
 <% if @exec_start -%>
-ExecStart=<%= @exec_start %>
+<% if @dropin -%>
+ExecStart=
+<% end -%>
+<% Array(@exec_start).each do |exec_start| -%>
+ExecStart=<%= exec_start %>
+<% end -%>
 <% end -%>
 <% if @exec_start_post -%>
-ExecStartPost=<%= @exec_start_post %>
+<% if @dropin -%>
+ExecStartPost=
+<% end -%>
+<% Array(@exec_start_post).each do |exec_start_post| -%>
+ExecStartPost=<%= exec_start_post %>
+<% end -%>
 <% end -%>
 <% if @exec_stop -%>
-ExecStop=<%= @exec_stop %>
+<% if @dropin -%>
+ExecStop=
+<% end -%>
+<% Array(@exec_stop).each do |exec_stop| -%>
+ExecStop=<%= exec_stop %>
+<% end -%>
+<% end -%>
+<% if @exec_stop_post -%>
+<% if @dropin -%>
+ExecStopPost=
+<% end -%>
+<% Array(@exec_stop_post).each do |exec_stop_post| -%>
+ExecStopPost=<%= exec_stop_post %>
+<% end -%>
 <% end -%>
 <% if @exec_reload -%>
+<% if @dropin -%>
+ExecReload=
+<% end -%>
 ExecReload=<%= @exec_reload %>
 <% end -%>
+<% if @runtime_max_sec -%>
+RuntimeMaxSec=<%= @runtime_max_sec %>
+<% end -%>
 <% if @runtime_directory -%>
 RuntimeDirectory=<%= @runtime_directory %>
 <% end -%>
 <% if @runtime_directory_mode -%>
 RuntimeDirectoryMode=<%= sprintf("0%o", @runtime_directory_mode) %>
 <% end -%>
+<% if @runtime_directory_preserve -%>
+RuntimeDirectoryPreserve=<%= @runtime_directory_preserve %>
+<% end -%>
+<% if @state_directory -%>
+StateDirectory=<%= @state_directory %>
+<% end -%>
+<% if @state_directory_mode -%>
+StateDirectoryMode=<%= sprintf("0%o", @state_directory_mode) %>
+<% end -%>
+<% if @cache_directory -%>
+CacheDirectory=<%= @cache_directory %>
+<% end -%>
+<% if @cache_directory_mode -%>
+CacheDirectoryMode=<%= sprintf("0%o", @cache_directory_mode) %>
+<% end -%>
+<% if @logs_directory -%>
+LogsDirectory=<%= @logs_directory %>
+<% end -%>
+<% if @logs_directory_mode -%>
+LogsDirectoryMode=<%= sprintf("0%o", @logs_directory_mode) %>
+<% end -%>
+<% if @configuration_directory -%>
+ConfigurationDirectory=<%= @configuration_directory %>
+<% end -%>
+<% if @configuration_directory_mode -%>
+ConfigurationDirectoryMode=<%= sprintf("0%o", @configuration_directory_mode) %>
+<% end -%>
 <% if @standard_input -%>
 StandardInput=<%= @standard_input %>
 <% end -%>
@@ -78,6 +163,42 @@ StandardOutput=<%= @standard_output %>
 <% if @standard_error -%>
 StandardError=<%= @standard_error %>
 <% end -%>
+<% if @protect_proc && node[:lsb][:release].to_f >= 22.04  -%>
+ProtectProc=<%= @protect_proc %>
+<% end -%>
+<% if @proc_subset && node[:lsb][:release].to_f >= 22.04 -%>
+ProcSubset=<%= @proc_subset %>
+<% end -%>
+<% if @bind_paths -%>
+BindPaths=<%= Array(@bind_paths).sort.uniq.join(" ") %>
+<% end -%>
+<% if @bind_read_only_paths -%>
+BindReadOnlyPaths=<%= Array(@bind_read_only_paths).sort.uniq.join(" ") %>
+<% end -%>
+<% if @no_new_privileges -%>
+NoNewPrivileges=<%= @no_new_privileges %>
+<% end -%>
+<% if @capability_bounding_set -%>
+CapabilityBoundingSet=<%= Array(@capability_bounding_set).sort.uniq.join(" ") %>
+<% end -%>
+<% if @ambient_capabilities -%>
+AmbientCapabilities=<%= Array(@ambient_capabilities).sort.uniq.join(" ") %>
+<% end -%>
+<% if @protect_system -%>
+ProtectSystem=<%= @protect_system %>
+<% end -%>
+<% if @protect_home -%>
+ProtectHome=<%= @protect_home %>
+<% end -%>
+<% if @read_write_paths -%>
+ReadWritePaths=<%= Array(@read_write_paths).sort.uniq.join(" ") %>
+<% end -%>
+<% if @read_only_paths -%>
+ReadOnlyPaths=<%= Array(@read_only_paths).sort.uniq.join(" ") %>
+<% end -%>
+<% if @inaccessible_paths -%>
+InaccessiblePaths=<%= Array(@inaccessible_paths).sort.uniq.join(" ") %>
+<% end -%>
 <% if @private_tmp -%>
 PrivateTmp=<%= @private_tmp %>
 <% end -%>
@@ -87,17 +208,56 @@ PrivateDevices=<%= @private_devices %>
 <% if @private_network -%>
 PrivateNetwork=<%= @private_network %>
 <% end -%>
-<% if @protect_system -%>
-ProtectSystem=<%= @protect_system %>
+<% if @private_ipc && node[:lsb][:release].to_f >= 22.04 -%>
+PrivateIPC=<%= @private_ipc %>
 <% end -%>
-<% if @protect_home -%>
-ProtectHome=<%= @protect_home %>
+<% if @private_users -%>
+PrivateUsers=<%= @private_users %>
+<% end -%>
+<% if @protect_hostname -%>
+ProtectHostname=<%= @protect_hostname %>
+<% end -%>
+<% if @protect_clock -%>
+ProtectClock=<%= @protect_clock %>
+<% end -%>
+<% if @protect_kernel_tunables -%>
+ProtectKernelTunables=<%= @protect_kernel_tunables %>
+<% end -%>
+<% if @protect_kernel_modules -%>
+ProtectKernelModules=<%= @protect_kernel_modules %>
+<% end -%>
+<% if @protect_kernel_logs -%>
+ProtectKernelLogs=<%= @protect_kernel_logs %>
+<% end -%>
+<% if @protect_control_groups -%>
+ProtectControlGroups=<%= @protect_control_groups %>
 <% end -%>
 <% if @restrict_address_families -%>
-RestrictAddressFamilies=<%= Array(@restrict_address_families).join(" ") %>
+RestrictAddressFamilies=<%= Array(@restrict_address_families).sort.uniq.join(" ") %>
 <% end -%>
-<% if @no_new_privileges -%>
-NoNewPrivileges=<%= @no_new_privileges %>
+<% if @restrict_namespaces -%>
+RestrictNamespaces=<%= Array(@restrict_namespaces).sort.uniq.join(" ") %>
+<% end -%>
+<% if @lock_personality -%>
+LockPersonality=<%= @lock_personality %>
+<% end -%>
+<% if @memory_deny_write_execute -%>
+MemoryDenyWriteExecute=<%= @memory_deny_write_execute %>
+<% end -%>
+<% if @restrict_realtime -%>
+RestrictRealtime=<%= @restrict_realtime %>
+<% end -%>
+<% if @restrict_suid_sgid -%>
+RestrictSUIDSGID=<%= @restrict_suid_sgid %>
+<% end -%>
+<% if @remove_ipc -%>
+RemoveIPC=<%= @remove_ipc %>
+<% end -%>
+<% if @system_call_filter -%>
+SystemCallFilter=<%= Array(@system_call_filter).join(" ") %>
+<% end -%>
+<% if @system_call_architectures -%>
+SystemCallArchitectures=<%= Array(@system_call_architectures).sort.uniq.join(" ") %>
 <% end -%>
 <% if @tasks_max -%>
 TasksMax=<%= @tasks_max %>
@@ -108,6 +268,18 @@ SuccessExitStatus=<%= Array(@success_exit_status).join(" ") %>
 <% if @restart -%>
 Restart=<%= @restart %>
 <% end -%>
+<% if @restart_sec -%>
+RestartSec=<%= @restart_sec %>
+<% end -%>
+<% if @timeout_start_sec -%>
+TimeoutStartSec=<%= @timeout_start_sec %>
+<% end -%>
+<% if @timeout_stop_sec -%>
+TimeoutStopSec=<%= @timeout_stop_sec %>
+<% end -%>
+<% if @timeout_abort_sec -%>
+TimeoutAbortSec=<%= @timeout_abort_sec %>
+<% end -%>
 <% if @timeout_sec -%>
 TimeoutSec=<%= @timeout_sec %>
 <% end -%>
diff --git a/cookbooks/systemd/templates/default/socket.erb b/cookbooks/systemd/templates/default/socket.erb
new file mode 100644 (file)
index 0000000..0da3533
--- /dev/null
@@ -0,0 +1,174 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+[Unit]
+Description=<%= @description %>
+<% if @after -%>
+After=<%= Array(@after).join(" ") %>
+<% end -%>
+<% if @wants -%>
+Wants=<%= Array(@wants).join(" ") %>
+<% end -%>
+
+[Socket]
+<% Array(@listen_stream).each do |listen| -%>
+ListenStream=<%= listen %>
+<% end -%>
+<% Array(@listen_datagram).each do |listen| -%>
+ListenDatagram=<%= listen %>
+<% end -%>
+<% Array(@listen_sequential_packet).each do |listen| -%>
+ListenSequentialPacket=<%= listen %>
+<% end -%>
+<% Array(@listen_fifo).each do |listen| -%>
+ListenFIFO=<%= listen %>
+<% end -%>
+<% Array(@listen_special).each do |listen| -%>
+ListenSpecial=<%= listen %>
+<% end -%>
+<% Array(@listen_netlink).each do |listen| -%>
+ListenNetlink=<%= listen %>
+<% end -%>
+<% Array(@listen_message_queue).each do |listen| -%>
+ListenMessageQueue=<%= listen %>
+<% end -%>
+<% Array(@listen_usb_function).each do |listen| -%>
+ListenUSBFunction=<%= listen %>
+<% end -%>
+<% if @socket_protocol -%>
+SocketProtocol=<%= @socket_protocol %>
+<% end -%>
+<% if @bind_ipv6_only -%>
+BindIpv6Only=<%= @bind_ipv6_only %>
+<% end -%>
+<% if @backlog -%>
+Backlog=<%= @backlog %>
+<% end -%>
+<% if @bind_to_device -%>
+BindToDevice=<%= @bind_to_device %>
+<% end -%>
+<% if @socket_user -%>
+SocketUser=<%= @socket_user %>
+<% end -%>
+<% if @socket_group -%>
+SocketGroup=<%= @socket_group %>
+<% end -%>
+<% if @socket_mode -%>
+SocketMode=<%= sprintf("0%o", @socket_mode) %>
+<% end -%>
+<% if @directory_mode -%>
+DirectoryMode=<%= sprintf("0%o", @directory_mode) %>
+<% end -%>
+<% if @accept -%>
+Accept=<%= @accept %>
+<% end -%>
+<% if @writable -%>
+Writable=<%= @writable %>
+<% end -%>
+<% if @max_connections -%>
+MaxConnections=<%= @max_connections %>
+<% end -%>
+<% if @max_connections_per_source -%>
+MaxConnectionsPerSource=<%= @max_connections_per_source %>
+<% end -%>
+<% if @keep_alive -%>
+KeepAlive=<%= @keep_alive %>
+<% end -%>
+<% if @keep_alive_time_sec -%>
+KeepAliveTimeSec=<%= @keep_alive_time_sec %>
+<% end -%>
+<% if @keep_alive_interval_sec -%>
+KeepAliveIntervalSec=<%= @keep_alive_interval_sec %>
+<% end -%>
+<% if @keep_alive_probes -%>
+KeepAliveProbes=<%= @keep_alive_probes %>
+<% end -%>
+<% if @no_delay -%>
+NoDelay=<%= @no_delay %>
+<% end -%>
+<% if @priority -%>
+Priority=<%= @priority %>
+<% end -%>
+<% if @defer_accept_sec -%>
+DeferAcceptSec=<%= @defer_accept_sec %>
+<% end -%>
+<% if @receive_buffer -%>
+ReceiveBuffer=<%= @receive_buffer %>
+<% end -%>
+<% if @send_buffer -%>
+SendBuffer=<%= @send_buffer %>
+<% end -%>
+<% if @ip_tos -%>
+IpTos=<%= @ip_tos %>
+<% end -%>
+<% if @ip_ttl -%>
+IpTtl=<%= @ip_ttl %>
+<% end -%>
+<% if @mark -%>
+Mark=<%= @mark %>
+<% end -%>
+<% if @reuse_port -%>
+ReusePort=<%= @reuse_port %>
+<% end -%>
+<% if @pipe_size -%>
+PipeSize=<%= @pipe_size %>
+<% end -%>
+<% if @message_queue_max_messages -%>
+MessageQueueMaxMessages=<%= @message_queue_max_messages %>
+<% end -%>
+<% if @message_queue_message_size -%>
+MessageQueueMessageSize=<%= @message_queue_message_size %>
+<% end -%>
+<% if @free_bind -%>
+FreeBind=<%= @free_bind %>
+<% end -%>
+<% if @transparent -%>
+Transparent=<%= @transparent %>
+<% end -%>
+<% if @broadcast -%>
+Broadcast=<%= @broadcast %>
+<% end -%>
+<% if @pass_credentials -%>
+PassCredentials=<%= @pass_credentials %>
+<% end -%>
+<% if @pass_security -%>
+PassSecurity=<%= @pass_security %>
+<% end -%>
+<% if @tcp_congestion -%>
+TcpCongestion=<%= @tcp_congestion %>
+<% end -%>
+<% Array(@exec_start_pre).each do |exec| -%>
+ExecStartPre=<%= exec %>
+<% end -%>
+<% Array(@exec_start).each do |exec| -%>
+ExecStart=<%= exec %>
+<% end -%>
+<% Array(@exec_stop_post).each do |exec| -%>
+ExecStopPost=<%= exec %>
+<% end -%>
+<% Array(@exec_stop).each do |exec| -%>
+ExecStop=<%= exec %>
+<% end -%>
+<% if @timeout_sec -%>
+TimeoutSec=<%= @timeout_sec %>
+<% end -%>
+<% if @service -%>
+Service=<%= @service %>
+<% end -%>
+<% if @remove_on_stop -%>
+RemoveOnStop=<%= @remove_on_stop %>
+<% end -%>
+<% Array(@symlinks).each do |symlink| -%>
+Symlinks=<%= symlink %>
+<% end -%>
+<% if @file_descriptor_name -%>
+FileDescriptorName=<%= @file_descriptor_name %>
+<% end -%>
+<% if @trigger_limit_interval_sec -%>
+TriggerLimitIntervalSec=<%= @trigger_limit_interval_sec %>
+<% end -%>
+<% if @trigger_limit_burst -%>
+TriggerLimitBurst=<%= @trigger_limit_burst %>
+<% end -%>
+
+[Install]
+WantedBy=multi-user.target
index c7098b77b7b58f17aa1e44917b5fae47b68c0acb..266ac250a6a7cd60aeb596bb4c5d4e2b1487a1f7 100644 (file)
@@ -1 +1,3 @@
 default[:taginfo][:sites] = []
+
+default[:accounts][:users][:taginfo][:status] = :role
index 37794a28ee4df3440679a4add44add9d696ec4a2..90517c121a1d210db3763c132731cddda0ea4958 100644 (file)
@@ -6,6 +6,10 @@ description       "Installs and configures taginfo"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
-depends           "passenger"
 depends           "git"
+depends           "passenger"
+depends           "planet"
+depends           "prometheus"
+depends           "ruby"
index 4289c0042d3b7f24b557959cd1055622421617a7..818561930412db0cdbc6521fce689eb766464866 100644 (file)
 
 require "json"
 
+include_recipe "accounts"
 include_recipe "apache"
-include_recipe "passenger"
 include_recipe "git"
+include_recipe "passenger"
+include_recipe "planet::current"
+include_recipe "prometheus"
+include_recipe "ruby"
 
 package %w[
   libsqlite3-dev
@@ -42,22 +46,13 @@ package %w[
 
 package %w[
   sqlite3
+  sqlite3-pcre
   osmium-tool
   pyosmium
   curl
   pbzip2
 ]
 
-ruby_version = node[:passenger][:ruby_version]
-
-package "ruby#{ruby_version}"
-
-gem_package "bundler#{ruby_version}" do
-  package_name "bundler"
-  gem_binary "gem#{ruby_version}"
-  options "--format-executable"
-end
-
 apache_module "cache"
 apache_module "cache_disk"
 apache_module "headers"
@@ -65,14 +60,35 @@ apache_module "headers"
 directory "/var/log/taginfo" do
   owner "taginfo"
   group "taginfo"
-  mode 0o755
+  mode "755"
 end
 
 template "/etc/sudoers.d/taginfo" do
   source "sudoers.erb"
   owner "root"
   group "root"
-  mode 0o440
+  mode "440"
+end
+
+systemd_service "taginfo-update@" do
+  description "Taginfo update for %i"
+  wants "planet-update.service"
+  after "planet-update.service"
+  exec_start "/srv/%i/bin/update"
+  user "taginfo"
+  sandbox :enable_network => true
+  restrict_address_families "AF_UNIX"
+  read_write_paths [
+    "/srv/%i/data",
+    "/srv/%i/download",
+    "/srv/%i/sources",
+    "/var/log/taginfo/%i"
+  ]
+end
+
+systemd_timer "taginfo-update@" do
+  description "Taginfo update for %i"
+  on_calendar "01:37"
 end
 
 node[:taginfo][:sites].each do |site|
@@ -87,19 +103,47 @@ node[:taginfo][:sites].each do |site|
   directory "/var/log/taginfo/#{site_name}" do
     owner "taginfo"
     group "taginfo"
-    mode 0o755
+    mode "755"
   end
 
   directory directory do
     owner "taginfo"
     group "taginfo"
-    mode 0o755
+    mode "755"
+  end
+
+  git "#{directory}/taginfo-tools" do
+    action :sync
+    repository "https://github.com/taginfo/taginfo-tools.git"
+    revision "osmorg-taginfo-live"
+    depth 1
+    enable_submodules true
+    user "taginfo"
+    group "taginfo"
+  end
+
+  directory "#{directory}/build" do
+    owner "taginfo"
+    group "taginfo"
+    mode "755"
+  end
+
+  execute "compile_taginfo_tools" do
+    action :nothing
+    user "taginfo"
+    group "taginfo"
+    cwd "#{directory}/build"
+    command "cmake #{directory}/taginfo-tools -DCMAKE_BUILD_TYPE=Release && make"
+    subscribes :run, "apt_package[libprotozero-dev]"
+    subscribes :run, "apt_package[libosmium2-dev]"
+    subscribes :run, "git[#{directory}/taginfo-tools]"
   end
 
   git "#{directory}/taginfo" do
     action :sync
-    repository "git://github.com/taginfo/taginfo.git"
+    repository "https://github.com/taginfo/taginfo.git"
     revision "osmorg-taginfo-live"
+    depth 1
     user "taginfo"
     group "taginfo"
   end
@@ -116,10 +160,11 @@ node[:taginfo][:sites].each do |site|
     settings["logging"]["directory"] = "/var/log/taginfo/#{site_name}"
     settings["opensearch"]["shortname"] = "Taginfo"
     settings["opensearch"]["contact"] = "webmaster@openstreetmap.org"
+    settings["paths"]["bin_dir"] = "#{directory}/build/src"
     settings["sources"]["download"] = ""
-    settings["sources"]["create"] = "db languages projects wiki"
-    settings["sources"]["db"]["planetfile"] = "/var/lib/planet/planet.pbf"
-    settings["sources"]["db"]["bindir"] = "#{directory}/taginfo/tagstats"
+    settings["sources"]["create"] = "db languages projects wiki wikidata chronology"
+    settings["sources"]["db"]["planetfile"] = "/var/lib/planet/planet.osh.pbf"
+    settings["sources"]["chronology"]["osm_history_file"] = "/var/lib/planet/planet.osh.pbf"
     settings["tagstats"]["geodistribution"] = "DenseMmapArray"
 
     JSON.pretty_generate(settings)
@@ -128,30 +173,15 @@ node[:taginfo][:sites].each do |site|
   file "#{directory}/taginfo-config.json" do
     owner "taginfo"
     group "taginfo"
-    mode 0o644
+    mode "644"
     content settings
     notifies :restart, "service[apache2]"
   end
 
-  execute "#{directory}/taginfo/tagstats/Makefile" do
+  bundle_install "#{directory}/taginfo" do
     action :nothing
-    command "make"
-    cwd "#{directory}/taginfo/tagstats"
-    user "taginfo"
-    group "taginfo"
-    subscribes :run, "apt_package[libprotozero-dev]"
-    subscribes :run, "apt_package[libosmium2-dev]"
-    subscribes :run, "git[#{directory}/taginfo]"
-    notifies :restart, "service[apache2]"
-  end
-
-  execute "#{directory}/taginfo/Gemfile" do
-    action :nothing
-    command "bundle#{ruby_version} install"
-    cwd "#{directory}/taginfo"
     user "root"
     group "root"
-    subscribes :run, "gem_package[bundler#{ruby_version}]"
     subscribes :run, "git[#{directory}/taginfo]"
     notifies :restart, "passenger_application[#{directory}/taginfo/web/public]"
   end
@@ -160,7 +190,7 @@ node[:taginfo][:sites].each do |site|
     directory "#{directory}/#{dir}" do
       owner "taginfo"
       group "taginfo"
-      mode 0o755
+      mode "755"
     end
   end
 
@@ -168,7 +198,7 @@ node[:taginfo][:sites].each do |site|
     source "update.erb"
     owner "taginfo"
     group "taginfo"
-    mode 0o755
+    mode "755"
     variables :name => site_name, :directory => directory
   end
 
@@ -186,12 +216,15 @@ node[:taginfo][:sites].each do |site|
     directory "#{directory}/taginfo/web/public"
     variables :aliases => site_aliases
   end
-end
 
-template "/usr/local/bin/taginfo-update" do
-  source "taginfo-update.erb"
-  owner "root"
-  group "root"
-  mode 0o755
-  variables :sites => node[:taginfo][:sites]
+  service "taginfo-update@#{site_name}.timer" do
+    action [:enable, :start]
+  end
+
+  prometheus_collector "taginfo-#{site_name}" do
+    interval "15m"
+    user "taginfo"
+    path "#{directory}/taginfo/sources/metrics.rb"
+    options "#{directory}/data"
+  end
 end
index 4965a9bc131b433218f92a7c4608c0734ba516ee..6d7dd08b48f9a08af8852f89a1118c94c24e48c5 100644 (file)
@@ -8,7 +8,7 @@
         SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
         SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         DocumentRoot <%= @directory %>
@@ -38,7 +38,7 @@
         SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
         SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         RedirectPermanent / https://<%= @name %>/
@@ -52,7 +52,7 @@
 <% end -%>
         ServerAdmin webmaster@openstreetmap.org
 
-        CustomLog /var/log/apache2/<%= @name %>-access.log combined
+        CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
         ErrorLog /var/log/apache2/<%= @name %>-error.log
 
         RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
diff --git a/cookbooks/taginfo/templates/default/taginfo-update.erb b/cookbooks/taginfo/templates/default/taginfo-update.erb
deleted file mode 100644 (file)
index 0dd05b8..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-<% @sites.each do |site| -%>
-<% if site[:directory] -%>
-<%= site[:directory] %>/bin/update
-<% else -%>
-/srv/<%= site[:name] %>/bin/update
-<% end -%>
-<% end -%>
index 99b322f57468357c1a844d875c76f37d49f0c6dc..f2d1dde59ac7b63e06a87ace4d2a97d96b44e8f4 100644 (file)
@@ -15,11 +15,11 @@ fi
 
 $ROOT/taginfo/sources/update_all.sh $ROOT/sources
 
-mv $ROOT/data/taginfo-* $ROOT/data/old
-mv $ROOT/sources/taginfo-*.db $ROOT/sources/*/taginfo-*.db $ROOT/data
+ln -f $ROOT/data/taginfo-* $ROOT/data/old
+mv -f $ROOT/sources/taginfo-*.db $ROOT/sources/*/taginfo-*.db $ROOT/data
 mv $ROOT/sources/download/* $ROOT/download
 
-sudo PASSENGER_INSTANCE_REGISTRY_DIR=<%= node[:passenger][:instance_registry_dir] %> /usr/bin/passenger-config restart-app $ROOT/taginfo/web > /dev/null
+PASSENGER_INSTANCE_REGISTRY_DIR=<%= node[:passenger][:instance_registry_dir] %> /usr/bin/passenger-config restart-app $ROOT/taginfo/web > /dev/null
 
 find $ROOT/sources/log -mtime +28 -delete
 
index 7ef34a9580b7f808f6059c2901e8ed15870923c1..776e274b08e11c7757833af9a347088a52e72f04 100644 (file)
@@ -1,2 +1,23 @@
+default[:tile][:database][:cluster] = "14/main"
+default[:tile][:database][:postgis] = "3"
+default[:tile][:database][:node_file] = "/store/database/nodes"
+default[:tile][:database][:multi_geometry] = true
+default[:tile][:database][:hstore] = true
+default[:tile][:database][:style_file] = nil
+default[:tile][:database][:tag_transform_script] = nil
+
+default[:tile][:mapnik] = "3.1"
+
+default[:tile][:replication][:url] = "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/minute"
+
 default[:tile][:data] = {}
 default[:tile][:styles] = {}
+
+default[:postgresql][:versions] |= [node[:tile][:database][:cluster].split("/").first]
+default[:postgresql][:monitor_database] = "gis"
+
+default[:accounts][:users][:tile][:status] = :role
+
+default[:apache][:event][:server_limit] = node.cpu_cores * 5 / 4
+default[:apache][:event][:max_request_workers] = node.cpu_cores * node[:apache][:event][:threads_per_child]
+default[:apache][:event][:max_spare_threads] = node.cpu_cores * node[:apache][:event][:threads_per_child]
diff --git a/cookbooks/tile/files/default/bin/expire-tiles-single b/cookbooks/tile/files/default/bin/expire-tiles-single
deleted file mode 100644 (file)
index 9951643..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/usr/bin/python
-"""
-Expire meta tiles from a OSM change file by resetting their modified time.
-"""
-
-import argparse
-import os
-import osmium as o
-import pyproj
-
-EXPIRY_TIME = 946681200 # 2000-01-01 00:00:00
-# width/height of the spherical mercator projection
-SIZE = 40075016.6855784
-
-proj_wsg84 = pyproj.Proj(init='epsg:4326')
-proj_merc = pyproj.Proj(init='epsg:3857')
-
-class TileCollector(o.SimpleHandler):
-
-    def __init__(self, node_cache, zoom):
-        super(TileCollector, self).__init__()
-        self.node_cache = o.index.create_map("dense_file_array," + node_cache)
-        self.done_nodes = set()
-        self.tile_set = set()
-        self.zoom = zoom
-
-    def add_tile_from_node(self, location):
-        if not location.valid():
-            return
-
-        lat = max(-85, min(85.0, location.lat))
-        x, y = pyproj.transform(proj_wsg84, proj_merc, location.lon, lat)
-
-        # renormalise into unit space [0,1]
-        x = 0.5 + x / SIZE
-        y = 0.5 - y / SIZE
-        # transform into tile space
-        x = x * 2**self.zoom
-        y = y * 2**self.zoom
-        # chop of the fractional parts
-        self.tile_set.add((int(x), int(y), self.zoom))
-
-    def node(self, node):
-        # we put all the nodes into the hash, as it doesn't matter whether the node was
-        # added, deleted or modified - the tile will need updating anyway.
-        self.done_nodes.add(node.id)
-        self.add_tile_from_node(node.location)
-
-    def way(self, way):
-        for n in way.nodes:
-            if not n.ref in self.done_nodes:
-                self.done_nodes.add(n.ref)
-                try:
-                    self.add_tile_from_node(self.node_cache.get(n.ref))
-                except KeyError:
-                    pass # no coordinate
-
-
-def xyz_to_meta(x, y, z, meta_size):
-    """ Return the file name of a meta tile.
-        This must match the definition of xyz to meta in mod_tile.
-    """
-    # mask off the final few bits
-    x = x & ~(meta_size - 1)
-    y = y & ~(meta_size - 1)
-
-    # generate the path
-    path = None
-    for i in range(0, 5):
-        part = str(((x & 0x0f) << 4) | (y & 0x0f))
-        x = x >> 4
-        y = y >> 4
-        if path is None:
-            path = (part + ".meta")
-        else:
-            path = os.path.join(part, path)
-
-    return os.path.join(str(z), path)
-
-
-def expire_meta(meta):
-    """Expire the meta tile by setting the modified time back.
-    """
-    if os.path.exists(meta):
-        print("Expiring " + meta)
-        os.utime(meta, (EXPIRY_TIME, EXPIRY_TIME))
-
-
-def expire_meta_tiles(options):
-    proc = TileCollector(options.node_cache, options.max_zoom)
-    proc.apply_file(options.inputfile)
-
-    tile_set = proc.tile_set
-
-    # turn all the tiles into expires, putting them in the set
-    # so that we don't expire things multiple times
-    for z in range(options.min_zoom, options.max_zoom + 1):
-        meta_set = set()
-        new_set = set()
-        for xy in tile_set:
-            meta = xyz_to_meta(xy[0], xy[1], xy[2], options.meta_size)
-
-            for tile_dir in options.tile_dir:
-                meta_set.add(os.path.join(tile_dir, meta))
-
-            # add the parent into the set for the next round
-            new_set.add((int(xy[0]/2), int(xy[1]/2), xy[2] - 1))
-
-        # expire all meta tiles
-        for meta in meta_set:
-            expire_meta(meta)
-
-        # continue with parent tiles
-        tile_set = new_set
-
-if __name__ == '__main__':
-
-    parser = argparse.ArgumentParser(description=__doc__,
-                                     formatter_class=argparse.RawDescriptionHelpFormatter,
-                                     usage='%(prog)s [options] <inputfile>')
-    parser.add_argument('--min', action='store', dest='min_zoom', default=13,
-                        type=int,
-                        help='Minimum zoom for expiry.')
-    parser.add_argument('--max', action='store', dest='max_zoom', default=20,
-                        type=int,
-                        help='Maximum zoom for expiry.')
-    parser.add_argument('-t', action='append', dest='tile_dir', default=None,
-                        required=True,
-                        help='Tile directory (repeat for multiple directories).')
-    parser.add_argument('--meta-tile-size', action='store', dest='meta_size',
-                        default=8, type=int,
-                        help='The size of the meta tile blocks.')
-    parser.add_argument('--node-cache', action='store', dest='node_cache',
-                        default='/store/database/nodes',
-                        help='osm2pgsql flatnode file.')
-    parser.add_argument('inputfile',
-                        help='OSC input file.')
-
-    options = parser.parse_args()
-
-    expire_meta_tiles(options)
diff --git a/cookbooks/tile/files/default/html/abuse.png b/cookbooks/tile/files/default/html/abuse.png
deleted file mode 100644 (file)
index f9f7910..0000000
Binary files a/cookbooks/tile/files/default/html/abuse.png and /dev/null differ
diff --git a/cookbooks/tile/files/default/html/abuse2.png b/cookbooks/tile/files/default/html/abuse2.png
deleted file mode 100644 (file)
index ba40a46..0000000
Binary files a/cookbooks/tile/files/default/html/abuse2.png and /dev/null differ
diff --git a/cookbooks/tile/files/default/html/abuse3.png b/cookbooks/tile/files/default/html/abuse3.png
deleted file mode 100644 (file)
index b297ae7..0000000
Binary files a/cookbooks/tile/files/default/html/abuse3.png and /dev/null differ
index 76aaf4aeef363680a5305dead1b8da99992f042d..35fc43447c07ebe1e743a07daf9972db5d053260 100644 (file)
@@ -3,4 +3,3 @@
 <cross-domain-policy>
     <allow-access-from domain="*" secure="false" />
 </cross-domain-policy>
-       
index 27b042b5cec16967462ab011cf4b47320fbc14c4..975e1cb0d9a56a11d5843a5bc851bd8ed2f6b0ca 100644 (file)
Binary files a/cookbooks/tile/files/default/html/favicon.ico and b/cookbooks/tile/files/default/html/favicon.ico differ
index eb5b273491b94c380f41570e33c165e2e29cae9c..bfb50b0ae13ea1686276a22b698dd60408038ee2 100644 (file)
@@ -11,4 +11,3 @@ Disallow: /20/
 Disallow: /21/
 Disallow: /22/
 Disallow: /23/
-
diff --git a/cookbooks/tile/files/default/html/tilejson.json b/cookbooks/tile/files/default/html/tilejson.json
new file mode 100644 (file)
index 0000000..3b07627
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "tilejson": "3.0.0",
+    "attribution": "© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",
+    "name": "OpenStreetMap Standard",
+    "tiles": [
+        "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
+    ],
+    "minzoom": 0,
+    "maxzoom": 19
+}
diff --git a/cookbooks/tile/files/default/html/update-url-tile.png b/cookbooks/tile/files/default/html/update-url-tile.png
deleted file mode 100644 (file)
index 3456d30..0000000
Binary files a/cookbooks/tile/files/default/html/update-url-tile.png and /dev/null differ
diff --git a/cookbooks/tile/files/default/ruby/expire.rb b/cookbooks/tile/files/default/ruby/expire.rb
deleted file mode 100755 (executable)
index 3d693ad..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/ruby
-
-require "rubygems"
-require "proj4"
-require "xml/libxml"
-require "set"
-require "time"
-
-module Expire
-  # projection object to go from latlon -> spherical mercator
-  PROJ = Proj4::Projection.new(["+proj=merc", "+a=6378137", "+b=6378137",
-                                "+lat_ts=0.0", "+lon_0=0.0", "+x_0=0.0",
-                                "+y_0=0", "+k=1.0", "+units=m",
-                                "+nadgrids=@null", "+no_defs +over"])
-
-  # width/height of the spherical mercator projection
-  SIZE = 40075016.6855784
-  # the size of the meta tile blocks
-  METATILE = 8
-  # the directory root for meta tiles
-  HASH_ROOT = "/tiles/default/".freeze
-  # node cache file
-  NODE_CACHE_FILE = "/store/database/nodes".freeze
-
-  # turns a spherical mercator coord into a tile coord
-  def self.tile_from_merc(point, zoom)
-    # renormalise into unit space [0,1]
-    point.x = 0.5 + point.x / SIZE
-    point.y = 0.5 - point.y / SIZE
-    # transform into tile space
-    point.x = point.x * 2**zoom
-    point.y = point.y * 2**zoom
-    # chop of the fractional parts
-    [point.x.to_int, point.y.to_int, zoom]
-  end
-
-  # turns a latlon -> tile x,y given a zoom level
-  def self.tile_from_latlon(latlon, zoom)
-    # first convert to spherical mercator
-    point = PROJ.forward(latlon)
-    tile_from_merc(point, zoom)
-  end
-
-  # this must match the definition of xyz_to_meta in mod_tile
-  def self.xyz_to_meta(x, y, z)
-    # mask off the final few bits
-    x &= ~(METATILE - 1)
-    y &= ~(METATILE - 1)
-    # generate the path
-    hash_path = (0..4).collect do |i|
-      (((x >> 4 * i) & 0xf) << 4) | ((y >> 4 * i) & 0xf)
-    end.reverse.join("/")
-    z.to_s + "/" + hash_path + ".meta"
-  end
-
-  # time to reset to, some very stupidly early time, before OSM started
-  EXPIRY_TIME = Time.parse("2000-01-01 00:00:00")
-
-  # expire the meta tile by setting the modified time back
-  def self.expire_meta(meta)
-    puts "Expiring #{meta}"
-    File.utime(EXPIRY_TIME, EXPIRY_TIME, meta)
-  end
-
-  def self.expire(change_file, min_zoom, max_zoom, tile_dirs)
-    do_expire(change_file, min_zoom, max_zoom) do |set|
-      new_set = Set.new
-      meta_set = Set.new
-
-      # turn all the tiles into expires, putting them in the set
-      # so that we don't expire things multiple times
-      set.each do |xy|
-        # this has to match the routine in mod_tile
-        meta = xyz_to_meta(xy[0], xy[1], xy[2])
-
-        # check each style working out what needs expiring
-        tile_dirs.each do |tile_dir|
-          meta_set.add(tile_dir + "/" + meta) if File.exist?(tile_dir + "/" + meta)
-        end
-
-        # add the parent into the set for the next round
-        new_set.add([xy[0] / 2, xy[1] / 2, xy[2] - 1])
-      end
-
-      # expire all meta tiles
-      meta_set.each do |meta|
-        expire_meta(meta)
-      end
-
-      # return the new set, consisting of all the parents
-      new_set
-    end
-  end
-
-  def self.do_expire(change_file, min_zoom, max_zoom, &_)
-    # read in the osm change file
-    doc = XML::Document.file(change_file)
-
-    # hash map to contain all the nodes
-    nodes = {}
-
-    # we put all the nodes into the hash, as it doesn't matter whether the node was
-    # added, deleted or modified - the tile will need updating anyway.
-    doc.find("//node").each do |node|
-      lat = node["lat"].to_f
-      lat = -85 if lat < -85
-      lat = 85 if lat > 85
-      point = Proj4::Point.new(Math::PI * node["lon"].to_f / 180,
-                               Math::PI * lat / 180)
-      nodes[node["id"].to_i] = tile_from_latlon(point, max_zoom)
-    end
-
-    # now we look for all the ways that have changed and put all of their nodes into
-    # the hash too. this will add too many nodes, as it is possible a long way will be
-    # changed at only a portion of its length. however, due to the non-local way that
-    # mapnik does text placement, it may stil not be enough.
-    #
-    # also, we miss cases where nodes are deleted from ways where that node is not
-    # itself deleted and the coverage of the point set isn't enough to encompass the
-    # change.
-    node_cache = NodeCache.new(NODE_CACHE_FILE)
-    doc.find("//way/nd").each do |node|
-      node_id = node["ref"].to_i
-
-      next if nodes.include? node_id
-
-      # this is a node referenced but not added, modified or deleted, so it should
-      # still be in the node cache.
-      if (entry = node_cache[node_id])
-        point = Proj4::Point.new(entry.lon, entry.lat)
-        nodes[node_id] = tile_from_merc(point, max_zoom)
-      end
-    end
-    node_cache.close
-
-    # create a set of all the tiles at the maximum zoom level which are touched by
-    # any of the nodes we've collected. we'll create the tiles at other zoom levels
-    # by a simple recursion.
-    set = Set.new nodes.values
-
-    # expire tiles and shrink to the set of parents
-    max_zoom.downto(min_zoom) do |_|
-      # allow the block to work on the set, returning the set at the next
-      # zoom level
-      set = yield set
-    end
-  end
-
-  # wrapper to access the osm2pgsql node cache
-  class NodeCache
-    # node cache entry
-    class Node
-      attr_reader :lon, :lat
-
-      def initialize(lon, lat)
-        @lat = lat.to_f / 100.0
-        @lon = lon.to_f / 100.0
-      end
-    end
-
-    # open the cache
-    def initialize(filename)
-      @cache = File.new(filename, "r")
-
-      throw "Unexpected format" unless @cache.sysread(4).unpack("l").first == 1
-      throw "Unexpected ID size" unless @cache.sysread(4).unpack("l").first == 8
-
-      @max_id = @cache.sysread(8).unpack("q").first
-    end
-
-    # close the cache
-    def close
-      @cache.close
-    end
-
-    # lookup a node
-    def [](id)
-      if id <= @max_id
-        offset = 16 + id * 8
-
-        @cache.sysseek(offset)
-
-        lon, lat = @cache.sysread(8).unpack("ll")
-
-        node = Node.new(lon, lat) if lon != -2147483648 && lat != -2147483648
-      end
-
-      node
-    end
-  end
-end
index 8c995d11e7734f97109a290d02c57ea7e34a0a69..eaf2843fd81e17da2c1e1731d3997ae4a4bcfcc3 100644 (file)
@@ -6,10 +6,13 @@ description       "Installs and configures tile servers"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
 depends           "git"
 depends           "nodejs"
 depends           "postgresql"
+depends           "prometheus"
 depends           "python"
+depends           "ruby"
 depends           "systemd"
 depends           "tools"
index 971e953840e08391b3e59c47fce193c86fd99d8b..0c9da1339385d5476eca1a746ce95d2fb92ac0a5 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "apache"
 include_recipe "git"
 include_recipe "nodejs"
 include_recipe "postgresql"
+include_recipe "prometheus"
 include_recipe "python"
+include_recipe "ruby"
 include_recipe "tools"
 
 blocks = data_bag_item("tile", "blocks")
+admins = data_bag_item("apache", "admins")
 web_passwords = data_bag_item("web", "passwords")
 
 apache_module "alias"
@@ -38,51 +42,80 @@ apache_module "tile" do
   conf "tile.conf.erb"
 end
 
+apache_conf "renderd" do
+  action :disable
+end
+
 ssl_certificate node[:fqdn] do
   domains [node[:fqdn], "tile.openstreetmap.org", "render.openstreetmap.org"]
   notifies :reload, "service[apache2]"
 end
 
-tilecaches = search(:node, "roles:tilecache").sort_by { |n| n[:hostname] }
+remote_file "#{Chef::Config[:file_cache_path]}/fastly-ip-list.json" do
+  source "https://api.fastly.com/public-ip-list"
+  compile_time true
+  ignore_failure true
+end
+
+fastlyips = JSON.parse(IO.read("#{Chef::Config[:file_cache_path]}/fastly-ip-list.json"))
+
+remote_file "#{Chef::Config[:file_cache_path]}/statuscake-locations.json" do
+  source "https://app.statuscake.com/Workfloor/Locations.php?format=json"
+  compile_time true
+  ignore_failure true
+end
+
+statuscakelocations = JSON.parse(IO.read("#{Chef::Config[:file_cache_path]}/statuscake-locations.json"))
 
 apache_site "default" do
-  action [:disable]
+  action :disable
+end
+
+apache_site "tileserver_site" do
+  action :disable
 end
 
 apache_site "tile.openstreetmap.org" do
   template "apache.erb"
-  variables :caches => tilecaches
+  variables :fastly => fastlyips["addresses"] + fastlyips["ipv6_addresses"],
+            :statuscake => statuscakelocations.flat_map { |_, v| [v["ip"], v["ipv6"]] },
+            :admins => admins["hosts"]
 end
 
 template "/etc/logrotate.d/apache2" do
   source "logrotate.apache.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
 
 directory "/srv/tile.openstreetmap.org" do
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
 end
 
-package "renderd"
+tile_directories = node[:tile][:styles].collect do |_, style|
+  style[:tile_directories].collect { |directory| directory[:name] }
+end.flatten.sort.uniq
+
+package %w[
+  renderd
+  libgoogle-perftools4
+]
 
 systemd_service "renderd" do
-  description "Mapnik rendering daemon"
+  dropin "chef"
   after "postgresql.service"
   wants "postgresql.service"
-  user "www-data"
-  exec_start "/usr/bin/renderd -f"
-  runtime_directory "renderd"
-  standard_error "null"
-  private_tmp true
-  private_devices true
-  private_network true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  environment "LD_PRELOAD" => "libtcmalloc.so.4"
+  limit_nofile 4096
+  memory_high "80%"
+  memory_max "90%"
+  sandbox true
+  restrict_address_families "AF_UNIX"
+  read_write_paths tile_directories
+  system_call_filter ["@system-service", "mincore"]
   restart "on-failure"
 end
 
@@ -94,14 +127,14 @@ end
 directory "/srv/tile.openstreetmap.org/tiles" do
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
 end
 
 template "/etc/renderd.conf" do
   source "renderd.conf.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
   notifies :reload, "service[apache2]"
   notifies :restart, "service[renderd]"
 end
@@ -110,56 +143,41 @@ remote_directory "/srv/tile.openstreetmap.org/html" do
   source "html"
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
   files_owner "tile"
   files_group "tile"
-  files_mode 0o644
+  files_mode "644"
 end
 
 template "/srv/tile.openstreetmap.org/html/index.html" do
   source "index.html.erb"
   owner "tile"
   group "tile"
-  mode 0o644
+  mode "644"
 end
 
 package %w[
-  python-cairo
-  python-mapnik
-  python-setuptools
-]
-
-python_package "pyotp"
-
-package %w[
-  fonts-noto-cjk
-  fonts-noto-hinted
-  fonts-noto-unhinted
-  fonts-hanazono
-  ttf-unifont
+  python3-cairo
+  python3-mapnik
+  python3-pyproj
+  python3-setuptools
 ]
 
-["NotoSansArabicUI-Regular.ttf", "NotoSansArabicUI-Bold.ttf"].each do |font|
-  remote_file "/usr/share/fonts/truetype/noto/#{font}" do
-    action :create_if_missing
-    source "https://github.com/googlei18n/noto-fonts/raw/master/hinted/#{font}"
-    owner "root"
-    group "root"
-    mode 0o644
-  end
+python_package "pyotp" do
+  python_version "3"
 end
 
 directory "/srv/tile.openstreetmap.org/cgi-bin" do
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
 end
 
 template "/srv/tile.openstreetmap.org/cgi-bin/export" do
   source "export.erb"
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
   variables :blocks => blocks, :totp_key => web_passwords["totp_key"]
 end
 
@@ -167,23 +185,38 @@ template "/srv/tile.openstreetmap.org/cgi-bin/debug" do
   source "debug.erb"
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
 end
 
-template "/etc/cron.hourly/export" do
-  source "export.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o755
+systemd_service "export-cleanup" do
+  description "Cleanup stale export temporary files"
+  joins_namespace_of "apache2.service"
+  exec_start "find /tmp -ignore_readdir_race -name 'export??????' -mmin +60 -delete"
+  user "www-data"
+  sandbox true
+end
+
+systemd_timer "export-cleanup" do
+  description "Cleanup stale export temporary files"
+  on_boot_sec "60m"
+  on_unit_inactive_sec "60m"
+end
+
+service "export-cleanup.timer" do
+  action [:enable, :start]
 end
 
 directory "/srv/tile.openstreetmap.org/data" do
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
 end
 
-package "mapnik-utils"
+package %w[
+  mapnik-utils
+  tar
+  unzip
+]
 
 node[:tile][:data].each_value do |data|
   url = data[:url]
@@ -195,15 +228,13 @@ node[:tile][:data].each_value do |data|
     directory directory do
       owner "tile"
       group "tile"
-      mode 0o755
+      mode "755"
     end
   else
     directory = "/srv/tile.openstreetmap.org/data"
   end
 
   if file =~ /\.tgz$/
-    package "tar"
-
     execute file do
       action :nothing
       command "tar -zxf #{file} -C #{directory}"
@@ -211,8 +242,6 @@ node[:tile][:data].each_value do |data|
       group "tile"
     end
   elsif file =~ /\.tar\.bz2$/
-    package "tar"
-
     execute file do
       action :nothing
       command "tar -jxf #{file} -C #{directory}"
@@ -220,8 +249,6 @@ node[:tile][:data].each_value do |data|
       group "tile"
     end
   elsif file =~ /\.zip$/
-    package "unzip"
-
     execute file do
       action :nothing
       command "unzip -qq -o #{file} -d #{directory}"
@@ -250,7 +277,7 @@ node[:tile][:data].each_value do |data|
     source url
     owner "tile"
     group "tile"
-    mode 0o644
+    mode "644"
     backup false
     notifies :run, "execute[#{file}]", :immediately
     notifies :restart, "service[renderd]"
@@ -258,25 +285,28 @@ node[:tile][:data].each_value do |data|
 end
 
 nodejs_package "carto"
-nodejs_package "millstone"
+
+lowzoom_threads = node.cpu_cores - 1
 
 systemd_service "update-lowzoom@" do
   description "Low zoom tile update service for %i layer"
   user "tile"
+  exec_start_pre "+/bin/systemctl stop render-lowzoom.service"
   exec_start "/bin/bash /usr/local/bin/update-lowzoom-%i"
-  private_tmp true
-  private_devices true
-  private_network true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  runtime_directory "update-lowzoom-%i"
+  sandbox true
+  restrict_address_families "AF_UNIX"
+  read_write_paths [
+    "/srv/tile.openstreetmap.org/tiles/%i",
+    "/var/log/tile"
+  ]
   restart "on-failure"
 end
 
 directory "/srv/tile.openstreetmap.org/styles" do
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
 end
 
 node[:tile][:styles].each do |name, details|
@@ -287,8 +317,8 @@ node[:tile][:styles].each do |name, details|
     source "update-lowzoom.erb"
     owner "root"
     group "root"
-    mode 0o755
-    variables :style => name
+    mode "755"
+    variables :style => name, :threads => lowzoom_threads
   end
 
   service "update-lowzoom@#{name}" do
@@ -299,21 +329,21 @@ node[:tile][:styles].each do |name, details|
   directory tile_directory do
     owner "tile"
     group "tile"
-    mode 0o755
+    mode "755"
   end
 
   details[:tile_directories].each do |directory|
     directory directory[:name] do
-      owner "www-data"
-      group "www-data"
-      mode 0o755
+      owner "_renderd"
+      group "_renderd"
+      mode "755"
     end
 
     directory[:min_zoom].upto(directory[:max_zoom]) do |zoom|
       directory "#{directory[:name]}/#{zoom}" do
-        owner "www-data"
-        group "www-data"
-        mode 0o755
+        owner "_renderd"
+        group "_renderd"
+        mode "755"
       end
 
       link "#{tile_directory}/#{zoom}" do
@@ -328,7 +358,7 @@ node[:tile][:styles].each do |name, details|
     action :create_if_missing
     owner "tile"
     group "tile"
-    mode 0o444
+    mode "444"
   end
 
   git style_directory do
@@ -345,9 +375,20 @@ node[:tile][:styles].each do |name, details|
     group "tile"
   end
 
+  if details[:fonts_script]
+    execute details[:fonts_script] do
+      action :nothing
+      command details[:fonts_script]
+      cwd style_directory
+      user "tile"
+      group "tile"
+      subscribes :run, "git[#{style_directory}]"
+    end
+  end
+
   execute "#{style_directory}/project.mml" do
     action :nothing
-    command "carto -a 3.0.0 project.mml > project.xml"
+    command "carto -a 3.0.22 project.mml > project.xml"
     cwd style_directory
     user "tile"
     group "tile"
@@ -372,6 +413,11 @@ postgresql_user "tomh" do
   superuser true
 end
 
+postgresql_user "pnorman" do
+  cluster node[:tile][:database][:cluster]
+  superuser true
+end
+
 postgresql_user "tile" do
   cluster node[:tile][:database][:cluster]
 end
@@ -380,6 +426,10 @@ postgresql_user "www-data" do
   cluster node[:tile][:database][:cluster]
 end
 
+postgresql_user "_renderd" do
+  cluster node[:tile][:database][:cluster]
+end
+
 postgresql_database "gis" do
   cluster node[:tile][:database][:cluster]
   owner "tile"
@@ -393,9 +443,10 @@ end
 postgresql_extension "hstore" do
   cluster node[:tile][:database][:cluster]
   database "gis"
+  only_if { node[:tile][:database][:hstore] }
 end
 
-%w[geography_columns planet_osm_nodes planet_osm_rels planet_osm_ways raster_columns raster_overviews spatial_ref_sys].each do |table|
+%w[geography_columns planet_osm_nodes planet_osm_rels planet_osm_ways raster_columns raster_overviews].each do |table|
   postgresql_table table do
     cluster node[:tile][:database][:cluster]
     database "gis"
@@ -404,87 +455,102 @@ end
   end
 end
 
-%w[geometry_columns planet_osm_line planet_osm_point planet_osm_polygon planet_osm_roads].each do |table|
+%w[geometry_columns planet_osm_line planet_osm_point planet_osm_polygon planet_osm_roads spatial_ref_sys].each do |table|
   postgresql_table table do
     cluster node[:tile][:database][:cluster]
     database "gis"
     owner "tile"
-    permissions "tile" => :all, "www-data" => :select
+    permissions "tile" => :all, "www-data" => :select, "_renderd" => :select
   end
 end
 
-postgresql_munin "gis" do
-  cluster node[:tile][:database][:cluster]
-  database "gis"
+package %w[
+  gdal-bin
+  python3-yaml
+  python3-psycopg2
+]
+
+if node[:tile][:database][:external_data_script]
+  execute node[:tile][:database][:external_data_script] do
+    command "#{node[:tile][:database][:external_data_script]} -R _renderd"
+    cwd "/srv/tile.openstreetmap.org"
+    user "tile"
+    group "tile"
+    ignore_failure true
+  end
+
+  Array(node[:tile][:database][:external_data_tables]).each do |table|
+    postgresql_table table do
+      cluster node[:tile][:database][:cluster]
+      database "gis"
+      owner "tile"
+      permissions "tile" => :all, "www-data" => :select, "_renderd" => :select
+    end
+  end
+end
+
+directory File.dirname(node[:tile][:database][:node_file]) do
+  owner "root"
+  group "root"
+  mode "755"
+  recursive true
 end
 
-file node[:tile][:node_file] do
+file node[:tile][:database][:node_file] do
   owner "tile"
-  group "www-data"
-  mode 0o660
+  group "_renderd"
+  mode "660"
 end
 
 directory "/var/log/tile" do
   owner "tile"
   group "tile"
-  mode 0o755
+  mode "755"
 end
 
 package %w[
   osm2pgsql
-  ruby
   osmium-tool
   pyosmium
-  python-pyproj
 ]
 
-remote_directory "/usr/local/bin" do
-  source "bin"
-  owner "root"
-  group "root"
-  mode 0o755
-  files_owner "root"
-  files_group "root"
-  files_mode 0o755
+directory "/var/lib/replicate" do
+  owner "tile"
+  group "tile"
+  mode "755"
 end
 
 template "/usr/local/bin/expire-tiles" do
   source "expire-tiles.erb"
   owner "root"
   group "root"
-  mode 0o755
-end
-
-directory "/var/lib/replicate" do
-  owner "tile"
-  group "tile"
-  mode 0o755
+  mode "755"
 end
 
 directory "/var/lib/replicate/expire-queue" do
   owner "tile"
-  group "www-data"
-  mode 0o775
+  group "_renderd"
+  mode "775"
 end
 
 template "/usr/local/bin/replicate" do
   source "replicate.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 systemd_service "expire-tiles" do
   description "Tile dirtying service"
   type "simple"
-  user "www-data"
+  user "_renderd"
   exec_start "/usr/local/bin/expire-tiles"
-  standard_output "null"
-  private_tmp true
-  private_devices true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  nice 10
+  sandbox true
+  restrict_address_families "AF_UNIX"
+  read_write_paths tile_directories + [
+                     "/var/lib/replicate/expire-queue"
+                   ]
 end
 
 systemd_path "expire-tiles" do
@@ -497,17 +563,36 @@ service "expire-tiles.path" do
   subscribes :restart, "systemd_path[expire-tiles]"
 end
 
+template "/usr/local/bin/replicate-post" do
+  source "replicate-post.erb"
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+osm2pgsql_arguments = %w[
+    --number-processes=1
+    --log-progress=false
+    --expire-tiles=13-19
+    --expire-output=/var/lib/replicate/dirty-tiles.txt
+  ]
+
+osm2pgsql_arguments.append("--multi-geometry") if node[:tile][:database][:multi_geometry]
+osm2pgsql_arguments.append("--hstore") if node[:tile][:database][:hstore]
+osm2pgsql_arguments.append("--tag-transform-script=#{node[:tile][:database][:tag_transform_script]}") if node[:tile][:database][:tag_transform_script]
+
 systemd_service "replicate" do
   description "Rendering database replication service"
   after "postgresql.service"
   wants "postgresql.service"
   user "tile"
   exec_start "/usr/local/bin/replicate"
-  private_tmp true
-  private_devices true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  sandbox :enable_network => true
+  restrict_address_families "AF_UNIX"
+  read_write_paths [
+    "/store/database/nodes",
+    "/var/lib/replicate"
+  ]
   restart "on-failure"
 end
 
@@ -517,45 +602,33 @@ service "replicate" do
   subscribes :restart, "systemd_service[replicate]"
 end
 
-template "/etc/logrotate.d/replicate" do
-  source "replicate.logrotate.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
 template "/usr/local/bin/render-lowzoom" do
   source "render-lowzoom.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
+  variables :threads => lowzoom_threads
 end
 
 systemd_service "render-lowzoom" do
   description "Render low zoom tiles"
+  condition_path_exists_glob "!/run/update-lowzoom-*"
   user "tile"
   exec_start "/usr/local/bin/render-lowzoom"
-  private_tmp true
-  private_devices true
-  private_network true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  sandbox true
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/var/log/tile"
 end
 
 systemd_timer "render-lowzoom" do
   description "Render low zoom tiles"
-  on_calendar "Sun *-*~07/1 01:00:00"
+  on_calendar "23:00 #{node[:timezone]}"
 end
 
 service "render-lowzoom.timer" do
   action [:enable, :start]
 end
 
-file "/etc/cron.d/render-lowzoom" do
-  action :delete
-end
-
 package "liblockfile-simple-perl"
 package "libfilesys-df-perl"
 
@@ -563,30 +636,39 @@ template "/usr/local/bin/cleanup-tiles" do
   source "cleanup-tiles.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
-tile_directories = node[:tile][:styles].collect do |_, style|
-  style[:tile_directories].collect { |directory| directory[:name] }
-end.flatten.sort.uniq
+systemd_service "cleanup-tiles@" do
+  description "Cleanup old tiles for /%I"
+  exec_start "/usr/local/bin/cleanup-tiles /%I"
+  user "_renderd"
+  io_scheduling_class "idle"
+  sandbox true
+  read_write_paths "/%I"
+end
 
-template "/etc/cron.d/cleanup-tiles" do
-  source "cleanup-tiles.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-  variables :directories => tile_directories
+systemd_timer "cleanup-tiles@" do
+  description "Cleanup old tiles for /%I"
+  on_boot_sec "30m"
+  on_unit_inactive_sec "60m"
+  randomized_delay_sec "10m"
 end
 
-munin_plugin "mod_tile_fresh"
-munin_plugin "mod_tile_latency"
-munin_plugin "mod_tile_response"
-munin_plugin "mod_tile_zoom"
+tile_directories.each do |directory|
+  label = directory[1..].gsub("/", "-")
 
-munin_plugin "renderd_processed"
-munin_plugin "renderd_queue"
-munin_plugin "renderd_queue_time"
-munin_plugin "renderd_zoom"
-munin_plugin "renderd_zoom_time"
+  service "cleanup-tiles@#{label}.timer" do
+    action [:enable, :start]
+  end
+end
+
+package "ruby-webrick"
 
-munin_plugin "replication_delay"
+prometheus_exporter "modtile" do
+  port 9494
+end
+
+prometheus_exporter "renderd" do
+  port 9393
+end
index e5d7f17192bbca6ebb7b2987e40da32a038a254e..9652ec8253ba6400ebdfcb5f3c8feba583657b12 100644 (file)
   #
   SSLEngine on
   SSLProxyEngine on
-  SSLCertificateFile /etc/ssl/certs/<%= node.name %>.pem
-  SSLCertificateKeyFile /etc/ssl/private/<%= node.name %>.key
+  SSLCertificateFile /etc/ssl/certs/<%= node[:fqdn] %>.pem
+  SSLCertificateKeyFile /etc/ssl/private/<%= node[:fqdn] %>.key
 
   # Configure location of static files and CGI scripts
   DocumentRoot /srv/tile.openstreetmap.org/html
   ScriptAlias /cgi-bin/ /srv/tile.openstreetmap.org/cgi-bin/
 
   # Get the real remote IP for requests via a trusted proxy
-  RemoteIPHeader X-Forwarded-For
-<% @caches.each do |cache| -%>
-<% cache.ipaddresses(:role => :external).sort.each do |address| -%>
+  RemoteIPHeader Fastly-Client-IP
+<% @fastly.sort.each do |address| -%>
   RemoteIPTrustedProxy <%= address %>
-<% end -%>
 <% end -%>
 
   # Setup logging
   RewriteRule ^/(\d+)/(\d+)/(\d+)\.png/dirty/?$   /default/$1/$2/$3.png/dirty  [PT,T=text/plain,L]
 
   # Historical Files redirect
-  RedirectPermanent /processed_p.tar.bz2 https://planet.openstreetmap.org/historical-shapefiles/processed_p.tar.bz2
-  RedirectPermanent /shoreline_300.tar.bz2 https://planet.openstreetmap.org/historical-shapefiles/shoreline_300.tar.bz2
-  RedirectPermanent /world_boundaries-spherical.tgz https://planet.openstreetmap.org/historical-shapefiles/world_boundaries-spherical.tgz
+  RedirectPermanent /processed_p.tar.bz2 https://planet.openstreetmap.org/historical-shapefiles/
+  RedirectPermanent /shoreline_300.tar.bz2 https://planet.openstreetmap.org/historical-shapefiles/
+  RedirectPermanent /world_boundaries-spherical.tgz https://planet.openstreetmap.org/historical-shapefiles/
 
   # Redirect ACME certificate challenges
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
+
+  # Restrict tile access to CDN nodes and admins
+  <LocationMatch ^/default/\d+/\d+/\d+\.png$>
+    Require expr "%{CONN_REMOTE_ADDR} != %{REMOTE_ADDR}"
+    # Fastly POPs
+<% @fastly.sort.each do |address| -%>
+    Require ip <%= address %>
+<% end -%>
+    # StatusCake monitoring
+<% @statuscake.sort.reject { |address| address.empty? }.each do |address| -%>
+    Require ip <%= address %>
+<% end -%>
+    # Administrators
+<% @admins.sort.each do |address| -%>
+    Require ip <%= address %>
+<% end -%>
+    # OSM Amsterdam IPv4
+    Require ip 184.104.179.128/27
+    # OSM Amsterdam IPv6
+    Require ip 2001:470:1:fa1::/64
+    # OSM Dublin IPv4
+    Require ip 184.104.226.96/27
+    # OSM Dublin IPv6
+    Require ip 2001:470:1:b3b::/64
+    # OSM UCL IPv4
+    Require ip 193.60.236.0/24
+  </LocationMatch>
 </VirtualHost>
 
 <VirtualHost *:80>
   ServerAlias render.openstreetmap.org
   ServerAdmin webmaster@openstreetmap.org
 
-  # Get the real remote IP for requests via a trusted proxy
-  RemoteIPHeader X-Forwarded-For
-<% @caches.each do |cache| -%>
-<% cache.ipaddresses(:role => :external).sort.each do |address| -%>
-  RemoteIPTrustedProxy <%= address %>
-<% end -%>
-<% end -%>
-
   # Setup logging
   LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined_with_remoteip
   CustomLog /var/log/apache2/access.log combined_with_remoteip
diff --git a/cookbooks/tile/templates/default/cleanup-tiles.cron.erb b/cookbooks/tile/templates/default/cleanup-tiles.cron.erb
deleted file mode 100644 (file)
index 28c631a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-MAILTO=admins@openstreetmap.org
-
-<% @directories.each do |directory| -%>
-0 * * * * www-data ionice -c 3 /usr/local/bin/cleanup-tiles <%= directory %>
-<% end -%>
index eb108e95e7d0c13f25034c02d1bc4c0c535a30e4..721660bb16795b234bf5779c91e76b099578f11d 100644 (file)
@@ -20,7 +20,7 @@ my $tempfile = tmpnam();
 
 if (df($tiledir)->{per} > 88)
 {
-    system("find", $tiledir, "-xdev", "-name", "lost+found", "-prune", "-o", "-type", "f", "-name", "*.meta", "-atime", "+3", "-fprintf", $tempfile, "%A@ %p\n");
+    system("find", $tiledir, "-xdev", "-name", "lost+found", "-prune", "-o", "-type", "f", "-name", "*.meta", "-atime", "+2", "-fprintf", $tempfile, "%A@ %p\n");
 
     open(TILES, "-|", "sort", "-n", $tempfile) || die "Can't open $tempfile: $!";
 
index 03af6549f4fec1510d24258b04e41c9034f795ff..e3e3852a0f4e91c573d59953b5c899d22c116366 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python -u
+#!/usr/bin/python3 -u
 # -*- coding: utf-8 -*-
 
 import cgi
@@ -22,35 +22,35 @@ resource.setrlimit(resource.RLIMIT_AS,(4000000000, 4000000000))
 
 # Routine to output HTTP headers
 def output_headers(content_type, filename = "", length = 0):
-  print "Cache-Control: no-cache, no-store, must-revalidate')"
-  print "Pragma: no-cache"
-  print "Expires: 0"
-  print "Content-Type: %s" % content_type
+  print("Cache-Control: no-cache, no-store, must-revalidate')")
+  print("Pragma: no-cache")
+  print("Expires: 0")
+  print("Content-Type: %s" % content_type)
   if filename:
-    print "Content-Disposition: attachment; filename=\"%s\"" % filename
+    print("Content-Disposition: attachment; filename=\"%s\"" % filename)
   if length:
-    print "Content-Length: %d" % length
-  print ""
+    print("Content-Length: %d" % length)
+  print("")
 
 # Routine to report an error
 def output_error(message):
   output_headers("text/html")
-  print "<html>"
-  print "<head>"
-  print "<title>Error</title>"
-  print "</head>"
-  print "<body>"
-  print "<h1>Error</h1>"
-  print "<p>%s</p>" % message
-  print "</body>"
-  print "</html>"
+  print("<html>")
+  print("<head>")
+  print("<title>Error</title>")
+  print("</head>")
+  print("<body>")
+  print("<h1>Error</h1>")
+  print("<p>%s</p>" % message)
+  print("</body>")
+  print("</html>")
 
 # Make sure we have a user agent
-if not os.environ.has_key('HTTP_USER_AGENT'):
+if 'HTTP_USER_AGENT' not in os.environ:
   os.environ['HTTP_USER_AGENT'] = 'NONE'
 
 # Get the cache server name
-if os.environ.has_key('HTTP_VIA'):
+if 'HTTP_VIA' in os.environ:
   cache_server = re.search('[a-z0-9-]+\.openstreetmap\.org', os.environ['HTTP_VIA']).group(0)
 else:
   cache_server = None
@@ -59,35 +59,35 @@ else:
 loadavg = float(open("/proc/loadavg").readline().split(" ")[0])
 
 output_headers("text/html")
-print "<html>"
-print "<head>"
-print "<title>tile.openstreetmap.org debug</title>"
-print "</head>"
-print "<body>"
-print "<h1>tile.openstreetmap.org debug</h1>"
-print "<h2>Server Stats</h2>"
+print("<html>")
+print("<head>")
+print("<title>tile.openstreetmap.org debug</title>")
+print("</head>")
+print("<body>")
+print("<h1>tile.openstreetmap.org debug</h1>")
+print("<h2>Server Stats</h2>")
 if cache_server:
-  print "<p><b>Cache Server</b>: %s</p>" % cache_server
-print "<p>"
-print "<b>Render Server</b>: <%= node['fqdn'] %><br />"
-print "<b>Load Average</b>: %s</p>" % loadavg
-print "<h2>File Status</h2>"
-print "<p>"
+  print("<p><b>Cache Server</b>: %s</p>" % cache_server)
+print("<p>")
+print("<b>Render Server</b>: <%= node['fqdn'] %><br />")
+print("<b>Load Average</b>: %s</p>" % loadavg)
+print("<h2>File Status</h2>")
+print("<p>")
 <%
 node[:tile][:data].each do |name,data|
   url = data[:url]
   file = "/srv/tile.openstreetmap.org/data/#{File.basename(url)}"
   file_basename = File.basename(url)
 -%>
-print "<b>%s</b> last modified: %s<br />" % ("<%= file_basename %>", time.ctime(os.path.getmtime("<%= file %>")))
+print("<b>%s</b> last modified: %s<br />" % ("<%= file_basename %>", time.ctime(os.path.getmtime("<%= file %>"))))
 <%
 end
 -%>
-print "</p>"
-print "<h2>Browser Request Headers</h2>"
-print "<p>"
-for param in os.environ.keys():
-  print "<b>%20s</b>: %s<br />" % (param, os.environ[param])
-print "</p>"
-print "</body>"
-print "</html>"
+print("</p>")
+print("<h2>Browser Request Headers</h2>")
+print("<p>")
+for param in sorted(os.environ):
+  print("<b>%20s</b>: %s<br />" % (param, os.environ[param]))
+print("</p>")
+print("</body>")
+print("</html>")
index 2f6a97d773ee9ddb27ab442477327f0ab04bcca9..1af7f0a64dd426e2257bc41c5fe801df705eb430 100644 (file)
@@ -3,13 +3,15 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
 args = [
-<% node[:tile][:styles].each do |name,details| -%>
-  "-t", "/srv/tile.openstreetmap.org/tiles/<%= name %>",
-<% end -%>
-  "--min", "13",
-  "--max", "<%= node[:tile][:styles].collect { |n,d| d[:max_zoom] }.max %>"
+  "--socket=/var/run/renderd/renderd.sock",
+  "--tile-dir=/srv/tile.openstreetmap.org/tiles",
+  "--touch-from=13",
+  "--min-zoom=13"
 ]
 
-Dir.glob("/var/lib/replicate/expire-queue/changes-*.gz").each do |f|
-   system("/usr/local/bin/expire-tiles-single", *args, f) && File::unlink(f)
+Dir.glob("/var/lib/replicate/expire-queue/changes-*.txt").sort.each do |f|
+  <% node[:tile][:styles].each do |name,details| -%>
+  system("/usr/bin/render_expired", "--map=<%= name %>", *args, "--max-zoom=<%= details[:max_zoom] %>", :in=> f) &&
+  <% end -%>
+  File::unlink(f)
 end
diff --git a/cookbooks/tile/templates/default/export.cron.erb b/cookbooks/tile/templates/default/export.cron.erb
deleted file mode 100644 (file)
index b598e41..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Removes stale tmp files from the export tab
-exec find /tmp -ignore_readdir_race -name 'export??????' -mmin +60 -delete
index 0cd115271c5bcf313560dd6fff074b2e7f95be42..8fa4672b98f3f716b937576706c1c9e400c7c20e 100644 (file)
@@ -1,12 +1,13 @@
-#!/usr/bin/python -u
+#!/usr/bin/python3 -u
 # -*- coding: utf-8 -*-
 
 import cairo
 import cgi
-import Cookie
+import http.cookies
 import mapnik
 import os
 import pyotp
+import pyproj
 import resource
 import shutil
 import signal
@@ -23,17 +24,17 @@ resource.setrlimit(resource.RLIMIT_AS,(4000000000, 4000000000))
 
 # Routine to output HTTP headers
 def output_headers(content_type, filename = "", length = 0):
-  print "Content-Type: %s" % content_type
+  print("Content-Type: %s" % content_type)
   if filename:
-    print "Content-Disposition: attachment; filename=\"%s\"" % filename
+    print("Content-Disposition: attachment; filename=\"%s\"" % filename)
   if length:
-    print "Content-Length: %d" % length
-  print ""
+    print("Content-Length: %d" % length)
+  print("")
 
 # Routine to output the contents of a file
 def output_file(file):
   file.seek(0)
-  shutil.copyfileobj(file, sys.stdout)
+  shutil.copyfileobj(file, sys.stdout.buffer)
 
 # Routine to get the size of a file
 def file_size(file):
@@ -41,17 +42,17 @@ def file_size(file):
 
 # Routine to report an error
 def output_error(message, status = "400 Bad Request"):
-  print "Status: %s" % status
+  print("Status: %s" % status)
   output_headers("text/html")
-  print "<html>"
-  print "<head>"
-  print "<title>Error</title>"
-  print "</head>"
-  print "<body>"
-  print "<h1>Error</h1>"
-  print "<p>%s</p>" % message
-  print "</body>"
-  print "</html>"
+  print("<html>")
+  print("<head>")
+  print("<title>Error</title>")
+  print("</head>")
+  print("<body>")
+  print("<h1>Error</h1>")
+  print("<p>%s</p>" % message)
+  print("</body>")
+  print("</html>")
 
 # Create TOTP token validator
 totp = pyotp.TOTP('<%= @totp_key %>', interval = 3600)
@@ -60,18 +61,18 @@ totp = pyotp.TOTP('<%= @totp_key %>', interval = 3600)
 form = cgi.FieldStorage()
 
 # Import cookies
-cookies = Cookie.SimpleCookie(os.environ.get('HTTP_COOKIE'))
+cookies = http.cookies.SimpleCookie(os.environ.get('HTTP_COOKIE'))
 
 # Make sure we have a user agent
-if not os.environ.has_key('HTTP_USER_AGENT'):
+if 'HTTP_USER_AGENT' not in os.environ:
   os.environ['HTTP_USER_AGENT'] = 'NONE'
 
 # Make sure we have a referer
-if not os.environ.has_key('HTTP_REFERER'):
+if 'HTTP_REFERER' not in os.environ:
   os.environ['HTTP_REFERER'] = 'NONE'
 
 # Look for TOTP token
-if cookies.has_key('_osm_totp_token'):
+if '_osm_totp_token' in cookies:
   token = cookies['_osm_totp_token'].value
 else:
   token = None
@@ -97,18 +98,18 @@ elif os.environ['HTTP_REFERER'] == '<%= referer %>':
   # Block scraper
   output_error("The server is too busy at the moment. Please wait a few minutes before trying again.", "503 Service Unavailable")
 <% end -%>
-elif not form.has_key("bbox"):
+elif "bbox" not in form:
   # No bounding box specified
   output_error("No bounding box specified")
-elif not form.has_key("scale"):
+elif "scale" not in form:
   # No scale specified
   output_error("No scale specified")
-elif not form.has_key("format"):
+elif "format" not in form:
   # No format specified
   output_error("No format specified")
 else:
   # Create projection object
-  prj = mapnik.Projection("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over");
+  transformer = pyproj.Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True)
 
   # Get the bounds of the area to render
   bbox = [float(x) for x in form.getvalue("bbox").split(",")]
@@ -118,7 +119,8 @@ else:
     output_error("Invalid bounding box")
   else:
     # Project the bounds to the map projection
-    bbox = mapnik.forward_(mapnik.Box2d(*bbox), prj)
+    bbox = mapnik.Box2d(*transformer.transform(bbox[0], bbox[1]),
+                        *transformer.transform(bbox[2], bbox[3]))
 
     # Get the style to use
     style = form.getvalue("style", "default")
@@ -152,13 +154,13 @@ else:
           mapnik.render(map, image)
           png = image.tostring("png")
           output_headers("image/png", "map.png", len(png))
-          sys.stdout.write(png)
+          sys.stdout.buffer.write(png)
         elif form.getvalue("format") == "jpeg":
           image = mapnik.Image(map.width, map.height)
           mapnik.render(map, image)
           jpeg = image.tostring("jpeg")
           output_headers("image/jpeg", "map.jpg", len(jpeg))
-          sys.stdout.write(jpeg)
+          sys.stdout.buffer.write(jpeg)
         elif form.getvalue("format") == "svg":
           file = tempfile.NamedTemporaryFile(prefix = "export")
           surface = cairo.SVGSurface(file.name, map.width, map.height)
index 586d8660762971334720cd767c9cba6843bd39a9..1d7e24e45fed23820c0821fc735dae9a6f1d23c1 100644 (file)
@@ -4,7 +4,7 @@
   daily
   size 1G
   missingok
-  rotate 28
+  rotate 14
   compress
   delaycompress
   notifempty
index 55a98a754557af9e2478e0e1c952b6ed4b9f47cb..eb3e2e84e2fcb7691e8ff59c4668bdad0988eb3f 100644 (file)
@@ -16,9 +16,9 @@ function update_<%= style %>
     --timestamp=${timestamp} \
     --tile-dir=/srv/tile.openstreetmap.org/tiles \
     --socket=/var/run/renderd/renderd.sock \
-    --num-threads=<%= node[:cpu][:total] - 2 %> \
+    --num-threads=<%= @threads %> \
     --map="<%= style %>" \
-    --max-load=70 \
+    --max-load=<%= node.cpu_cores - 1 %> \
     --min-zoom=0 --max-zoom=12
 }
 
index 69479e0b013556ace35eb3079f6d1859a5edf9e1..d29c58aa7728f9512a6fe22d2dac67269319ed9e 100644 (file)
@@ -2,12 +2,12 @@
 
 [renderd]
 socketname=/var/run/renderd/renderd.sock
-num_threads=<%= node[:cpu][:total] - 2 %>
+num_threads=<%= node.cpu_cores - 1 %>
 tile_dir=/srv/tile.openstreetmap.org/tiles
 stats_file=/var/run/renderd/renderd.stats
 
 [mapnik]
-plugins_dir=/usr/lib/mapnik/3.0/input
+plugins_dir=/usr/lib/mapnik/<%= node[:tile][:mapnik] %>/input
 font_dir=/usr/share/fonts
 font_dir_recurse=true
 <% node[:tile][:styles].each do |name,details| -%>
diff --git a/cookbooks/tile/templates/default/replicate-post.erb b/cookbooks/tile/templates/default/replicate-post.erb
new file mode 100644 (file)
index 0000000..63ca93b
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+# DO NOT EDIT - This file is being maintained by Chef
+
+sequence="$1"
+timestamp="$2"
+
+mv /var/lib/replicate/dirty-tiles.txt /var/lib/replicate/expire-queue/changes-${sequence}.txt
+
+echo "$sequence" > /var/lib/replicate/sequence.txt
+echo "$timestamp" > /var/lib/replicate/timestamp.txt
index 81fc66419e153fa5e4e7970bae7b816ff02c3553..88917dff29cd2f99f2833ead15cbe4afa70a322b 100644 (file)
-#!/bin/bash
+#!/bin/sh
 
 # DO NOT EDIT - This file is being maintained by Chef
 
-# Before running updates, the replication needs to be set up with the timestamp
-# set to the day of the latest planet dump. Setting to midnight ensures we get
-# conistent data after first run. osmosis --read-replication-interval-init is
-# used to initially create the state file
-
-# Define exit handler
-function onexit {
-    [ -f sequence-prev.txt ] && mv sequence-prev.txt sequence.txt
-}
-
-# Send output to the log
-exec > /var/log/tile/replicate.log 2>&1
-
-# Change to the replication state directory
-cd /var/lib/replicate
-
-# Install exit handler
-trap onexit EXIT
-
-# Loop indefinitely
-while true
+while [ 1 = 1 ]
 do
-    # Work out the name of the next file
-    file="changes-$(cat sequence.txt).osc.gz"
-
-    # Save sequence file so we can rollback if an error occurs
-    cp sequence.txt sequence-prev.txt
-
-    # Fetch the next set of changes
-    pyosmium-get-changes --sequence-file=sequence.txt --outfile=${file}
-
-    # Save exit status
-    status=$?
-
-    # Check for errors
-    if [ $status -eq 0 ]
-    then
-        # Enable exit on error
-        set -e
-
-        # Log the new data
-        echo "Fetched new data from $(cat sequence-prev.txt) to $(cat sequence.txt) into ${file}"
-
-        # Apply the changes to the database
-        osm2pgsql --database gis --slim --append --number-processes=1 \
-<% if node[:tile][:node_file] -%>
-                  --flat-nodes=<%= node[:tile][:node_file] %> \
+  /bin/osm2pgsql-replication update \
+    --database gis \
+    --post-processing /usr/local/bin/replicate-post \
+    -- \
+    --number-processes=1 \
+    --log-progress=false \
+    --expire-tiles=13-19 \
+    --expire-output=/var/lib/replicate/dirty-tiles.txt \
+<% if node[:tile][:database][:multi_geometry] -%>
+    --multi-geometry \
 <% end -%>
-<% if node[:tile][:styles][:default][:revision] >= "v4.0.0" -%>
-                  --multi-geometry --hstore \
-                  --style=/srv/tile.openstreetmap.org/styles/default/openstreetmap-carto.style \
-                  --tag-transform-script=/srv/tile.openstreetmap.org/styles/default/openstreetmap-carto.lua \
+<% if node[:tile][:database][:hstore] -%>
+    --hstore \
+<% end -%>
+<% if node[:tile][:database][:tag_transform_script] -%>
+    --tag-transform-script=<%= node[:tile][:database][:tag_transform_script] %>
 <% end -%>
-                  ${file}
-
-        # No need to rollback now
-        rm sequence-prev.txt
-
-        # Get buffer count
-        buffers=$(osmium fileinfo --extended --get=data.buffers.count ${file})
-
-        # If this diff has content mark it as the latest diff
-        if [ $buffers -gt 0 ]
-        then
-            ln -f ${file} changes-latest.osc.gz
-        fi
-
-        # Queue these changes for expiry processing
-        ln ${file} expire-queue/${file}
-
-        # Delete old downloads
-        find . -name 'changes-*.gz' -mmin +300 -exec rm -f {} \;
-
-        # Disable exit on error
-        set +e
-    elif [ $status -eq 3 ]
-    then
-        # Log the lack of data
-        echo "No new data available. Sleeping..."
-
-        # Remove file, it will just be an empty changeset
-        rm ${file}
-
-        # Sleep for a short while
-        sleep 30
-    else
-        # Log our failure to fetch changes
-        echo "Failed to fetch changes - waiting a few minutes before retry"
-
-        # Remove any output that was produced
-        rm -f ${file}
 
-        # Wait five minutes and have another go
-        sleep 300
-    fi
+    sleep 30
 done
diff --git a/cookbooks/tile/templates/default/replicate.logrotate.erb b/cookbooks/tile/templates/default/replicate.logrotate.erb
deleted file mode 100644 (file)
index 9c2c29f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-/var/log/tile/replicate.log {
-  compress
-  delaycompress
-  notifempty
-  postrotate
-    /bin/systemctl try-restart replicate
-  endscript
-}
index 277c71fc6f7f2d7c062739c614b6c0ec02b7e733..0455493d993bc2f2a2830d63eab95228fc84a4b4 100644 (file)
@@ -12,9 +12,9 @@ function update_tiles
     --timestamp=$(stat -c %Y "/srv/tile.openstreetmap.org/styles/<%= @style %>/project.xml") \
     --tile-dir=/srv/tile.openstreetmap.org/tiles \
     --socket=/var/run/renderd/renderd.sock \
-    --num-threads=<%= node[:cpu][:total] - 2 %> \
+    --num-threads=<%= @threads %> \
     --map="<%= @style %>" \
-    --max-load=70 \
+    --max-load=<%= node.cpu_cores - 1 %> \
     --min-zoom=0 --max-zoom=12
 }
 
diff --git a/cookbooks/tilecache/README.md b/cookbooks/tilecache/README.md
deleted file mode 100644 (file)
index 4966746..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# tilecache cookbook
-
-This cookbook installs and configures the tile caches for the
-tile.openstreetmap.org tileservers.
diff --git a/cookbooks/tilecache/attributes/default.rb b/cookbooks/tilecache/attributes/default.rb
deleted file mode 100644 (file)
index a552ee6..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-default[:tilecache][:tile_parent] = "render.openstreetmap.org"
-default[:tilecache][:tile_siblings] = []
-
-# Per IP bucket refill rate
-default[:tilecache][:ip_bucket_refill] = 4096
-# Per IP bucket size
-default[:tilecache][:ip_bucket_size] = 67108864
-# Per Class C refill rate
-default[:tilecache][:net_bucket_refill] = 8192
-# Per Class C bucket size
-default[:tilecache][:net_bucket_size] = 134217728
diff --git a/cookbooks/tilecache/metadata.rb b/cookbooks/tilecache/metadata.rb
deleted file mode 100644 (file)
index a207486..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-name              "tilecache"
-maintainer        "OpenStreetMap Administrators"
-maintainer_email  "admins@openstreetmap.org"
-license           "Apache-2.0"
-description       "Installs and configures a tile cache"
-
-version           "1.0.0"
-supports          "ubuntu"
-depends           "ssl"
-depends           "squid"
-depends           "nginx"
-depends           "munin"
-depends           "fail2ban"
diff --git a/cookbooks/tilecache/recipes/default.rb b/cookbooks/tilecache/recipes/default.rb
deleted file mode 100644 (file)
index 63de8a5..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-#
-# Cookbook:: tilecache
-# Recipe:: default
-#
-# Copyright:: 2011, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-require "ipaddr"
-
-include_recipe "ssl"
-include_recipe "squid"
-include_recipe "nginx"
-include_recipe "fail2ban"
-
-package "apache2" do
-  action :remove
-end
-
-package %w[
-  xz-utils
-  openssl
-]
-
-# oathtool for QoS token
-package "oathtool"
-
-tilecaches = search(:node, "roles:tilecache").sort_by { |n| n[:hostname] }
-tilerenders = search(:node, "roles:tile").sort_by { |n| n[:hostname] }
-
-web_passwords = data_bag_item("web", "passwords")
-
-tilecaches.each do |cache|
-  cache.ipaddresses(:family => :inet, :role => :external).sort.each do |address|
-    firewall_rule "accept-squid" do
-      action :accept
-      family "inet"
-      source "net:#{address}"
-      dest "fw"
-      proto "tcp:syn"
-      dest_ports "3128"
-      source_ports "1024:"
-    end
-
-    firewall_rule "accept-squid-icp" do
-      action :accept
-      family "inet"
-      source "net:#{address}"
-      dest "fw"
-      proto "udp"
-      dest_ports "3130"
-      source_ports "3130"
-    end
-
-    firewall_rule "accept-squid-icp-reply" do
-      action :accept
-      family "inet"
-      source "fw"
-      dest "net:#{address}"
-      proto "udp"
-      dest_ports "3130"
-      source_ports "3130"
-    end
-
-    firewall_rule "accept-squid-htcp" do
-      action :accept
-      family "inet"
-      source "net:#{address}"
-      dest "fw"
-      proto "udp"
-      dest_ports "4827"
-      source_ports "4827"
-    end
-
-    firewall_rule "accept-squid-htcp-reply" do
-      action :accept
-      family "inet"
-      source "fw"
-      dest "net:#{address}"
-      proto "udp"
-      dest_ports "4827"
-      source_ports "4827"
-    end
-  end
-end
-
-squid_fragment "tilecache" do
-  template "squid.conf.erb"
-  variables :caches => tilecaches, :renders => tilerenders
-end
-
-package "rsync"
-
-template "/etc/logrotate.d/squid" do
-  source "logrotate.squid.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
-# Configure cron with lower cpu and IO priority
-systemd_service "cron-load" do
-  service "cron"
-  dropin "load"
-  nice 19
-  io_scheduling_class "best-effort"
-  io_scheduling_priority 7
-  notifies :restart, "service[cron]"
-end
-
-nginx_site "default" do
-  action [:delete]
-end
-
-template "/usr/local/bin/nginx_generate_tilecache_qos_map" do
-  source "nginx_generate_tilecache_qos_map.erb"
-  owner "root"
-  group "root"
-  mode 0o750
-  variables :totp_key => web_passwords["totp_key"]
-end
-
-template "/etc/cron.d/tilecache" do
-  source "cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
-execute "execute_nginx_generate_tilecache_qos_map" do
-  command "/usr/local/bin/nginx_generate_tilecache_qos_map"
-  creates "/etc/nginx/conf.d/tile_qos_rates.map"
-  action :run
-end
-
-ssl_certificate "tile.openstreetmap.org" do
-  domains ["tile.openstreetmap.org",
-           "a.tile.openstreetmap.org",
-           "b.tile.openstreetmap.org",
-           "c.tile.openstreetmap.org",
-           "tile.osm.org",
-           "a.tile.osm.org",
-           "b.tile.osm.org",
-           "c.tile.osm.org"]
-  notifies :restart, "service[nginx]"
-end
-
-nginx_site "tile" do
-  template "nginx_tile.conf.erb"
-  variables :caches => tilecaches
-end
-
-template "/etc/logrotate.d/nginx" do
-  source "logrotate.nginx.erb"
-  owner "root"
-  group "root"
-  mode 0o644
-end
-
-fail2ban_jail "squid" do
-  maxretry 1000
-end
-
-tilerenders.each do |render|
-  munin_plugin "ping_#{render[:fqdn]}" do
-    target "ping_"
-    conf "munin.ping.erb"
-    conf_variables :host => render[:fqdn]
-  end
-end
diff --git a/cookbooks/tilecache/templates/default/cron.erb b/cookbooks/tilecache/templates/default/cron.erb
deleted file mode 100644 (file)
index 32fb067..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-0 * * * * root /usr/local/bin/nginx_generate_tilecache_qos_map
diff --git a/cookbooks/tilecache/templates/default/logrotate.nginx.erb b/cookbooks/tilecache/templates/default/logrotate.nginx.erb
deleted file mode 100644 (file)
index b52d294..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-/var/log/nginx/*.log {
-  daily
-  missingok
-  rotate 7
-  compress
-  delaycompress
-  notifempty
-  create 640 nginx adm
-  sharedscripts
-  postrotate
-    [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
-  endscript
-}
diff --git a/cookbooks/tilecache/templates/default/logrotate.squid.erb b/cookbooks/tilecache/templates/default/logrotate.squid.erb
deleted file mode 100644 (file)
index 697f0c5..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-/var/log/squid/*.log {
-  daily
-  compress
-  compresscmd /usr/bin/xz
-  compressoptions --threads=<%= [ node[:cpu][:total] / 2, 1 ].max.ceil %>
-  uncompresscmd /usr/bin/unxz
-  compressext .xz
-  rotate 2
-  missingok
-  nocreate
-  sharedscripts
-  postrotate
-    test ! -e /var/run/squid.pid || /usr/sbin/squid -k rotate
-  endscript
-  lastaction
-    /usr/bin/rsync --preallocate /var/log/squid/access.log.1.xz ironbelly::logs/tile.openstreetmap.org/<%= node[:hostname] %>-`date -d "-1 days" +%Y-%m-%d`.xz || true
-  endscript
-}
diff --git a/cookbooks/tilecache/templates/default/munin.ping.erb b/cookbooks/tilecache/templates/default/munin.ping.erb
deleted file mode 100644 (file)
index b09f976..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[ping_<%= @host %>]
-env.ping_args -c 1 -w 20
-env.ping_warn 0.5
-env.ping_crit 1.0
-env.packetloss_warn 10
-env.packetloss_crit 30
diff --git a/cookbooks/tilecache/templates/default/nginx_generate_tilecache_qos_map.erb b/cookbooks/tilecache/templates/default/nginx_generate_tilecache_qos_map.erb
deleted file mode 100755 (executable)
index 869b30d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-# DO NOT EDIT - This file is being maintained by Chef
-set -e
-
-NUM_TOKENS=4 # current + 4
-VALID_TOKEN=3600 # in seconds
-
-SECONDS_AGO=$((${NUM_TOKENS} * ${VALID_TOKEN}))
-OLD_TIME=$(/bin/date -u "+%Y-%m-%dT %H:%M:%S %z" -d "${SECONDS_AGO} seconds ago")
-QOS_TOKENS=($(/usr/bin/oathtool --totp --now="${OLD_TIME}" --window=${NUM_TOKENS} --time-step-size=${VALID_TOKEN}s -b "<%= @totp_key %>"))
-
-# ${qos_tokens[4]/[-1] } = OSM.org exclusive / current
-# ${qos_tokens[3]/[-2] } = OSM.org exclusive / stale
-# ${qos_tokens[2]/[-3] } = tile.openstreetmap.org default
-# ${qos_tokens[1]/[-4] } = stale ~ 1 hour
-# ${qos_tokens[0]} = expired
-
-# Test if number of tokens returned by oathtool is expected number
-if [ "${#QOS_TOKENS[@]}" -ne "$((${NUM_TOKENS}+1))" ]; then
-  >&2 echo "ERROR: Unexpected number of tokens"
-  exit 1
-fi
-
-QOS_TOKEN_OSM=${QOS_TOKENS[-1]} # Cookie set by openstreetmap.org
-QOS_TOKEN_OSM_STALE=${QOS_TOKENS[-2]} # Cookie set by openstreetmap.org stale
-QOS_TOKEN_DEFAULT=${QOS_TOKENS[-3]} # Cookie presented by tile.openstreetmap.org to browsers
-QOS_TOKEN_STALE=${QOS_TOKENS[-4]} # Cookie which has become stale and will be replaced
-
-if [ -z "$QOS_TOKEN_OSM" -o -z "$QOS_TOKEN_DEFAULT" -o -z "$QOS_TOKEN_STALE" ]; then
-  >&2 echo "ERROR: Unexpected blank token"
-  exit 2
-fi
-
-cat <<EOF >/etc/nginx/conf.d/tile_qos_rates.map
-default 8192; # Default Rate (No QoS cookie)
-"${QOS_TOKEN_STALE}" 24576; # Stale
-"${QOS_TOKEN_DEFAULT}" 24576; # Default
-"${QOS_TOKEN_OSM_STALE}" 32768; # Exclusive Stale
-"${QOS_TOKEN_OSM}" 32768; # Exclusive
-EOF
-
-cat <<EOF >/etc/nginx/conf.d/tile_qos_cookies.map
-default '_osm_totp_token=${QOS_TOKEN_DEFAULT}; Max-Age=${VALID_TOKEN}; Domain=openstreetmap.org; Path=/'; # Cookie Domain per RFC6265
-"${QOS_TOKEN_DEFAULT}" ''; # Do not Set-Cookie. # Default
-"${QOS_TOKEN_OSM_STALE}" ''; # Do not Set-Cookie. # Exclusive Stale
-"${QOS_TOKEN_OSM}" ''; # Do not Set-Cookie. # Exclusive
-EOF
-
-# Check config, reload config and fail safe
-/etc/init.d/nginx configtest 2>/dev/null && /bin/systemctl try-reload-or-restart nginx
diff --git a/cookbooks/tilecache/templates/default/nginx_tile.conf.erb b/cookbooks/tilecache/templates/default/nginx_tile.conf.erb
deleted file mode 100644 (file)
index f273a78..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-upstream tile_cache_backend {
-  server 127.0.0.1:8080;
-  server 127.0.0.2:8080;
-
-  # Add the other caches to relieve pressure if local squid failing
-  # Balancer: round-robin
-<% @caches.each do |cache| -%>
-<% if cache[:hostname] != node[:hostname] -%>
-<% cache.ipaddresses(:family => :inet, :role => :external).sort.each do |address| -%>
-  server <%= address %>:80 backup; # Server <%= cache[:hostname] %>
-<% end -%>
-<% end -%>
-<% end -%>
-
-  keepalive 512;
-  keepalive_requests 1024;
-}
-
-# Geo Map of tile caches
-geo $tile_cache {
-  default 0;
-<% @caches.each do |cache| -%>
-<% cache.ipaddresses(:family => :inet, :role => :external).sort.each do |address| -%>
-  <%= address %> 1; # <%= cache[:hostname] %>
-<% end -%>
-<% end -%>
-}
-
-# Rates table based on current cookie value
-map $cookie__osm_totp_token $limit_rate_qos {
-  include /etc/nginx/conf.d/tile_qos_rates.map;
-}
-
-# Set-Cookie table based on current cookie value
-map $cookie__osm_totp_token $cookie_qos_token_set {
-  include /etc/nginx/conf.d/tile_qos_cookies.map;
-}
-
-map $http_user_agent $approved_scraper {
-  default                   0; # Not approved
-  '~^JOSM\/'                1; # JOSM
-  '~^Mozilla\/5\.0\ QGIS\/' 1; # QGIS
-}
-
-map $http_user_agent $denied_scraper {
-  default                0; # Not denied
-  ''                     1; # No User-Agent Set
-  '~^Python\-urllib\/'   1; # Library Default
-  '~^python\-requests\/' 1; # Library Default
-  '~^node\-fetch\/'      1; # Library Default
-  '~^R$'                 1; # Library Default
-  '~^Java\/'             1; # Library Default
-  '~^tiles$'             1; # Library Default
-  '~^runtastic'          1; # App
-  'Mozilla/4.0'          1; # Fake
-  'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)' 1;  # Fake
-}
-
-map $http_referer $denied_referer {
-  default                          0; # Not denied
-  'http://www.openstreetmap.org/'  1; # Faked
-  'http://www.openstreetmap.org'   1; # Faked
-  'http://openstreetmap.org/'      1; # Faked
-  'http://openstreetmap.org'       1; # Faked
-  'http://www.osm.org/'            1; # Faked
-  'http://www.osm.org'             1; # Faked
-  'http://osm.org/'                1; # Faked
-  'http://osm.org'                 1; # Faked
-}
-
-map $http_referer $osm_referer {
-  default                                 '';    # False
-  '~^https:\/\/www\.openstreetmap\.org\/' 'osm'; # True
-}
-
-# Limit Cache-Control header to only approved User-Agents
-map $osm_referer$http_user_agent $limit_http_cache_control {
-  default '';                                # Unset Header
-  '~^osmMozilla\/5\.0\ QGIS\/' '';            # Unset Header
-  '~^osmMozilla\/5\.0\ ' $http_cache_control; # Pass Header
-}
-
-# Limit Pragma header to only approved User-Agents
-map $osm_referer$http_user_agent $limit_http_pragma {
-  default '';                          # Unset Header
-  '~^osmMozilla\/5\.0\ QGIS\/' '';     # Unset Header
-  '~^osmMozilla\/5\.0\ ' $http_pragma; # Pass Header
-}
-
-server {
-    listen       443 ssl deferred backlog=16384 reuseport fastopen=2048 http2 default_server;
-    server_name  localhost;
-
-    proxy_buffers 8 64k;
-
-    ssl_certificate      /etc/ssl/certs/tile.openstreetmap.org.pem;
-    ssl_certificate_key  /etc/ssl/private/tile.openstreetmap.org.key;
-
-    # Requests sent within early data are subject to replay attacks.
-    # See: http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
-    ssl_early_data on;
-
-    # Immediately 404 layers we do not support
-<% for i in 20..99 do %>
-    location /<%= i %>/ {
-      set $limit_rate 512;
-      return 404;
-    }
-<% end %>
-
-    # Immediately 404 silly tile requests
-    location = /0/0/-1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /1/0/-1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /1/-1/0.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /1/-1/1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /1/-1/-1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /1/-1/2.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /1/1/-1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /1/2/-1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /2/0/-1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /2/-1/0.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /2/-1/1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /2/1/-1.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /2/-1/2.png {
-      set $limit_rate 512;
-      return 404;
-    }
-    location = /2/-1/3.png {
-      set $limit_rate 512;
-      return 404;
-    }
-
-<% for i in 0..14 do %>
-<% if i == 0 -%>
-    # Default Fallback Location Handler (lowest)
-    location / {
-<% elsif -%>
-    # Dedicated zoom handler for caching
-    location /<%= i %>/ {
-<% end %>
-      # Only allow GET / HEAD / OPTIONS (CORS) requests
-      limit_except GET HEAD OPTIONS {
-        deny all;
-      }
-
-      proxy_pass http://tile_cache_backend;
-      proxy_set_header X-Forwarded-For $remote_addr;
-      proxy_http_version 1.1;
-      proxy_set_header Connection '';
-
-      proxy_connect_timeout 10s;
-
-      # Replace host header.
-      proxy_set_header Host 'tile.openstreetmap.org';
-      # Do not pass cookies to backends.
-      proxy_set_header Cookie '';
-      # Do not pass Accept-Encoding to backends.
-      proxy_set_header Accept-Encoding '';
-      # Do not pass Accept to backends.
-      proxy_set_header Accept '';
-      # Do not pass Accept-Language to backends as unused.
-      proxy_set_header Accept-Language '';
-      proxy_set_header Accept-Charset '';
-      # Do not send origin, we allow all.
-      proxy_set_header origin '';
-      # Do not pass invalid headers to backend.
-      proxy_set_header X-Forwarded-Host '';
-      proxy_set_header X-Host '';
-      proxy_set_header Authorization '';
-      proxy_set_header Proxy-Authorization '';
-
-      # Drop partial requests
-      proxy_set_header range '';
-
-      # Do not allow setting cookies from backends due to caching.
-      proxy_ignore_headers Set-Cookie;
-      proxy_hide_header Set-Cookie;
-
-<% if i != 0 -%>
-      # Caching
-      proxy_cache "proxy_cache_zone";
-      proxy_cache_lock on;
-      proxy_cache_valid 200 1d;
-      proxy_cache_valid 404 15m;
-      # Serve stale cache on errors or if updating
-      proxy_cache_use_stale error timeout updating http_500 http_503 http_504;
-      # If in cache as stale, serve stale and update in background
-      proxy_cache_background_update on;
-      proxy_cache_min_uses 8;
-
-      add_header X-Nginx-Cache-Status $upstream_cache_status;
-<% end -%>
-
-      # Set a QoS cookie if none presented (uses nginx Map)
-      add_header Set-Cookie $cookie_qos_token_set;
-<% if node[:ssl][:strict_transport_security] -%>
-      # Ensure Strict-Transport-Security header is removed from proxied server responses
-      proxy_hide_header Strict-Transport-Security;
-
-      # Enable HSTS
-      add_header Strict-Transport-Security "<%= node[:ssl][:strict_transport_security] %>" always;
-<% end -%>
-
-      # QoS Traffic Rate see $limit_rate on http://nginx.org/en/docs/http/ngx_http_core_module.html
-      set $limit_rate $limit_rate_qos;
-
-      # Allow Higher Traffic Rate from Approved User-Agents which do not support cookies (uses nginx Map)
-      if ($approved_scraper) {
-        set $limit_rate 65536;
-      }
-
-      if ($denied_scraper) {
-        set $limit_rate 512;
-        return 429;
-      }
-      if ($denied_referer) {
-        set $limit_rate 512;
-        return 418;
-      }
-
-      # Strip any ?query parameters from urls
-      set $args '';
-
-      # Allow cache purging headers only from select User-Agents (uses nginx Map)
-      proxy_set_header Cache-Control $limit_http_cache_control;
-      proxy_set_header Pragma $limit_http_pragma;
-    }
-<% end %>
-}
diff --git a/cookbooks/tilecache/templates/default/squid.conf.erb b/cookbooks/tilecache/templates/default/squid.conf.erb
deleted file mode 100644 (file)
index 69e9197..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-acl osmtile_thishost dstdomain <%= node.name %>
-acl osmtile_sites dstdomain <%= node.name %> a.tile.openstreetmap.org b.tile.openstreetmap.org c.tile.openstreetmap.org tile.openstreetmap.org a.tile.osm.org b.tile.osm.org c.tile.osm.org tile.osm.org
-acl osmtiles_png urlpath_regex .png$
-
-acl osmtileScrapers browser ^$
-acl osmtileScrapers browser ^MOBAC
-acl osmtileScrapers browser ^JTileDownloader
-acl osmtileScrapers browser ^Apache\-HttpClient
-acl osmtileScrapers browser ^Go-http-client\/
-acl osmtileScrapers browser ^Opera\/10\.00
-acl osmtileScrapers browser ^shipxy01
-# acl osmtileScrapers browser ^OsmAnd # Victor + Email. Whitelist for 1 week
-# acl osmtileScrapers browser ^apemap # CGI143 + Email. Whitelist for 1 week
-acl osmtileScrapers browser Firefox\/2\.0\.0\.11$
-acl osmtileScrapers browser Firefox\/3\.5\.7$
-acl osmtileScrapers browser Firefox\/3\.6$
-acl osmtileScrapers browser ^Mozilla\/4\.0$
-acl osmtileScrapers browser ^Mozilla\/5\.0$ # QLandkarte unwilling to set a real user-agent.
-acl osmtileScrapers browser ^Mozilla$ # Intentionally faked user-agent
-acl osmtileScrapers browser ^User\-Agent
-acl osmtileScrapers browser Firefox\/0\.8$
-acl osmtileScrapers browser Firefox\/1\.0$
-acl osmtileScrapers browser Firefox\/1\.0\.7$
-acl osmtileScrapers browser K\-Meleon\/1\.02$
-acl osmtileScrapers browser MSIE.7\.0.*Windows.NT.5\.1.*2\.0\.50727.$
-acl osmtileScrapers browser MSIE.5.5
-acl osmtileScrapers browser ^LoadOSM\.exe$
-acl osmtileScrapers browser ^app_name$
-acl osmtileScrapers browser ^osmdroid$ # app using osmdroid library not setting app-specific User-Agent
-# acl osmtileScrapers browser ^Mozilla/5\.0 \(Windows NT 5\.1\)$ # Faked User-Agent
-acl osmtileScrapers browser Firefox\/3\.0
-acl osmtileScrapers browser Firefox\/4\.0
-acl osmtileScrapers browser Firefox\/5\.0
-acl osmtileScrapers browser Firefox\/6\.0
-acl osmtileScrapers browser Firefox\/7\.0
-acl osmtileScrapers browser Firefox\/8\.0
-acl osmtileScrapers browser Firefox\/9\.0
-acl osmtileScrapers browser Firefox\/10\.0
-acl osmtileScrapers browser Firefox\/11\.0
-acl osmtileScrapers browser Firefox\/12\.0
-acl osmtileScrapers browser Firefox\/13\.0
-acl osmtileScrapers browser ^Python\-urllib\/
-acl osmtileScrapers browser ^python\-requests\/
-acl osmtileScrapers browser ^node\-fetch\/
-acl osmtileScrapers browser ^R$
-acl osmtileScrapers browser ^Java\/
-acl osmtileScrapers browser ^tiles$
-acl osmtileScrapers browser ^runtastic
-
-acl is_fake_browser browser Firefox\/3\.0
-acl is_fake_browser browser Firefox\/4\.0
-acl is_fake_browser browser Firefox\/5\.0
-acl is_fake_browser browser Firefox\/6\.0
-acl is_fake_browser browser Firefox\/7\.0
-acl is_fake_browser browser Firefox\/8\.0
-acl is_fake_browser browser Firefox\/9\.0
-acl is_fake_browser browser Firefox\/10\.0
-acl is_fake_browser browser Firefox\/11\.0
-acl is_fake_browser browser Firefox\/12\.0
-acl is_fake_browser browser Firefox\/13\.0
-
-http_access deny osmtile_sites osmtileScrapers
-
-acl osmtileOverusers referer_regex ^https?://pmap\.kuku\.lu/
-acl osmtileOverusers referer_regex ^https?://[^.]*\.pmap\.kuku\.lu/
-acl osmtileOverusers referer_regex ^https?://fastpokemap\.com/
-acl osmtileOverusers referer_regex ^https?://[^.]*\.fastpokemap\.com/
-acl osmtileOverusers referer_regex ^https?://pkget\.com/
-acl osmtileOverusers referer_regex ^https?://[^.]*\.pkget\.com/
-
-# Faked OSM referers
-acl osmtileOverusers referer_regex ^http://www\.openstreetmap\.org/?$
-acl osmtileOverusers referer_regex ^http://openstreetmap\.org/?$
-acl osmtileOverusers referer_regex ^http://www\.osm\.org/?$
-acl osmtileOverusers referer_regex ^http://osm\.org/?$
-
-http_access deny osmtile_sites osmtileOverusers
-
-# Delay pool when !has_referer and is_browser
-acl has_referer referer_regex .
-acl is_browser browser Chrome\/
-acl is_browser browser Firefox\/
-acl is_browser browser Trident\/
-acl is_browser browser Safari\/
-acl is_browser browser AppleWebKit\/
-
-acl whitelist_path urlpath_regex ^/cgi-bin/(export|debug)
-acl blacklist_path urlpath_regex ^/cgi-bin/
-acl blacklist_path urlpath_regex ^/MyAdmin/
-acl blacklist_path urlpath_regex ^/myadmin/
-acl blacklist_path urlpath_regex ^/pma/
-acl blacklist_path urlpath_regex ^/phpmyadmin/
-acl blacklist_path urlpath_regex ^/phpMyAdmin/
-acl blacklist_path urlpath_regex ^/idssvc/
-acl blacklist_path urlpath_regex ^/iesvc/
-acl blacklist_path urlpath_regex ^/invoker/
-acl blacklist_path urlpath_regex ^/jmx-console/
-acl blacklist_path urlpath_regex ^/manager/
-acl blacklist_path urlpath_regex ^/service/
-acl blacklist_path urlpath_regex ^/web-console/
-acl blacklist_path urlpath_regex ^/wstats/
-acl blacklist_path urlpath_regex ^/zecmd/
-
-http_access allow osmtile_sites whitelist_path
-http_access deny blacklist_path
-
-acl requestMethodGet method GET
-
-http_access allow osmtile_sites requestMethodGet
-
-acl osmtile_nocache_url urlpath_regex \.png/(status|dirty)$
-cache deny osmtile_sites osmtile_nocache_url
-
-<% @caches.each do |cache| -%>
-<% cache.ipaddresses(:family => :inet, :role => :external).sort.each do |address| -%>
-acl tile_caches src <%= address %>
-<% end -%>
-<% end -%>
-
-# Siblings
-<% node[:tilecache][:tile_siblings].each do |sibling| -%>
-cache_peer <%= sibling %> sibling 3128 4827 htcp weight=1500
-<% end -%>
-
-# Primary Parent
-<% if node[:squid][:version] < 4 -%>
-cache_peer <%= node[:tilecache][:tile_parent] %> parent 443 0 no-query originserver name=osmtileAccel login=PASS connect-timeout=120 no-digest weight=1000 ssl ssldomain=render.openstreetmap.org
-<% else -%>
-cache_peer <%= node[:tilecache][:tile_parent] %> parent 443 0 no-query originserver name=osmtileAccel login=PASS connect-timeout=120 no-digest weight=1000 tls tlsdomain=render.openstreetmap.org
-<% end -%>
-cache_peer_access osmtileAccel allow osmtile_sites
-
-# Backup Parents
-<% @renders.each do |renders| -%>
-<% if node[:squid][:version] < 4 -%>
-cache_peer <%= renders[:hostname] %>.render.openstreetmap.org parent 443 0 no-query originserver name=osmtileAccelBackup<%= renders[:hostname] %> login=PASS connect-timeout=60 no-digest weight=10 ssl ssldomain=render.openstreetmap.org
-<% else -%>
-cache_peer <%= renders[:hostname] %>.render.openstreetmap.org parent 443 0 no-query originserver name=osmtileAccelBackup<%= renders[:hostname] %> login=PASS connect-timeout=60 no-digest weight=10 tls tlsdomain=render.openstreetmap.org
-<% end -%>
-cache_peer_access osmtileAccelBackup<%= renders[:hostname] %> allow osmtile_sites
-<% end -%>
-
-# ----------------------------------
-# Create an unlimited pool for cache IP addresses
-acl pool_unlimited src 127.0.0.1
-<% @caches.each do |cache| -%>
-<% cache.ipaddresses(:family => :inet, :role => :external).sort.each do |address| -%>
-acl pool_unlimited src <%= address %>
-<% end -%>
-<% end -%>
-
-# Juno Minsk office - me@komzpa.net
-acl pool_unlimited src 212.98.173.54
-<% if node[:squid][:version] < 4 -%>
-
-#Allow tile_caches HTCP access
-htcp_access allow tile_caches
-
-#Allow tile_caches ICP access
-icp_access allow tile_caches
-<% end %>
-
-<% (0..127).each do |i| -%>
-acl pool_<%= sprintf("%03d", 2*i) %> src <%= 2*i %>.0.0.0/7
-<% end %>
-
-delay_pools 256
-delay_initial_bucket_level 25
-
-<% (1..256).each do |i| -%>
-delay_class <%= i %> 3
-<% end %>
-#bit mask
-# xxxxxxx- -------- xxxxxxxx xxxxxxxx
-
-# small pools for !has_referer && is_browser - designed to slow down anyone
-# using no-referer to bypass blocks due to abusive levels of use.
-<% (0..127).each do |i| -%>
-delay_access <%= i+1 %> allow pool_<%= sprintf("%03d", 2*i) %> !pool_unlimited is_fake_browser osmtile_sites
-delay_access <%= i+1 %> allow pool_<%= sprintf("%03d", 2*i) %> !pool_unlimited !has_referer is_browser osmtile_sites
-delay_access <%= i+1 %> deny all
-delay_parameters <%= i+1 %> -1/-1 <%= node[:tilecache][:net_bucket_refill] / 10 %>/<%= node[:tilecache][:net_bucket_size] / 10 %> <%= node[:tilecache][:ip_bucket_refill] / 10 %>/<%= node[:tilecache][:ip_bucket_size] / 10 %>
-<% end %>
-
-# bigger pools for users providing a referer (assuming it's not blocked)
-# or non-browser users.
-<% (0..127).each do |i| %>
-delay_access <%= i+129 %> allow pool_<%= sprintf("%03d", 2*i) %> !pool_unlimited osmtile_sites
-delay_access <%= i+129 %> deny all
-delay_parameters <%= i+129 %> -1/-1 <%= node[:tilecache][:net_bucket_refill] %>/<%= node[:tilecache][:net_bucket_size] %> <%= node[:tilecache][:ip_bucket_refill] %>/<%= node[:tilecache][:ip_bucket_size] %>
-<% end %>
-
-#----------------------------------
index 3846951a5d393696ad432ce35fa83706bc105a14..34901632951e93b1a871f4371b7c6b30fa06d9f5 100644 (file)
@@ -1,3 +1,3 @@
-default[:tilelog][:source_directory] = "/opt/tilelog"
-default[:tilelog][:input_directory] = "/store/logs/tile.openstreetmap.org"
+default[:accounts][:users][:planet][:status] = :role
+
 default[:tilelog][:output_directory] = "/store/planet/tile_logs"
index 7abc77ea2a523fdadda44455539557a7b9b1faec..d3f5a753c72bae4d9af5cc61addaaac1a8544741 100644 (file)
@@ -6,5 +6,7 @@ description      "Installs and configures tile log analysis"
 
 version          "1.0.0"
 supports         "ubuntu"
-depends          "git"
-depends          "tools"
+depends          "accounts"
+depends          "planet"
+depends          "python"
+depends          "systemd"
index edc6e7e72e4def87898104c918ffdbb0dc84d021..9370225150ec2f748ae8686174c6fdec409436e5 100644 (file)
@@ -2,7 +2,7 @@
 # Cookbook:: tilelog
 # Recipe:: default
 #
-# Copyright:: 2014, OpenStreetMap Foundation
+# Copyright:: 2014-2022, OpenStreetMap Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # limitations under the License.
 #
 
-include_recipe "tools"
+include_recipe "accounts"
+include_recipe "planet::aws"
+include_recipe "python"
 
-package %w[
-  gcc
-  make
-  autoconf
-  automake
-  libboost-filesystem-dev
-  libboost-system-dev
-  libboost-program-options-dev
-]
+passwords = data_bag_item("tilelog", "passwords")
 
-tilelog_source_directory = node[:tilelog][:source_directory]
-tilelog_input_directory = node[:tilelog][:input_directory]
+tilelog_directory = "/opt/tilelog"
 tilelog_output_directory = node[:tilelog][:output_directory]
 
-# resources for building the tile analysis binary
-git tilelog_source_directory do
-  action :sync
-  repository "https://github.com/zerebubuth/openstreetmap-tile-analyze.git"
-  revision "live"
-  user "root"
-  group "root"
-  notifies :run, "execute[tilelog-autogen]", :immediate
-end
-
-execute "tilelog-autogen" do
-  action :nothing
-  command "autoreconf -i"
-  cwd tilelog_source_directory
-  user "root"
-  group "root"
-  notifies :run, "execute[tilelog-configure]", :immediate
+python_virtualenv tilelog_directory do
+  interpreter "/usr/bin/python3"
 end
 
-execute "tilelog-configure" do
-  action :nothing
-  command "./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu"
-  cwd tilelog_source_directory
-  user "root"
-  group "root"
-  notifies :run, "execute[tilelog-build]", :immediate
+python_package "tilelog" do
+  python_virtualenv tilelog_directory
+  python_version "3"
+  version "1.7.0"
 end
 
-execute "tilelog-build" do
-  action :nothing
-  command "make"
-  cwd tilelog_source_directory
-  user "root"
-  group "root"
+directory tilelog_output_directory do
+  user "planet"
+  group "planet"
+  mode "755"
+  recursive true
 end
 
-# resources for running the tile analysis
 template "/usr/local/bin/tilelog" do
   source "tilelog.erb"
   owner "root"
   group "root"
-  mode 0o755
-  variables :analyze_bin => "#{tilelog_source_directory}/openstreetmap-tile-analyze",
-            :input_dir => tilelog_input_directory,
-            :output_dir => tilelog_output_directory
+  mode "755"
+  variables :output_dir => tilelog_output_directory,
+            :aws_key => passwords["aws_key"]
 end
 
-template "/etc/cron.d/tilelog" do
-  source "tilelog.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+systemd_service "tilelog" do
+  description "Tile log analysis"
+  user "planet"
+  exec_start "/usr/local/bin/tilelog"
+  nice 10
+  sandbox :enable_network => true
+  protect_home "tmpfs"
+  bind_paths "/home/planet"
+  read_write_paths tilelog_output_directory
 end
 
-# resources related to the output of the analysis and where it
-# can be publicly downloaded.
-directory tilelog_output_directory do
-  user "www-data"
-  group "www-data"
-  mode 0o755
+systemd_timer "tilelog" do
+  description "Tile log analysis"
+  on_calendar "*-*-* 01:07:00"
+end
+
+service "tilelog.timer" do
+  action [:enable, :start]
 end
diff --git a/cookbooks/tilelog/templates/default/tilelog.cron.erb b/cookbooks/tilelog/templates/default/tilelog.cron.erb
deleted file mode 100644 (file)
index bd3278e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-MAILTO=zerebubuth@gmail.com
-17 22 * * * www-data /usr/local/bin/tilelog
index 598c1e127770eaadafcde00f3c3e69227c06db8a..978974d8964e8c2f55c51d3998e90374c9c9c169 100644 (file)
@@ -1,28 +1,35 @@
 #!/bin/sh
+set -e
 
-ANALYZE=<%= @analyze_bin %>
-LOGDIR=<%= @input_dir %>
-OUTDIR=<%= @output_dir %>
-if [ -z "$DATE" ]; then
-               DATE=`date -d "1 day ago" "+%Y-%m-%d"`
+if [ -z "$DATE" ]
+then
+  DATE=$(date -u -d "1 day ago" "+%Y-%m-%d")
+  YEAR=$(date -u -d "1 day ago" "+%Y")
 fi
-TMPDIR=`mktemp -d -t tmp.XXXXXXXXX`
-ORIGDIR=`pwd`
 
-clean_up() {
-               cd $ORIGDIR
-               rm -rf $TMPDIR
-}
+OUTDIR="<%= @output_dir %>"
+TMPDIR=$(mktemp -d -t tilelog.XXXXXXXXX)
 
-trap clean_up 0 HUP INT TERM
-cd $TMPDIR
+cd "$TMPDIR"
 
-mkdir db
-nice -n 19 $ANALYZE $LOGDIR/*-${DATE}.xz > analyze.log
-if [ -f tiles.txt ]; then
-               nice -n 19 xz -9e -z tiles.txt
-               mv tiles.txt.xz $OUTDIR/tiles-${DATE}.txt.xz
+export AWS_ACCESS_KEY_ID="AKIASQUXHPE7JFCFMOUP"
+export AWS_SECRET_ACCESS_KEY="<%= @aws_key %>"
+export AWS_REGION="eu-west-1"
 
-else
-               cat analyze.log
-fi
+TILEFILE="tiles-${DATE}.txt.xz"
+HOSTFILE="hosts-${DATE}.csv"
+APPFILE="apps-${DATE}.csv"
+COUNTRYFILE="countries-${DATE}.csv"
+
+nice -n 19 /opt/tilelog/bin/tilelog --date "${DATE}" \
+  --generate-success --generate-minimise --generate-location \
+  --tile "${TILEFILE}" --host "${HOSTFILE}" --app "${APPFILE}" --country "${COUNTRYFILE}"
+
+mv "${TILEFILE}" "${HOSTFILE}" "${APPFILE}" "${COUNTRYFILE}" "${OUTDIR}"
+
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "${OUTDIR}/${TILEFILE}" "s3://osm-planet-eu-central-1/tile_logs/standard_layer/tiles/${YEAR}/${TILEFILE}"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "${OUTDIR}/${HOSTFILE}" "s3://osm-planet-eu-central-1/tile_logs/standard_layer/hosts/${YEAR}/${HOSTFILE}"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "${OUTDIR}/${APPFILE}" "s3://osm-planet-eu-central-1/tile_logs/standard_layer/apps/${YEAR}/${APPFILE}"
+/opt/awscli/v2/current/bin/aws --profile=osm-pds-upload s3 cp --storage-class=INTELLIGENT_TIERING --no-progress "${OUTDIR}/${COUNTRYFILE}" "s3://osm-planet-eu-central-1/tile_logs/standard_layer/countries/${YEAR}/${COUNTRYFILE}"
+
+rm -rf "$TMPDIR"
diff --git a/cookbooks/tools/attributes/default.rb b/cookbooks/tools/attributes/default.rb
new file mode 100644 (file)
index 0000000..b77bd1b
--- /dev/null
@@ -0,0 +1 @@
+default[:tools][:cron] = {}
index eaceb9d8eac55a7e9761391be0734a8e35efb137..6ff55543f58f188ca8b6f784f7051d495985e3b0 100644 (file)
@@ -36,6 +36,9 @@ package %w[
   lvm2
   rsyslog
   cron
+  locales-all
+  systemd-coredump
+  vim
 ]
 
 service "rsyslog" do
@@ -44,20 +47,10 @@ service "rsyslog" do
 end
 
 # Remove some unused and unwanted packages
-package %w[mlocate nano whoopsie] do
+package %w[mlocate whoopsie] do
   action :purge
 end
 
-# Remove screen-cleanup left behind by old release.
-file "/etc/init.d/screen-cleanup" do
-  action :delete
-end
-
-# Cleanup unused file
-file "/etc/systemd/system/cron.service.d/chef.conf" do
-  action :delete
-end
-
 # Configure cron to run in the local timezone of the machine
 systemd_service "cron-timezone" do
   service "cron"
@@ -67,7 +60,27 @@ systemd_service "cron-timezone" do
   only_if { node[:timezone] }
 end
 
+# Configure cron with lower cpu and IO priority
+if node[:tools][:cron][:load]
+  systemd_service "cron-load" do
+    service "cron"
+    dropin "load"
+    nice node[:tools][:cron][:load][:nice]
+    io_scheduling_class node[:tools][:cron][:load][:io_scheduling_class]
+    io_scheduling_priority node[:tools][:cron][:load][:io_scheduling_priority]
+    notifies :restart, "service[cron]"
+  end
+end
+
 # Make sure cron is running
 service "cron" do
   action [:enable, :start]
 end
+
+# Ubuntu MOTD adverts be-gone
+template "/etc/default/motd-news" do
+  source "motd-news.erb"
+  owner "root"
+  group "root"
+  mode "644"
+end
diff --git a/cookbooks/tools/templates/default/motd-news.erb b/cookbooks/tools/templates/default/motd-news.erb
new file mode 100644 (file)
index 0000000..ac0f13a
--- /dev/null
@@ -0,0 +1,21 @@
+# DO NOT EDIT - This file is being maintained by Chef
+
+# Enable/disable the dynamic MOTD news service
+# This is a useful way to provide dynamic, informative
+# information pertinent to the users and administrators
+# of the local system
+ENABLED=0
+
+# Configure the source of dynamic MOTD news
+# White space separated list of 0 to many news services
+# For security reasons, these must be https
+# and have a valid certificate
+# Canonical runs a service at motd.ubuntu.com, and you
+# can easily run one too
+URLS="https://motd.ubuntu.com"
+
+# Specify the time in seconds, you're willing to wait for
+# dynamic MOTD news
+# Note that news messages are fetched in the background by
+# a systemd timer, so this should never block boot or login
+WAIT=5
diff --git a/cookbooks/trac/files/default/htdocs/osm.ico b/cookbooks/trac/files/default/htdocs/osm.ico
deleted file mode 100644 (file)
index 4448dd6..0000000
Binary files a/cookbooks/trac/files/default/htdocs/osm.ico and /dev/null differ
diff --git a/cookbooks/trac/files/default/htdocs/osm.png b/cookbooks/trac/files/default/htdocs/osm.png
deleted file mode 100644 (file)
index abce19d..0000000
Binary files a/cookbooks/trac/files/default/htdocs/osm.png and /dev/null differ
diff --git a/cookbooks/trac/files/default/htdocs/robots.txt b/cookbooks/trac/files/default/htdocs/robots.txt
deleted file mode 100644 (file)
index 876457d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#Trac really does not handle well being scraped.
-User-agent: *
-Disallow: /changeset
-Disallow: /changeset/
-Disallow: /wiki/
diff --git a/cookbooks/trac/files/default/templates/site.html b/cookbooks/trac/files/default/templates/site.html
deleted file mode 100644 (file)
index 6360c4a..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml"
-      xmlns:py="http://genshi.edgewall.org/" py:strip="">
-
-  <form py:match="div[@id='content' and @class='ticket']/form" py:attrs="select('@*')">
-    <py:if test="req.environ['PATH_INFO'] == '/newticket' and (not 'preview' in req.args)">
-      <p>Before opening a new ticket, please:</p>
-      <ol>
-        <li>Check that you're in the right place. This is the bug-tracker for many OpenStreetMap related projects but not everything uses this site, so check the following list to make sure there isn't a better place to raise your issue:
-          <ul>
-            <li>Raise JOSM issues <a href="http://josm.openstreetmap.de/">here</a>.</li>
-            <li>Raise JXAPI issues <a href="https://github.com/iandees/xapi-servlet/issues">here</a>.</li>
-          </ul>
-        </li>
-        <li><a href="/report/1?sort=created&amp;asc=1">View the list of tickets</a> to make sure that your bug hasn't already been reported. You should also try <a href="/search">searching</a>.</li>
-        <li>Enter your bug descriptively. <i>Be sure you set the 'component' field (e.g. "website" or "potlatch (Flash editor)") so that it goes to the right person</i></li>
-      </ol>
-      <p>You can also use this to request enhancements.</p>
-      <h2>How to be a helpful bug reporter</h2>
-      <p>Where you can, always provide "steps to reproduce" - in other words, a series of instructions that the developers can follow to reproduce your bug. The more you can do to pinpoint the problem, the more likely it'll be fixed.</p>
-      <ol>
-        <li>Give any pertinent details of your system (operating system and version, browser and version, etc.).</li>
-        <li>If the problem is with a web page or web application, give its URL. If the problem is encountered with a particular set of data, say what (e.g. a location in <a class="wiki" href="/wiki/OpenStreetMap">OpenStreetMap</a>).</li>
-        <li>Explain what you are doing, click-by-click.</li>
-        <li>Explain what you expect to happen.</li>
-        <li>Explain what is happening instead.</li>
-      </ol>
-      <script type="text/javascript">
-        $(document).ready(function () {
-          var c = document.createElement("option");
-          $(c).attr("selected", "selected");
-          $("#field-component").prepend(c);
-
-          $("#propertyform").submit(function () {
-            if ($("#field-component").val() == "") {
-              alert("Please select a component!");
-              return false;
-            } else {
-              return true;
-            }
-          });
-        });
-      </script>
-    </py:if>
-    ${select('*')} 
-  </form>
-
-</html>
diff --git a/cookbooks/trac/files/default/trac-authenticate b/cookbooks/trac/files/default/trac-authenticate
deleted file mode 100755 (executable)
index a255637..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/ruby
-
-require "net/http"
-require "uri"
-
-user = gets.chop
-pass = gets.chop
-
-request = Net::HTTP::Get.new("/api/0.6/user/details")
-request.basic_auth user, pass
-
-response = Net::HTTP.start("api.openstreetmap.org", :use_ssl => true) do |http|
-  http.request(request)
-end
-
-exit!(0) if response.is_a?(Net::HTTPSuccess)
-exit!(1)
index 57fe9e358f1518472c3abd4a8e9b496c6cea429c..e781638263ca52e224285736abe2881579eeb5fd 100644 (file)
@@ -6,4 +6,4 @@ description       "Installs and configures trac servers"
 
 version           "1.0.0"
 supports          "ubuntu"
-depends           "apache"
+depends           "podman"
index f7472131d398b1c98486e40dc78c70fae05bb1dd..4099810f1d89a2da9904c9dc7e4e8efbcfb70c15 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "apache"
+include_recipe "podman::apache"
 
-package %w[
-  trac
-  trac-git
-  ruby
-]
-
-site_name = "trac.openstreetmap.org"
-site_directory = "/srv/#{site_name}"
-
-template "/var/lib/trac/conf/trac.ini" do
-  source "trac.ini.erb"
-  owner "trac"
-  group "www-data"
-  mode 0o644
-  variables :name => site_name
-end
-
-remote_directory "/var/lib/trac/htdocs" do
-  source "htdocs"
-  owner "trac"
-  group "trac"
-  mode 0o755
-  files_owner "trac"
-  files_group "trac"
-  files_mode 0o644
-  purge true
-end
-
-remote_directory "/var/lib/trac/templates" do
-  source "templates"
-  owner "trac"
-  group "trac"
-  mode 0o755
-  files_owner "trac"
-  files_group "trac"
-  files_mode 0o644
-  purge true
-end
-
-execute "trac-deploy-#{site_name}" do
-  command "trac-admin /var/lib/trac deploy #{site_directory}"
-  user "root"
-  group "root"
-  not_if { File.exist?(site_directory) }
-end
-
-cookbook_file "/usr/local/bin/trac-authenticate" do
-  owner "root"
-  group "root"
-  mode 0o755
-end
-
-apache_module "wsgi"
-
-ssl_certificate "trac.openstreetmap.org" do
-  domains ["trac.openstreetmap.org", "trac.osm.org"]
-  notifies :reload, "service[apache2]"
-end
-
-apache_site site_name do
-  template "apache.erb"
-  directory site_directory
-  variables :user => "trac", :group => "trac", :aliases => ["trac.osm.org"]
-end
-
-template "/etc/sudoers.d/trac" do
-  source "sudoers.erb"
-  owner "root"
-  group "root"
-  mode 0o440
-end
-
-template "/etc/cron.daily/trac-backup" do
-  source "backup.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o755
+podman_site "trac.openstreetmap.org" do
+  image "ghcr.io/openstreetmap/trac-website:latest"
+  aliases ["trac.osm.org"]
 end
diff --git a/cookbooks/trac/templates/default/apache.erb b/cookbooks/trac/templates/default/apache.erb
deleted file mode 100644 (file)
index bc58ed2..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-WSGIDaemonProcess <%= @name %> user=<%= @user %> group=<%= @group %> maximum-requests=5000 threads=25 inactivity-timeout=180
-
-<VirtualHost *:80>
-  ServerName <%= @name %>
-<% @aliases.each do |alias_name| -%>
-  ServerAlias <%= alias_name %>
-<% end -%>
-  ServerAdmin webmaster@openstreetmap.org
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
-  RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
-<% unless @aliases.empty? -%>
-
-<VirtualHost *:443>
-  ServerName <%= @aliases.first %>
-<% @aliases.drop(1).each do |alias_name| -%>
-  ServerAlias <%= alias_name %>
-<% end -%>
-  ServerAdmin webmaster@openstreetmap.org
-
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  RedirectPermanent / https://<%= @name %>/
-</VirtualHost>
-<% end -%>
-
-<VirtualHost *:443>
-  ServerName <%= @name %>
-  ServerAdmin webmaster@openstreetmap.org
-
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
-  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
-
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
-  ErrorLog /var/log/apache2/<%= @name %>-error.log
-
-  DocumentRoot <%= @directory %>/htdocs
-  Alias /robots.txt <%= @directory %>/htdocs/site/robots.txt
-  WSGIScriptAlias / <%= @directory %>/cgi-bin/trac.wsgi
-
-  WSGIProcessGroup <%= @name %>
-
-  DefineExternalAuth osm pipe /usr/local/bin/trac-authenticate
-
-  <Location /login>
-    AuthType Basic
-    AuthName "OpenStreetMap Trac"
-    AuthBasicProvider external
-    AuthExternal osm
-    Require valid-user
-  </Location>
-</VirtualHost>
-
-<Directory <%= @directory %>/htdocs>
-  Require all granted
-</Directory>
-
-<Directory <%= @directory %>/cgi-bin>
-  Require all granted
-</Directory>
diff --git a/cookbooks/trac/templates/default/backup.cron.erb b/cookbooks/trac/templates/default/backup.cron.erb
deleted file mode 100644 (file)
index e4e4bd8..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-# DO NOT EDIT - This file is being maintained by Chef
-
-T=$(mktemp -d -t -p /var/tmp trac.XXXXXXXXXX)
-D=$(date +%Y-%m-%d)
-B=trac-$D.tar.gz
-
-trac-admin /var/lib/trac hotcopy $T/trac-$D > /dev/null
-
-export GZIP="--rsyncable -9"
-export RSYNC_RSH="ssh -ax"
-
-nice tar --create --gzip --directory=$T --file=$T/$B trac-$D
-nice rsync --preallocate --fuzzy $T/$B backup::backup
-
-rm -rf $T
diff --git a/cookbooks/trac/templates/default/sudoers.erb b/cookbooks/trac/templates/default/sudoers.erb
deleted file mode 100644 (file)
index 85b74a6..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-# Allow subversion to notify trac of commits
-www-data ALL=(trac) NOPASSWD: /usr/bin/trac-admin /var/lib/trac changeset *
-
-# Allow git to notify trac of commits
-%git ALL=(trac) NOPASSWD: /usr/bin/trac-admin /var/lib/trac changeset *
diff --git a/cookbooks/trac/templates/default/trac.ini.erb b/cookbooks/trac/templates/default/trac.ini.erb
deleted file mode 100644 (file)
index 3cff049..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-[attachment]
-max_size = 262144
-max_zip_size = 2097152
-render_unsafe_content = false
-
-[browser]
-color_scale = True
-downloadable_paths = /trunk, /branches/*, /tags/*
-hide_properties = svk:merge
-intermediate_color = 
-intermediate_point = 
-newest_color = (255, 136, 136)
-oldest_color = (136, 136, 255)
-oneliner_properties = trac:summary
-render_unsafe_content = false
-wiki_properties = trac:description
-
-[changeset]
-max_diff_bytes = 10000000
-max_diff_files = 0
-wiki_format_messages = true
-
-[components]
-tracopt.ticket.deleter = enabled
-tracopt.versioncontrol.git.* = enabled
-tracopt.versioncontrol.svn.* = enabled
-
-[header_logo]
-alt = OpenStreetMap
-height = 80
-link = https://<%= @name %>/
-src = site/osm.png
-width = 228
-
-[inherit]
-htdocs_dir = 
-plugins_dir = 
-templates_dir = 
-
-[intertrac]
-josm.compat = false
-josm.title = JOSM Trac
-josm.url = https://josm.openstreetmap.de
-
-[logging]
-log_file = trac.log
-# log_format = <inherited>
-log_level = INFO
-log_type = file
-
-[milestone]
-stats_provider = DefaultTicketGroupStatsProvider
-
-[mimeviewer]
-max_preview_size = 262144
-mime_map = text/x-dylan:dylan,text/x-idl:ice,text/x-ada:ads:adb
-mime_map_patterns = text/plain:README|INSTALL|COPYING.*
-pygments_default_style = trac
-pygments_modes = 
-tab_width = 8
-treat_as_binary = application/octet-stream, application/pdf, application/postscript, application/msword,application/rtf,
-
-[notification]
-admit_domains = 
-always_notify_owner = true
-always_notify_reporter = true
-always_notify_updater = true
-ambiguous_char_width = single
-batch_subject_template = $prefix Batch modify: $tickets_descr
-email_sender = SmtpEmailSender
-ignore_domains = 
-mime_encoding = none
-sendmail_path = sendmail
-smtp_always_bcc = 
-smtp_always_cc = 
-smtp_default_domain = 
-smtp_enabled = true
-smtp_from = trac@noreply.openstreetmap.org
-smtp_from_author = false
-smtp_from_name = 
-smtp_password = 
-smtp_port = 25
-smtp_replyto = trac@noreply.openstreetmap.org
-smtp_server = localhost
-smtp_subject_prefix = __default__
-smtp_user = 
-ticket_subject_template = $prefix #$ticket.id: $summary
-use_public_cc = true
-use_short_addr = false
-use_tls = false
-
-[project]
-admin = 
-admin_trac_url = .
-descr = OpenStreetMap is a free editable map of the whole world
-footer = Visit the map at<br /><a href="https://www.openstreetmap.org/">https://www.openstreetmap.org/</a>
-icon = site/osm.ico
-name = OpenStreetMap
-url = https://www.openstreetmap.org/
-
-[query]
-default_anonymous_query = status!=closed&cc~=$USER
-default_query = status!=closed&owner=$USER
-items_per_page = 100
-ticketlink_query = ?status=!closed
-
-[report]
-items_per_page = 100
-items_per_page_rss = 0
-
-[repositories]
-subversion.dir = /var/lib/subversion/repos/openstreetmap
-subversion.description = Legacy subversion repository
-subversion.type = svn
-subversion.url = https://svn.openstreetmap.org/
-subversion.hidden = true
-<% Dir.glob("/var/lib/git/*.git").sort.each do |repository| -%>
-<%= File.basename(repository, ".git") %>.dir = <%= repository %>
-<%= File.basename(repository, ".git") %>.description = <%= IO.read("#{repository}/description").strip %>
-<%= File.basename(repository, ".git") %>.type = git
-<%= File.basename(repository, ".git") %>.url = https://git.openstreetmap.org/public/<%= File.basename(repository) %>
-<% end -%>
-.alias = subversion
-
-[revisionlog]
-default_log_limit = 100
-graph_colors = ['#cc0', '#0c0', '#0cc', '#00c', '#c0c', '#c00']
-
-[roadmap]
-stats_provider = DefaultTicketGroupStatsProvider
-
-[search]
-# default_disabled_filters = <inherited>
-min_query_length = 3
-
-[sqlite]
-# extensions = <inherited>
-
-[svn]
-branches = trunk,branches/*
-tags = tags/*
-
-[ticket]
-default_cc = 
-default_component = 
-default_description = 
-default_keywords = 
-default_milestone = 
-default_owner = < default >
-default_priority = minor
-default_resolution = fixed
-default_severity = 
-default_summary = 
-default_type = defect
-default_version = 
-max_comment_size = 262144
-max_description_size = 262144
-preserve_newlines = default
-restrict_owner = false
-workflow = ConfigurableTicketWorkflow
-
-[ticket-workflow]
-accept = new,assigned,accepted,reopened -> accepted
-accept.operations = set_owner_to_self
-accept.permissions = TICKET_MODIFY
-leave = * -> *
-leave.default = 1
-leave.operations = leave_status
-reassign = new,assigned,accepted,reopened -> assigned
-reassign.operations = set_owner
-reassign.permissions = TICKET_MODIFY
-reopen = closed -> reopened
-reopen.operations = del_resolution
-reopen.permissions = TICKET_CREATE
-resolve = new,assigned,accepted,reopened -> closed
-resolve.operations = set_resolution
-resolve.permissions = TICKET_MODIFY
-
-[timeline]
-abbreviated_messages = True
-changeset_collapse_events = false
-changeset_long_messages = false
-changeset_show_files = 0
-default_daysback = 30
-max_daysback = 90
-newticket_formatter = oneliner
-ticket_show_details = false
-
-[trac]
-auth_cookie_lifetime = 0
-auth_cookie_path = 
-authz_file = 
-authz_module_name = 
-auto_preview_timeout = 2.0
-auto_reload = False
-backup_dir = db
-base_url = https://<%= @name %>/
-check_auth_ip = false
-database = sqlite:db/trac.db
-debug_sql = False
-default_charset = utf-8
-default_dateinfo_format = relative
-genshi_cache_size = 128
-htdocs_location = 
-ignore_auth_case = false
-jquery_location = 
-jquery_ui_location = 
-jquery_ui_theme_location = 
-mainnav = wiki,timeline,roadmap,browser,tickets,newticket,search
-metanav = login,logout,prefs,help,about
-mysqldump_path = mysqldump
-never_obfuscate_mailto = false
-permission_policies = DefaultPermissionPolicy, LegacyAttachmentPolicy
-permission_store = DefaultPermissionStore
-pg_dump_path = pg_dump
-repository_dir = 
-repository_sync_per_request = (default)
-repository_type = svn
-resizable_textareas = true
-secure_cookies = False
-show_email_addresses = false
-show_ip_addresses = false
-timeout = 20
-use_base_url_for_redirect = False
-
-[versioncontrol]
-allowed_repository_dir_prefixes = 
-
-[wiki]
-ignore_missing_pages = false
-max_size = 262144
-render_unsafe_content = false
-safe_schemes = cvs, file, ftp, git, irc, http, https, news, sftp, smb, ssh, svn, svn+ssh
-split_page_names = false
-
index b9e8a502750f09ed6ddaa0954f3e38e018294f09..da294e4e808d98e9504e8b3c2527c865ec628c3f 100644 (file)
@@ -3,7 +3,6 @@
 This cookbook installs and configures the web frontend machines that power
 [www.openstreetmap.org](https://www.openstreetmap.org). There are several recipes
 
-* `web::backend` - sets up the backend servers, used for processing longer-running requests
 * `web::base` - sets up common storage configuration between all the machines
 * `web::cgimap` - builds and configures [cgimap](https://github.com/openstreetmap/cgimap)
 * `web::cleanup` - configures a cleanup script to be run daily
index 79890cbdb18361c460376b9d5f95c726bfe1c5e2..81e7d94dff028f9c22ed541969cc29d3a0d04819 100644 (file)
@@ -1,4 +1,10 @@
 default[:web][:base_directory] = "/srv/www.openstreetmap.org"
-default[:web][:pid_directory] = "/var/run/web"
+default[:web][:pid_directory] = "/run/web"
 default[:web][:log_directory] = "/var/log/web"
 default[:web][:primary_cluster] = false
+default[:web][:max_request_area] = 0.25
+default[:web][:max_number_of_nodes] = 50000
+default[:web][:max_number_of_way_nodes] = 2000
+default[:web][:max_number_of_relation_members] = 32000
+
+default[:accounts][:users][:rails][:status] = :role
diff --git a/cookbooks/web/files/default/static/openlayers/OpenLayers.js b/cookbooks/web/files/default/static/openlayers/OpenLayers.js
new file mode 100644 (file)
index 0000000..ad5df5a
--- /dev/null
@@ -0,0 +1,1422 @@
+/*
+
+  OpenLayers.js -- OpenLayers Map Viewer Library
+
+  Copyright (c) 2006-2012 by OpenLayers Contributors
+  Published under the 2-clause BSD license.
+  See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.
+
+  Includes compressed code under the following licenses:
+
+  (For uncompressed versions of the code used, please see the
+  OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
+
+*/
+
+/**
+ * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
+ * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+/**
+ * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
+ * Copyright (c) 2006, Yahoo! Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use of this software in source and binary forms, with or
+ * without modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
+ *   used to endorse or promote products derived from this software without
+ *   specific prior written permission of Yahoo! Inc.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+var OpenLayers={VERSION_NUMBER:"Release 2.12",singleFile:true,_getScriptLocation:(function(){var r=new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"),s=document.getElementsByTagName('script'),src,m,l="";for(var i=0,len=s.length;i<len;i++){src=s[i].getAttribute('src');if(src){m=src.match(r);if(m){l=m[1];break;}}}
+return(function(){return l;});})(),ImgPath:''};OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s\s*/,'').replace(/\s\s*$/,'');},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1,len=oStringList.length;i<len;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
+return camelizedString;},format:function(template,context,args){if(!context){context=window;}
+var replacer=function(str,match){var replacement;var subs=match.split(/\.+/);for(var i=0;i<subs.length;i++){if(i==0){replacement=context;}
+replacement=replacement[subs[i]];}
+if(typeof replacement=="function"){replacement=args?replacement.apply(null,args):replacement();}
+if(typeof replacement=='undefined'){return'undefined';}else{return replacement;}};return template.replace(OpenLayers.String.tokenRegEx,replacer);},tokenRegEx:/\$\{([\w.]+?)\}/g,numberRegEx:/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,isNumeric:function(value){return OpenLayers.String.numberRegEx.test(value);},numericIf:function(value){return OpenLayers.String.isNumeric(value)?parseFloat(value):value;}};OpenLayers.Number={decimalSeparator:".",thousandsSeparator:",",limitSigDigs:function(num,sig){var fig=0;if(sig>0){fig=parseFloat(num.toPrecision(sig));}
+return fig;},format:function(num,dec,tsep,dsep){dec=(typeof dec!="undefined")?dec:0;tsep=(typeof tsep!="undefined")?tsep:OpenLayers.Number.thousandsSeparator;dsep=(typeof dsep!="undefined")?dsep:OpenLayers.Number.decimalSeparator;if(dec!=null){num=parseFloat(num.toFixed(dec));}
+var parts=num.toString().split(".");if(parts.length==1&&dec==null){dec=0;}
+var integer=parts[0];if(tsep){var thousands=/(-?[0-9]+)([0-9]{3})/;while(thousands.test(integer)){integer=integer.replace(thousands,"$1"+tsep+"$2");}}
+var str;if(dec==0){str=integer;}else{var rem=parts.length>1?parts[1]:"0";if(dec!=null){rem=rem+new Array(dec-rem.length+1).join("0");}
+str=integer+dsep+rem;}
+return str;}};OpenLayers.Function={bind:function(func,object){var args=Array.prototype.slice.apply(arguments,[2]);return function(){var newArgs=args.concat(Array.prototype.slice.apply(arguments,[0]));return func.apply(object,newArgs);};},bindAsEventListener:function(func,object){return function(event){return func.call(object,event||window.event);};},False:function(){return false;},True:function(){return true;},Void:function(){}};OpenLayers.Array={filter:function(array,callback,caller){var selected=[];if(Array.prototype.filter){selected=array.filter(callback,caller);}else{var len=array.length;if(typeof callback!="function"){throw new TypeError();}
+for(var i=0;i<len;i++){if(i in array){var val=array[i];if(callback.call(caller,val,i,array)){selected.push(val);}}}}
+return selected;}};OpenLayers.Class=function(){var len=arguments.length;var P=arguments[0];var F=arguments[len-1];var C=typeof F.initialize=="function"?F.initialize:function(){P.prototype.initialize.apply(this,arguments);};if(len>1){var newArgs=[C,P].concat(Array.prototype.slice.call(arguments).slice(1,len-1),F);OpenLayers.inherit.apply(null,newArgs);}else{C.prototype=F;}
+return C;};OpenLayers.inherit=function(C,P){var F=function(){};F.prototype=P.prototype;C.prototype=new F;var i,l,o;for(i=2,l=arguments.length;i<l;i++){o=arguments[i];if(typeof o==="function"){o=o.prototype;}
+OpenLayers.Util.extend(C.prototype,o);}};OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.extend=function(destination,source){destination=destination||{};if(source){for(var property in source){var value=source[property];if(value!==undefined){destination[property]=value;}}
+var sourceIsEvt=typeof window.Event=="function"&&source instanceof window.Event;if(!sourceIsEvt&&source.hasOwnProperty&&source.hasOwnProperty("toString")){destination.toString=source.toString;}}
+return destination;};OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,centerLonLat:null,initialize:function(left,bottom,right,top){if(OpenLayers.Util.isArray(left)){top=left[3];right=left[2];bottom=left[1];left=left[0];}
+if(left!=null){this.left=OpenLayers.Util.toFloat(left);}
+if(bottom!=null){this.bottom=OpenLayers.Util.toFloat(bottom);}
+if(right!=null){this.right=OpenLayers.Util.toFloat(right);}
+if(top!=null){this.top=OpenLayers.Util.toFloat(top);}},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top);},equals:function(bounds){var equals=false;if(bounds!=null){equals=((this.left==bounds.left)&&(this.right==bounds.right)&&(this.top==bounds.top)&&(this.bottom==bounds.bottom));}
+return equals;},toString:function(){return[this.left,this.bottom,this.right,this.top].join(",");},toArray:function(reverseAxisOrder){if(reverseAxisOrder===true){return[this.bottom,this.left,this.top,this.right];}else{return[this.left,this.bottom,this.right,this.top];}},toBBOX:function(decimal,reverseAxisOrder){if(decimal==null){decimal=6;}
+var mult=Math.pow(10,decimal);var xmin=Math.round(this.left*mult)/mult;var ymin=Math.round(this.bottom*mult)/mult;var xmax=Math.round(this.right*mult)/mult;var ymax=Math.round(this.top*mult)/mult;if(reverseAxisOrder===true){return ymin+","+xmin+","+ymax+","+xmax;}else{return xmin+","+ymin+","+xmax+","+ymax;}},toGeometry:function(){return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(this.left,this.bottom),new OpenLayers.Geometry.Point(this.right,this.bottom),new OpenLayers.Geometry.Point(this.right,this.top),new OpenLayers.Geometry.Point(this.left,this.top)])]);},getWidth:function(){return(this.right-this.left);},getHeight:function(){return(this.top-this.bottom);},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight());},getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2);},getCenterLonLat:function(){if(!this.centerLonLat){this.centerLonLat=new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2);}
+return this.centerLonLat;},scale:function(ratio,origin){if(origin==null){origin=this.getCenterLonLat();}
+var origx,origy;if(origin.CLASS_NAME=="OpenLayers.LonLat"){origx=origin.lon;origy=origin.lat;}else{origx=origin.x;origy=origin.y;}
+var left=(this.left-origx)*ratio+origx;var bottom=(this.bottom-origy)*ratio+origy;var right=(this.right-origx)*ratio+origx;var top=(this.top-origy)*ratio+origy;return new OpenLayers.Bounds(left,bottom,right,top);},add:function(x,y){if((x==null)||(y==null)){throw new TypeError('Bounds.add cannot receive null values');}
+return new OpenLayers.Bounds(this.left+x,this.bottom+y,this.right+x,this.top+y);},extend:function(object){var bounds=null;if(object){switch(object.CLASS_NAME){case"OpenLayers.LonLat":bounds=new OpenLayers.Bounds(object.lon,object.lat,object.lon,object.lat);break;case"OpenLayers.Geometry.Point":bounds=new OpenLayers.Bounds(object.x,object.y,object.x,object.y);break;case"OpenLayers.Bounds":bounds=object;break;}
+if(bounds){this.centerLonLat=null;if((this.left==null)||(bounds.left<this.left)){this.left=bounds.left;}
+if((this.bottom==null)||(bounds.bottom<this.bottom)){this.bottom=bounds.bottom;}
+if((this.right==null)||(bounds.right>this.right)){this.right=bounds.right;}
+if((this.top==null)||(bounds.top>this.top)){this.top=bounds.top;}}}},containsLonLat:function(ll,options){if(typeof options==="boolean"){options={inclusive:options};}
+options=options||{};var contains=this.contains(ll.lon,ll.lat,options.inclusive),worldBounds=options.worldBounds;if(worldBounds&&!contains){var worldWidth=worldBounds.getWidth();var worldCenterX=(worldBounds.left+worldBounds.right)/2;var worldsAway=Math.round((ll.lon-worldCenterX)/worldWidth);contains=this.containsLonLat({lon:ll.lon-worldsAway*worldWidth,lat:ll.lat},{inclusive:options.inclusive});}
+return contains;},containsPixel:function(px,inclusive){return this.contains(px.x,px.y,inclusive);},contains:function(x,y,inclusive){if(inclusive==null){inclusive=true;}
+if(x==null||y==null){return false;}
+x=OpenLayers.Util.toFloat(x);y=OpenLayers.Util.toFloat(y);var contains=false;if(inclusive){contains=((x>=this.left)&&(x<=this.right)&&(y>=this.bottom)&&(y<=this.top));}else{contains=((x>this.left)&&(x<this.right)&&(y>this.bottom)&&(y<this.top));}
+return contains;},intersectsBounds:function(bounds,options){if(typeof options==="boolean"){options={inclusive:options};}
+options=options||{};if(options.worldBounds){var self=this.wrapDateLine(options.worldBounds);bounds=bounds.wrapDateLine(options.worldBounds);}else{self=this;}
+if(options.inclusive==null){options.inclusive=true;}
+var intersects=false;var mightTouch=(self.left==bounds.right||self.right==bounds.left||self.top==bounds.bottom||self.bottom==bounds.top);if(options.inclusive||!mightTouch){var inBottom=(((bounds.bottom>=self.bottom)&&(bounds.bottom<=self.top))||((self.bottom>=bounds.bottom)&&(self.bottom<=bounds.top)));var inTop=(((bounds.top>=self.bottom)&&(bounds.top<=self.top))||((self.top>bounds.bottom)&&(self.top<bounds.top)));var inLeft=(((bounds.left>=self.left)&&(bounds.left<=self.right))||((self.left>=bounds.left)&&(self.left<=bounds.right)));var inRight=(((bounds.right>=self.left)&&(bounds.right<=self.right))||((self.right>=bounds.left)&&(self.right<=bounds.right)));intersects=((inBottom||inTop)&&(inLeft||inRight));}
+if(options.worldBounds&&!intersects){var world=options.worldBounds;var width=world.getWidth();var selfCrosses=!world.containsBounds(self);var boundsCrosses=!world.containsBounds(bounds);if(selfCrosses&&!boundsCrosses){bounds=bounds.add(-width,0);intersects=self.intersectsBounds(bounds,{inclusive:options.inclusive});}else if(boundsCrosses&&!selfCrosses){self=self.add(-width,0);intersects=bounds.intersectsBounds(self,{inclusive:options.inclusive});}}
+return intersects;},containsBounds:function(bounds,partial,inclusive){if(partial==null){partial=false;}
+if(inclusive==null){inclusive=true;}
+var bottomLeft=this.contains(bounds.left,bounds.bottom,inclusive);var bottomRight=this.contains(bounds.right,bounds.bottom,inclusive);var topLeft=this.contains(bounds.left,bounds.top,inclusive);var topRight=this.contains(bounds.right,bounds.top,inclusive);return(partial)?(bottomLeft||bottomRight||topLeft||topRight):(bottomLeft&&bottomRight&&topLeft&&topRight);},determineQuadrant:function(lonlat){var quadrant="";var center=this.getCenterLonLat();quadrant+=(lonlat.lat<center.lat)?"b":"t";quadrant+=(lonlat.lon<center.lon)?"l":"r";return quadrant;},transform:function(source,dest){this.centerLonLat=null;var ll=OpenLayers.Projection.transform({'x':this.left,'y':this.bottom},source,dest);var lr=OpenLayers.Projection.transform({'x':this.right,'y':this.bottom},source,dest);var ul=OpenLayers.Projection.transform({'x':this.left,'y':this.top},source,dest);var ur=OpenLayers.Projection.transform({'x':this.right,'y':this.top},source,dest);this.left=Math.min(ll.x,ul.x);this.bottom=Math.min(ll.y,lr.y);this.right=Math.max(lr.x,ur.x);this.top=Math.max(ul.y,ur.y);return this;},wrapDateLine:function(maxExtent,options){options=options||{};var leftTolerance=options.leftTolerance||0;var rightTolerance=options.rightTolerance||0;var newBounds=this.clone();if(maxExtent){var width=maxExtent.getWidth();while(newBounds.left<maxExtent.left&&newBounds.right-rightTolerance<=maxExtent.left){newBounds=newBounds.add(width,0);}
+while(newBounds.left+leftTolerance>=maxExtent.right&&newBounds.right>maxExtent.right){newBounds=newBounds.add(-width,0);}
+var newLeft=newBounds.left+leftTolerance;if(newLeft<maxExtent.right&&newLeft>maxExtent.left&&newBounds.right-rightTolerance>maxExtent.right){newBounds=newBounds.add(-width,0);}}
+return newBounds;},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(str,reverseAxisOrder){var bounds=str.split(",");return OpenLayers.Bounds.fromArray(bounds,reverseAxisOrder);};OpenLayers.Bounds.fromArray=function(bbox,reverseAxisOrder){return reverseAxisOrder===true?new OpenLayers.Bounds(bbox[1],bbox[0],bbox[3],bbox[2]):new OpenLayers.Bounds(bbox[0],bbox[1],bbox[2],bbox[3]);};OpenLayers.Bounds.fromSize=function(size){return new OpenLayers.Bounds(0,size.h,size.w,0);};OpenLayers.Bounds.oppositeQuadrant=function(quadrant){var opp="";opp+=(quadrant.charAt(0)=='t')?'b':'t';opp+=(quadrant.charAt(1)=='l')?'r':'l';return opp;};OpenLayers.Element={visible:function(element){return OpenLayers.Util.getElement(element).style.display!='none';},toggle:function(){for(var i=0,len=arguments.length;i<len;i++){var element=OpenLayers.Util.getElement(arguments[i]);var display=OpenLayers.Element.visible(element)?'none':'';element.style.display=display;}},remove:function(element){element=OpenLayers.Util.getElement(element);element.parentNode.removeChild(element);},getHeight:function(element){element=OpenLayers.Util.getElement(element);return element.offsetHeight;},hasClass:function(element,name){var names=element.className;return(!!names&&new RegExp("(^|\\s)"+name+"(\\s|$)").test(names));},addClass:function(element,name){if(!OpenLayers.Element.hasClass(element,name)){element.className+=(element.className?" ":"")+name;}
+return element;},removeClass:function(element,name){var names=element.className;if(names){element.className=OpenLayers.String.trim(names.replace(new RegExp("(^|\\s+)"+name+"(\\s+|$)")," "));}
+return element;},toggleClass:function(element,name){if(OpenLayers.Element.hasClass(element,name)){OpenLayers.Element.removeClass(element,name);}else{OpenLayers.Element.addClass(element,name);}
+return element;},getStyle:function(element,style){element=OpenLayers.Util.getElement(element);var value=null;if(element&&element.style){value=element.style[OpenLayers.String.camelize(style)];if(!value){if(document.defaultView&&document.defaultView.getComputedStyle){var css=document.defaultView.getComputedStyle(element,null);value=css?css.getPropertyValue(style):null;}else if(element.currentStyle){value=element.currentStyle[OpenLayers.String.camelize(style)];}}
+var positions=['left','top','right','bottom'];if(window.opera&&(OpenLayers.Util.indexOf(positions,style)!=-1)&&(OpenLayers.Element.getStyle(element,'position')=='static')){value='auto';}}
+return value=='auto'?null:value;}};OpenLayers.LonLat=OpenLayers.Class({lon:0.0,lat:0.0,initialize:function(lon,lat){if(OpenLayers.Util.isArray(lon)){lat=lon[1];lon=lon[0];}
+this.lon=OpenLayers.Util.toFloat(lon);this.lat=OpenLayers.Util.toFloat(lat);},toString:function(){return("lon="+this.lon+",lat="+this.lat);},toShortString:function(){return(this.lon+", "+this.lat);},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat);},add:function(lon,lat){if((lon==null)||(lat==null)){throw new TypeError('LonLat.add cannot receive null values');}
+return new OpenLayers.LonLat(this.lon+OpenLayers.Util.toFloat(lon),this.lat+OpenLayers.Util.toFloat(lat));},equals:function(ll){var equals=false;if(ll!=null){equals=((this.lon==ll.lon&&this.lat==ll.lat)||(isNaN(this.lon)&&isNaN(this.lat)&&isNaN(ll.lon)&&isNaN(ll.lat)));}
+return equals;},transform:function(source,dest){var point=OpenLayers.Projection.transform({'x':this.lon,'y':this.lat},source,dest);this.lon=point.x;this.lat=point.y;return this;},wrapDateLine:function(maxExtent){var newLonLat=this.clone();if(maxExtent){while(newLonLat.lon<maxExtent.left){newLonLat.lon+=maxExtent.getWidth();}
+while(newLonLat.lon>maxExtent.right){newLonLat.lon-=maxExtent.getWidth();}}
+return newLonLat;},CLASS_NAME:"OpenLayers.LonLat"});OpenLayers.LonLat.fromString=function(str){var pair=str.split(",");return new OpenLayers.LonLat(pair[0],pair[1]);};OpenLayers.LonLat.fromArray=function(arr){var gotArr=OpenLayers.Util.isArray(arr),lon=gotArr&&arr[0],lat=gotArr&&arr[1];return new OpenLayers.LonLat(lon,lat);};OpenLayers.Pixel=OpenLayers.Class({x:0.0,y:0.0,initialize:function(x,y){this.x=parseFloat(x);this.y=parseFloat(y);},toString:function(){return("x="+this.x+",y="+this.y);},clone:function(){return new OpenLayers.Pixel(this.x,this.y);},equals:function(px){var equals=false;if(px!=null){equals=((this.x==px.x&&this.y==px.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(px.x)&&isNaN(px.y)));}
+return equals;},distanceTo:function(px){return Math.sqrt(Math.pow(this.x-px.x,2)+
+Math.pow(this.y-px.y,2));},add:function(x,y){if((x==null)||(y==null)){throw new TypeError('Pixel.add cannot receive null values');}
+return new OpenLayers.Pixel(this.x+x,this.y+y);},offset:function(px){var newPx=this.clone();if(px){newPx=this.add(px.x,px.y);}
+return newPx;},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0.0,h:0.0,initialize:function(w,h){this.w=parseFloat(w);this.h=parseFloat(h);},toString:function(){return("w="+this.w+",h="+this.h);},clone:function(){return new OpenLayers.Size(this.w,this.h);},equals:function(sz){var equals=false;if(sz!=null){equals=((this.w==sz.w&&this.h==sz.h)||(isNaN(this.w)&&isNaN(this.h)&&isNaN(sz.w)&&isNaN(sz.h)));}
+return equals;},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(error){alert(error);},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};(function(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("firebug.js")!=-1){if(console){OpenLayers.Util.extend(OpenLayers.Console,console);break;}}}})();OpenLayers.Lang={code:null,defaultCode:"en",getCode:function(){if(!OpenLayers.Lang.code){OpenLayers.Lang.setCode();}
+return OpenLayers.Lang.code;},setCode:function(code){var lang;if(!code){code=(OpenLayers.BROWSER_NAME=="msie")?navigator.userLanguage:navigator.language;}
+var parts=code.split('-');parts[0]=parts[0].toLowerCase();if(typeof OpenLayers.Lang[parts[0]]=="object"){lang=parts[0];}
+if(parts[1]){var testLang=parts[0]+'-'+parts[1].toUpperCase();if(typeof OpenLayers.Lang[testLang]=="object"){lang=testLang;}}
+if(!lang){OpenLayers.Console.warn('Failed to find OpenLayers.Lang.'+parts.join("-")+' dictionary, falling back to default language');lang=OpenLayers.Lang.defaultCode;}
+OpenLayers.Lang.code=lang;},translate:function(key,context){var dictionary=OpenLayers.Lang[OpenLayers.Lang.getCode()];var message=dictionary&&dictionary[key];if(!message){message=key;}
+if(context){message=OpenLayers.String.format(message,context);}
+return message;}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.getElement=function(){var elements=[];for(var i=0,len=arguments.length;i<len;i++){var element=arguments[i];if(typeof element=='string'){element=document.getElementById(element);}
+if(arguments.length==1){return element;}
+elements.push(element);}
+return elements;};OpenLayers.Util.isElement=function(o){return!!(o&&o.nodeType===1);};OpenLayers.Util.isArray=function(a){return(Object.prototype.toString.call(a)==='[object Array]');};if(typeof window.$==="undefined"){window.$=OpenLayers.Util.getElement;}
+OpenLayers.Util.removeItem=function(array,item){for(var i=array.length-1;i>=0;i--){if(array[i]==item){array.splice(i,1);}}
+return array;};OpenLayers.Util.indexOf=function(array,obj){if(typeof array.indexOf=="function"){return array.indexOf(obj);}else{for(var i=0,len=array.length;i<len;i++){if(array[i]==obj){return i;}}
+return-1;}};OpenLayers.Util.modifyDOMElement=function(element,id,px,sz,position,border,overflow,opacity){if(id){element.id=id;}
+if(px){element.style.left=px.x+"px";element.style.top=px.y+"px";}
+if(sz){element.style.width=sz.w+"px";element.style.height=sz.h+"px";}
+if(position){element.style.position=position;}
+if(border){element.style.border=border;}
+if(overflow){element.style.overflow=overflow;}
+if(parseFloat(opacity)>=0.0&&parseFloat(opacity)<1.0){element.style.filter='alpha(opacity='+(opacity*100)+')';element.style.opacity=opacity;}else if(parseFloat(opacity)==1.0){element.style.filter='';element.style.opacity='';}};OpenLayers.Util.createDiv=function(id,px,sz,imgURL,position,border,overflow,opacity){var dom=document.createElement('div');if(imgURL){dom.style.backgroundImage='url('+imgURL+')';}
+if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
+if(!position){position="absolute";}
+OpenLayers.Util.modifyDOMElement(dom,id,px,sz,position,border,overflow,opacity);return dom;};OpenLayers.Util.createImage=function(id,px,sz,imgURL,position,border,opacity,delayDisplay){var image=document.createElement("img");if(!id){id=OpenLayers.Util.createUniqueID("OpenLayersDiv");}
+if(!position){position="relative";}
+OpenLayers.Util.modifyDOMElement(image,id,px,sz,position,border,null,opacity);if(delayDisplay){image.style.display="none";function display(){image.style.display="";OpenLayers.Event.stopObservingElement(image);}
+OpenLayers.Event.observe(image,"load",display);OpenLayers.Event.observe(image,"error",display);}
+image.style.alt=id;image.galleryImg="no";if(imgURL){image.src=imgURL;}
+return image;};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var arVersion=navigator.appVersion.split("MSIE");var version=parseFloat(arVersion[1]);var filter=false;try{filter=!!(document.body.filters);}catch(e){}
+OpenLayers.Util.alphaHackNeeded=(filter&&(version>=5.5)&&(version<7));}
+return OpenLayers.Util.alphaHackNeeded;};OpenLayers.Util.modifyAlphaImageDiv=function(div,id,px,sz,imgURL,position,border,sizing,opacity){OpenLayers.Util.modifyDOMElement(div,id,px,sz,position,null,null,opacity);var img=div.childNodes[0];if(imgURL){img.src=imgURL;}
+OpenLayers.Util.modifyDOMElement(img,div.id+"_innerImage",null,sz,"relative",border);if(OpenLayers.Util.alphaHack()){if(div.style.display!="none"){div.style.display="inline-block";}
+if(sizing==null){sizing="scale";}
+div.style.filter="progid:DXImageTransform.Microsoft"+".AlphaImageLoader(src='"+img.src+"', "+"sizingMethod='"+sizing+"')";if(parseFloat(div.style.opacity)>=0.0&&parseFloat(div.style.opacity)<1.0){div.style.filter+=" alpha(opacity="+div.style.opacity*100+")";}
+img.style.filter="alpha(opacity=0)";}};OpenLayers.Util.createAlphaImageDiv=function(id,px,sz,imgURL,position,border,sizing,opacity,delayDisplay){var div=OpenLayers.Util.createDiv();var img=OpenLayers.Util.createImage(null,null,null,null,null,null,null,delayDisplay);img.className="olAlphaImg";div.appendChild(img);OpenLayers.Util.modifyAlphaImageDiv(div,id,px,sz,imgURL,position,border,sizing,opacity);return div;};OpenLayers.Util.upperCaseObject=function(object){var uObject={};for(var key in object){uObject[key.toUpperCase()]=object[key];}
+return uObject;};OpenLayers.Util.applyDefaults=function(to,from){to=to||{};var fromIsEvt=typeof window.Event=="function"&&from instanceof window.Event;for(var key in from){if(to[key]===undefined||(!fromIsEvt&&from.hasOwnProperty&&from.hasOwnProperty(key)&&!to.hasOwnProperty(key))){to[key]=from[key];}}
+if(!fromIsEvt&&from&&from.hasOwnProperty&&from.hasOwnProperty('toString')&&!to.hasOwnProperty('toString')){to.toString=from.toString;}
+return to;};OpenLayers.Util.getParameterString=function(params){var paramsArray=[];for(var key in params){var value=params[key];if((value!=null)&&(typeof value!='function')){var encodedValue;if(typeof value=='object'&&value.constructor==Array){var encodedItemArray=[];var item;for(var itemIndex=0,len=value.length;itemIndex<len;itemIndex++){item=value[itemIndex];encodedItemArray.push(encodeURIComponent((item===null||item===undefined)?"":item));}
+encodedValue=encodedItemArray.join(",");}
+else{encodedValue=encodeURIComponent(value);}
+paramsArray.push(encodeURIComponent(key)+"="+encodedValue);}}
+return paramsArray.join("&");};OpenLayers.Util.urlAppend=function(url,paramStr){var newUrl=url;if(paramStr){var parts=(url+" ").split(/[?&]/);newUrl+=(parts.pop()===" "?paramStr:parts.length?"&"+paramStr:"?"+paramStr);}
+return newUrl;};OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||(OpenLayers._getScriptLocation()+"img/");};OpenLayers.Util.getImageLocation=function(image){return OpenLayers.Util.getImagesLocation()+image;};OpenLayers.Util.Try=function(){var returnValue=null;for(var i=0,len=arguments.length;i<len;i++){var lambda=arguments[i];try{returnValue=lambda();break;}catch(e){}}
+return returnValue;};OpenLayers.Util.getXmlNodeValue=function(node){var val=null;OpenLayers.Util.Try(function(){val=node.text;if(!val){val=node.textContent;}
+if(!val){val=node.firstChild.nodeValue;}},function(){val=node.textContent;});return val;};OpenLayers.Util.mouseLeft=function(evt,div){var target=(evt.relatedTarget)?evt.relatedTarget:evt.toElement;while(target!=div&&target!=null){target=target.parentNode;}
+return(target!=div);};OpenLayers.Util.DEFAULT_PRECISION=14;OpenLayers.Util.toFloat=function(number,precision){if(precision==null){precision=OpenLayers.Util.DEFAULT_PRECISION;}
+if(typeof number!=="number"){number=parseFloat(number);}
+return precision===0?number:parseFloat(number.toPrecision(precision));};OpenLayers.Util.rad=function(x){return x*Math.PI/180;};OpenLayers.Util.deg=function(x){return x*180/Math.PI;};OpenLayers.Util.VincentyConstants={a:6378137,b:6356752.3142,f:1/298.257223563};OpenLayers.Util.distVincenty=function(p1,p2){var ct=OpenLayers.Util.VincentyConstants;var a=ct.a,b=ct.b,f=ct.f;var L=OpenLayers.Util.rad(p2.lon-p1.lon);var U1=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p1.lat)));var U2=Math.atan((1-f)*Math.tan(OpenLayers.Util.rad(p2.lat)));var sinU1=Math.sin(U1),cosU1=Math.cos(U1);var sinU2=Math.sin(U2),cosU2=Math.cos(U2);var lambda=L,lambdaP=2*Math.PI;var iterLimit=20;while(Math.abs(lambda-lambdaP)>1e-12&&--iterLimit>0){var sinLambda=Math.sin(lambda),cosLambda=Math.cos(lambda);var sinSigma=Math.sqrt((cosU2*sinLambda)*(cosU2*sinLambda)+
+(cosU1*sinU2-sinU1*cosU2*cosLambda)*(cosU1*sinU2-sinU1*cosU2*cosLambda));if(sinSigma==0){return 0;}
+var cosSigma=sinU1*sinU2+cosU1*cosU2*cosLambda;var sigma=Math.atan2(sinSigma,cosSigma);var alpha=Math.asin(cosU1*cosU2*sinLambda/sinSigma);var cosSqAlpha=Math.cos(alpha)*Math.cos(alpha);var cos2SigmaM=cosSigma-2*sinU1*sinU2/cosSqAlpha;var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));lambdaP=lambda;lambda=L+(1-C)*f*Math.sin(alpha)*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));}
+if(iterLimit==0){return NaN;}
+var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
+B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));var s=b*A*(sigma-deltaSigma);var d=s.toFixed(3)/1000;return d;};OpenLayers.Util.destinationVincenty=function(lonlat,brng,dist){var u=OpenLayers.Util;var ct=u.VincentyConstants;var a=ct.a,b=ct.b,f=ct.f;var lon1=lonlat.lon;var lat1=lonlat.lat;var s=dist;var alpha1=u.rad(brng);var sinAlpha1=Math.sin(alpha1);var cosAlpha1=Math.cos(alpha1);var tanU1=(1-f)*Math.tan(u.rad(lat1));var cosU1=1/Math.sqrt((1+tanU1*tanU1)),sinU1=tanU1*cosU1;var sigma1=Math.atan2(tanU1,cosAlpha1);var sinAlpha=cosU1*sinAlpha1;var cosSqAlpha=1-sinAlpha*sinAlpha;var uSq=cosSqAlpha*(a*a-b*b)/(b*b);var A=1+uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));var B=uSq/1024*(256+uSq*(-128+uSq*(74-47*uSq)));var sigma=s/(b*A),sigmaP=2*Math.PI;while(Math.abs(sigma-sigmaP)>1e-12){var cos2SigmaM=Math.cos(2*sigma1+sigma);var sinSigma=Math.sin(sigma);var cosSigma=Math.cos(sigma);var deltaSigma=B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
+B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));sigmaP=sigma;sigma=s/(b*A)+deltaSigma;}
+var tmp=sinU1*sinSigma-cosU1*cosSigma*cosAlpha1;var lat2=Math.atan2(sinU1*cosSigma+cosU1*sinSigma*cosAlpha1,(1-f)*Math.sqrt(sinAlpha*sinAlpha+tmp*tmp));var lambda=Math.atan2(sinSigma*sinAlpha1,cosU1*cosSigma-sinU1*sinSigma*cosAlpha1);var C=f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));var L=lambda-(1-C)*f*sinAlpha*(sigma+C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));var revAz=Math.atan2(sinAlpha,-tmp);return new OpenLayers.LonLat(lon1+u.deg(L),u.deg(lat2));};OpenLayers.Util.getParameters=function(url){url=(url===null||url===undefined)?window.location.href:url;var paramsString="";if(OpenLayers.String.contains(url,'?')){var start=url.indexOf('?')+1;var end=OpenLayers.String.contains(url,"#")?url.indexOf('#'):url.length;paramsString=url.substring(start,end);}
+var parameters={};var pairs=paramsString.split(/[&;]/);for(var i=0,len=pairs.length;i<len;++i){var keyValue=pairs[i].split('=');if(keyValue[0]){var key=keyValue[0];try{key=decodeURIComponent(key);}catch(err){key=unescape(key);}
+var value=(keyValue[1]||'').replace(/\+/g," ");try{value=decodeURIComponent(value);}catch(err){value=unescape(value);}
+value=value.split(",");if(value.length==1){value=value[0];}
+parameters[key]=value;}}
+return parameters;};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(prefix){if(prefix==null){prefix="id_";}
+OpenLayers.Util.lastSeqID+=1;return prefix+OpenLayers.Util.lastSeqID;};OpenLayers.INCHES_PER_UNIT={'inches':1.0,'ft':12.0,'mi':63360.0,'m':39.3701,'km':39370.1,'dd':4374754,'yd':36};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT["degrees"]=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.INCHES_PER_UNIT["nmi"]=1852*OpenLayers.INCHES_PER_UNIT.m;OpenLayers.METERS_PER_INCH=0.02540005080010160020;OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{"Inch":OpenLayers.INCHES_PER_UNIT.inches,"Meter":1.0/OpenLayers.METERS_PER_INCH,"Foot":0.30480060960121920243/OpenLayers.METERS_PER_INCH,"IFoot":0.30480000000000000000/OpenLayers.METERS_PER_INCH,"ClarkeFoot":0.3047972651151/OpenLayers.METERS_PER_INCH,"SearsFoot":0.30479947153867624624/OpenLayers.METERS_PER_INCH,"GoldCoastFoot":0.30479971018150881758/OpenLayers.METERS_PER_INCH,"IInch":0.02540000000000000000/OpenLayers.METERS_PER_INCH,"MicroInch":0.00002540000000000000/OpenLayers.METERS_PER_INCH,"Mil":0.00000002540000000000/OpenLayers.METERS_PER_INCH,"Centimeter":0.01000000000000000000/OpenLayers.METERS_PER_INCH,"Kilometer":1000.00000000000000000000/OpenLayers.METERS_PER_INCH,"Yard":0.91440182880365760731/OpenLayers.METERS_PER_INCH,"SearsYard":0.914398414616029/OpenLayers.METERS_PER_INCH,"IndianYard":0.91439853074444079983/OpenLayers.METERS_PER_INCH,"IndianYd37":0.91439523/OpenLayers.METERS_PER_INCH,"IndianYd62":0.9143988/OpenLayers.METERS_PER_INCH,"IndianYd75":0.9143985/OpenLayers.METERS_PER_INCH,"IndianFoot":0.30479951/OpenLayers.METERS_PER_INCH,"IndianFt37":0.30479841/OpenLayers.METERS_PER_INCH,"IndianFt62":0.3047996/OpenLayers.METERS_PER_INCH,"IndianFt75":0.3047995/OpenLayers.METERS_PER_INCH,"Mile":1609.34721869443738887477/OpenLayers.METERS_PER_INCH,"IYard":0.91440000000000000000/OpenLayers.METERS_PER_INCH,"IMile":1609.34400000000000000000/OpenLayers.METERS_PER_INCH,"NautM":1852.00000000000000000000/OpenLayers.METERS_PER_INCH,"Lat-66":110943.316488932731/OpenLayers.METERS_PER_INCH,"Lat-83":110946.25736872234125/OpenLayers.METERS_PER_INCH,"Decimeter":0.10000000000000000000/OpenLayers.METERS_PER_INCH,"Millimeter":0.00100000000000000000/OpenLayers.METERS_PER_INCH,"Dekameter":10.00000000000000000000/OpenLayers.METERS_PER_INCH,"Decameter":10.00000000000000000000/OpenLayers.METERS_PER_INCH,"Hectometer":100.00000000000000000000/OpenLayers.METERS_PER_INCH,"GermanMeter":1.0000135965/OpenLayers.METERS_PER_INCH,"CaGrid":0.999738/OpenLayers.METERS_PER_INCH,"ClarkeChain":20.1166194976/OpenLayers.METERS_PER_INCH,"GunterChain":20.11684023368047/OpenLayers.METERS_PER_INCH,"BenoitChain":20.116782494375872/OpenLayers.METERS_PER_INCH,"SearsChain":20.11676512155/OpenLayers.METERS_PER_INCH,"ClarkeLink":0.201166194976/OpenLayers.METERS_PER_INCH,"GunterLink":0.2011684023368047/OpenLayers.METERS_PER_INCH,"BenoitLink":0.20116782494375872/OpenLayers.METERS_PER_INCH,"SearsLink":0.2011676512155/OpenLayers.METERS_PER_INCH,"Rod":5.02921005842012/OpenLayers.METERS_PER_INCH,"IntnlChain":20.1168/OpenLayers.METERS_PER_INCH,"IntnlLink":0.201168/OpenLayers.METERS_PER_INCH,"Perch":5.02921005842012/OpenLayers.METERS_PER_INCH,"Pole":5.02921005842012/OpenLayers.METERS_PER_INCH,"Furlong":201.1684023368046/OpenLayers.METERS_PER_INCH,"Rood":3.778266898/OpenLayers.METERS_PER_INCH,"CapeFoot":0.3047972615/OpenLayers.METERS_PER_INCH,"Brealey":375.00000000000000000000/OpenLayers.METERS_PER_INCH,"ModAmFt":0.304812252984505969011938/OpenLayers.METERS_PER_INCH,"Fathom":1.8288/OpenLayers.METERS_PER_INCH,"NautM-UK":1853.184/OpenLayers.METERS_PER_INCH,"50kilometers":50000.0/OpenLayers.METERS_PER_INCH,"150kilometers":150000.0/OpenLayers.METERS_PER_INCH});OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{"mm":OpenLayers.INCHES_PER_UNIT["Meter"]/1000.0,"cm":OpenLayers.INCHES_PER_UNIT["Meter"]/100.0,"dm":OpenLayers.INCHES_PER_UNIT["Meter"]*100.0,"km":OpenLayers.INCHES_PER_UNIT["Meter"]*1000.0,"kmi":OpenLayers.INCHES_PER_UNIT["nmi"],"fath":OpenLayers.INCHES_PER_UNIT["Fathom"],"ch":OpenLayers.INCHES_PER_UNIT["IntnlChain"],"link":OpenLayers.INCHES_PER_UNIT["IntnlLink"],"us-in":OpenLayers.INCHES_PER_UNIT["inches"],"us-ft":OpenLayers.INCHES_PER_UNIT["Foot"],"us-yd":OpenLayers.INCHES_PER_UNIT["Yard"],"us-ch":OpenLayers.INCHES_PER_UNIT["GunterChain"],"us-mi":OpenLayers.INCHES_PER_UNIT["Mile"],"ind-yd":OpenLayers.INCHES_PER_UNIT["IndianYd37"],"ind-ft":OpenLayers.INCHES_PER_UNIT["IndianFt37"],"ind-ch":20.11669506/OpenLayers.METERS_PER_INCH});OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(scale){var normScale=(scale>1.0)?(1.0/scale):scale;return normScale;};OpenLayers.Util.getResolutionFromScale=function(scale,units){var resolution;if(scale){if(units==null){units="degrees";}
+var normScale=OpenLayers.Util.normalizeScale(scale);resolution=1/(normScale*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH);}
+return resolution;};OpenLayers.Util.getScaleFromResolution=function(resolution,units){if(units==null){units="degrees";}
+var scale=resolution*OpenLayers.INCHES_PER_UNIT[units]*OpenLayers.DOTS_PER_INCH;return scale;};OpenLayers.Util.pagePosition=function(forElement){var pos=[0,0];var viewportElement=OpenLayers.Util.getViewportElement();if(!forElement||forElement==window||forElement==viewportElement){return pos;}
+var BUGGY_GECKO_BOX_OBJECT=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(forElement,'position')=='absolute'&&(forElement.style.top==''||forElement.style.left=='');var parent=null;var box;if(forElement.getBoundingClientRect){box=forElement.getBoundingClientRect();var scrollTop=viewportElement.scrollTop;var scrollLeft=viewportElement.scrollLeft;pos[0]=box.left+scrollLeft;pos[1]=box.top+scrollTop;}else if(document.getBoxObjectFor&&!BUGGY_GECKO_BOX_OBJECT){box=document.getBoxObjectFor(forElement);var vpBox=document.getBoxObjectFor(viewportElement);pos[0]=box.screenX-vpBox.screenX;pos[1]=box.screenY-vpBox.screenY;}else{pos[0]=forElement.offsetLeft;pos[1]=forElement.offsetTop;parent=forElement.offsetParent;if(parent!=forElement){while(parent){pos[0]+=parent.offsetLeft;pos[1]+=parent.offsetTop;parent=parent.offsetParent;}}
+var browser=OpenLayers.BROWSER_NAME;if(browser=="opera"||(browser=="safari"&&OpenLayers.Element.getStyle(forElement,'position')=='absolute')){pos[1]-=document.body.offsetTop;}
+parent=forElement.offsetParent;while(parent&&parent!=document.body){pos[0]-=parent.scrollLeft;if(browser!="opera"||parent.tagName!='TR'){pos[1]-=parent.scrollTop;}
+parent=parent.offsetParent;}}
+return pos;};OpenLayers.Util.getViewportElement=function(){var viewportElement=arguments.callee.viewportElement;if(viewportElement==undefined){viewportElement=(OpenLayers.BROWSER_NAME=="msie"&&document.compatMode!='CSS1Compat')?document.body:document.documentElement;arguments.callee.viewportElement=viewportElement;}
+return viewportElement;};OpenLayers.Util.isEquivalentUrl=function(url1,url2,options){options=options||{};OpenLayers.Util.applyDefaults(options,{ignoreCase:true,ignorePort80:true,ignoreHash:true});var urlObj1=OpenLayers.Util.createUrlObject(url1,options);var urlObj2=OpenLayers.Util.createUrlObject(url2,options);for(var key in urlObj1){if(key!=="args"){if(urlObj1[key]!=urlObj2[key]){return false;}}}
+for(var key in urlObj1.args){if(urlObj1.args[key]!=urlObj2.args[key]){return false;}
+delete urlObj2.args[key];}
+for(var key in urlObj2.args){return false;}
+return true;};OpenLayers.Util.createUrlObject=function(url,options){options=options||{};if(!(/^\w+:\/\//).test(url)){var loc=window.location;var port=loc.port?":"+loc.port:"";var fullUrl=loc.protocol+"//"+loc.host.split(":").shift()+port;if(url.indexOf("/")===0){url=fullUrl+url;}else{var parts=loc.pathname.split("/");parts.pop();url=fullUrl+parts.join("/")+"/"+url;}}
+if(options.ignoreCase){url=url.toLowerCase();}
+var a=document.createElement('a');a.href=url;var urlObject={};urlObject.host=a.host.split(":").shift();urlObject.protocol=a.protocol;if(options.ignorePort80){urlObject.port=(a.port=="80"||a.port=="0")?"":a.port;}else{urlObject.port=(a.port==""||a.port=="0")?"80":a.port;}
+urlObject.hash=(options.ignoreHash||a.hash==="#")?"":a.hash;var queryString=a.search;if(!queryString){var qMark=url.indexOf("?");queryString=(qMark!=-1)?url.substr(qMark):"";}
+urlObject.args=OpenLayers.Util.getParameters(queryString);urlObject.pathname=(a.pathname.charAt(0)=="/")?a.pathname:"/"+a.pathname;return urlObject;};OpenLayers.Util.removeTail=function(url){var head=null;var qMark=url.indexOf("?");var hashMark=url.indexOf("#");if(qMark==-1){head=(hashMark!=-1)?url.substr(0,hashMark):url;}else{head=(hashMark!=-1)?url.substr(0,Math.min(qMark,hashMark)):url.substr(0,qMark);}
+return head;};OpenLayers.IS_GECKO=(function(){var ua=navigator.userAgent.toLowerCase();return ua.indexOf("webkit")==-1&&ua.indexOf("gecko")!=-1;})();OpenLayers.CANVAS_SUPPORTED=(function(){var elem=document.createElement('canvas');return!!(elem.getContext&&elem.getContext('2d'));})();OpenLayers.BROWSER_NAME=(function(){var name="";var ua=navigator.userAgent.toLowerCase();if(ua.indexOf("opera")!=-1){name="opera";}else if(ua.indexOf("msie")!=-1){name="msie";}else if(ua.indexOf("safari")!=-1){name="safari";}else if(ua.indexOf("mozilla")!=-1){if(ua.indexOf("firefox")!=-1){name="firefox";}else{name="mozilla";}}
+return name;})();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME;};OpenLayers.Util.getRenderedDimensions=function(contentHTML,size,options){var w,h;var container=document.createElement("div");container.style.visibility="hidden";var containerElement=(options&&options.containerElement)?options.containerElement:document.body;var parentHasPositionAbsolute=false;var superContainer=null;var parent=containerElement;while(parent&&parent.tagName.toLowerCase()!="body"){var parentPosition=OpenLayers.Element.getStyle(parent,"position");if(parentPosition=="absolute"){parentHasPositionAbsolute=true;break;}else if(parentPosition&&parentPosition!="static"){break;}
+parent=parent.parentNode;}
+if(parentHasPositionAbsolute&&(containerElement.clientHeight===0||containerElement.clientWidth===0)){superContainer=document.createElement("div");superContainer.style.visibility="hidden";superContainer.style.position="absolute";superContainer.style.overflow="visible";superContainer.style.width=document.body.clientWidth+"px";superContainer.style.height=document.body.clientHeight+"px";superContainer.appendChild(container);}
+container.style.position="absolute";if(size){if(size.w){w=size.w;container.style.width=w+"px";}else if(size.h){h=size.h;container.style.height=h+"px";}}
+if(options&&options.displayClass){container.className=options.displayClass;}
+var content=document.createElement("div");content.innerHTML=contentHTML;content.style.overflow="visible";if(content.childNodes){for(var i=0,l=content.childNodes.length;i<l;i++){if(!content.childNodes[i].style)continue;content.childNodes[i].style.overflow="visible";}}
+container.appendChild(content);if(superContainer){containerElement.appendChild(superContainer);}else{containerElement.appendChild(container);}
+if(!w){w=parseInt(content.scrollWidth);container.style.width=w+"px";}
+if(!h){h=parseInt(content.scrollHeight);}
+container.removeChild(content);if(superContainer){superContainer.removeChild(container);containerElement.removeChild(superContainer);}else{containerElement.removeChild(container);}
+return new OpenLayers.Size(w,h);};OpenLayers.Util.getScrollbarWidth=function(){var scrollbarWidth=OpenLayers.Util._scrollbarWidth;if(scrollbarWidth==null){var scr=null;var inn=null;var wNoScroll=0;var wScroll=0;scr=document.createElement('div');scr.style.position='absolute';scr.style.top='-1000px';scr.style.left='-1000px';scr.style.width='100px';scr.style.height='50px';scr.style.overflow='hidden';inn=document.createElement('div');inn.style.width='100%';inn.style.height='200px';scr.appendChild(inn);document.body.appendChild(scr);wNoScroll=inn.offsetWidth;scr.style.overflow='scroll';wScroll=inn.offsetWidth;document.body.removeChild(document.body.lastChild);OpenLayers.Util._scrollbarWidth=(wNoScroll-wScroll);scrollbarWidth=OpenLayers.Util._scrollbarWidth;}
+return scrollbarWidth;};OpenLayers.Util.getFormattedLonLat=function(coordinate,axis,dmsOption){if(!dmsOption){dmsOption='dms';}
+coordinate=(coordinate+540)%360-180;var abscoordinate=Math.abs(coordinate);var coordinatedegrees=Math.floor(abscoordinate);var coordinateminutes=(abscoordinate-coordinatedegrees)/(1/60);var tempcoordinateminutes=coordinateminutes;coordinateminutes=Math.floor(coordinateminutes);var coordinateseconds=(tempcoordinateminutes-coordinateminutes)/(1/60);coordinateseconds=Math.round(coordinateseconds*10);coordinateseconds/=10;if(coordinateseconds>=60){coordinateseconds-=60;coordinateminutes+=1;if(coordinateminutes>=60){coordinateminutes-=60;coordinatedegrees+=1;}}
+if(coordinatedegrees<10){coordinatedegrees="0"+coordinatedegrees;}
+var str=coordinatedegrees+"\u00B0";if(dmsOption.indexOf('dm')>=0){if(coordinateminutes<10){coordinateminutes="0"+coordinateminutes;}
+str+=coordinateminutes+"'";if(dmsOption.indexOf('dms')>=0){if(coordinateseconds<10){coordinateseconds="0"+coordinateseconds;}
+str+=coordinateseconds+'"';}}
+if(axis=="lon"){str+=coordinate<0?OpenLayers.i18n("W"):OpenLayers.i18n("E");}else{str+=coordinate<0?OpenLayers.i18n("S"):OpenLayers.i18n("N");}
+return str;};OpenLayers.Event={observers:false,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(event){return event.target||event.srcElement;},isSingleTouch:function(event){return event.touches&&event.touches.length==1;},isMultiTouch:function(event){return event.touches&&event.touches.length>1;},isLeftClick:function(event){return(((event.which)&&(event.which==1))||((event.button)&&(event.button==1)));},isRightClick:function(event){return(((event.which)&&(event.which==3))||((event.button)&&(event.button==2)));},stop:function(event,allowDefault){if(!allowDefault){if(event.preventDefault){event.preventDefault();}else{event.returnValue=false;}}
+if(event.stopPropagation){event.stopPropagation();}else{event.cancelBubble=true;}},findElement:function(event,tagName){var element=OpenLayers.Event.element(event);while(element.parentNode&&(!element.tagName||(element.tagName.toUpperCase()!=tagName.toUpperCase()))){element=element.parentNode;}
+return element;},observe:function(elementParam,name,observer,useCapture){var element=OpenLayers.Util.getElement(elementParam);useCapture=useCapture||false;if(name=='keypress'&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.attachEvent)){name='keydown';}
+if(!this.observers){this.observers={};}
+if(!element._eventCacheID){var idPrefix="eventCacheID_";if(element.id){idPrefix=element.id+"_"+idPrefix;}
+element._eventCacheID=OpenLayers.Util.createUniqueID(idPrefix);}
+var cacheID=element._eventCacheID;if(!this.observers[cacheID]){this.observers[cacheID]=[];}
+this.observers[cacheID].push({'element':element,'name':name,'observer':observer,'useCapture':useCapture});if(element.addEventListener){element.addEventListener(name,observer,useCapture);}else if(element.attachEvent){element.attachEvent('on'+name,observer);}},stopObservingElement:function(elementParam){var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[cacheID]);},_removeElementObservers:function(elementObservers){if(elementObservers){for(var i=elementObservers.length-1;i>=0;i--){var entry=elementObservers[i];var args=new Array(entry.element,entry.name,entry.observer,entry.useCapture);var removed=OpenLayers.Event.stopObserving.apply(this,args);}}},stopObserving:function(elementParam,name,observer,useCapture){useCapture=useCapture||false;var element=OpenLayers.Util.getElement(elementParam);var cacheID=element._eventCacheID;if(name=='keypress'){if(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||element.detachEvent){name='keydown';}}
+var foundEntry=false;var elementObservers=OpenLayers.Event.observers[cacheID];if(elementObservers){var i=0;while(!foundEntry&&i<elementObservers.length){var cacheEntry=elementObservers[i];if((cacheEntry.name==name)&&(cacheEntry.observer==observer)&&(cacheEntry.useCapture==useCapture)){elementObservers.splice(i,1);if(elementObservers.length==0){delete OpenLayers.Event.observers[cacheID];}
+foundEntry=true;break;}
+i++;}}
+if(foundEntry){if(element.removeEventListener){element.removeEventListener(name,observer,useCapture);}else if(element&&element.detachEvent){element.detachEvent('on'+name,observer);}}
+return foundEntry;},unloadCache:function(){if(OpenLayers.Event&&OpenLayers.Event.observers){for(var cacheID in OpenLayers.Event.observers){var elementObservers=OpenLayers.Event.observers[cacheID];OpenLayers.Event._removeElementObservers.apply(this,[elementObservers]);}
+OpenLayers.Event.observers=false;}},CLASS_NAME:"OpenLayers.Event"};OpenLayers.Event.observe(window,'unload',OpenLayers.Event.unloadCache,false);OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:["mouseover","mouseout","mousedown","mouseup","mousemove","click","dblclick","rightclick","dblrightclick","resize","focus","blur","touchstart","touchmove","touchend","keydown"],listeners:null,object:null,element:null,eventHandler:null,fallThrough:null,includeXY:false,extensions:null,extensionCount:null,clearMouseListener:null,initialize:function(object,element,eventTypes,fallThrough,options){OpenLayers.Util.extend(this,options);this.object=object;this.fallThrough=fallThrough;this.listeners={};this.extensions={};this.extensionCount={};if(element!=null){this.attachToElement(element);}},destroy:function(){for(var e in this.extensions){if(typeof this.extensions[e]!=="boolean"){this.extensions[e].destroy();}}
+this.extensions=null;if(this.element){OpenLayers.Event.stopObservingElement(this.element);if(this.element.hasScrollEvent){OpenLayers.Event.stopObserving(window,"scroll",this.clearMouseListener);}}
+this.element=null;this.listeners=null;this.object=null;this.fallThrough=null;this.eventHandler=null;},addEventType:function(eventName){},attachToElement:function(element){if(this.element){OpenLayers.Event.stopObservingElement(this.element);}else{this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this);this.clearMouseListener=OpenLayers.Function.bind(this.clearMouseCache,this);}
+this.element=element;for(var i=0,len=this.BROWSER_EVENTS.length;i<len;i++){OpenLayers.Event.observe(element,this.BROWSER_EVENTS[i],this.eventHandler);}
+OpenLayers.Event.observe(element,"dragstart",OpenLayers.Event.stop);},on:function(object){for(var type in object){if(type!="scope"&&object.hasOwnProperty(type)){this.register(type,object.scope,object[type]);}}},register:function(type,obj,func,priority){if(type in OpenLayers.Events&&!this.extensions[type]){this.extensions[type]=new OpenLayers.Events[type](this);}
+if(func!=null){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(!listeners){listeners=[];this.listeners[type]=listeners;this.extensionCount[type]=0;}
+var listener={obj:obj,func:func};if(priority){listeners.splice(this.extensionCount[type],0,listener);if(typeof priority==="object"&&priority.extension){this.extensionCount[type]++;}}else{listeners.push(listener);}}},registerPriority:function(type,obj,func){this.register(type,obj,func,true);},un:function(object){for(var type in object){if(type!="scope"&&object.hasOwnProperty(type)){this.unregister(type,object.scope,object[type]);}}},unregister:function(type,obj,func){if(obj==null){obj=this.object;}
+var listeners=this.listeners[type];if(listeners!=null){for(var i=0,len=listeners.length;i<len;i++){if(listeners[i].obj==obj&&listeners[i].func==func){listeners.splice(i,1);break;}}}},remove:function(type){if(this.listeners[type]!=null){this.listeners[type]=[];}},triggerEvent:function(type,evt){var listeners=this.listeners[type];if(!listeners||listeners.length==0){return undefined;}
+if(evt==null){evt={};}
+evt.object=this.object;evt.element=this.element;if(!evt.type){evt.type=type;}
+listeners=listeners.slice();var continueChain;for(var i=0,len=listeners.length;i<len;i++){var callback=listeners[i];continueChain=callback.func.apply(callback.obj,[evt]);if((continueChain!=undefined)&&(continueChain==false)){break;}}
+if(!this.fallThrough){OpenLayers.Event.stop(evt,true);}
+return continueChain;},handleBrowserEvent:function(evt){var type=evt.type,listeners=this.listeners[type];if(!listeners||listeners.length==0){return;}
+var touches=evt.touches;if(touches&&touches[0]){var x=0;var y=0;var num=touches.length;var touch;for(var i=0;i<num;++i){touch=touches[i];x+=touch.clientX;y+=touch.clientY;}
+evt.clientX=x/num;evt.clientY=y/num;}
+if(this.includeXY){evt.xy=this.getMousePosition(evt);}
+this.triggerEvent(type,evt);},clearMouseCache:function(){this.element.scrolls=null;this.element.lefttop=null;var body=document.body;if(body&&!((body.scrollTop!=0||body.scrollLeft!=0)&&navigator.userAgent.match(/iPhone/i))){this.element.offsets=null;}},getMousePosition:function(evt){if(!this.includeXY){this.clearMouseCache();}else if(!this.element.hasScrollEvent){OpenLayers.Event.observe(window,"scroll",this.clearMouseListener);this.element.hasScrollEvent=true;}
+if(!this.element.scrolls){var viewportElement=OpenLayers.Util.getViewportElement();this.element.scrolls=[viewportElement.scrollLeft,viewportElement.scrollTop];}
+if(!this.element.lefttop){this.element.lefttop=[(document.documentElement.clientLeft||0),(document.documentElement.clientTop||0)];}
+if(!this.element.offsets){this.element.offsets=OpenLayers.Util.pagePosition(this.element);}
+return new OpenLayers.Pixel((evt.clientX+this.element.scrolls[0])-this.element.offsets[0]
+-this.element.lefttop[0],(evt.clientY+this.element.scrolls[1])-this.element.offsets[1]
+-this.element.lefttop[1]);},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Events.buttonclick=OpenLayers.Class({target:null,events:['mousedown','mouseup','click','dblclick','touchstart','touchmove','touchend','keydown'],startRegEx:/^mousedown|touchstart$/,cancelRegEx:/^touchmove$/,completeRegEx:/^mouseup|touchend$/,initialize:function(target){this.target=target;for(var i=this.events.length-1;i>=0;--i){this.target.register(this.events[i],this,this.buttonClick,{extension:true});}},destroy:function(){for(var i=this.events.length-1;i>=0;--i){this.target.unregister(this.events[i],this,this.buttonClick);}
+delete this.target;},getPressedButton:function(element){var depth=3,button;do{if(OpenLayers.Element.hasClass(element,"olButton")){button=element;break;}
+element=element.parentNode;}while(--depth>0&&element);return button;},buttonClick:function(evt){var propagate=true,element=OpenLayers.Event.element(evt);if(element&&(OpenLayers.Event.isLeftClick(evt)||!~evt.type.indexOf("mouse"))){var button=this.getPressedButton(element);if(button){if(evt.type==="keydown"){switch(evt.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",{buttonElement:button});OpenLayers.Event.stop(evt);propagate=false;break;}}else if(this.startEvt){if(this.completeRegEx.test(evt.type)){var pos=OpenLayers.Util.pagePosition(button);this.target.triggerEvent("buttonclick",{buttonElement:button,buttonXY:{x:this.startEvt.clientX-pos[0],y:this.startEvt.clientY-pos[1]}});}
+if(this.cancelRegEx.test(evt.type)){delete this.startEvt;}
+OpenLayers.Event.stop(evt);propagate=false;}
+if(this.startRegEx.test(evt.type)){this.startEvt=evt;OpenLayers.Event.stop(evt);propagate=false;}}else{delete this.startEvt;}}
+return propagate;}});OpenLayers.Lang["is"]=OpenLayers.Util.applyDefaults({'Permalink':"Varanlegur tengill",'Overlays':"Þekjur",'Base Layer':"Grunnlag",'Scale = 1 : ${scaleDenom}':"Skali = 1 : ${scaleDenom}",'methodDeprecated':"Þetta fall hefur verið úrelt og verður fjarlægt í 3.0. Notaðu ${newMethod} í staðin."});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){this.id=null;this.bounds=null;},clone:function(){return new OpenLayers.Geometry();},setBounds:function(bounds){if(bounds){this.bounds=bounds.clone();}},clearBounds:function(){this.bounds=null;if(this.parent){this.parent.clearBounds();}},extendBounds:function(newBounds){var bounds=this.getBounds();if(!bounds){this.setBounds(newBounds);}else{this.bounds.extend(newBounds);}},getBounds:function(){if(this.bounds==null){this.calculateBounds();}
+return this.bounds;},calculateBounds:function(){},distanceTo:function(geometry,options){},getVertices:function(nodes){},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;var bounds=this.getBounds();if((bounds!=null)&&(lonlat!=null)){var dX=(toleranceLon!=null)?toleranceLon:0;var dY=(toleranceLat!=null)?toleranceLat:0;var toleranceBounds=new OpenLayers.Bounds(this.bounds.left-dX,this.bounds.bottom-dY,this.bounds.right+dX,this.bounds.top+dY);atPoint=toleranceBounds.containsLonLat(lonlat);}
+return atPoint;},getLength:function(){return 0.0;},getArea:function(){return 0.0;},getCentroid:function(){return null;},toString:function(){var string;if(OpenLayers.Format&&OpenLayers.Format.WKT){string=OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this));}else{string=Object.prototype.toString.call(this);}
+return string;},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(wkt){var geom;if(OpenLayers.Format&&OpenLayers.Format.WKT){var format=OpenLayers.Geometry.fromWKT.format;if(!format){format=new OpenLayers.Format.WKT();OpenLayers.Geometry.fromWKT.format=format;}
+var result=format.read(wkt);if(result instanceof OpenLayers.Feature.Vector){geom=result.geometry;}else if(OpenLayers.Util.isArray(result)){var len=result.length;var components=new Array(len);for(var i=0;i<len;++i){components[i]=result[i].geometry;}
+geom=new OpenLayers.Geometry.Collection(components);}}
+return geom;};OpenLayers.Geometry.segmentsIntersect=function(seg1,seg2,options){var point=options&&options.point;var tolerance=options&&options.tolerance;var intersection=false;var x11_21=seg1.x1-seg2.x1;var y11_21=seg1.y1-seg2.y1;var x12_11=seg1.x2-seg1.x1;var y12_11=seg1.y2-seg1.y1;var y22_21=seg2.y2-seg2.y1;var x22_21=seg2.x2-seg2.x1;var d=(y22_21*x12_11)-(x22_21*y12_11);var n1=(x22_21*y11_21)-(y22_21*x11_21);var n2=(x12_11*y11_21)-(y12_11*x11_21);if(d==0){if(n1==0&&n2==0){intersection=true;}}else{var along1=n1/d;var along2=n2/d;if(along1>=0&&along1<=1&&along2>=0&&along2<=1){if(!point){intersection=true;}else{var x=seg1.x1+(along1*x12_11);var y=seg1.y1+(along1*y12_11);intersection=new OpenLayers.Geometry.Point(x,y);}}}
+if(tolerance){var dist;if(intersection){if(point){var segs=[seg1,seg2];var seg,x,y;outer:for(var i=0;i<2;++i){seg=segs[i];for(var j=1;j<3;++j){x=seg["x"+j];y=seg["y"+j];dist=Math.sqrt(Math.pow(x-intersection.x,2)+
+Math.pow(y-intersection.y,2));if(dist<tolerance){intersection.x=x;intersection.y=y;break outer;}}}}}else{var segs=[seg1,seg2];var source,target,x,y,p,result;outer:for(var i=0;i<2;++i){source=segs[i];target=segs[(i+1)%2];for(var j=1;j<3;++j){p={x:source["x"+j],y:source["y"+j]};result=OpenLayers.Geometry.distanceToSegment(p,target);if(result.distance<tolerance){if(point){intersection=new OpenLayers.Geometry.Point(p.x,p.y);}else{intersection=true;}
+break outer;}}}}}
+return intersection;};OpenLayers.Geometry.distanceToSegment=function(point,segment){var x0=point.x;var y0=point.y;var x1=segment.x1;var y1=segment.y1;var x2=segment.x2;var y2=segment.y2;var dx=x2-x1;var dy=y2-y1;var along=((dx*(x0-x1))+(dy*(y0-y1)))/(Math.pow(dx,2)+Math.pow(dy,2));var x,y;if(along<=0.0){x=x1;y=y1;}else if(along>=1.0){x=x2;y=y2;}else{x=x1+along*dx;y=y1+along*dy;}
+return{distance:Math.sqrt(Math.pow(x-x0,2)+Math.pow(y-y0,2)),x:x,y:y};};OpenLayers.Lang["te"]=OpenLayers.Util.applyDefaults({'Permalink':"స్థిరలింకు",'W':"ప",'E':"తూ",'N':"ఉ",'S':"ద"});OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:false,displayClass:"",title:"",autoActivate:false,active:null,handler:null,eventListeners:null,events:null,initialize:function(options){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,options);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
+if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}},destroy:function(){if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
+this.events.destroy();this.events=null;}
+this.eventListeners=null;if(this.handler){this.handler.destroy();this.handler=null;}
+if(this.handlers){for(var key in this.handlers){if(this.handlers.hasOwnProperty(key)&&typeof this.handlers[key].destroy=="function"){this.handlers[key].destroy();}}
+this.handlers=null;}
+if(this.map){this.map.removeControl(this);this.map=null;}
+this.div=null;},setMap:function(map){this.map=map;if(this.handler){this.handler.setMap(map);}},draw:function(px){if(this.div==null){this.div=OpenLayers.Util.createDiv(this.id);this.div.className=this.displayClass;if(!this.allowSelection){this.div.className+=" olControlNoSelect";this.div.setAttribute("unselectable","on",0);this.div.onselectstart=OpenLayers.Function.False;}
+if(this.title!=""){this.div.title=this.title;}}
+if(px!=null){this.position=px.clone();}
+this.moveTo(this.position);return this.div;},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},activate:function(){if(this.active){return false;}
+if(this.handler){this.handler.activate();}
+this.active=true;if(this.map){OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");}
+this.events.triggerEvent("activate");return true;},deactivate:function(){if(this.active){if(this.handler){this.handler.deactivate();}
+this.active=false;if(this.map){OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");}
+this.events.triggerEvent("deactivate");return true;}
+return false;},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,slideRatio:null,buttons:null,position:null,initialize:function(options){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){if(this.map){this.map.events.unregister("buttonclick",this,this.onButtonClick);}
+this.removeButtons();this.buttons=null;this.position=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.register("buttonclick",this,this.onButtonClick);},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position;this.buttons=[];var sz={w:18,h:18};var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);this._addButton("panright","east-mini.png",px.add(sz.w,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);this._addButton("zoomworld","zoom-world-mini.png",centered.add(0,sz.h*4+5),sz);this._addButton("zoomout","zoom-minus-mini.png",centered.add(0,sz.h*5+5),sz);return this.div;},_addButton:function(id,img,xy,sz){var imgLocation=OpenLayers.Util.getImageLocation(img);var btn=OpenLayers.Util.createAlphaImageDiv(this.id+"_"+id,xy,sz,imgLocation,"absolute");btn.style.cursor="pointer";this.div.appendChild(btn);btn.action=id;btn.className="olButton";this.buttons.push(btn);return btn;},_removeButton:function(btn){this.div.removeChild(btn);OpenLayers.Util.removeItem(this.buttons,btn);},removeButtons:function(){for(var i=this.buttons.length-1;i>=0;--i){this._removeButton(this.buttons[i]);}},onButtonClick:function(evt){var btn=evt.buttonElement;switch(btn.action){case"panup":this.map.pan(0,-this.getSlideFactor("h"));break;case"pandown":this.map.pan(0,this.getSlideFactor("h"));break;case"panleft":this.map.pan(-this.getSlideFactor("w"),0);break;case"panright":this.map.pan(this.getSlideFactor("w"),0);break;case"zoomin":this.map.zoomIn();break;case"zoomout":this.map.zoomOut();break;case"zoomworld":this.map.zoomToMaxExtent();break;}},getSlideFactor:function(dim){return this.slideRatio?this.map.getSize()[dim]*this.slideRatio:this.slideFactor;},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Control.PanZoomBar=OpenLayers.Class(OpenLayers.Control.PanZoom,{zoomStopWidth:18,zoomStopHeight:11,slider:null,sliderEvents:null,zoombarDiv:null,zoomWorldIcon:false,panIcons:true,forceFixedZoomLevel:false,mouseDragStart:null,deltaY:null,zoomStart:null,destroy:function(){this._removeZoomBar();this.map.events.un({"changebaselayer":this.redraw,scope:this});OpenLayers.Control.PanZoom.prototype.destroy.apply(this,arguments);delete this.mouseDragStart;delete this.zoomStart;},setMap:function(map){OpenLayers.Control.PanZoom.prototype.setMap.apply(this,arguments);this.map.events.register("changebaselayer",this,this.redraw);},redraw:function(){if(this.div!=null){this.removeButtons();this._removeZoomBar();}
+this.draw();},draw:function(px){OpenLayers.Control.prototype.draw.apply(this,arguments);px=this.position.clone();this.buttons=[];var sz={w:18,h:18};if(this.panIcons){var centered=new OpenLayers.Pixel(px.x+sz.w/2,px.y);var wposition=sz.w;if(this.zoomWorldIcon){centered=new OpenLayers.Pixel(px.x+sz.w,px.y);}
+this._addButton("panup","north-mini.png",centered,sz);px.y=centered.y+sz.h;this._addButton("panleft","west-mini.png",px,sz);if(this.zoomWorldIcon){this._addButton("zoomworld","zoom-world-mini.png",px.add(sz.w,0),sz);wposition*=2;}
+this._addButton("panright","east-mini.png",px.add(wposition,0),sz);this._addButton("pandown","south-mini.png",centered.add(0,sz.h*2),sz);this._addButton("zoomin","zoom-plus-mini.png",centered.add(0,sz.h*3+5),sz);centered=this._addZoomBar(centered.add(0,sz.h*4+5));this._addButton("zoomout","zoom-minus-mini.png",centered,sz);}
+else{this._addButton("zoomin","zoom-plus-mini.png",px,sz);centered=this._addZoomBar(px.add(0,sz.h));this._addButton("zoomout","zoom-minus-mini.png",centered,sz);if(this.zoomWorldIcon){centered=centered.add(0,sz.h+3);this._addButton("zoomworld","zoom-world-mini.png",centered,sz);}}
+return this.div;},_addZoomBar:function(centered){var imgLocation=OpenLayers.Util.getImageLocation("slider.png");var id=this.id+"_"+this.map.id;var zoomsToEnd=this.map.getNumZoomLevels()-1-this.map.getZoom();var slider=OpenLayers.Util.createAlphaImageDiv(id,centered.add(-1,zoomsToEnd*this.zoomStopHeight),{w:20,h:9},imgLocation,"absolute");slider.style.cursor="move";this.slider=slider;this.sliderEvents=new OpenLayers.Events(this,slider,null,true,{includeXY:true});this.sliderEvents.on({"touchstart":this.zoomBarDown,"touchmove":this.zoomBarDrag,"touchend":this.zoomBarUp,"mousedown":this.zoomBarDown,"mousemove":this.zoomBarDrag,"mouseup":this.zoomBarUp});var sz={w:this.zoomStopWidth,h:this.zoomStopHeight*this.map.getNumZoomLevels()};var imgLocation=OpenLayers.Util.getImageLocation("zoombar.png");var div=null;if(OpenLayers.Util.alphaHack()){var id=this.id+"_"+this.map.id;div=OpenLayers.Util.createAlphaImageDiv(id,centered,{w:sz.w,h:this.zoomStopHeight},imgLocation,"absolute",null,"crop");div.style.height=sz.h+"px";}else{div=OpenLayers.Util.createDiv('OpenLayers_Control_PanZoomBar_Zoombar'+this.map.id,centered,sz,imgLocation);}
+div.style.cursor="pointer";div.className="olButton";this.zoombarDiv=div;this.div.appendChild(div);this.startTop=parseInt(div.style.top);this.div.appendChild(slider);this.map.events.register("zoomend",this,this.moveZoomBar);centered=centered.add(0,this.zoomStopHeight*this.map.getNumZoomLevels());return centered;},_removeZoomBar:function(){this.sliderEvents.un({"touchstart":this.zoomBarDown,"touchmove":this.zoomBarDrag,"touchend":this.zoomBarUp,"mousedown":this.zoomBarDown,"mousemove":this.zoomBarDrag,"mouseup":this.zoomBarUp});this.sliderEvents.destroy();this.div.removeChild(this.zoombarDiv);this.zoombarDiv=null;this.div.removeChild(this.slider);this.slider=null;this.map.events.unregister("zoomend",this,this.moveZoomBar);},onButtonClick:function(evt){OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this,arguments);if(evt.buttonElement===this.zoombarDiv){var levels=evt.buttonXY.y/this.zoomStopHeight;if(this.forceFixedZoomLevel||!this.map.fractionalZoom){levels=Math.floor(levels);}
+var zoom=(this.map.getNumZoomLevels()-1)-levels;zoom=Math.min(Math.max(zoom,0),this.map.getNumZoomLevels()-1);this.map.zoomTo(zoom);}},passEventToSlider:function(evt){this.sliderEvents.handleBrowserEvent(evt);},zoomBarDown:function(evt){if(!OpenLayers.Event.isLeftClick(evt)&&!OpenLayers.Event.isSingleTouch(evt)){return;}
+this.map.events.on({"touchmove":this.passEventToSlider,"mousemove":this.passEventToSlider,"mouseup":this.passEventToSlider,scope:this});this.mouseDragStart=evt.xy.clone();this.zoomStart=evt.xy.clone();this.div.style.cursor="move";this.zoombarDiv.offsets=null;OpenLayers.Event.stop(evt);},zoomBarDrag:function(evt){if(this.mouseDragStart!=null){var deltaY=this.mouseDragStart.y-evt.xy.y;var offsets=OpenLayers.Util.pagePosition(this.zoombarDiv);if((evt.clientY-offsets[1])>0&&(evt.clientY-offsets[1])<parseInt(this.zoombarDiv.style.height)-2){var newTop=parseInt(this.slider.style.top)-deltaY;this.slider.style.top=newTop+"px";this.mouseDragStart=evt.xy.clone();}
+this.deltaY=this.zoomStart.y-evt.xy.y;OpenLayers.Event.stop(evt);}},zoomBarUp:function(evt){if(!OpenLayers.Event.isLeftClick(evt)&&evt.type!=="touchend"){return;}
+if(this.mouseDragStart){this.div.style.cursor="";this.map.events.un({"touchmove":this.passEventToSlider,"mouseup":this.passEventToSlider,"mousemove":this.passEventToSlider,scope:this});var zoomLevel=this.map.zoom;if(!this.forceFixedZoomLevel&&this.map.fractionalZoom){zoomLevel+=this.deltaY/this.zoomStopHeight;zoomLevel=Math.min(Math.max(zoomLevel,0),this.map.getNumZoomLevels()-1);}else{zoomLevel+=this.deltaY/this.zoomStopHeight;zoomLevel=Math.max(Math.round(zoomLevel),0);}
+this.map.zoomTo(zoomLevel);this.mouseDragStart=null;this.zoomStart=null;this.deltaY=0;OpenLayers.Event.stop(evt);}},moveZoomBar:function(){var newTop=((this.map.getNumZoomLevels()-1)-this.map.getZoom())*this.zoomStopHeight+this.startTop+1;this.slider.style.top=newTop+"px";},CLASS_NAME:"OpenLayers.Control.PanZoomBar"});OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(components){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];if(components!=null){this.addComponents(components);}},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments);},clone:function(){var geometry=eval("new "+this.CLASS_NAME+"()");for(var i=0,len=this.components.length;i<len;i++){geometry.addComponent(this.components[i].clone());}
+OpenLayers.Util.applyDefaults(geometry,this);return geometry;},getComponentsString:function(){var strings=[];for(var i=0,len=this.components.length;i<len;i++){strings.push(this.components[i].toShortString());}
+return strings.join(",");},calculateBounds:function(){this.bounds=null;var bounds=new OpenLayers.Bounds();var components=this.components;if(components){for(var i=0,len=components.length;i<len;i++){bounds.extend(components[i].getBounds());}}
+if(bounds.left!=null&&bounds.bottom!=null&&bounds.right!=null&&bounds.top!=null){this.setBounds(bounds);}},addComponents:function(components){if(!(OpenLayers.Util.isArray(components))){components=[components];}
+for(var i=0,len=components.length;i<len;i++){this.addComponent(components[i]);}},addComponent:function(component,index){var added=false;if(component){if(this.componentTypes==null||(OpenLayers.Util.indexOf(this.componentTypes,component.CLASS_NAME)>-1)){if(index!=null&&(index<this.components.length)){var components1=this.components.slice(0,index);var components2=this.components.slice(index,this.components.length);components1.push(component);this.components=components1.concat(components2);}else{this.components.push(component);}
+component.parent=this;this.clearBounds();added=true;}}
+return added;},removeComponents:function(components){var removed=false;if(!(OpenLayers.Util.isArray(components))){components=[components];}
+for(var i=components.length-1;i>=0;--i){removed=this.removeComponent(components[i])||removed;}
+return removed;},removeComponent:function(component){OpenLayers.Util.removeItem(this.components,component);this.clearBounds();return true;},getLength:function(){var length=0.0;for(var i=0,len=this.components.length;i<len;i++){length+=this.components[i].getLength();}
+return length;},getArea:function(){var area=0.0;for(var i=0,len=this.components.length;i<len;i++){area+=this.components[i].getArea();}
+return area;},getGeodesicArea:function(projection){var area=0.0;for(var i=0,len=this.components.length;i<len;i++){area+=this.components[i].getGeodesicArea(projection);}
+return area;},getCentroid:function(weighted){if(!weighted){return this.components.length&&this.components[0].getCentroid();}
+var len=this.components.length;if(!len){return false;}
+var areas=[];var centroids=[];var areaSum=0;var minArea=Number.MAX_VALUE;var component;for(var i=0;i<len;++i){component=this.components[i];var area=component.getArea();var centroid=component.getCentroid(true);if(isNaN(area)||isNaN(centroid.x)||isNaN(centroid.y)){continue;}
+areas.push(area);areaSum+=area;minArea=(area<minArea&&area>0)?area:minArea;centroids.push(centroid);}
+len=areas.length;if(areaSum===0){for(var i=0;i<len;++i){areas[i]=1;}
+areaSum=areas.length;}else{for(var i=0;i<len;++i){areas[i]/=minArea;}
+areaSum/=minArea;}
+var xSum=0,ySum=0,centroid,area;for(var i=0;i<len;++i){centroid=centroids[i];area=areas[i];xSum+=centroid.x*area;ySum+=centroid.y*area;}
+return new OpenLayers.Geometry.Point(xSum/areaSum,ySum/areaSum);},getGeodesicLength:function(projection){var length=0.0;for(var i=0,len=this.components.length;i<len;i++){length+=this.components[i].getGeodesicLength(projection);}
+return length;},move:function(x,y){for(var i=0,len=this.components.length;i<len;i++){this.components[i].move(x,y);}},rotate:function(angle,origin){for(var i=0,len=this.components.length;i<len;++i){this.components[i].rotate(angle,origin);}},resize:function(scale,origin,ratio){for(var i=0;i<this.components.length;++i){this.components[i].resize(scale,origin,ratio);}
+return this;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var result,best,distance;var min=Number.POSITIVE_INFINITY;for(var i=0,len=this.components.length;i<len;++i){result=this.components[i].distanceTo(geometry,options);distance=details?result.distance:result;if(distance<min){min=distance;best=result;if(min==0){break;}}}
+return best;},equals:function(geometry){var equivalent=true;if(!geometry||!geometry.CLASS_NAME||(this.CLASS_NAME!=geometry.CLASS_NAME)){equivalent=false;}else if(!(OpenLayers.Util.isArray(geometry.components))||(geometry.components.length!=this.components.length)){equivalent=false;}else{for(var i=0,len=this.components.length;i<len;++i){if(!this.components[i].equals(geometry.components[i])){equivalent=false;break;}}}
+return equivalent;},transform:function(source,dest){if(source&&dest){for(var i=0,len=this.components.length;i<len;i++){var component=this.components[i];component.transform(source,dest);}
+this.bounds=null;}
+return this;},intersects:function(geometry){var intersect=false;for(var i=0,len=this.components.length;i<len;++i){intersect=geometry.intersects(this.components[i]);if(intersect){break;}}
+return intersect;},getVertices:function(nodes){var vertices=[];for(var i=0,len=this.components.length;i<len;++i){Array.prototype.push.apply(vertices,this.components[i].getVertices(nodes));}
+return vertices;},CLASS_NAME:"OpenLayers.Geometry.Collection"});OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(x,y){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(x);this.y=parseFloat(y);},clone:function(obj){if(obj==null){obj=new OpenLayers.Geometry.Point(this.x,this.y);}
+OpenLayers.Util.applyDefaults(obj,this);return obj;},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y);},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var distance,x0,y0,x1,y1,result;if(geometry instanceof OpenLayers.Geometry.Point){x0=this.x;y0=this.y;x1=geometry.x;y1=geometry.y;distance=Math.sqrt(Math.pow(x0-x1,2)+Math.pow(y0-y1,2));result=!details?distance:{x0:x0,y0:y0,x1:x1,y1:y1,distance:distance};}else{result=geometry.distanceTo(this,options);if(details){result={x0:result.x1,y0:result.y1,x1:result.x0,y1:result.y0,distance:result.distance};}}
+return result;},equals:function(geom){var equals=false;if(geom!=null){equals=((this.x==geom.x&&this.y==geom.y)||(isNaN(this.x)&&isNaN(this.y)&&isNaN(geom.x)&&isNaN(geom.y)));}
+return equals;},toShortString:function(){return(this.x+", "+this.y);},move:function(x,y){this.x=this.x+x;this.y=this.y+y;this.clearBounds();},rotate:function(angle,origin){angle*=Math.PI/180;var radius=this.distanceTo(origin);var theta=angle+Math.atan2(this.y-origin.y,this.x-origin.x);this.x=origin.x+(radius*Math.cos(theta));this.y=origin.y+(radius*Math.sin(theta));this.clearBounds();},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y);},resize:function(scale,origin,ratio){ratio=(ratio==undefined)?1:ratio;this.x=origin.x+(scale*ratio*(this.x-origin.x));this.y=origin.y+(scale*(this.y-origin.y));this.clearBounds();return this;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.equals(geometry);}else{intersect=geometry.intersects(this);}
+return intersect;},transform:function(source,dest){if((source&&dest)){OpenLayers.Projection.transform(this,source,dest);this.bounds=null;}
+return this;},getVertices:function(nodes){return[this];},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.MultiPoint=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Point"],addPoint:function(point,index){this.addComponent(point,index);},removePoint:function(point){this.removeComponent(point);},CLASS_NAME:"OpenLayers.Geometry.MultiPoint"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],getLength:function(){var length=0.0;if(this.components&&(this.components.length>1)){for(var i=1,len=this.components.length;i<len;i++){length+=this.components[i-1].distanceTo(this.components[i]);}}
+return length;},getGeodesicLength:function(projection){var geom=this;if(projection){var gg=new OpenLayers.Projection("EPSG:4326");if(!gg.equals(projection)){geom=this.clone().transform(projection,gg);}}
+var length=0.0;if(geom.components&&(geom.components.length>1)){var p1,p2;for(var i=1,len=geom.components.length;i<len;i++){p1=geom.components[i-1];p2=geom.components[i];length+=OpenLayers.Util.distVincenty({lon:p1.x,lat:p1.y},{lon:p2.x,lat:p2.y});}}
+return length*1000;},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{removeComponent:function(point){var removed=this.components&&(this.components.length>2);if(removed){OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);}
+return removed;},intersects:function(geometry){var intersect=false;var type=geometry.CLASS_NAME;if(type=="OpenLayers.Geometry.LineString"||type=="OpenLayers.Geometry.LinearRing"||type=="OpenLayers.Geometry.Point"){var segs1=this.getSortedSegments();var segs2;if(type=="OpenLayers.Geometry.Point"){segs2=[{x1:geometry.x,y1:geometry.y,x2:geometry.x,y2:geometry.y}];}else{segs2=geometry.getSortedSegments();}
+var seg1,seg1x1,seg1x2,seg1y1,seg1y2,seg2,seg2y1,seg2y2;outer:for(var i=0,len=segs1.length;i<len;++i){seg1=segs1[i];seg1x1=seg1.x1;seg1x2=seg1.x2;seg1y1=seg1.y1;seg1y2=seg1.y2;inner:for(var j=0,jlen=segs2.length;j<jlen;++j){seg2=segs2[j];if(seg2.x1>seg1x2){break;}
+if(seg2.x2<seg1x1){continue;}
+seg2y1=seg2.y1;seg2y2=seg2.y2;if(Math.min(seg2y1,seg2y2)>Math.max(seg1y1,seg1y2)){continue;}
+if(Math.max(seg2y1,seg2y2)<Math.min(seg1y1,seg1y2)){continue;}
+if(OpenLayers.Geometry.segmentsIntersect(seg1,seg2)){intersect=true;break outer;}}}}else{intersect=geometry.intersects(this);}
+return intersect;},getSortedSegments:function(){var numSeg=this.components.length-1;var segments=new Array(numSeg),point1,point2;for(var i=0;i<numSeg;++i){point1=this.components[i];point2=this.components[i+1];if(point1.x<point2.x){segments[i]={x1:point1.x,y1:point1.y,x2:point2.x,y2:point2.y};}else{segments[i]={x1:point2.x,y1:point2.y,x2:point1.x,y2:point1.y};}}
+function byX1(seg1,seg2){return seg1.x1-seg2.x1;}
+return segments.sort(byX1);},splitWithSegment:function(seg,options){var edge=!(options&&options.edge===false);var tolerance=options&&options.tolerance;var lines=[];var verts=this.getVertices();var points=[];var intersections=[];var split=false;var vert1,vert2,point;var node,vertex,target;var interOptions={point:true,tolerance:tolerance};var result=null;for(var i=0,stop=verts.length-2;i<=stop;++i){vert1=verts[i];points.push(vert1.clone());vert2=verts[i+1];target={x1:vert1.x,y1:vert1.y,x2:vert2.x,y2:vert2.y};point=OpenLayers.Geometry.segmentsIntersect(seg,target,interOptions);if(point instanceof OpenLayers.Geometry.Point){if((point.x===seg.x1&&point.y===seg.y1)||(point.x===seg.x2&&point.y===seg.y2)||point.equals(vert1)||point.equals(vert2)){vertex=true;}else{vertex=false;}
+if(vertex||edge){if(!point.equals(intersections[intersections.length-1])){intersections.push(point.clone());}
+if(i===0){if(point.equals(vert1)){continue;}}
+if(point.equals(vert2)){continue;}
+split=true;if(!point.equals(vert1)){points.push(point);}
+lines.push(new OpenLayers.Geometry.LineString(points));points=[point.clone()];}}}
+if(split){points.push(vert2.clone());lines.push(new OpenLayers.Geometry.LineString(points));}
+if(intersections.length>0){var xDir=seg.x1<seg.x2?1:-1;var yDir=seg.y1<seg.y2?1:-1;result={lines:lines,points:intersections.sort(function(p1,p2){return(xDir*p1.x-xDir*p2.x)||(yDir*p1.y-yDir*p2.y);})};}
+return result;},split:function(target,options){var results=null;var mutual=options&&options.mutual;var sourceSplit,targetSplit,sourceParts,targetParts;if(target instanceof OpenLayers.Geometry.LineString){var verts=this.getVertices();var vert1,vert2,seg,splits,lines,point;var points=[];sourceParts=[];for(var i=0,stop=verts.length-2;i<=stop;++i){vert1=verts[i];vert2=verts[i+1];seg={x1:vert1.x,y1:vert1.y,x2:vert2.x,y2:vert2.y};targetParts=targetParts||[target];if(mutual){points.push(vert1.clone());}
+for(var j=0;j<targetParts.length;++j){splits=targetParts[j].splitWithSegment(seg,options);if(splits){lines=splits.lines;if(lines.length>0){lines.unshift(j,1);Array.prototype.splice.apply(targetParts,lines);j+=lines.length-2;}
+if(mutual){for(var k=0,len=splits.points.length;k<len;++k){point=splits.points[k];if(!point.equals(vert1)){points.push(point);sourceParts.push(new OpenLayers.Geometry.LineString(points));if(point.equals(vert2)){points=[];}else{points=[point.clone()];}}}}}}}
+if(mutual&&sourceParts.length>0&&points.length>0){points.push(vert2.clone());sourceParts.push(new OpenLayers.Geometry.LineString(points));}}else{results=target.splitWith(this,options);}
+if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
+if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
+if(targetSplit||sourceSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
+return results;},splitWith:function(geometry,options){return geometry.split(this,options);},getVertices:function(nodes){var vertices;if(nodes===true){vertices=[this.components[0],this.components[this.components.length-1]];}else if(nodes===false){vertices=this.components.slice(1,this.components.length-1);}else{vertices=this.components.slice();}
+return vertices;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var details=edge&&options&&options.details;var result,best={};var min=Number.POSITIVE_INFINITY;if(geometry instanceof OpenLayers.Geometry.Point){var segs=this.getSortedSegments();var x=geometry.x;var y=geometry.y;var seg;for(var i=0,len=segs.length;i<len;++i){seg=segs[i];result=OpenLayers.Geometry.distanceToSegment(geometry,seg);if(result.distance<min){min=result.distance;best=result;if(min===0){break;}}else{if(seg.x2>x&&((y>seg.y1&&y<seg.y2)||(y<seg.y1&&y>seg.y2))){break;}}}
+if(details){best={distance:best.distance,x0:best.x,y0:best.y,x1:x,y1:y};}else{best=best.distance;}}else if(geometry instanceof OpenLayers.Geometry.LineString){var segs0=this.getSortedSegments();var segs1=geometry.getSortedSegments();var seg0,seg1,intersection,x0,y0;var len1=segs1.length;var interOptions={point:true};outer:for(var i=0,len=segs0.length;i<len;++i){seg0=segs0[i];x0=seg0.x1;y0=seg0.y1;for(var j=0;j<len1;++j){seg1=segs1[j];intersection=OpenLayers.Geometry.segmentsIntersect(seg0,seg1,interOptions);if(intersection){min=0;best={distance:0,x0:intersection.x,y0:intersection.y,x1:intersection.x,y1:intersection.y};break outer;}else{result=OpenLayers.Geometry.distanceToSegment({x:x0,y:y0},seg1);if(result.distance<min){min=result.distance;best={distance:min,x0:x0,y0:y0,x1:result.x,y1:result.y};}}}}
+if(!details){best=best.distance;}
+if(min!==0){if(seg0){result=geometry.distanceTo(new OpenLayers.Geometry.Point(seg0.x2,seg0.y2),options);var dist=details?result.distance:result;if(dist<min){if(details){best={distance:min,x0:result.x1,y0:result.y1,x1:result.x0,y1:result.y0};}else{best=dist;}}}}}else{best=geometry.distanceTo(this,options);if(details){best={distance:best.distance,x0:best.x1,y0:best.y1,x1:best.x0,y1:best.y0};}}
+return best;},simplify:function(tolerance){if(this&&this!==null){var points=this.getVertices();if(points.length<3){return this;}
+var compareNumbers=function(a,b){return(a-b);};var douglasPeuckerReduction=function(points,firstPoint,lastPoint,tolerance){var maxDistance=0;var indexFarthest=0;for(var index=firstPoint,distance;index<lastPoint;index++){distance=perpendicularDistance(points[firstPoint],points[lastPoint],points[index]);if(distance>maxDistance){maxDistance=distance;indexFarthest=index;}}
+if(maxDistance>tolerance&&indexFarthest!=firstPoint){pointIndexsToKeep.push(indexFarthest);douglasPeuckerReduction(points,firstPoint,indexFarthest,tolerance);douglasPeuckerReduction(points,indexFarthest,lastPoint,tolerance);}};var perpendicularDistance=function(point1,point2,point){var area=Math.abs(0.5*(point1.x*point2.y+point2.x*point.y+point.x*point1.y-point2.x*point1.y-point.x*point2.y-point1.x*point.y));var bottom=Math.sqrt(Math.pow(point1.x-point2.x,2)+Math.pow(point1.y-point2.y,2));var height=area/bottom*2;return height;};var firstPoint=0;var lastPoint=points.length-1;var pointIndexsToKeep=[];pointIndexsToKeep.push(firstPoint);pointIndexsToKeep.push(lastPoint);while(points[firstPoint].equals(points[lastPoint])){lastPoint--;pointIndexsToKeep.push(lastPoint);}
+douglasPeuckerReduction(points,firstPoint,lastPoint,tolerance);var returnPoints=[];pointIndexsToKeep.sort(compareNumbers);for(var index=0;index<pointIndexsToKeep.length;index++){returnPoints.push(points[pointIndexsToKeep[index]]);}
+return new OpenLayers.Geometry.LineString(returnPoints);}
+else{return this;}},CLASS_NAME:"OpenLayers.Geometry.LineString"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(point,index){var added=false;var lastPoint=this.components.pop();if(index!=null||!point.equals(lastPoint)){added=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments);}
+var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);return added;},removeComponent:function(point){var removed=this.components&&(this.components.length>3);if(removed){this.components.pop();OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);var firstPoint=this.components[0];OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[firstPoint]);}
+return removed;},move:function(x,y){for(var i=0,len=this.components.length;i<len-1;i++){this.components[i].move(x,y);}},rotate:function(angle,origin){for(var i=0,len=this.components.length;i<len-1;++i){this.components[i].rotate(angle,origin);}},resize:function(scale,origin,ratio){for(var i=0,len=this.components.length;i<len-1;++i){this.components[i].resize(scale,origin,ratio);}
+return this;},transform:function(source,dest){if(source&&dest){for(var i=0,len=this.components.length;i<len-1;i++){var component=this.components[i];component.transform(source,dest);}
+this.bounds=null;}
+return this;},getCentroid:function(){if(this.components&&(this.components.length>2)){var sumX=0.0;var sumY=0.0;for(var i=0;i<this.components.length-1;i++){var b=this.components[i];var c=this.components[i+1];sumX+=(b.x+c.x)*(b.x*c.y-c.x*b.y);sumY+=(b.y+c.y)*(b.x*c.y-c.x*b.y);}
+var area=-1*this.getArea();var x=sumX/(6*area);var y=sumY/(6*area);return new OpenLayers.Geometry.Point(x,y);}else{return null;}},getArea:function(){var area=0.0;if(this.components&&(this.components.length>2)){var sum=0.0;for(var i=0,len=this.components.length;i<len-1;i++){var b=this.components[i];var c=this.components[i+1];sum+=(b.x+c.x)*(c.y-b.y);}
+area=-sum/2.0;}
+return area;},getGeodesicArea:function(projection){var ring=this;if(projection){var gg=new OpenLayers.Projection("EPSG:4326");if(!gg.equals(projection)){ring=this.clone().transform(projection,gg);}}
+var area=0.0;var len=ring.components&&ring.components.length;if(len>2){var p1,p2;for(var i=0;i<len-1;i++){p1=ring.components[i];p2=ring.components[i+1];area+=OpenLayers.Util.rad(p2.x-p1.x)*(2+Math.sin(OpenLayers.Util.rad(p1.y))+
+Math.sin(OpenLayers.Util.rad(p2.y)));}
+area=area*6378137.0*6378137.0/2.0;}
+return area;},containsPoint:function(point){var approx=OpenLayers.Number.limitSigDigs;var digs=14;var px=approx(point.x,digs);var py=approx(point.y,digs);function getX(y,x1,y1,x2,y2){return(y-y2)*((x2-x1)/(y2-y1))+x2;}
+var numSeg=this.components.length-1;var start,end,x1,y1,x2,y2,cx,cy;var crosses=0;for(var i=0;i<numSeg;++i){start=this.components[i];x1=approx(start.x,digs);y1=approx(start.y,digs);end=this.components[i+1];x2=approx(end.x,digs);y2=approx(end.y,digs);if(y1==y2){if(py==y1){if(x1<=x2&&(px>=x1&&px<=x2)||x1>=x2&&(px<=x1&&px>=x2)){crosses=-1;break;}}
+continue;}
+cx=approx(getX(py,x1,y1,x2,y2),digs);if(cx==px){if(y1<y2&&(py>=y1&&py<=y2)||y1>y2&&(py<=y1&&py>=y2)){crosses=-1;break;}}
+if(cx<=px){continue;}
+if(x1!=x2&&(cx<Math.min(x1,x2)||cx>Math.max(x1,x2))){continue;}
+if(y1<y2&&(py>=y1&&py<y2)||y1>y2&&(py<y1&&py>=y2)){++crosses;}}
+var contained=(crosses==-1)?1:!!(crosses&1);return contained;},intersects:function(geometry){var intersect=false;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.containsPoint(geometry);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"){intersect=geometry.intersects(this);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){intersect=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[geometry]);}else{for(var i=0,len=geometry.components.length;i<len;++i){intersect=geometry.components[i].intersects(this);if(intersect){break;}}}
+return intersect;},getVertices:function(nodes){return(nodes===true)?[]:this.components.slice(0,this.components.length-1);},CLASS_NAME:"OpenLayers.Geometry.LinearRing"});OpenLayers.Animation=(function(window){var isNative=!!(window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame);var requestFrame=(function(){var request=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(callback,element){window.setTimeout(callback,16);};return function(callback,element){request.apply(window,[callback,element]);};})();var counter=0;var loops={};function start(callback,duration,element){duration=duration>0?duration:Number.POSITIVE_INFINITY;var id=++counter;var start=+new Date;loops[id]=function(){if(loops[id]&&+new Date-start<=duration){callback();if(loops[id]){requestFrame(loops[id],element);}}else{delete loops[id];}};requestFrame(loops[id],element);return id;}
+function stop(id){delete loops[id];}
+return{isNative:isNative,requestFrame:requestFrame,start:start,stop:stop};})(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,animationId:null,playing:false,initialize:function(easing){this.easing=(easing)?easing:OpenLayers.Easing.Expo.easeOut;},start:function(begin,finish,duration,options){this.playing=true;this.begin=begin;this.finish=finish;this.duration=duration;this.callbacks=options.callbacks;this.time=0;OpenLayers.Animation.stop(this.animationId);this.animationId=null;if(this.callbacks&&this.callbacks.start){this.callbacks.start.call(this,this.begin);}
+this.animationId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.play,this));},stop:function(){if(!this.playing){return;}
+if(this.callbacks&&this.callbacks.done){this.callbacks.done.call(this,this.finish);}
+OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.playing=false;},play:function(){var value={};for(var i in this.begin){var b=this.begin[i];var f=this.finish[i];if(b==null||f==null||isNaN(b)||isNaN(f)){throw new TypeError('invalid value for Tween');}
+var c=f-b;value[i]=this.easing.apply(this,[this.time,b,c,this.duration]);}
+this.time++;if(this.callbacks&&this.callbacks.eachStep){this.callbacks.eachStep.call(this,value);}
+if(this.time>this.duration){this.stop();}},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(t,b,c,d){return c*t/d+b;},easeOut:function(t,b,c,d){return c*t/d+b;},easeInOut:function(t,b,c,d){return c*t/d+b;},CLASS_NAME:"OpenLayers.Easing.Linear"};OpenLayers.Easing.Expo={easeIn:function(t,b,c,d){return(t==0)?b:c*Math.pow(2,10*(t/d-1))+b;},easeOut:function(t,b,c,d){return(t==d)?b+c:c*(-Math.pow(2,-10*t/d)+1)+b;},easeInOut:function(t,b,c,d){if(t==0)return b;if(t==d)return b+c;if((t/=d/2)<1)return c/2*Math.pow(2,10*(t-1))+b;return c/2*(-Math.pow(2,-10*--t)+2)+b;},CLASS_NAME:"OpenLayers.Easing.Expo"};OpenLayers.Easing.Quad={easeIn:function(t,b,c,d){return c*(t/=d)*t+b;},easeOut:function(t,b,c,d){return-c*(t/=d)*(t-2)+b;},easeInOut:function(t,b,c,d){if((t/=d/2)<1)return c/2*t*t+b;return-c/2*((--t)*(t-2)-1)+b;},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(projCode,options){OpenLayers.Util.extend(this,options);this.projCode=projCode;if(window.Proj4js){this.proj=new Proj4js.Proj(projCode);}},getCode:function(){return this.proj?this.proj.srsCode:this.projCode;},getUnits:function(){return this.proj?this.proj.units:null;},toString:function(){return this.getCode();},equals:function(projection){var p=projection,equals=false;if(p){if(!(p instanceof OpenLayers.Projection)){p=new OpenLayers.Projection(p);}
+if(window.Proj4js&&this.proj.defData&&p.proj.defData){equals=this.proj.defData.replace(this.titleRegEx,"")==p.proj.defData.replace(this.titleRegEx,"");}else if(p.getCode){var source=this.getCode(),target=p.getCode();equals=source==target||!!OpenLayers.Projection.transforms[source]&&OpenLayers.Projection.transforms[source][target]===OpenLayers.Projection.nullTransform;}}
+return equals;},destroy:function(){delete this.proj;delete this.projCode;},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};OpenLayers.Projection.defaults={"EPSG:4326":{units:"degrees",maxExtent:[-180,-90,180,90],yx:true},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-20037508.34,-20037508.34,20037508.34,20037508.34]}};OpenLayers.Projection.addTransform=function(from,to,method){if(method===OpenLayers.Projection.nullTransform){var defaults=OpenLayers.Projection.defaults[from];if(defaults&&!OpenLayers.Projection.defaults[to]){OpenLayers.Projection.defaults[to]=defaults;}}
+if(!OpenLayers.Projection.transforms[from]){OpenLayers.Projection.transforms[from]={};}
+OpenLayers.Projection.transforms[from][to]=method;};OpenLayers.Projection.transform=function(point,source,dest){if(source&&dest){if(!(source instanceof OpenLayers.Projection)){source=new OpenLayers.Projection(source);}
+if(!(dest instanceof OpenLayers.Projection)){dest=new OpenLayers.Projection(dest);}
+if(source.proj&&dest.proj){point=Proj4js.transform(source.proj,dest.proj,point);}else{var sourceCode=source.getCode();var destCode=dest.getCode();var transforms=OpenLayers.Projection.transforms;if(transforms[sourceCode]&&transforms[sourceCode][destCode]){transforms[sourceCode][destCode](point);}}}
+return point;};OpenLayers.Projection.nullTransform=function(point){return point;};(function(){var pole=20037508.34;function inverseMercator(xy){xy.x=180*xy.x/pole;xy.y=180/Math.PI*(2*Math.atan(Math.exp((xy.y/pole)*Math.PI))-Math.PI/2);return xy;}
+function forwardMercator(xy){xy.x=xy.x*pole/180;xy.y=Math.log(Math.tan((90+xy.y)*Math.PI/360))/Math.PI*pole;return xy;}
+function map(base,codes){var add=OpenLayers.Projection.addTransform;var same=OpenLayers.Projection.nullTransform;var i,len,code,other,j;for(i=0,len=codes.length;i<len;++i){code=codes[i];add(base,code,forwardMercator);add(code,base,inverseMercator);for(j=i+1;j<len;++j){other=codes[j];add(code,other,same);add(other,code,same);}}}
+var mercator=["EPSG:900913","EPSG:3857","EPSG:102113","EPSG:102100"],geographic=["CRS:84","urn:ogc:def:crs:EPSG:6.6:4326","EPSG:4326"],i;for(i=mercator.length-1;i>=0;--i){map(mercator[i],geographic);}
+for(i=geographic.length-1;i>=0;--i){map(geographic[i],mercator);}})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1000},id:null,fractionalZoom:false,events:null,allOverlays:false,div:null,dragging:false,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,options:null,tileSize:null,projection:"EPSG:4326",units:null,resolutions:null,maxResolution:null,minResolution:null,maxScale:null,minScale:null,maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:true,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,paddingForPopups:null,minPx:null,maxPx:null,initialize:function(div,options){if(arguments.length===1&&typeof div==="object"){options=div;div=options&&options.div;}
+this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()+'theme/default/style.css';this.options=OpenLayers.Util.extend({},options);OpenLayers.Util.extend(this,options);var projCode=this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection;OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[projCode]);if(this.maxExtent&&!(this.maxExtent instanceof OpenLayers.Bounds)){this.maxExtent=new OpenLayers.Bounds(this.maxExtent);}
+if(this.minExtent&&!(this.minExtent instanceof OpenLayers.Bounds)){this.minExtent=new OpenLayers.Bounds(this.minExtent);}
+if(this.restrictedExtent&&!(this.restrictedExtent instanceof OpenLayers.Bounds)){this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent);}
+if(this.center&&!(this.center instanceof OpenLayers.LonLat)){this.center=new OpenLayers.LonLat(this.center);}
+this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(div);if(!this.div){this.div=document.createElement("div");this.div.style.height="1px";this.div.style.width="1px";}
+OpenLayers.Element.addClass(this.div,'olMap');var id=this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(id,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);this.events=new OpenLayers.Events(this,this.viewPortDiv,null,this.fallThrough,{includeXY:true});id=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(id);this.layerContainerDiv.style.width='100px';this.layerContainerDiv.style.height='100px';this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.updateSize();if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}
+if(parseFloat(navigator.appVersion.split("MSIE")[1])<9){this.events.register("resize",this,this.updateSize);}else{this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this);OpenLayers.Event.observe(window,'resize',this.updateSizeDestroy);}
+if(this.theme){var addNode=true;var nodes=document.getElementsByTagName('link');for(var i=0,len=nodes.length;i<len;++i){if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,this.theme)){addNode=false;break;}}
+if(addNode){var cssNode=document.createElement('link');cssNode.setAttribute('rel','stylesheet');cssNode.setAttribute('type','text/css');cssNode.setAttribute('href',this.theme);document.getElementsByTagName('head')[0].appendChild(cssNode);}}
+if(this.controls==null){this.controls=[];if(OpenLayers.Control!=null){if(OpenLayers.Control.Navigation){this.controls.push(new OpenLayers.Control.Navigation());}else if(OpenLayers.Control.TouchNavigation){this.controls.push(new OpenLayers.Control.TouchNavigation());}
+if(OpenLayers.Control.Zoom){this.controls.push(new OpenLayers.Control.Zoom());}else if(OpenLayers.Control.PanZoom){this.controls.push(new OpenLayers.Control.PanZoom());}
+if(OpenLayers.Control.ArgParser){this.controls.push(new OpenLayers.Control.ArgParser());}
+if(OpenLayers.Control.Attribution){this.controls.push(new OpenLayers.Control.Attribution());}}}
+for(var i=0,len=this.controls.length;i<len;i++){this.addControlToMap(this.controls[i]);}
+this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,'unload',this.unloadDestroy);if(options&&options.layers){delete this.center;this.addLayers(options.layers);if(options.center&&!this.getCenter()){this.setCenter(options.center,options.zoom);}}},getViewport:function(){return this.viewPortDiv;},render:function(div){this.div=OpenLayers.Util.getElement(div);OpenLayers.Element.addClass(this.div,'olMap');this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);this.div.appendChild(this.viewPortDiv);this.updateSize();},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy){return false;}
+if(this.panTween){this.panTween.stop();this.panTween=null;}
+OpenLayers.Event.stopObserving(window,'unload',this.unloadDestroy);this.unloadDestroy=null;if(this.updateSizeDestroy){OpenLayers.Event.stopObserving(window,'resize',this.updateSizeDestroy);}else{this.events.unregister("resize",this,this.updateSize);}
+this.paddingForPopups=null;if(this.controls!=null){for(var i=this.controls.length-1;i>=0;--i){this.controls[i].destroy();}
+this.controls=null;}
+if(this.layers!=null){for(var i=this.layers.length-1;i>=0;--i){this.layers[i].destroy(false);}
+this.layers=null;}
+if(this.viewPortDiv){this.div.removeChild(this.viewPortDiv);}
+this.viewPortDiv=null;if(this.eventListeners){this.events.un(this.eventListeners);this.eventListeners=null;}
+this.events.destroy();this.events=null;this.options=null;},setOptions:function(options){var updatePxExtent=this.minPx&&options.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,options);updatePxExtent&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:true});},getTileSize:function(){return this.tileSize;},getBy:function(array,property,match){var test=(typeof match.test=="function");var found=OpenLayers.Array.filter(this[array],function(item){return item[property]==match||(test&&match.test(item[property]));});return found;},getLayersBy:function(property,match){return this.getBy("layers",property,match);},getLayersByName:function(match){return this.getLayersBy("name",match);},getLayersByClass:function(match){return this.getLayersBy("CLASS_NAME",match);},getControlsBy:function(property,match){return this.getBy("controls",property,match);},getControlsByClass:function(match){return this.getControlsBy("CLASS_NAME",match);},getLayer:function(id){var foundLayer=null;for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];if(layer.id==id){foundLayer=layer;break;}}
+return foundLayer;},setLayerZIndex:function(layer,zIdx){layer.setZIndex(this.Z_INDEX_BASE[layer.isBaseLayer?'BaseLayer':'Overlay']
++zIdx*5);},resetLayersZIndex:function(){for(var i=0,len=this.layers.length;i<len;i++){var layer=this.layers[i];this.setLayerZIndex(layer,i);}},addLayer:function(layer){for(var i=0,len=this.layers.length;i<len;i++){if(this.layers[i]==layer){return false;}}
+if(this.events.triggerEvent("preaddlayer",{layer:layer})===false){return false;}
+if(this.allOverlays){layer.isBaseLayer=false;}
+layer.div.className="olLayerDiv";layer.div.style.overflow="";this.setLayerZIndex(layer,this.layers.length);if(layer.isFixed){this.viewPortDiv.appendChild(layer.div);}else{this.layerContainerDiv.appendChild(layer.div);}
+this.layers.push(layer);layer.setMap(this);if(layer.isBaseLayer||(this.allOverlays&&!this.baseLayer)){if(this.baseLayer==null){this.setBaseLayer(layer);}else{layer.setVisibility(false);}}else{layer.redraw();}
+this.events.triggerEvent("addlayer",{layer:layer});layer.events.triggerEvent("added",{map:this,layer:layer});layer.afterAdd();return true;},addLayers:function(layers){for(var i=0,len=layers.length;i<len;i++){this.addLayer(layers[i]);}},removeLayer:function(layer,setNewBaseLayer){if(this.events.triggerEvent("preremovelayer",{layer:layer})===false){return;}
+if(setNewBaseLayer==null){setNewBaseLayer=true;}
+if(layer.isFixed){this.viewPortDiv.removeChild(layer.div);}else{this.layerContainerDiv.removeChild(layer.div);}
+OpenLayers.Util.removeItem(this.layers,layer);layer.removeMap(this);layer.map=null;if(this.baseLayer==layer){this.baseLayer=null;if(setNewBaseLayer){for(var i=0,len=this.layers.length;i<len;i++){var iLayer=this.layers[i];if(iLayer.isBaseLayer||this.allOverlays){this.setBaseLayer(iLayer);break;}}}}
+this.resetLayersZIndex();this.events.triggerEvent("removelayer",{layer:layer});layer.events.triggerEvent("removed",{map:this,layer:layer});},getNumLayers:function(){return this.layers.length;},getLayerIndex:function(layer){return OpenLayers.Util.indexOf(this.layers,layer);},setLayerIndex:function(layer,idx){var base=this.getLayerIndex(layer);if(idx<0){idx=0;}else if(idx>this.layers.length){idx=this.layers.length;}
+if(base!=idx){this.layers.splice(base,1);this.layers.splice(idx,0,layer);for(var i=0,len=this.layers.length;i<len;i++){this.setLayerZIndex(this.layers[i],i);}
+this.events.triggerEvent("changelayer",{layer:layer,property:"order"});if(this.allOverlays){if(idx===0){this.setBaseLayer(layer);}else if(this.baseLayer!==this.layers[0]){this.setBaseLayer(this.layers[0]);}}}},raiseLayer:function(layer,delta){var idx=this.getLayerIndex(layer)+delta;this.setLayerIndex(layer,idx);},setBaseLayer:function(newBaseLayer){if(newBaseLayer!=this.baseLayer){if(OpenLayers.Util.indexOf(this.layers,newBaseLayer)!=-1){var center=this.getCachedCenter();var newResolution=OpenLayers.Util.getResolutionFromScale(this.getScale(),newBaseLayer.units);if(this.baseLayer!=null&&!this.allOverlays){this.baseLayer.setVisibility(false);}
+this.baseLayer=newBaseLayer;if(!this.allOverlays||this.baseLayer.visibility){this.baseLayer.setVisibility(true);if(this.baseLayer.inRange===false){this.baseLayer.redraw();}}
+if(center!=null){var newZoom=this.getZoomForResolution(newResolution||this.resolution,true);this.setCenter(center,newZoom,false,true);}
+this.events.triggerEvent("changebaselayer",{layer:this.baseLayer});}}},addControl:function(control,px){this.controls.push(control);this.addControlToMap(control,px);},addControls:function(controls,pixels){var pxs=(arguments.length===1)?[]:pixels;for(var i=0,len=controls.length;i<len;i++){var ctrl=controls[i];var px=(pxs[i])?pxs[i]:null;this.addControl(ctrl,px);}},addControlToMap:function(control,px){control.outsideViewport=(control.div!=null);if(this.displayProjection&&!control.displayProjection){control.displayProjection=this.displayProjection;}
+control.setMap(this);var div=control.draw(px);if(div){if(!control.outsideViewport){div.style.zIndex=this.Z_INDEX_BASE['Control']+
+this.controls.length;this.viewPortDiv.appendChild(div);}}
+if(control.autoActivate){control.activate();}},getControl:function(id){var returnControl=null;for(var i=0,len=this.controls.length;i<len;i++){var control=this.controls[i];if(control.id==id){returnControl=control;break;}}
+return returnControl;},removeControl:function(control){if((control)&&(control==this.getControl(control.id))){if(control.div&&(control.div.parentNode==this.viewPortDiv)){this.viewPortDiv.removeChild(control.div);}
+OpenLayers.Util.removeItem(this.controls,control);}},addPopup:function(popup,exclusive){if(exclusive){for(var i=this.popups.length-1;i>=0;--i){this.removePopup(this.popups[i]);}}
+popup.map=this;this.popups.push(popup);var popupDiv=popup.draw();if(popupDiv){popupDiv.style.zIndex=this.Z_INDEX_BASE['Popup']+
+this.popups.length;this.layerContainerDiv.appendChild(popupDiv);}},removePopup:function(popup){OpenLayers.Util.removeItem(this.popups,popup);if(popup.div){try{this.layerContainerDiv.removeChild(popup.div);}
+catch(e){}}
+popup.map=null;},getSize:function(){var size=null;if(this.size!=null){size=this.size.clone();}
+return size;},updateSize:function(){var newSize=this.getCurrentSize();if(newSize&&!isNaN(newSize.h)&&!isNaN(newSize.w)){this.events.clearMouseCache();var oldSize=this.getSize();if(oldSize==null){this.size=oldSize=newSize;}
+if(!newSize.equals(oldSize)){this.size=newSize;for(var i=0,len=this.layers.length;i<len;i++){this.layers[i].onMapResize();}
+var center=this.getCachedCenter();if(this.baseLayer!=null&&center!=null){var zoom=this.getZoom();this.zoom=null;this.setCenter(center,zoom);}}}},getCurrentSize:function(){var size=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=this.div.offsetWidth;size.h=this.div.offsetHeight;}
+if(size.w==0&&size.h==0||isNaN(size.w)&&isNaN(size.h)){size.w=parseInt(this.div.style.width);size.h=parseInt(this.div.style.height);}
+return size;},calculateBounds:function(center,resolution){var extent=null;if(center==null){center=this.getCachedCenter();}
+if(resolution==null){resolution=this.getResolution();}
+if((center!=null)&&(resolution!=null)){var halfWDeg=(this.size.w*resolution)/2;var halfHDeg=(this.size.h*resolution)/2;extent=new OpenLayers.Bounds(center.lon-halfWDeg,center.lat-halfHDeg,center.lon+halfWDeg,center.lat+halfHDeg);}
+return extent;},getCenter:function(){var center=null;var cachedCenter=this.getCachedCenter();if(cachedCenter){center=cachedCenter.clone();}
+return center;},getCachedCenter:function(){if(!this.center&&this.size){this.center=this.getLonLatFromViewPortPx({x:this.size.w/2,y:this.size.h/2});}
+return this.center;},getZoom:function(){return this.zoom;},pan:function(dx,dy,options){options=OpenLayers.Util.applyDefaults(options,{animate:true,dragging:false});if(options.dragging){if(dx!=0||dy!=0){this.moveByPx(dx,dy);}}else{var centerPx=this.getViewPortPxFromLonLat(this.getCachedCenter());var newCenterPx=centerPx.add(dx,dy);if(this.dragging||!newCenterPx.equals(centerPx)){var newCenterLonLat=this.getLonLatFromViewPortPx(newCenterPx);if(options.animate){this.panTo(newCenterLonLat);}else{this.moveTo(newCenterLonLat);if(this.dragging){this.dragging=false;this.events.triggerEvent("moveend");}}}}},panTo:function(lonlat){if(this.panMethod&&this.getExtent().scale(this.panRatio).containsLonLat(lonlat)){if(!this.panTween){this.panTween=new OpenLayers.Tween(this.panMethod);}
+var center=this.getCachedCenter();if(lonlat.equals(center)){return;}
+var from=this.getPixelFromLonLat(center);var to=this.getPixelFromLonLat(lonlat);var vector={x:to.x-from.x,y:to.y-from.y};var last={x:0,y:0};this.panTween.start({x:0,y:0},vector,this.panDuration,{callbacks:{eachStep:OpenLayers.Function.bind(function(px){var x=px.x-last.x,y=px.y-last.y;this.moveByPx(x,y);last.x=Math.round(px.x);last.y=Math.round(px.y);},this),done:OpenLayers.Function.bind(function(px){this.moveTo(lonlat);this.dragging=false;this.events.triggerEvent("moveend");},this)}});}else{this.setCenter(lonlat);}},setCenter:function(lonlat,zoom,dragging,forceZoomChange){this.panTween&&this.panTween.stop();this.moveTo(lonlat,zoom,{'dragging':dragging,'forceZoomChange':forceZoomChange});},moveByPx:function(dx,dy){var hw=this.size.w/2;var hh=this.size.h/2;var x=hw+dx;var y=hh+dy;var wrapDateLine=this.baseLayer.wrapDateLine;var xRestriction=0;var yRestriction=0;if(this.restrictedExtent){xRestriction=hw;yRestriction=hh;wrapDateLine=false;}
+dx=wrapDateLine||x<=this.maxPx.x-xRestriction&&x>=this.minPx.x+xRestriction?Math.round(dx):0;dy=y<=this.maxPx.y-yRestriction&&y>=this.minPx.y+yRestriction?Math.round(dy):0;if(dx||dy){if(!this.dragging){this.dragging=true;this.events.triggerEvent("movestart");}
+this.center=null;if(dx){this.layerContainerDiv.style.left=parseInt(this.layerContainerDiv.style.left)-dx+"px";this.minPx.x-=dx;this.maxPx.x-=dx;}
+if(dy){this.layerContainerDiv.style.top=parseInt(this.layerContainerDiv.style.top)-dy+"px";this.minPx.y-=dy;this.maxPx.y-=dy;}
+var layer,i,len;for(i=0,len=this.layers.length;i<len;++i){layer=this.layers[i];if(layer.visibility&&(layer===this.baseLayer||layer.inRange)){layer.moveByPx(dx,dy);layer.events.triggerEvent("move");}}
+this.events.triggerEvent("move");}},adjustZoom:function(zoom){var resolution,resolutions=this.baseLayer.resolutions,maxResolution=this.getMaxExtent().getWidth()/this.size.w;if(this.getResolutionForZoom(zoom)>maxResolution){for(var i=zoom|0,ii=resolutions.length;i<ii;++i){if(resolutions[i]<=maxResolution){zoom=i;break;}}}
+return zoom;},moveTo:function(lonlat,zoom,options){if(lonlat!=null&&!(lonlat instanceof OpenLayers.LonLat)){lonlat=new OpenLayers.LonLat(lonlat);}
+if(!options){options={};}
+if(zoom!=null){zoom=parseFloat(zoom);if(!this.fractionalZoom){zoom=Math.round(zoom);}}
+if(this.baseLayer.wrapDateLine){var requestedZoom=zoom;zoom=this.adjustZoom(zoom);if(zoom!==requestedZoom){lonlat=this.getCenter();}}
+var dragging=options.dragging||this.dragging;var forceZoomChange=options.forceZoomChange;if(!this.getCachedCenter()&&!this.isValidLonLat(lonlat)){lonlat=this.maxExtent.getCenterLonLat();this.center=lonlat.clone();}
+if(this.restrictedExtent!=null){if(lonlat==null){lonlat=this.center;}
+if(zoom==null){zoom=this.getZoom();}
+var resolution=this.getResolutionForZoom(zoom);var extent=this.calculateBounds(lonlat,resolution);if(!this.restrictedExtent.containsBounds(extent)){var maxCenter=this.restrictedExtent.getCenterLonLat();if(extent.getWidth()>this.restrictedExtent.getWidth()){lonlat=new OpenLayers.LonLat(maxCenter.lon,lonlat.lat);}else if(extent.left<this.restrictedExtent.left){lonlat=lonlat.add(this.restrictedExtent.left-
+extent.left,0);}else if(extent.right>this.restrictedExtent.right){lonlat=lonlat.add(this.restrictedExtent.right-
+extent.right,0);}
+if(extent.getHeight()>this.restrictedExtent.getHeight()){lonlat=new OpenLayers.LonLat(lonlat.lon,maxCenter.lat);}else if(extent.bottom<this.restrictedExtent.bottom){lonlat=lonlat.add(0,this.restrictedExtent.bottom-
+extent.bottom);}
+else if(extent.top>this.restrictedExtent.top){lonlat=lonlat.add(0,this.restrictedExtent.top-
+extent.top);}}}
+var zoomChanged=forceZoomChange||((this.isValidZoomLevel(zoom))&&(zoom!=this.getZoom()));var centerChanged=(this.isValidLonLat(lonlat))&&(!lonlat.equals(this.center));if(zoomChanged||centerChanged||dragging){dragging||this.events.triggerEvent("movestart");if(centerChanged){if(!zoomChanged&&this.center){this.centerLayerContainer(lonlat);}
+this.center=lonlat.clone();}
+var res=zoomChanged?this.getResolutionForZoom(zoom):this.getResolution();if(zoomChanged||this.layerContainerOrigin==null){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";var maxExtent=this.getMaxExtent({restricted:true});var maxExtentCenter=maxExtent.getCenterLonLat();var lonDelta=this.center.lon-maxExtentCenter.lon;var latDelta=maxExtentCenter.lat-this.center.lat;var extentWidth=Math.round(maxExtent.getWidth()/res);var extentHeight=Math.round(maxExtent.getHeight()/res);this.minPx={x:(this.size.w-extentWidth)/2-lonDelta/res,y:(this.size.h-extentHeight)/2-latDelta/res};this.maxPx={x:this.minPx.x+Math.round(maxExtent.getWidth()/res),y:this.minPx.y+Math.round(maxExtent.getHeight()/res)};}
+if(zoomChanged){this.zoom=zoom;this.resolution=res;}
+var bounds=this.getExtent();if(this.baseLayer.visibility){this.baseLayer.moveTo(bounds,zoomChanged,options.dragging);options.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:zoomChanged});}
+bounds=this.baseLayer.getExtent();for(var i=this.layers.length-1;i>=0;--i){var layer=this.layers[i];if(layer!==this.baseLayer&&!layer.isBaseLayer){var inRange=layer.calculateInRange();if(layer.inRange!=inRange){layer.inRange=inRange;if(!inRange){layer.display(false);}
+this.events.triggerEvent("changelayer",{layer:layer,property:"visibility"});}
+if(inRange&&layer.visibility){layer.moveTo(bounds,zoomChanged,options.dragging);options.dragging||layer.events.triggerEvent("moveend",{zoomChanged:zoomChanged});}}}
+this.events.triggerEvent("move");dragging||this.events.triggerEvent("moveend");if(zoomChanged){for(var i=0,len=this.popups.length;i<len;i++){this.popups[i].updatePosition();}
+this.events.triggerEvent("zoomend");}}},centerLayerContainer:function(lonlat){var originPx=this.getViewPortPxFromLonLat(this.layerContainerOrigin);var newPx=this.getViewPortPxFromLonLat(lonlat);if((originPx!=null)&&(newPx!=null)){var oldLeft=parseInt(this.layerContainerDiv.style.left);var oldTop=parseInt(this.layerContainerDiv.style.top);var newLeft=Math.round(originPx.x-newPx.x);var newTop=Math.round(originPx.y-newPx.y);this.layerContainerDiv.style.left=newLeft+"px";this.layerContainerDiv.style.top=newTop+"px";var dx=oldLeft-newLeft;var dy=oldTop-newTop;this.minPx.x-=dx;this.maxPx.x-=dx;this.minPx.y-=dy;this.maxPx.y-=dy;}},isValidZoomLevel:function(zoomLevel){return((zoomLevel!=null)&&(zoomLevel>=0)&&(zoomLevel<this.getNumZoomLevels()));},isValidLonLat:function(lonlat){var valid=false;if(lonlat!=null){var maxExtent=this.getMaxExtent();var worldBounds=this.baseLayer.wrapDateLine&&maxExtent;valid=maxExtent.containsLonLat(lonlat,{worldBounds:worldBounds});}
+return valid;},getProjection:function(){var projection=this.getProjectionObject();return projection?projection.getCode():null;},getProjectionObject:function(){var projection=null;if(this.baseLayer!=null){projection=this.baseLayer.projection;}
+return projection;},getMaxResolution:function(){var maxResolution=null;if(this.baseLayer!=null){maxResolution=this.baseLayer.maxResolution;}
+return maxResolution;},getMaxExtent:function(options){var maxExtent=null;if(options&&options.restricted&&this.restrictedExtent){maxExtent=this.restrictedExtent;}else if(this.baseLayer!=null){maxExtent=this.baseLayer.maxExtent;}
+return maxExtent;},getNumZoomLevels:function(){var numZoomLevels=null;if(this.baseLayer!=null){numZoomLevels=this.baseLayer.numZoomLevels;}
+return numZoomLevels;},getExtent:function(){var extent=null;if(this.baseLayer!=null){extent=this.baseLayer.getExtent();}
+return extent;},getResolution:function(){var resolution=null;if(this.baseLayer!=null){resolution=this.baseLayer.getResolution();}else if(this.allOverlays===true&&this.layers.length>0){resolution=this.layers[0].getResolution();}
+return resolution;},getUnits:function(){var units=null;if(this.baseLayer!=null){units=this.baseLayer.units;}
+return units;},getScale:function(){var scale=null;if(this.baseLayer!=null){var res=this.getResolution();var units=this.baseLayer.units;scale=OpenLayers.Util.getScaleFromResolution(res,units);}
+return scale;},getZoomForExtent:function(bounds,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForExtent(bounds,closest);}
+return zoom;},getResolutionForZoom:function(zoom){var resolution=null;if(this.baseLayer){resolution=this.baseLayer.getResolutionForZoom(zoom);}
+return resolution;},getZoomForResolution:function(resolution,closest){var zoom=null;if(this.baseLayer!=null){zoom=this.baseLayer.getZoomForResolution(resolution,closest);}
+return zoom;},zoomTo:function(zoom){if(this.isValidZoomLevel(zoom)){this.setCenter(null,zoom);}},zoomIn:function(){this.zoomTo(this.getZoom()+1);},zoomOut:function(){this.zoomTo(this.getZoom()-1);},zoomToExtent:function(bounds,closest){if(!(bounds instanceof OpenLayers.Bounds)){bounds=new OpenLayers.Bounds(bounds);}
+var center=bounds.getCenterLonLat();if(this.baseLayer.wrapDateLine){var maxExtent=this.getMaxExtent();bounds=bounds.clone();while(bounds.right<bounds.left){bounds.right+=maxExtent.getWidth();}
+center=bounds.getCenterLonLat().wrapDateLine(maxExtent);}
+this.setCenter(center,this.getZoomForExtent(bounds,closest));},zoomToMaxExtent:function(options){var restricted=(options)?options.restricted:true;var maxExtent=this.getMaxExtent({'restricted':restricted});this.zoomToExtent(maxExtent);},zoomToScale:function(scale,closest){var res=OpenLayers.Util.getResolutionFromScale(scale,this.baseLayer.units);var halfWDeg=(this.size.w*res)/2;var halfHDeg=(this.size.h*res)/2;var center=this.getCachedCenter();var extent=new OpenLayers.Bounds(center.lon-halfWDeg,center.lat-halfHDeg,center.lon+halfWDeg,center.lat+halfHDeg);this.zoomToExtent(extent,closest);},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;if(this.baseLayer!=null){lonlat=this.baseLayer.getLonLatFromViewPortPx(viewPortPx);}
+return lonlat;},getViewPortPxFromLonLat:function(lonlat){var px=null;if(this.baseLayer!=null){px=this.baseLayer.getViewPortPxFromLonLat(lonlat);}
+return px;},getLonLatFromPixel:function(px){return this.getLonLatFromViewPortPx(px);},getPixelFromLonLat:function(lonlat){var px=this.getViewPortPxFromLonLat(lonlat);px.x=Math.round(px.x);px.y=Math.round(px.y);return px;},getGeodesicPixelSize:function(px){var lonlat=px?this.getLonLatFromPixel(px):(this.getCachedCenter()||new OpenLayers.LonLat(0,0));var res=this.getResolution();var left=lonlat.add(-res/2,0);var right=lonlat.add(res/2,0);var bottom=lonlat.add(0,-res/2);var top=lonlat.add(0,res/2);var dest=new OpenLayers.Projection("EPSG:4326");var source=this.getProjectionObject()||dest;if(!source.equals(dest)){left.transform(source,dest);right.transform(source,dest);bottom.transform(source,dest);top.transform(source,dest);}
+return new OpenLayers.Size(OpenLayers.Util.distVincenty(left,right),OpenLayers.Util.distVincenty(bottom,top));},getViewPortPxFromLayerPx:function(layerPx){var viewPortPx=null;if(layerPx!=null){var dX=parseInt(this.layerContainerDiv.style.left);var dY=parseInt(this.layerContainerDiv.style.top);viewPortPx=layerPx.add(dX,dY);}
+return viewPortPx;},getLayerPxFromViewPortPx:function(viewPortPx){var layerPx=null;if(viewPortPx!=null){var dX=-parseInt(this.layerContainerDiv.style.left);var dY=-parseInt(this.layerContainerDiv.style.top);layerPx=viewPortPx.add(dX,dY);if(isNaN(layerPx.x)||isNaN(layerPx.y)){layerPx=null;}}
+return layerPx;},getLonLatFromLayerPx:function(px){px=this.getViewPortPxFromLayerPx(px);return this.getLonLatFromViewPortPx(px);},getLayerPxFromLonLat:function(lonlat){var px=this.getPixelFromLonLat(lonlat);return this.getLayerPxFromViewPortPx(px);},CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:1,alwaysInRange:null,RESOLUTION_PROPERTIES:['scales','resolutions','maxScale','minScale','maxResolution','minResolution','numZoomLevels','maxZoomLevel'],events:null,map:null,isBaseLayer:false,alpha:false,displayInLayerSwitcher:true,visibility:true,attribution:null,inRange:false,imageSize:null,options:null,eventListeners:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:false,wrapDateLine:false,metadata:null,initialize:function(name,options){this.metadata={};this.addOptions(options);this.name=name;if(this.id==null){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");this.div=OpenLayers.Util.createDiv(this.id);this.div.style.width="100%";this.div.style.height="100%";this.div.dir="ltr";this.events=new OpenLayers.Events(this,this.div);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}}},destroy:function(setNewBaseLayer){if(setNewBaseLayer==null){setNewBaseLayer=true;}
+if(this.map!=null){this.map.removeLayer(this,setNewBaseLayer);}
+this.projection=null;this.map=null;this.name=null;this.div=null;this.options=null;if(this.events){if(this.eventListeners){this.events.un(this.eventListeners);}
+this.events.destroy();}
+this.eventListeners=null;this.events=null;},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer(this.name,this.getOptions());}
+OpenLayers.Util.applyDefaults(obj,this);obj.map=null;return obj;},getOptions:function(){var options={};for(var o in this.options){options[o]=this[o];}
+return options;},setName:function(newName){if(newName!=this.name){this.name=newName;if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"name"});}}},addOptions:function(newOptions,reinitialize){if(this.options==null){this.options={};}
+if(newOptions){if(typeof newOptions.projection=="string"){newOptions.projection=new OpenLayers.Projection(newOptions.projection);}
+if(newOptions.projection){OpenLayers.Util.applyDefaults(newOptions,OpenLayers.Projection.defaults[newOptions.projection.getCode()]);}
+if(newOptions.maxExtent&&!(newOptions.maxExtent instanceof OpenLayers.Bounds)){newOptions.maxExtent=new OpenLayers.Bounds(newOptions.maxExtent);}
+if(newOptions.minExtent&&!(newOptions.minExtent instanceof OpenLayers.Bounds)){newOptions.minExtent=new OpenLayers.Bounds(newOptions.minExtent);}}
+OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);if(this.projection&&this.projection.getUnits()){this.units=this.projection.getUnits();}
+if(this.map){var resolution=this.map.getResolution();var properties=this.RESOLUTION_PROPERTIES.concat(["projection","units","minExtent","maxExtent"]);for(var o in newOptions){if(newOptions.hasOwnProperty(o)&&OpenLayers.Util.indexOf(properties,o)>=0){this.initResolutions();if(reinitialize&&this.map.baseLayer===this){this.map.setCenter(this.map.getCenter(),this.map.getZoomForResolution(resolution),false,true);this.map.events.triggerEvent("changebaselayer",{layer:this});}
+break;}}}},onMapResize:function(){},redraw:function(){var redrawn=false;if(this.map){this.inRange=this.calculateInRange();var extent=this.getExtent();if(extent&&this.inRange&&this.visibility){var zoomChanged=true;this.moveTo(extent,zoomChanged,false);this.events.triggerEvent("moveend",{"zoomChanged":zoomChanged});redrawn=true;}}
+return redrawn;},moveTo:function(bounds,zoomChanged,dragging){var display=this.visibility;if(!this.isBaseLayer){display=display&&this.inRange;}
+this.display(display);},moveByPx:function(dx,dy){},setMap:function(map){if(this.map==null){this.map=map;this.maxExtent=this.maxExtent||this.map.maxExtent;this.minExtent=this.minExtent||this.map.minExtent;this.projection=this.projection||this.map.projection;if(typeof this.projection=="string"){this.projection=new OpenLayers.Projection(this.projection);}
+this.units=this.projection.getUnits()||this.units||this.map.units;this.initResolutions();if(!this.isBaseLayer){this.inRange=this.calculateInRange();var show=((this.visibility)&&(this.inRange));this.div.style.display=show?"":"none";}
+this.setTileSize();}},afterAdd:function(){},removeMap:function(map){},getImageSize:function(bounds){return(this.imageSize||this.tileSize);},setTileSize:function(size){var tileSize=(size)?size:((this.tileSize)?this.tileSize:this.map.getTileSize());this.tileSize=tileSize;if(this.gutter){this.imageSize=new OpenLayers.Size(tileSize.w+(2*this.gutter),tileSize.h+(2*this.gutter));}},getVisibility:function(){return this.visibility;},setVisibility:function(visibility){if(visibility!=this.visibility){this.visibility=visibility;this.display(visibility);this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"});}
+this.events.triggerEvent("visibilitychanged");}},display:function(display){if(display!=(this.div.style.display!="none")){this.div.style.display=(display&&this.calculateInRange())?"block":"none";}},calculateInRange:function(){var inRange=false;if(this.alwaysInRange){inRange=true;}else{if(this.map){var resolution=this.map.getResolution();inRange=((resolution>=this.minResolution)&&(resolution<=this.maxResolution));}}
+return inRange;},setIsBaseLayer:function(isBaseLayer){if(isBaseLayer!=this.isBaseLayer){this.isBaseLayer=isBaseLayer;if(this.map!=null){this.map.events.triggerEvent("changebaselayer",{layer:this});}}},initResolutions:function(){var i,len,p;var props={},alwaysInRange=true;for(i=0,len=this.RESOLUTION_PROPERTIES.length;i<len;i++){p=this.RESOLUTION_PROPERTIES[i];props[p]=this.options[p];if(alwaysInRange&&this.options[p]){alwaysInRange=false;}}
+if(this.alwaysInRange==null){this.alwaysInRange=alwaysInRange;}
+if(props.resolutions==null){props.resolutions=this.resolutionsFromScales(props.scales);}
+if(props.resolutions==null){props.resolutions=this.calculateResolutions(props);}
+if(props.resolutions==null){for(i=0,len=this.RESOLUTION_PROPERTIES.length;i<len;i++){p=this.RESOLUTION_PROPERTIES[i];props[p]=this.options[p]!=null?this.options[p]:this.map[p];}
+if(props.resolutions==null){props.resolutions=this.resolutionsFromScales(props.scales);}
+if(props.resolutions==null){props.resolutions=this.calculateResolutions(props);}}
+var maxResolution;if(this.options.maxResolution&&this.options.maxResolution!=="auto"){maxResolution=this.options.maxResolution;}
+if(this.options.minScale){maxResolution=OpenLayers.Util.getResolutionFromScale(this.options.minScale,this.units);}
+var minResolution;if(this.options.minResolution&&this.options.minResolution!=="auto"){minResolution=this.options.minResolution;}
+if(this.options.maxScale){minResolution=OpenLayers.Util.getResolutionFromScale(this.options.maxScale,this.units);}
+if(props.resolutions){props.resolutions.sort(function(a,b){return(b-a);});if(!maxResolution){maxResolution=props.resolutions[0];}
+if(!minResolution){var lastIdx=props.resolutions.length-1;minResolution=props.resolutions[lastIdx];}}
+this.resolutions=props.resolutions;if(this.resolutions){len=this.resolutions.length;this.scales=new Array(len);for(i=0;i<len;i++){this.scales[i]=OpenLayers.Util.getScaleFromResolution(this.resolutions[i],this.units);}
+this.numZoomLevels=len;}
+this.minResolution=minResolution;if(minResolution){this.maxScale=OpenLayers.Util.getScaleFromResolution(minResolution,this.units);}
+this.maxResolution=maxResolution;if(maxResolution){this.minScale=OpenLayers.Util.getScaleFromResolution(maxResolution,this.units);}},resolutionsFromScales:function(scales){if(scales==null){return;}
+var resolutions,i,len;len=scales.length;resolutions=new Array(len);for(i=0;i<len;i++){resolutions[i]=OpenLayers.Util.getResolutionFromScale(scales[i],this.units);}
+return resolutions;},calculateResolutions:function(props){var viewSize,wRes,hRes;var maxResolution=props.maxResolution;if(props.minScale!=null){maxResolution=OpenLayers.Util.getResolutionFromScale(props.minScale,this.units);}else if(maxResolution=="auto"&&this.maxExtent!=null){viewSize=this.map.getSize();wRes=this.maxExtent.getWidth()/viewSize.w;hRes=this.maxExtent.getHeight()/viewSize.h;maxResolution=Math.max(wRes,hRes);}
+var minResolution=props.minResolution;if(props.maxScale!=null){minResolution=OpenLayers.Util.getResolutionFromScale(props.maxScale,this.units);}else if(props.minResolution=="auto"&&this.minExtent!=null){viewSize=this.map.getSize();wRes=this.minExtent.getWidth()/viewSize.w;hRes=this.minExtent.getHeight()/viewSize.h;minResolution=Math.max(wRes,hRes);}
+if(typeof maxResolution!=="number"&&typeof minResolution!=="number"&&this.maxExtent!=null){var tileSize=this.map.getTileSize();maxResolution=Math.max(this.maxExtent.getWidth()/tileSize.w,this.maxExtent.getHeight()/tileSize.h);}
+var maxZoomLevel=props.maxZoomLevel;var numZoomLevels=props.numZoomLevels;if(typeof minResolution==="number"&&typeof maxResolution==="number"&&numZoomLevels===undefined){var ratio=maxResolution/minResolution;numZoomLevels=Math.floor(Math.log(ratio)/Math.log(2))+1;}else if(numZoomLevels===undefined&&maxZoomLevel!=null){numZoomLevels=maxZoomLevel+1;}
+if(typeof numZoomLevels!=="number"||numZoomLevels<=0||(typeof maxResolution!=="number"&&typeof minResolution!=="number")){return;}
+var resolutions=new Array(numZoomLevels);var base=2;if(typeof minResolution=="number"&&typeof maxResolution=="number"){base=Math.pow((maxResolution/minResolution),(1/(numZoomLevels-1)));}
+var i;if(typeof maxResolution==="number"){for(i=0;i<numZoomLevels;i++){resolutions[i]=maxResolution/Math.pow(base,i);}}else{for(i=0;i<numZoomLevels;i++){resolutions[numZoomLevels-1-i]=minResolution*Math.pow(base,i);}}
+return resolutions;},getResolution:function(){var zoom=this.map.getZoom();return this.getResolutionForZoom(zoom);},getExtent:function(){return this.map.calculateBounds();},getZoomForExtent:function(extent,closest){var viewSize=this.map.getSize();var idealResolution=Math.max(extent.getWidth()/viewSize.w,extent.getHeight()/viewSize.h);return this.getZoomForResolution(idealResolution,closest);},getDataExtent:function(){},getResolutionForZoom:function(zoom){zoom=Math.max(0,Math.min(zoom,this.resolutions.length-1));var resolution;if(this.map.fractionalZoom){var low=Math.floor(zoom);var high=Math.ceil(zoom);resolution=this.resolutions[low]-
+((zoom-low)*(this.resolutions[low]-this.resolutions[high]));}else{resolution=this.resolutions[Math.round(zoom)];}
+return resolution;},getZoomForResolution:function(resolution,closest){var zoom,i,len;if(this.map.fractionalZoom){var lowZoom=0;var highZoom=this.resolutions.length-1;var highRes=this.resolutions[lowZoom];var lowRes=this.resolutions[highZoom];var res;for(i=0,len=this.resolutions.length;i<len;++i){res=this.resolutions[i];if(res>=resolution){highRes=res;lowZoom=i;}
+if(res<=resolution){lowRes=res;highZoom=i;break;}}
+var dRes=highRes-lowRes;if(dRes>0){zoom=lowZoom+((highRes-resolution)/dRes);}else{zoom=lowZoom;}}else{var diff;var minDiff=Number.POSITIVE_INFINITY;for(i=0,len=this.resolutions.length;i<len;i++){if(closest){diff=Math.abs(this.resolutions[i]-resolution);if(diff>minDiff){break;}
+minDiff=diff;}else{if(this.resolutions[i]<resolution){break;}}}
+zoom=Math.max(0,i-1);}
+return zoom;},getLonLatFromViewPortPx:function(viewPortPx){var lonlat=null;var map=this.map;if(viewPortPx!=null&&map.minPx){var res=map.getResolution();var maxExtent=map.getMaxExtent({restricted:true});var lon=(viewPortPx.x-map.minPx.x)*res+maxExtent.left;var lat=(map.minPx.y-viewPortPx.y)*res+maxExtent.top;lonlat=new OpenLayers.LonLat(lon,lat);if(this.wrapDateLine){lonlat=lonlat.wrapDateLine(this.maxExtent);}}
+return lonlat;},getViewPortPxFromLonLat:function(lonlat,resolution){var px=null;if(lonlat!=null){resolution=resolution||this.map.getResolution();var extent=this.map.calculateBounds(null,resolution);px=new OpenLayers.Pixel((1/resolution*(lonlat.lon-extent.left)),(1/resolution*(extent.top-lonlat.lat)));}
+return px;},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;var childNodes=this.div.childNodes;for(var i=0,len=childNodes.length;i<len;++i){var element=childNodes[i].firstChild||childNodes[i];var lastChild=childNodes[i].lastChild;if(lastChild&&lastChild.nodeName.toLowerCase()==="iframe"){element=lastChild.parentNode;}
+OpenLayers.Util.modifyDOMElement(element,null,null,null,null,null,null,opacity);}
+if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"});}}},getZIndex:function(){return this.div.style.zIndex;},setZIndex:function(zIndex){this.div.style.zIndex=zIndex;},adjustBounds:function(bounds){if(this.gutter){var mapGutter=this.gutter*this.map.getResolution();bounds=new OpenLayers.Bounds(bounds.left-mapGutter,bounds.bottom-mapGutter,bounds.right+mapGutter,bounds.top+mapGutter);}
+if(this.wrapDateLine){var wrappingOptions={'rightTolerance':this.getResolution(),'leftTolerance':this.getResolution()};bounds=bounds.wrapDateLine(this.maxExtent,wrappingOptions);}
+return bounds;},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:false,initialize:function(name,url,params,options){OpenLayers.Layer.prototype.initialize.apply(this,[name,options]);this.url=url;if(!this.params){this.params=OpenLayers.Util.extend({},params);}},destroy:function(){this.url=null;this.params=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.getOptions());}
+obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);return obj;},setUrl:function(newUrl){this.url=newUrl;},mergeNewParams:function(newParams){this.params=OpenLayers.Util.extend(this.params,newParams);var ret=this.redraw();if(this.map!=null){this.map.events.triggerEvent("changelayer",{layer:this,property:"params"});}
+return ret;},redraw:function(force){if(force){return this.mergeNewParams({"_olSalt":Math.random()});}else{return OpenLayers.Layer.prototype.redraw.apply(this,[]);}},selectUrl:function(paramString,urls){var product=1;for(var i=0,len=paramString.length;i<len;i++){product*=paramString.charCodeAt(i)*this.URL_HASH_FACTOR;product-=Math.floor(product);}
+return urls[Math.floor(product*urls.length)];},getFullRequestString:function(newParams,altUrl){var url=altUrl||this.url;var allParams=OpenLayers.Util.extend({},this.params);allParams=OpenLayers.Util.extend(allParams,newParams);var paramsString=OpenLayers.Util.getParameterString(allParams);if(OpenLayers.Util.isArray(url)){url=this.selectUrl(paramsString,url);}
+var urlParams=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(url));for(var key in allParams){if(key.toUpperCase()in urlParams){delete allParams[key];}}
+paramsString=OpenLayers.Util.getParameterString(allParams);return OpenLayers.Util.urlAppend(url,paramsString);},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Tile=OpenLayers.Class({events:null,eventListeners:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:false,initialize:function(layer,position,bounds,url,size,options){this.layer=layer;this.position=position.clone();this.setBounds(bounds);this.url=url;if(size){this.size=size.clone();}
+this.id=OpenLayers.Util.createUniqueID("Tile_");OpenLayers.Util.extend(this,options);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object){this.events.on(this.eventListeners);}},unload:function(){if(this.isLoading){this.isLoading=false;this.events.triggerEvent("unload");}},destroy:function(){this.layer=null;this.bounds=null;this.size=null;this.position=null;if(this.eventListeners){this.events.un(this.eventListeners);}
+this.events.destroy();this.eventListeners=null;this.events=null;},draw:function(deferred){if(!deferred){this.clear();}
+var draw=this.shouldDraw();if(draw&&!deferred){draw=this.events.triggerEvent("beforedraw")!==false;}
+return draw;},shouldDraw:function(){var withinMaxExtent=false,maxExtent=this.layer.maxExtent;if(maxExtent){var map=this.layer.map;var worldBounds=map.baseLayer.wrapDateLine&&map.getMaxExtent();if(this.bounds.intersectsBounds(maxExtent,{inclusive:false,worldBounds:worldBounds})){withinMaxExtent=true;}}
+return withinMaxExtent||this.layer.displayOutsideMaxExtent;},setBounds:function(bounds){bounds=bounds.clone();if(this.layer.map.baseLayer.wrapDateLine){var worldExtent=this.layer.map.getMaxExtent(),tolerance=this.layer.map.getResolution();bounds=bounds.wrapDateLine(worldExtent,{leftTolerance:tolerance,rightTolerance:tolerance});}
+this.bounds=bounds;},moveTo:function(bounds,position,redraw){if(redraw==null){redraw=true;}
+this.setBounds(bounds);this.position=position.clone();if(redraw){this.draw();}},clear:function(draw){},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,imageReloadAttempts:null,layerAlphaHack:null,asyncRequestId:null,blankImageUrl:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7",maxGetUrlLength:null,canvasContext:null,crossOriginKeyword:null,initialize:function(layer,position,bounds,url,size,options){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=url;this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();if(this.maxGetUrlLength!=null||this.layer.gutter||this.layerAlphaHack){this.frame=document.createElement("div");this.frame.style.position="absolute";this.frame.style.overflow="hidden";}
+if(this.maxGetUrlLength!=null){OpenLayers.Util.extend(this,OpenLayers.Tile.Image.IFrame);}},destroy:function(){if(this.imgDiv){this.clear();this.imgDiv=null;this.frame=null;}
+this.asyncRequestId=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments);},draw:function(){var drawn=OpenLayers.Tile.prototype.draw.apply(this,arguments);if(drawn){if(this.layer!=this.layer.map.baseLayer&&this.layer.reproject){this.bounds=this.getBoundsFromBaseLayer(this.position);}
+if(this.isLoading){this._loadEvent="reload";}else{this.isLoading=true;this._loadEvent="loadstart";}
+this.positionTile();this.renderTile();}else{this.unload();}
+return drawn;},renderTile:function(){this.layer.div.appendChild(this.getTile());if(this.layer.async){var id=this.asyncRequestId=(this.asyncRequestId||0)+1;this.layer.getURLasync(this.bounds,function(url){if(id==this.asyncRequestId){this.url=url;this.initImage();}},this);}else{this.url=this.layer.getURL(this.bounds);this.initImage();}},positionTile:function(){var style=this.getTile().style,size=this.frame?this.size:this.layer.getImageSize(this.bounds);style.left=this.position.x+"%";style.top=this.position.y+"%";style.width=size.w+"%";style.height=size.h+"%";},clear:function(){OpenLayers.Tile.prototype.clear.apply(this,arguments);var img=this.imgDiv;if(img){OpenLayers.Event.stopObservingElement(img);var tile=this.getTile();if(tile.parentNode===this.layer.div){this.layer.div.removeChild(tile);}
+this.setImgSrc();if(this.layerAlphaHack===true){img.style.filter="";}
+OpenLayers.Element.removeClass(img,"olImageLoadError");}
+this.canvasContext=null;},getImage:function(){if(!this.imgDiv){this.imgDiv=document.createElement("img");this.imgDiv.className="olTileImage";this.imgDiv.galleryImg="no";var style=this.imgDiv.style;if(this.frame){var left=0,top=0;if(this.layer.gutter){left=this.layer.gutter/this.layer.tileSize.w*100;top=this.layer.gutter/this.layer.tileSize.h*100;}
+style.left=-left+"%";style.top=-top+"%";style.width=(2*left+100)+"%";style.height=(2*top+100)+"%";}
+style.visibility="hidden";style.opacity=0;if(this.layer.opacity<1){style.filter='alpha(opacity='+
+(this.layer.opacity*100)+')';}
+style.position="absolute";if(this.layerAlphaHack){style.paddingTop=style.height;style.height="0";style.width="100%";}
+if(this.frame){this.frame.appendChild(this.imgDiv);}}
+return this.imgDiv;},initImage:function(){this.events.triggerEvent(this._loadEvent);var img=this.getImage();if(this.url&&img.getAttribute("src")==this.url){this.onImageLoad();}else{var load=OpenLayers.Function.bind(function(){OpenLayers.Event.stopObservingElement(img);OpenLayers.Event.observe(img,"load",OpenLayers.Function.bind(this.onImageLoad,this));OpenLayers.Event.observe(img,"error",OpenLayers.Function.bind(this.onImageError,this));this.imageReloadAttempts=0;this.setImgSrc(this.url);},this);if(img.getAttribute("src")==this.blankImageUrl){load();}else{OpenLayers.Event.observe(img,"load",load);OpenLayers.Event.observe(img,"error",load);if(this.crossOriginKeyword){img.removeAttribute("crossorigin");}
+img.src=this.blankImageUrl;}}},setImgSrc:function(url){var img=this.imgDiv;img.style.visibility='hidden';img.style.opacity=0;if(url){if(this.crossOriginKeyword){if(url.substr(0,5)!=='data:'){img.setAttribute("crossorigin",this.crossOriginKeyword);}else{img.removeAttribute("crossorigin");}}
+img.src=url;}},getTile:function(){return this.frame?this.frame:this.getImage();},createBackBuffer:function(){if(!this.imgDiv||this.isLoading){return;}
+var backBuffer;if(this.frame){backBuffer=this.frame.cloneNode(false);backBuffer.appendChild(this.imgDiv);}else{backBuffer=this.imgDiv;}
+this.imgDiv=null;return backBuffer;},onImageLoad:function(){var img=this.imgDiv;OpenLayers.Event.stopObservingElement(img);img.style.visibility='inherit';img.style.opacity=this.layer.opacity;this.isLoading=false;this.canvasContext=null;this.events.triggerEvent("loadend");if(parseFloat(navigator.appVersion.split("MSIE")[1])<7&&this.layer&&this.layer.div){var span=document.createElement("span");span.style.display="none";var layerDiv=this.layer.div;layerDiv.appendChild(span);window.setTimeout(function(){span.parentNode===layerDiv&&span.parentNode.removeChild(span);},0);}
+if(this.layerAlphaHack===true){img.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+
+img.src+"', sizingMethod='scale')";}},onImageError:function(){var img=this.imgDiv;if(img.src!=null){this.imageReloadAttempts++;if(this.imageReloadAttempts<=OpenLayers.IMAGE_RELOAD_ATTEMPTS){this.setImgSrc(this.layer.getURL(this.bounds));}else{OpenLayers.Element.addClass(img,"olImageLoadError");this.events.triggerEvent("loaderror");this.onImageLoad();}}},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var canvas=document.createElement("canvas");canvas.width=this.size.w;canvas.height=this.size.h;this.canvasContext=canvas.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0);}
+return this.canvasContext;}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:false,ratio:1.5,buffer:0,transitionEffect:null,numLoadingTiles:0,tileLoadingDelay:85,serverResolutions:null,moveTimerId:null,deferMoveGriddedTiles:null,tileQueueId:null,tileQueue:null,loading:false,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null,className:null,initialize:function(name,url,params,options){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this.tileQueue=[];if(this.removeBackBufferDelay===null){this.removeBackBufferDelay=this.singleTile?0:2500;}
+if(this.className===null){this.className=this.singleTile?'olLayerGridSingleTile':'olLayerGrid';}
+if(!OpenLayers.Animation.isNative){this.deferMoveGriddedTiles=OpenLayers.Function.bind(function(){this.moveGriddedTiles(true);this.moveTimerId=null;},this);}},setMap:function(map){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this,map);OpenLayers.Element.addClass(this.div,this.className);},removeMap:function(map){if(this.moveTimerId!==null){window.clearTimeout(this.moveTimerId);this.moveTimerId=null;}
+this.clearTileQueue();if(this.backBufferTimerId!==null){window.clearTimeout(this.backBufferTimerId);this.backBufferTimerId=null;}},destroy:function(){this.removeBackBuffer();this.clearGrid();this.grid=null;this.tileSize=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments);},clearGrid:function(){this.clearTileQueue();if(this.grid){for(var iRow=0,len=this.grid.length;iRow<len;iRow++){var row=this.grid[iRow];for(var iCol=0,clen=row.length;iCol<clen;iCol++){var tile=row[iCol];this.destroyTile(tile);}}
+this.grid=[];this.gridResolution=null;}},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.getOptions());}
+obj=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[obj]);if(this.tileSize!=null){obj.tileSize=this.tileSize.clone();}
+obj.grid=[];obj.gridResolution=null;obj.backBuffer=null;obj.backBufferTimerId=null;obj.tileQueue=[];obj.tileQueueId=null;obj.loading=false;obj.moveTimerId=null;return obj;},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);bounds=bounds||this.map.getExtent();if(bounds!=null){var forceReTile=!this.grid.length||zoomChanged;var tilesBounds=this.getTilesBounds();var resolution=this.map.getResolution();var serverResolution=this.getServerResolution(resolution);if(this.singleTile){if(forceReTile||(!dragging&&!tilesBounds.containsBounds(bounds))){if(zoomChanged&&this.transitionEffect!=='resize'){this.removeBackBuffer();}
+if(!zoomChanged||this.transitionEffect==='resize'){this.applyBackBuffer(serverResolution);}
+this.initSingleTile(bounds);}}else{forceReTile=forceReTile||!tilesBounds.intersectsBounds(bounds,{worldBounds:this.map.baseLayer.wrapDateLine&&this.map.getMaxExtent()});if(resolution!==serverResolution){bounds=this.map.calculateBounds(null,serverResolution);if(forceReTile){var scale=serverResolution/resolution;this.transformDiv(scale);}}else{this.div.style.width='100%';this.div.style.height='100%';this.div.style.left='0%';this.div.style.top='0%';}
+if(forceReTile){if(zoomChanged&&this.transitionEffect==='resize'){this.applyBackBuffer(serverResolution);}
+this.initGriddedTiles(bounds);}else{this.moveGriddedTiles();}}}},getTileData:function(loc){var data=null,x=loc.lon,y=loc.lat,numRows=this.grid.length;if(this.map&&numRows){var res=this.map.getResolution(),tileWidth=this.tileSize.w,tileHeight=this.tileSize.h,bounds=this.grid[0][0].bounds,left=bounds.left,top=bounds.top;if(x<left){if(this.map.baseLayer.wrapDateLine){var worldWidth=this.map.getMaxExtent().getWidth();var worldsAway=Math.ceil((left-x)/worldWidth);x+=worldWidth*worldsAway;}}
+var dtx=(x-left)/(res*tileWidth);var dty=(top-y)/(res*tileHeight);var col=Math.floor(dtx);var row=Math.floor(dty);if(row>=0&&row<numRows){var tile=this.grid[row][col];if(tile){data={tile:tile,i:Math.floor((dtx-col)*tileWidth),j:Math.floor((dty-row)*tileHeight)};}}}
+return data;},queueTileDraw:function(evt){var tile=evt.object;if(!~OpenLayers.Util.indexOf(this.tileQueue,tile)){this.tileQueue.push(tile);}
+if(!this.tileQueueId){this.tileQueueId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.drawTileFromQueue,this),null,this.div);}
+return false;},drawTileFromQueue:function(){if(this.tileQueue.length===0){this.clearTileQueue();}else{this.tileQueue.shift().draw(true);}},clearTileQueue:function(){OpenLayers.Animation.stop(this.tileQueueId);this.tileQueueId=null;this.tileQueue=[];},destroyTile:function(tile){this.removeTileMonitoringHooks(tile);tile.destroy();},getServerResolution:function(resolution){resolution=resolution||this.map.getResolution();if(this.serverResolutions&&OpenLayers.Util.indexOf(this.serverResolutions,resolution)===-1){var i,serverResolution;for(i=this.serverResolutions.length-1;i>=0;i--){serverResolution=this.serverResolutions[i];if(serverResolution>resolution){resolution=serverResolution;break;}}
+if(i===-1){throw'no appropriate resolution in serverResolutions';}}
+return resolution;},getServerZoom:function(){var resolution=this.getServerResolution();return this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,resolution):this.map.getZoomForResolution(resolution)+(this.zoomOffset||0);},transformDiv:function(scale){this.div.style.width=100*scale+'%';this.div.style.height=100*scale+'%';var size=this.map.getSize();var lcX=parseInt(this.map.layerContainerDiv.style.left,10);var lcY=parseInt(this.map.layerContainerDiv.style.top,10);var x=(lcX-(size.w/2.0))*(scale-1);var y=(lcY-(size.h/2.0))*(scale-1);this.div.style.left=x+'%';this.div.style.top=y+'%';},getResolutionScale:function(){return parseInt(this.div.style.width,10)/100;},applyBackBuffer:function(resolution){if(this.backBufferTimerId!==null){this.removeBackBuffer();}
+var backBuffer=this.backBuffer;if(!backBuffer){backBuffer=this.createBackBuffer();if(!backBuffer){return;}
+this.div.insertBefore(backBuffer,this.div.firstChild);this.backBuffer=backBuffer;var topLeftTileBounds=this.grid[0][0].bounds;this.backBufferLonLat={lon:topLeftTileBounds.left,lat:topLeftTileBounds.top};this.backBufferResolution=this.gridResolution;}
+var style=backBuffer.style;var ratio=this.backBufferResolution/resolution;style.width=100*ratio+'%';style.height=100*ratio+'%';var position=this.getViewPortPxFromLonLat(this.backBufferLonLat,resolution);var leftOffset=parseInt(this.map.layerContainerDiv.style.left,10);var topOffset=parseInt(this.map.layerContainerDiv.style.top,10);backBuffer.style.left=Math.round(position.x-leftOffset)+'%';backBuffer.style.top=Math.round(position.y-topOffset)+'%';},createBackBuffer:function(){var backBuffer;if(this.grid.length>0){backBuffer=document.createElement('div');backBuffer.id=this.div.id+'_bb';backBuffer.className='olBackBuffer';backBuffer.style.position='absolute';backBuffer.style.width='100%';backBuffer.style.height='100%';for(var i=0,lenI=this.grid.length;i<lenI;i++){for(var j=0,lenJ=this.grid[i].length;j<lenJ;j++){var tile=this.grid[i][j].createBackBuffer();if(!tile){continue;}
+tile.style.top=(i*this.tileSize.h)+'%';tile.style.left=(j*this.tileSize.w)+'%';backBuffer.appendChild(tile);}}}
+return backBuffer;},removeBackBuffer:function(){if(this.backBuffer){this.div.removeChild(this.backBuffer);this.backBuffer=null;this.backBufferResolution=null;if(this.backBufferTimerId!==null){window.clearTimeout(this.backBufferTimerId);this.backBufferTimerId=null;}}},moveByPx:function(dx,dy){if(!this.singleTile){this.moveGriddedTiles();}},setTileSize:function(size){if(this.singleTile){size=this.map.getSize();size.h=parseInt(size.h*this.ratio);size.w=parseInt(size.w*this.ratio);}
+OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[size]);},getTilesBounds:function(){var bounds=null;var length=this.grid.length;if(length){var bottomLeftTileBounds=this.grid[length-1][0].bounds,width=this.grid[0].length*bottomLeftTileBounds.getWidth(),height=this.grid.length*bottomLeftTileBounds.getHeight();bounds=new OpenLayers.Bounds(bottomLeftTileBounds.left,bottomLeftTileBounds.bottom,bottomLeftTileBounds.left+width,bottomLeftTileBounds.bottom+height);}
+return bounds;},initSingleTile:function(bounds){this.clearTileQueue();var center=bounds.getCenterLonLat();var tileWidth=bounds.getWidth()*this.ratio;var tileHeight=bounds.getHeight()*this.ratio;var tileBounds=new OpenLayers.Bounds(center.lon-(tileWidth/2),center.lat-(tileHeight/2),center.lon+(tileWidth/2),center.lat+(tileHeight/2));var px=this.map.getLayerPxFromLonLat({lon:tileBounds.left,lat:tileBounds.top});if(!this.grid.length){this.grid[0]=[];}
+var tile=this.grid[0][0];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);tile.draw();this.grid[0][0]=tile;}else{tile.moveTo(tileBounds,px);}
+this.removeExcessTiles(1,1);this.gridResolution=this.getServerResolution();},calculateGridLayout:function(bounds,origin,resolution){var tilelon=resolution*this.tileSize.w;var tilelat=resolution*this.tileSize.h;var offsetlon=bounds.left-origin.lon;var tilecol=Math.floor(offsetlon/tilelon)-this.buffer;var tilecolremain=offsetlon/tilelon-tilecol;var tileoffsetx=-tilecolremain*this.tileSize.w;var tileoffsetlon=origin.lon+tilecol*tilelon;var offsetlat=bounds.top-(origin.lat+tilelat);var tilerow=Math.ceil(offsetlat/tilelat)+this.buffer;var tilerowremain=tilerow-offsetlat/tilelat;var tileoffsety=-tilerowremain*this.tileSize.h;var tileoffsetlat=origin.lat+tilerow*tilelat;return{tilelon:tilelon,tilelat:tilelat,tileoffsetlon:tileoffsetlon,tileoffsetlat:tileoffsetlat,tileoffsetx:tileoffsetx,tileoffsety:tileoffsety};},getTileOrigin:function(){var origin=this.tileOrigin;if(!origin){var extent=this.getMaxExtent();var edges=({"tl":["left","top"],"tr":["right","top"],"bl":["left","bottom"],"br":["right","bottom"]})[this.tileOriginCorner];origin=new OpenLayers.LonLat(extent[edges[0]],extent[edges[1]]);}
+return origin;},initGriddedTiles:function(bounds){this.clearTileQueue();var viewSize=this.map.getSize();var minRows=Math.ceil(viewSize.h/this.tileSize.h)+
+Math.max(1,2*this.buffer);var minCols=Math.ceil(viewSize.w/this.tileSize.w)+
+Math.max(1,2*this.buffer);var origin=this.getTileOrigin();var resolution=this.getServerResolution();var tileLayout=this.calculateGridLayout(bounds,origin,resolution);var tileoffsetx=Math.round(tileLayout.tileoffsetx);var tileoffsety=Math.round(tileLayout.tileoffsety);var tileoffsetlon=tileLayout.tileoffsetlon;var tileoffsetlat=tileLayout.tileoffsetlat;var tilelon=tileLayout.tilelon;var tilelat=tileLayout.tilelat;var startX=tileoffsetx;var startLon=tileoffsetlon;var rowidx=0;var layerContainerDivLeft=parseInt(this.map.layerContainerDiv.style.left);var layerContainerDivTop=parseInt(this.map.layerContainerDiv.style.top);var tileData=[],center=this.map.getCenter();do{var row=this.grid[rowidx++];if(!row){row=[];this.grid.push(row);}
+tileoffsetlon=startLon;tileoffsetx=startX;var colidx=0;do{var tileBounds=new OpenLayers.Bounds(tileoffsetlon,tileoffsetlat,tileoffsetlon+tilelon,tileoffsetlat+tilelat);var x=tileoffsetx;x-=layerContainerDivLeft;var y=tileoffsety;y-=layerContainerDivTop;var px=new OpenLayers.Pixel(x,y);var tile=row[colidx++];if(!tile){tile=this.addTile(tileBounds,px);this.addTileMonitoringHooks(tile);row.push(tile);}else{tile.moveTo(tileBounds,px,false);}
+var tileCenter=tileBounds.getCenterLonLat();tileData.push({tile:tile,distance:Math.pow(tileCenter.lon-center.lon,2)+
+Math.pow(tileCenter.lat-center.lat,2)});tileoffsetlon+=tilelon;tileoffsetx+=this.tileSize.w;}while((tileoffsetlon<=bounds.right+tilelon*this.buffer)||colidx<minCols);tileoffsetlat-=tilelat;tileoffsety+=this.tileSize.h;}while((tileoffsetlat>=bounds.bottom-tilelat*this.buffer)||rowidx<minRows);this.removeExcessTiles(rowidx,colidx);this.gridResolution=this.getServerResolution();tileData.sort(function(a,b){return a.distance-b.distance;});for(var i=0,ii=tileData.length;i<ii;++i){tileData[i].tile.draw();}},getMaxExtent:function(){return this.maxExtent;},addTile:function(bounds,position){var tile=new this.tileClass(this,position,bounds,null,this.tileSize,this.tileOptions);tile.events.register("beforedraw",this,this.queueTileDraw);return tile;},addTileMonitoringHooks:function(tile){tile.onLoadStart=function(){if(this.loading===false){this.loading=true;this.events.triggerEvent("loadstart");}
+this.events.triggerEvent("tileloadstart",{tile:tile});this.numLoadingTiles++;};tile.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded",{tile:tile});if(this.tileQueue.length===0&&this.numLoadingTiles===0){this.loading=false;this.events.triggerEvent("loadend");if(this.backBuffer){this.backBufferTimerId=window.setTimeout(OpenLayers.Function.bind(this.removeBackBuffer,this),this.removeBackBufferDelay);}}};tile.onLoadError=function(){this.events.triggerEvent("tileerror",{tile:tile});};tile.events.on({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,"loaderror":tile.onLoadError,scope:this});},removeTileMonitoringHooks:function(tile){tile.unload();tile.events.un({"loadstart":tile.onLoadStart,"loadend":tile.onLoadEnd,"unload":tile.onLoadEnd,"loaderror":tile.onLoadError,scope:this});},moveGriddedTiles:function(deferred){if(!deferred&&!OpenLayers.Animation.isNative){if(this.moveTimerId!=null){window.clearTimeout(this.moveTimerId);}
+this.moveTimerId=window.setTimeout(this.deferMoveGriddedTiles,this.tileLoadingDelay);return;}
+var buffer=this.buffer||1;var scale=this.getResolutionScale();while(true){var tlViewPort={x:(this.grid[0][0].position.x*scale)+
+parseInt(this.div.style.left,10)+
+parseInt(this.map.layerContainerDiv.style.left),y:(this.grid[0][0].position.y*scale)+
+parseInt(this.div.style.top,10)+
+parseInt(this.map.layerContainerDiv.style.top)};var tileSize={w:this.tileSize.w*scale,h:this.tileSize.h*scale};if(tlViewPort.x>-tileSize.w*(buffer-1)){this.shiftColumn(true);}else if(tlViewPort.x<-tileSize.w*buffer){this.shiftColumn(false);}else if(tlViewPort.y>-tileSize.h*(buffer-1)){this.shiftRow(true);}else if(tlViewPort.y<-tileSize.h*buffer){this.shiftRow(false);}else{break;}}},shiftRow:function(prepend){var modelRowIndex=(prepend)?0:(this.grid.length-1);var grid=this.grid;var modelRow=grid[modelRowIndex];var resolution=this.getServerResolution();var deltaY=(prepend)?-this.tileSize.h:this.tileSize.h;var deltaLat=resolution*-deltaY;var row=(prepend)?grid.pop():grid.shift();for(var i=0,len=modelRow.length;i<len;i++){var modelTile=modelRow[i];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.bottom=bounds.bottom+deltaLat;bounds.top=bounds.top+deltaLat;position.y=position.y+deltaY;row[i].moveTo(bounds,position);}
+if(prepend){grid.unshift(row);}else{grid.push(row);}},shiftColumn:function(prepend){var deltaX=(prepend)?-this.tileSize.w:this.tileSize.w;var resolution=this.getServerResolution();var deltaLon=resolution*deltaX;for(var i=0,len=this.grid.length;i<len;i++){var row=this.grid[i];var modelTileIndex=(prepend)?0:(row.length-1);var modelTile=row[modelTileIndex];var bounds=modelTile.bounds.clone();var position=modelTile.position.clone();bounds.left=bounds.left+deltaLon;bounds.right=bounds.right+deltaLon;position.x=position.x+deltaX;var tile=prepend?this.grid[i].pop():this.grid[i].shift();tile.moveTo(bounds,position);if(prepend){row.unshift(tile);}else{row.push(tile);}}},removeExcessTiles:function(rows,columns){var i,l;while(this.grid.length>rows){var row=this.grid.pop();for(i=0,l=row.length;i<l;i++){var tile=row[i];this.destroyTile(tile);}}
+for(i=0,l=this.grid.length;i<l;i++){while(this.grid[i].length>columns){var row=this.grid[i];var tile=row.pop();this.destroyTile(tile);}}},onMapResize:function(){if(this.singleTile){this.clearGrid();this.setTileSize();}},getTileBounds:function(viewPortPx){var maxExtent=this.maxExtent;var resolution=this.getResolution();var tileMapWidth=resolution*this.tileSize.w;var tileMapHeight=resolution*this.tileSize.h;var mapPoint=this.getLonLatFromViewPortPx(viewPortPx);var tileLeft=maxExtent.left+(tileMapWidth*Math.floor((mapPoint.lon-
+maxExtent.left)/tileMapWidth));var tileBottom=maxExtent.bottom+(tileMapHeight*Math.floor((mapPoint.lat-
+maxExtent.bottom)/tileMapHeight));return new OpenLayers.Bounds(tileLeft,tileBottom,tileLeft+tileMapWidth,tileBottom+tileMapHeight);},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:true,sphericalMercator:false,zoomOffset:0,serverResolutions:null,initialize:function(name,url,options){if(options&&options.sphericalMercator||this.sphericalMercator){options=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},options);}
+OpenLayers.Layer.Grid.prototype.initialize.apply(this,[name||this.name,url||this.url,{},options]);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions());}
+obj=OpenLayers.Layer.Grid.prototype.clone.apply(this,[obj]);return obj;},getURL:function(bounds){var xyz=this.getXYZ(bounds);var url=this.url;if(OpenLayers.Util.isArray(url)){var s=''+xyz.x+xyz.y+xyz.z;url=this.selectUrl(s,url);}
+return OpenLayers.String.format(url,xyz);},getXYZ:function(bounds){var res=this.getServerResolution();var x=Math.round((bounds.left-this.maxExtent.left)/(res*this.tileSize.w));var y=Math.round((this.maxExtent.top-bounds.top)/(res*this.tileSize.h));var z=this.getServerZoom();if(this.wrapDateLine){var limit=Math.pow(2,z);x=((x%limit)+limit)%limit;}
+return{'x':x,'y':y,'z':z};},setMap:function(map){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);if(!this.tileOrigin){this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.bottom);}},CLASS_NAME:"OpenLayers.Layer.XYZ"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:['http://a.tile.openstreetmap.org/${z}/${x}/${y}.png','http://b.tile.openstreetmap.org/${z}/${x}/${y}.png','http://c.tile.openstreetmap.org/${z}/${x}/${y}.png'],attribution:"Data CC-By-SA by <a href='http://openstreetmap.org/'>OpenStreetMap</a>",sphericalMercator:true,wrapDateLine:true,tileOptions:null,initialize:function(name,url,options){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:'anonymous'},this.options&&this.options.tileOptions);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions());}
+obj=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[obj]);return obj;},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:false,size:null,resolution:null,map:null,featureDx:0,initialize:function(containerID,options){this.container=OpenLayers.Util.getElement(containerID);OpenLayers.Util.extend(this,options);},destroy:function(){this.container=null;this.extent=null;this.size=null;this.resolution=null;this.map=null;},supported:function(){return false;},setExtent:function(extent,resolutionChanged){this.extent=extent.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var ratio=extent.getWidth()/this.map.getExtent().getWidth(),extent=extent.scale(1/ratio);this.extent=extent.wrapDateLine(this.map.getMaxExtent()).scale(ratio);}
+if(resolutionChanged){this.resolution=null;}
+return true;},setSize:function(size){this.size=size.clone();this.resolution=null;},getResolution:function(){this.resolution=this.resolution||this.map.getResolution();return this.resolution;},drawFeature:function(feature,style){if(style==null){style=feature.style;}
+if(feature.geometry){var bounds=feature.geometry.getBounds();if(bounds){var worldBounds;if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){worldBounds=this.map.getMaxExtent();}
+if(!bounds.intersectsBounds(this.extent,{worldBounds:worldBounds})){style={display:"none"};}else{this.calculateFeatureDx(bounds,worldBounds);}
+var rendered=this.drawGeometry(feature.geometry,style,feature.id);if(style.display!="none"&&style.label&&rendered!==false){var location=feature.geometry.getCentroid();if(style.labelXOffset||style.labelYOffset){var xOffset=isNaN(style.labelXOffset)?0:style.labelXOffset;var yOffset=isNaN(style.labelYOffset)?0:style.labelYOffset;var res=this.getResolution();location.move(xOffset*res,yOffset*res);}
+this.drawText(feature.id,style,location);}else{this.removeText(feature.id);}
+return rendered;}}},calculateFeatureDx:function(bounds,worldBounds){this.featureDx=0;if(worldBounds){var worldWidth=worldBounds.getWidth(),rendererCenterX=(this.extent.left+this.extent.right)/2,featureCenterX=(bounds.left+bounds.right)/2,worldsAway=Math.round((featureCenterX-rendererCenterX)/worldWidth);this.featureDx=worldsAway*worldWidth;}},drawGeometry:function(geometry,style,featureId){},drawText:function(featureId,style,location){},removeText:function(featureId){},clear:function(){},getFeatureIdFromEvent:function(evt){},eraseFeatures:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];}
+for(var i=0,len=features.length;i<len;++i){var feature=features[i];this.eraseGeometry(feature.geometry,feature.id);this.removeText(feature.id);}},eraseGeometry:function(geometry,featureId){},moveRoot:function(renderer){},getRenderLayerId:function(){return this.container.id;},applyDefaultSymbolizer:function(symbolizer){var result=OpenLayers.Util.extend({},OpenLayers.Renderer.defaultSymbolizer);if(symbolizer.stroke===false){delete result.strokeWidth;delete result.strokeColor;}
+if(symbolizer.fill===false){delete result.fillColor;}
+OpenLayers.Util.extend(result,symbolizer);return result;},CLASS_NAME:"OpenLayers.Renderer"});OpenLayers.Renderer.defaultSymbolizer={fillColor:"#000000",strokeColor:"#000000",strokeWidth:2,fillOpacity:1,strokeOpacity:1,pointRadius:0,labelAlign:'cm'};OpenLayers.Renderer.symbol={"star":[350,75,379,161,469,161,397,215,423,301,350,250,277,301,303,215,231,161,321,161,350,75],"cross":[4,0,6,0,6,4,10,4,10,6,6,6,6,10,4,10,4,6,0,6,0,4,4,4,4,0],"x":[0,0,25,0,50,35,75,0,100,0,65,50,100,100,75,100,50,65,25,100,0,100,35,50,0,0],"square":[0,0,0,1,1,1,1,0,0,0],"triangle":[0,10,10,10,5,0,0,10]};OpenLayers.Renderer.Canvas=OpenLayers.Class(OpenLayers.Renderer,{hitDetection:true,hitOverflow:0,canvas:null,features:null,pendingRedraw:false,cachedSymbolBounds:{},initialize:function(containerID,options){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.root=document.createElement("canvas");this.container.appendChild(this.root);this.canvas=this.root.getContext("2d");this.features={};if(this.hitDetection){this.hitCanvas=document.createElement("canvas");this.hitContext=this.hitCanvas.getContext("2d");}},setExtent:function(){OpenLayers.Renderer.prototype.setExtent.apply(this,arguments);return false;},eraseGeometry:function(geometry,featureId){this.eraseFeatures(this.features[featureId][0]);},supported:function(){return OpenLayers.CANVAS_SUPPORTED;},setSize:function(size){this.size=size.clone();var root=this.root;root.style.width=size.w+"px";root.style.height=size.h+"px";root.width=size.w;root.height=size.h;this.resolution=null;if(this.hitDetection){var hitCanvas=this.hitCanvas;hitCanvas.style.width=size.w+"px";hitCanvas.style.height=size.h+"px";hitCanvas.width=size.w;hitCanvas.height=size.h;}},drawFeature:function(feature,style){var rendered;if(feature.geometry){style=this.applyDefaultSymbolizer(style||feature.style);var bounds=feature.geometry.getBounds();var worldBounds;if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){worldBounds=this.map.getMaxExtent();}
+var intersects=bounds&&bounds.intersectsBounds(this.extent,{worldBounds:worldBounds});rendered=(style.display!=="none")&&!!bounds&&intersects;if(rendered){this.features[feature.id]=[feature,style];}
+else{delete(this.features[feature.id]);}
+this.pendingRedraw=true;}
+if(this.pendingRedraw&&!this.locked){this.redraw();this.pendingRedraw=false;}
+return rendered;},drawGeometry:function(geometry,style,featureId){var className=geometry.CLASS_NAME;if((className=="OpenLayers.Geometry.Collection")||(className=="OpenLayers.Geometry.MultiPoint")||(className=="OpenLayers.Geometry.MultiLineString")||(className=="OpenLayers.Geometry.MultiPolygon")){for(var i=0;i<geometry.components.length;i++){this.drawGeometry(geometry.components[i],style,featureId);}
+return;}
+switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":this.drawPoint(geometry,style,featureId);break;case"OpenLayers.Geometry.LineString":this.drawLineString(geometry,style,featureId);break;case"OpenLayers.Geometry.LinearRing":this.drawLinearRing(geometry,style,featureId);break;case"OpenLayers.Geometry.Polygon":this.drawPolygon(geometry,style,featureId);break;default:break;}},drawExternalGraphic:function(geometry,style,featureId){var img=new Image();if(style.graphicTitle){img.title=style.graphicTitle;}
+var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);var opacity=style.graphicOpacity||style.fillOpacity;var onLoad=function(){if(!this.features[featureId]){return;}
+var pt=this.getLocalXY(geometry);var p0=pt[0];var p1=pt[1];if(!isNaN(p0)&&!isNaN(p1)){var x=(p0+xOffset)|0;var y=(p1+yOffset)|0;var canvas=this.canvas;canvas.globalAlpha=opacity;var factor=OpenLayers.Renderer.Canvas.drawImageScaleFactor||(OpenLayers.Renderer.Canvas.drawImageScaleFactor=/android 2.1/.test(navigator.userAgent.toLowerCase())?320/window.screen.width:1);canvas.drawImage(img,x*factor,y*factor,width*factor,height*factor);if(this.hitDetection){this.setHitContextStyle("fill",featureId);this.hitContext.fillRect(x,y,width,height);}}};img.onload=OpenLayers.Function.bind(onLoad,this);img.src=style.externalGraphic;},drawNamedSymbol:function(geometry,style,featureId){var x,y,cx,cy,i,symbolBounds,scaling,angle;var unscaledStrokeWidth;var deg2rad=Math.PI/180.0;var symbol=OpenLayers.Renderer.symbol[style.graphicName];if(!symbol){throw new Error(style.graphicName+' is not a valid symbol name');}
+if(!symbol.length||symbol.length<2)return;var pt=this.getLocalXY(geometry);var p0=pt[0];var p1=pt[1];if(isNaN(p0)||isNaN(p1))return;this.canvas.lineCap="round";this.canvas.lineJoin="round";if(this.hitDetection){this.hitContext.lineCap="round";this.hitContext.lineJoin="round";}
+if(style.graphicName in this.cachedSymbolBounds){symbolBounds=this.cachedSymbolBounds[style.graphicName];}else{symbolBounds=new OpenLayers.Bounds();for(i=0;i<symbol.length;i+=2){symbolBounds.extend(new OpenLayers.LonLat(symbol[i],symbol[i+1]));}
+this.cachedSymbolBounds[style.graphicName]=symbolBounds;}
+this.canvas.save();if(this.hitDetection){this.hitContext.save();}
+this.canvas.translate(p0,p1);if(this.hitDetection){this.hitContext.translate(p0,p1);}
+angle=deg2rad*style.rotation;if(!isNaN(angle)){this.canvas.rotate(angle);if(this.hitDetection){this.hitContext.rotate(angle);}}
+scaling=2.0*style.pointRadius/Math.max(symbolBounds.getWidth(),symbolBounds.getHeight());this.canvas.scale(scaling,scaling);if(this.hitDetection){this.hitContext.scale(scaling,scaling);}
+cx=symbolBounds.getCenterLonLat().lon;cy=symbolBounds.getCenterLonLat().lat;this.canvas.translate(-cx,-cy);if(this.hitDetection){this.hitContext.translate(-cx,-cy);}
+unscaledStrokeWidth=style.strokeWidth;style.strokeWidth=unscaledStrokeWidth/scaling;if(style.fill!==false){this.setCanvasStyle("fill",style);this.canvas.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.canvas.moveTo(x,y);this.canvas.lineTo(x,y);}
+this.canvas.closePath();this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.hitContext.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.canvas.moveTo(x,y);this.hitContext.lineTo(x,y);}
+this.hitContext.closePath();this.hitContext.fill();}}
+if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.canvas.moveTo(x,y);this.canvas.lineTo(x,y);}
+this.canvas.closePath();this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style,scaling);this.hitContext.beginPath();for(i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];if(i==0)this.hitContext.moveTo(x,y);this.hitContext.lineTo(x,y);}
+this.hitContext.closePath();this.hitContext.stroke();}}
+style.strokeWidth=unscaledStrokeWidth;this.canvas.restore();if(this.hitDetection){this.hitContext.restore();}
+this.setCanvasStyle("reset");},setCanvasStyle:function(type,style){if(type==="fill"){this.canvas.globalAlpha=style['fillOpacity'];this.canvas.fillStyle=style['fillColor'];}else if(type==="stroke"){this.canvas.globalAlpha=style['strokeOpacity'];this.canvas.strokeStyle=style['strokeColor'];this.canvas.lineWidth=style['strokeWidth'];}else{this.canvas.globalAlpha=0;this.canvas.lineWidth=1;}},featureIdToHex:function(featureId){var id=Number(featureId.split("_").pop())+1;if(id>=16777216){this.hitOverflow=id-16777215;id=id%16777216+1;}
+var hex="000000"+id.toString(16);var len=hex.length;hex="#"+hex.substring(len-6,len);return hex;},setHitContextStyle:function(type,featureId,symbolizer,strokeScaling){var hex=this.featureIdToHex(featureId);if(type=="fill"){this.hitContext.globalAlpha=1.0;this.hitContext.fillStyle=hex;}else if(type=="stroke"){this.hitContext.globalAlpha=1.0;this.hitContext.strokeStyle=hex;if(typeof strokeScaling==="undefined"){this.hitContext.lineWidth=symbolizer.strokeWidth+2;}else{if(!isNaN(strokeScaling)){this.hitContext.lineWidth=symbolizer.strokeWidth+2.0/strokeScaling;}}}else{this.hitContext.globalAlpha=0;this.hitContext.lineWidth=1;}},drawPoint:function(geometry,style,featureId){if(style.graphic!==false){if(style.externalGraphic){this.drawExternalGraphic(geometry,style,featureId);}else if(style.graphicName&&(style.graphicName!="circle")){this.drawNamedSymbol(geometry,style,featureId);}else{var pt=this.getLocalXY(geometry);var p0=pt[0];var p1=pt[1];if(!isNaN(p0)&&!isNaN(p1)){var twoPi=Math.PI*2;var radius=style.pointRadius;if(style.fill!==false){this.setCanvasStyle("fill",style);this.canvas.beginPath();this.canvas.arc(p0,p1,radius,0,twoPi,true);this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.hitContext.beginPath();this.hitContext.arc(p0,p1,radius,0,twoPi,true);this.hitContext.fill();}}
+if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.canvas.beginPath();this.canvas.arc(p0,p1,radius,0,twoPi,true);this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style);this.hitContext.beginPath();this.hitContext.arc(p0,p1,radius,0,twoPi,true);this.hitContext.stroke();}
+this.setCanvasStyle("reset");}}}}},drawLineString:function(geometry,style,featureId){style=OpenLayers.Util.applyDefaults({fill:false},style);this.drawLinearRing(geometry,style,featureId);},drawLinearRing:function(geometry,style,featureId){if(style.fill!==false){this.setCanvasStyle("fill",style);this.renderPath(this.canvas,geometry,style,featureId,"fill");if(this.hitDetection){this.setHitContextStyle("fill",featureId,style);this.renderPath(this.hitContext,geometry,style,featureId,"fill");}}
+if(style.stroke!==false){this.setCanvasStyle("stroke",style);this.renderPath(this.canvas,geometry,style,featureId,"stroke");if(this.hitDetection){this.setHitContextStyle("stroke",featureId,style);this.renderPath(this.hitContext,geometry,style,featureId,"stroke");}}
+this.setCanvasStyle("reset");},renderPath:function(context,geometry,style,featureId,type){var components=geometry.components;var len=components.length;context.beginPath();var start=this.getLocalXY(components[0]);var x=start[0];var y=start[1];if(!isNaN(x)&&!isNaN(y)){context.moveTo(start[0],start[1]);for(var i=1;i<len;++i){var pt=this.getLocalXY(components[i]);context.lineTo(pt[0],pt[1]);}
+if(type==="fill"){context.fill();}else{context.stroke();}}},drawPolygon:function(geometry,style,featureId){var components=geometry.components;var len=components.length;this.drawLinearRing(components[0],style,featureId);for(var i=1;i<len;++i){this.canvas.globalCompositeOperation="destination-out";if(this.hitDetection){this.hitContext.globalCompositeOperation="destination-out";}
+this.drawLinearRing(components[i],OpenLayers.Util.applyDefaults({stroke:false,fillOpacity:1.0},style),featureId);this.canvas.globalCompositeOperation="source-over";if(this.hitDetection){this.hitContext.globalCompositeOperation="source-over";}
+this.drawLinearRing(components[i],OpenLayers.Util.applyDefaults({fill:false},style),featureId);}},drawText:function(location,style){var pt=this.getLocalXY(location);this.setCanvasStyle("reset");this.canvas.fillStyle=style.fontColor;this.canvas.globalAlpha=style.fontOpacity||1.0;var fontStyle=[style.fontStyle?style.fontStyle:"normal","normal",style.fontWeight?style.fontWeight:"normal",style.fontSize?style.fontSize:"1em",style.fontFamily?style.fontFamily:"sans-serif"].join(" ");var labelRows=style.label.split('\n');var numRows=labelRows.length;if(this.canvas.fillText){this.canvas.font=fontStyle;this.canvas.textAlign=OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]]||"center";this.canvas.textBaseline=OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[1]]||"middle";var vfactor=OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];if(vfactor==null){vfactor=-.5;}
+var lineHeight=this.canvas.measureText('Mg').height||this.canvas.measureText('xx').width;pt[1]+=lineHeight*vfactor*(numRows-1);for(var i=0;i<numRows;i++){if(style.labelOutlineWidth){this.canvas.save();this.canvas.strokeStyle=style.labelOutlineColor;this.canvas.lineWidth=style.labelOutlineWidth;this.canvas.strokeText(labelRows[i],pt[0],pt[1]+(lineHeight*i)+1);this.canvas.restore();}
+this.canvas.fillText(labelRows[i],pt[0],pt[1]+(lineHeight*i));}}else if(this.canvas.mozDrawText){this.canvas.mozTextStyle=fontStyle;var hfactor=OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[0]];if(hfactor==null){hfactor=-.5;}
+var vfactor=OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];if(vfactor==null){vfactor=-.5;}
+var lineHeight=this.canvas.mozMeasureText('xx');pt[1]+=lineHeight*(1+(vfactor*numRows));for(var i=0;i<numRows;i++){var x=pt[0]+(hfactor*this.canvas.mozMeasureText(labelRows[i]));var y=pt[1]+(i*lineHeight);this.canvas.translate(x,y);this.canvas.mozDrawText(labelRows[i]);this.canvas.translate(-x,-y);}}
+this.setCanvasStyle("reset");},getLocalXY:function(point){var resolution=this.getResolution();var extent=this.extent;var x=((point.x-this.featureDx)/resolution+(-extent.left/resolution));var y=((extent.top/resolution)-point.y/resolution);return[x,y];},clear:function(){var height=this.root.height;var width=this.root.width;this.canvas.clearRect(0,0,width,height);this.features={};if(this.hitDetection){this.hitContext.clearRect(0,0,width,height);}},getFeatureIdFromEvent:function(evt){var featureId,feature;if(this.hitDetection&&this.root.style.display!=="none"){if(!this.map.dragging){var xy=evt.xy;var x=xy.x|0;var y=xy.y|0;var data=this.hitContext.getImageData(x,y,1,1).data;if(data[3]===255){var id=data[2]+(256*(data[1]+(256*data[0])));if(id){featureId="OpenLayers.Feature.Vector_"+(id-1+this.hitOverflow);try{feature=this.features[featureId][0];}catch(err){}}}}}
+return feature;},eraseFeatures:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];}
+for(var i=0;i<features.length;++i){delete this.features[features[i].id];}
+this.redraw();},redraw:function(){if(!this.locked){var height=this.root.height;var width=this.root.width;this.canvas.clearRect(0,0,width,height);if(this.hitDetection){this.hitContext.clearRect(0,0,width,height);}
+var labelMap=[];var feature,geometry,style;var worldBounds=(this.map.baseLayer&&this.map.baseLayer.wrapDateLine)&&this.map.getMaxExtent();for(var id in this.features){if(!this.features.hasOwnProperty(id)){continue;}
+feature=this.features[id][0];geometry=feature.geometry;this.calculateFeatureDx(geometry.getBounds(),worldBounds);style=this.features[id][1];this.drawGeometry(geometry,style,feature.id);if(style.label){labelMap.push([feature,style]);}}
+var item;for(var i=0,len=labelMap.length;i<len;++i){item=labelMap[i];this.drawText(item[0].geometry.getCentroid(),item[1]);}}},CLASS_NAME:"OpenLayers.Renderer.Canvas"});OpenLayers.Renderer.Canvas.LABEL_ALIGN={"l":"left","r":"right","t":"top","b":"bottom"};OpenLayers.Renderer.Canvas.LABEL_FACTOR={"l":0,"r":-1,"t":0,"b":-1};OpenLayers.Renderer.Canvas.drawImageScaleFactor=null;OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:false,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;},destroy:function(){},read:function(data){throw new Error('Read not implemented.');},write:function(object){throw new Error('Write not implemented.');},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(options){if(window.ActiveXObject){this.xmldom=new ActiveXObject("Microsoft.XMLDOM");}
+OpenLayers.Format.prototype.initialize.apply(this,[options]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var alias in this.namespaces){this.namespaceAlias[this.namespaces[alias]]=alias;}},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this,arguments);},setNamespace:function(alias,uri){this.namespaces[alias]=uri;this.namespaceAlias[uri]=alias;},read:function(text){var index=text.indexOf('<');if(index>0){text=text.substring(index);}
+var node=OpenLayers.Util.Try(OpenLayers.Function.bind((function(){var xmldom;if(window.ActiveXObject&&!this.xmldom){xmldom=new ActiveXObject("Microsoft.XMLDOM");}else{xmldom=this.xmldom;}
+xmldom.loadXML(text);return xmldom;}),this),function(){return new DOMParser().parseFromString(text,'text/xml');},function(){var req=new XMLHttpRequest();req.open("GET","data:"+"text/xml"+";charset=utf-8,"+encodeURIComponent(text),false);if(req.overrideMimeType){req.overrideMimeType("text/xml");}
+req.send(null);return req.responseXML;});if(this.keepData){this.data=node;}
+return node;},write:function(node){var data;if(this.xmldom){data=node.xml;}else{var serializer=new XMLSerializer();if(node.nodeType==1){var doc=document.implementation.createDocument("","",null);if(doc.importNode){node=doc.importNode(node,true);}
+doc.appendChild(node);data=serializer.serializeToString(doc);}else{data=serializer.serializeToString(node);}}
+return data;},createElementNS:function(uri,name){var element;if(this.xmldom){if(typeof uri=="string"){element=this.xmldom.createNode(1,name,uri);}else{element=this.xmldom.createNode(1,name,"");}}else{element=document.createElementNS(uri,name);}
+return element;},createTextNode:function(text){var node;if(typeof text!=="string"){text=String(text);}
+if(this.xmldom){node=this.xmldom.createTextNode(text);}else{node=document.createTextNode(text);}
+return node;},getElementsByTagNameNS:function(node,uri,name){var elements=[];if(node.getElementsByTagNameNS){elements=node.getElementsByTagNameNS(uri,name);}else{var allNodes=node.getElementsByTagName("*");var potentialNode,fullName;for(var i=0,len=allNodes.length;i<len;++i){potentialNode=allNodes[i];fullName=(potentialNode.prefix)?(potentialNode.prefix+":"+name):name;if((name=="*")||(fullName==potentialNode.nodeName)){if((uri=="*")||(uri==potentialNode.namespaceURI)){elements.push(potentialNode);}}}}
+return elements;},getAttributeNodeNS:function(node,uri,name){var attributeNode=null;if(node.getAttributeNodeNS){attributeNode=node.getAttributeNodeNS(uri,name);}else{var attributes=node.attributes;var potentialNode,fullName;for(var i=0,len=attributes.length;i<len;++i){potentialNode=attributes[i];if(potentialNode.namespaceURI==uri){fullName=(potentialNode.prefix)?(potentialNode.prefix+":"+name):name;if(fullName==potentialNode.nodeName){attributeNode=potentialNode;break;}}}}
+return attributeNode;},getAttributeNS:function(node,uri,name){var attributeValue="";if(node.getAttributeNS){attributeValue=node.getAttributeNS(uri,name)||"";}else{var attributeNode=this.getAttributeNodeNS(node,uri,name);if(attributeNode){attributeValue=attributeNode.nodeValue;}}
+return attributeValue;},getChildValue:function(node,def){var value=def||"";if(node){for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 3:case 4:value+=child.nodeValue;}}}
+return value;},isSimpleContent:function(node){var simple=true;for(var child=node.firstChild;child;child=child.nextSibling){if(child.nodeType===1){simple=false;break;}}
+return simple;},contentType:function(node){var simple=false,complex=false;var type=OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;for(var child=node.firstChild;child;child=child.nextSibling){switch(child.nodeType){case 1:complex=true;break;case 8:break;default:simple=true;}
+if(complex&&simple){break;}}
+if(complex&&simple){type=OpenLayers.Format.XML.CONTENT_TYPE.MIXED;}else if(complex){return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;}else if(simple){return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;}
+return type;},hasAttributeNS:function(node,uri,name){var found=false;if(node.hasAttributeNS){found=node.hasAttributeNS(uri,name);}else{found=!!this.getAttributeNodeNS(node,uri,name);}
+return found;},setAttributeNS:function(node,uri,name,value){if(node.setAttributeNS){node.setAttributeNS(uri,name,value);}else{if(this.xmldom){if(uri){var attribute=node.ownerDocument.createNode(2,name,uri);attribute.nodeValue=value;node.setAttributeNode(attribute);}else{node.setAttribute(name,value);}}else{throw"setAttributeNS not implemented";}}},createElementNSPlus:function(name,options){options=options||{};var uri=options.uri||this.namespaces[options.prefix];if(!uri){var loc=name.indexOf(":");uri=this.namespaces[name.substring(0,loc)];}
+if(!uri){uri=this.namespaces[this.defaultPrefix];}
+var node=this.createElementNS(uri,name);if(options.attributes){this.setAttributes(node,options.attributes);}
+var value=options.value;if(value!=null){node.appendChild(this.createTextNode(value));}
+return node;},setAttributes:function(node,obj){var value,uri;for(var name in obj){if(obj[name]!=null&&obj[name].toString){value=obj[name].toString();uri=this.namespaces[name.substring(0,name.indexOf(":"))]||null;this.setAttributeNS(node,uri,name,value);}}},readNode:function(node,obj){if(!obj){obj={};}
+var group=this.readers[node.namespaceURI?this.namespaceAlias[node.namespaceURI]:this.defaultPrefix];if(group){var local=node.localName||node.nodeName.split(":").pop();var reader=group[local]||group["*"];if(reader){reader.apply(this,[node,obj]);}}
+return obj;},readChildNodes:function(node,obj){if(!obj){obj={};}
+var children=node.childNodes;var child;for(var i=0,len=children.length;i<len;++i){child=children[i];if(child.nodeType==1){this.readNode(child,obj);}}
+return obj;},writeNode:function(name,obj,parent){var prefix,local;var split=name.indexOf(":");if(split>0){prefix=name.substring(0,split);local=name.substring(split+1);}else{if(parent){prefix=this.namespaceAlias[parent.namespaceURI];}else{prefix=this.defaultPrefix;}
+local=name;}
+var child=this.writers[prefix][local].apply(this,[obj]);if(parent){parent.appendChild(child);}
+return child;},getChildEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.firstChild,name,uri);},getNextEl:function(node,name,uri){return node&&this.getThisOrNextEl(node.nextSibling,name,uri);},getThisOrNextEl:function(node,name,uri){outer:for(var sibling=node;sibling;sibling=sibling.nextSibling){switch(sibling.nodeType){case 1:if((!name||name===(sibling.localName||sibling.nodeName.split(":").pop()))&&(!uri||uri===sibling.namespaceURI)){break outer;}
+sibling=null;break outer;case 3:if(/^\s*$/.test(sibling.nodeValue)){break;}
+case 4:case 6:case 12:case 10:case 11:sibling=null;break outer;}}
+return sibling||null;},lookupNamespaceURI:function(node,prefix){var uri=null;if(node){if(node.lookupNamespaceURI){uri=node.lookupNamespaceURI(prefix);}else{outer:switch(node.nodeType){case 1:if(node.namespaceURI!==null&&node.prefix===prefix){uri=node.namespaceURI;break outer;}
+var len=node.attributes.length;if(len){var attr;for(var i=0;i<len;++i){attr=node.attributes[i];if(attr.prefix==="xmlns"&&attr.name==="xmlns:"+prefix){uri=attr.value||null;break outer;}else if(attr.name==="xmlns"&&prefix===null){uri=attr.value||null;break outer;}}}
+uri=this.lookupNamespaceURI(node.parentNode,prefix);break outer;case 2:uri=this.lookupNamespaceURI(node.ownerElement,prefix);break outer;case 9:uri=this.lookupNamespaceURI(node.documentElement,prefix);break outer;case 6:case 12:case 10:case 11:break outer;default:uri=this.lookupNamespaceURI(node.parentNode,prefix);break outer;}}}
+return uri;},getXMLDoc:function(){if(!OpenLayers.Format.XML.document&&!this.xmldom){if(document.implementation&&document.implementation.createDocument){OpenLayers.Format.XML.document=document.implementation.createDocument("","",null);}else if(!this.xmldom&&window.ActiveXObject){this.xmldom=new ActiveXObject("Microsoft.XMLDOM");}}
+return OpenLayers.Format.XML.document||this.xmldom;},CLASS_NAME:"OpenLayers.Format.XML"});OpenLayers.Format.XML.CONTENT_TYPE={EMPTY:0,SIMPLE:1,COMPLEX:2,MIXED:3};OpenLayers.Format.XML.lookupNamespaceURI=OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI,OpenLayers.Format.XML.prototype);OpenLayers.Format.XML.document=null;OpenLayers.Feature=OpenLayers.Class({layer:null,id:null,lonlat:null,data:null,marker:null,popupClass:null,popup:null,initialize:function(layer,lonlat,data){this.layer=layer;this.lonlat=lonlat;this.data=(data!=null)?data:{};this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){if((this.layer!=null)&&(this.layer.map!=null)){if(this.popup!=null){this.layer.map.removePopup(this.popup);}}
+if(this.layer!=null&&this.marker!=null){this.layer.removeMarker(this.marker);}
+this.layer=null;this.id=null;this.lonlat=null;this.data=null;if(this.marker!=null){this.destroyMarker(this.marker);this.marker=null;}
+if(this.popup!=null){this.destroyPopup(this.popup);this.popup=null;}},onScreen:function(){var onScreen=false;if((this.layer!=null)&&(this.layer.map!=null)){var screenBounds=this.layer.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
+return onScreen;},createMarker:function(){if(this.lonlat!=null){this.marker=new OpenLayers.Marker(this.lonlat,this.data.icon);}
+return this.marker;},destroyMarker:function(){this.marker.destroy();},createPopup:function(closeBox){if(this.lonlat!=null){if(!this.popup){var anchor=(this.marker)?this.marker.icon:null;var popupClass=this.popupClass?this.popupClass:OpenLayers.Popup.Anchored;this.popup=new popupClass(this.id+"_popup",this.lonlat,this.data.popupSize,this.data.popupContentHTML,anchor,closeBox);}
+if(this.data.overflow!=null){this.popup.contentDiv.style.overflow=this.data.overflow;}
+this.popup.feature=this;}
+return this.popup;},destroyPopup:function(){if(this.popup){this.popup.feature=null;this.popup.destroy();this.popup=null;}},CLASS_NAME:"OpenLayers.Feature"});OpenLayers.State={UNKNOWN:'Unknown',INSERT:'Insert',UPDATE:'Update',DELETE:'Delete'};OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,bounds:null,state:null,style:null,url:null,renderIntent:"default",modified:null,initialize:function(geometry,attributes,style){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,attributes]);this.lonlat=null;this.geometry=geometry?geometry:null;this.state=null;this.attributes={};if(attributes){this.attributes=OpenLayers.Util.extend(this.attributes,attributes);}
+this.style=style?style:null;},destroy:function(){if(this.layer){this.layer.removeFeatures(this);this.layer=null;}
+this.geometry=null;this.modified=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments);},clone:function(){return new OpenLayers.Feature.Vector(this.geometry?this.geometry.clone():null,this.attributes,this.style);},onScreen:function(boundsOnly){var onScreen=false;if(this.layer&&this.layer.map){var screenBounds=this.layer.map.getExtent();if(boundsOnly){var featureBounds=this.geometry.getBounds();onScreen=screenBounds.intersectsBounds(featureBounds);}else{var screenPoly=screenBounds.toGeometry();onScreen=screenPoly.intersects(this.geometry);}}
+return onScreen;},getVisibility:function(){return!(this.style&&this.style.display=='none'||!this.layer||this.layer&&this.layer.styleMap&&this.layer.styleMap.createSymbolizer(this,this.renderIntent).display=='none'||this.layer&&!this.layer.getVisibility());},createMarker:function(){return null;},destroyMarker:function(){},createPopup:function(){return null;},atPoint:function(lonlat,toleranceLon,toleranceLat){var atPoint=false;if(this.geometry){atPoint=this.geometry.atPoint(lonlat,toleranceLon,toleranceLat);}
+return atPoint;},destroyPopup:function(){},move:function(location){if(!this.layer||!this.geometry.move){return undefined;}
+var pixel;if(location.CLASS_NAME=="OpenLayers.LonLat"){pixel=this.layer.getViewPortPxFromLonLat(location);}else{pixel=location;}
+var lastPixel=this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat());var res=this.layer.map.getResolution();this.geometry.move(res*(pixel.x-lastPixel.x),res*(lastPixel.y-pixel.y));this.layer.drawFeature(this);return lastPixel;},toState:function(state){if(state==OpenLayers.State.UPDATE){switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.DELETE:this.state=state;break;case OpenLayers.State.UPDATE:case OpenLayers.State.INSERT:break;}}else if(state==OpenLayers.State.INSERT){switch(this.state){case OpenLayers.State.UNKNOWN:break;default:this.state=state;break;}}else if(state==OpenLayers.State.DELETE){switch(this.state){case OpenLayers.State.INSERT:break;case OpenLayers.State.DELETE:break;case OpenLayers.State.UNKNOWN:case OpenLayers.State.UPDATE:this.state=state;break;}}else if(state==OpenLayers.State.UNKNOWN){this.state=state;}},CLASS_NAME:"OpenLayers.Feature.Vector"});OpenLayers.Feature.Vector.style={'default':{fillColor:"#ee9900",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#ee9900",strokeOpacity:1,strokeWidth:1,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},'select':{fillColor:"blue",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"blue",strokeOpacity:1,strokeWidth:2,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"pointer",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},'temporary':{fillColor:"#66cccc",fillOpacity:0.2,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#66cccc",strokeOpacity:1,strokeLinecap:"round",strokeWidth:2,strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},'delete':{display:"none"}};OpenLayers.Geometry.Polygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LinearRing"],getArea:function(){var area=0.0;if(this.components&&(this.components.length>0)){area+=Math.abs(this.components[0].getArea());for(var i=1,len=this.components.length;i<len;i++){area-=Math.abs(this.components[i].getArea());}}
+return area;},getGeodesicArea:function(projection){var area=0.0;if(this.components&&(this.components.length>0)){area+=Math.abs(this.components[0].getGeodesicArea(projection));for(var i=1,len=this.components.length;i<len;i++){area-=Math.abs(this.components[i].getGeodesicArea(projection));}}
+return area;},containsPoint:function(point){var numRings=this.components.length;var contained=false;if(numRings>0){contained=this.components[0].containsPoint(point);if(contained!==1){if(contained&&numRings>1){var hole;for(var i=1;i<numRings;++i){hole=this.components[i].containsPoint(point);if(hole){if(hole===1){contained=1;}else{contained=false;}
+break;}}}}}
+return contained;},intersects:function(geometry){var intersect=false;var i,len;if(geometry.CLASS_NAME=="OpenLayers.Geometry.Point"){intersect=this.containsPoint(geometry);}else if(geometry.CLASS_NAME=="OpenLayers.Geometry.LineString"||geometry.CLASS_NAME=="OpenLayers.Geometry.LinearRing"){for(i=0,len=this.components.length;i<len;++i){intersect=geometry.intersects(this.components[i]);if(intersect){break;}}
+if(!intersect){for(i=0,len=geometry.components.length;i<len;++i){intersect=this.containsPoint(geometry.components[i]);if(intersect){break;}}}}else{for(i=0,len=geometry.components.length;i<len;++i){intersect=this.intersects(geometry.components[i]);if(intersect){break;}}}
+if(!intersect&&geometry.CLASS_NAME=="OpenLayers.Geometry.Polygon"){var ring=this.components[0];for(i=0,len=ring.components.length;i<len;++i){intersect=geometry.containsPoint(ring.components[i]);if(intersect){break;}}}
+return intersect;},distanceTo:function(geometry,options){var edge=!(options&&options.edge===false);var result;if(!edge&&this.intersects(geometry)){result=0;}else{result=OpenLayers.Geometry.Collection.prototype.distanceTo.apply(this,[geometry,options]);}
+return result;},CLASS_NAME:"OpenLayers.Geometry.Polygon"});OpenLayers.Geometry.Polygon.createRegularPolygon=function(origin,radius,sides,rotation){var angle=Math.PI*((1/sides)-(1/2));if(rotation){angle+=(rotation/180)*Math.PI;}
+var rotatedAngle,x,y;var points=[];for(var i=0;i<sides;++i){rotatedAngle=angle+(i*2*Math.PI/sides);x=origin.x+(radius*Math.cos(rotatedAngle));y=origin.y+(radius*Math.sin(rotatedAngle));points.push(new OpenLayers.Geometry.Point(x,y));}
+var ring=new OpenLayers.Geometry.LinearRing(points);return new OpenLayers.Geometry.Polygon([ring]);};OpenLayers.Format.OSM=OpenLayers.Class(OpenLayers.Format.XML,{checkTags:false,interestingTagsExclude:null,areaTags:null,initialize:function(options){var layer_defaults={'interestingTagsExclude':['source','source_ref','source:ref','history','attribution','created_by'],'areaTags':['area','building','leisure','tourism','ruins','historic','landuse','military','natural','sport']};layer_defaults=OpenLayers.Util.extend(layer_defaults,options);var interesting={};for(var i=0;i<layer_defaults.interestingTagsExclude.length;i++){interesting[layer_defaults.interestingTagsExclude[i]]=true;}
+layer_defaults.interestingTagsExclude=interesting;var area={};for(var i=0;i<layer_defaults.areaTags.length;i++){area[layer_defaults.areaTags[i]]=true;}
+layer_defaults.areaTags=area;this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[layer_defaults]);},read:function(doc){if(typeof doc=="string"){doc=OpenLayers.Format.XML.prototype.read.apply(this,[doc]);}
+var nodes=this.getNodes(doc);var ways=this.getWays(doc);var feat_list=new Array(ways.length);for(var i=0;i<ways.length;i++){var point_list=new Array(ways[i].nodes.length);var poly=this.isWayArea(ways[i])?1:0;for(var j=0;j<ways[i].nodes.length;j++){var node=nodes[ways[i].nodes[j]];var point=new OpenLayers.Geometry.Point(node.lon,node.lat);point.osm_id=parseInt(ways[i].nodes[j]);point_list[j]=point;node.used=true;}
+var geometry=null;if(poly){geometry=new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(point_list));}else{geometry=new OpenLayers.Geometry.LineString(point_list);}
+if(this.internalProjection&&this.externalProjection){geometry.transform(this.externalProjection,this.internalProjection);}
+var feat=new OpenLayers.Feature.Vector(geometry,ways[i].tags);feat.osm_id=parseInt(ways[i].id);feat.fid="way."+feat.osm_id;feat_list[i]=feat;}
+for(var node_id in nodes){var node=nodes[node_id];if(!node.used||this.checkTags){var tags=null;if(this.checkTags){var result=this.getTags(node.node,true);if(node.used&&!result[1]){continue;}
+tags=result[0];}else{tags=this.getTags(node.node);}
+var feat=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(node['lon'],node['lat']),tags);if(this.internalProjection&&this.externalProjection){feat.geometry.transform(this.externalProjection,this.internalProjection);}
+feat.osm_id=parseInt(node_id);feat.fid="node."+feat.osm_id;feat_list.push(feat);}
+node.node=null;}
+return feat_list;},getNodes:function(doc){var node_list=doc.getElementsByTagName("node");var nodes={};for(var i=0;i<node_list.length;i++){var node=node_list[i];var id=node.getAttribute("id");nodes[id]={'lat':node.getAttribute("lat"),'lon':node.getAttribute("lon"),'node':node};}
+return nodes;},getWays:function(doc){var way_list=doc.getElementsByTagName("way");var return_ways=[];for(var i=0;i<way_list.length;i++){var way=way_list[i];var way_object={id:way.getAttribute("id")};way_object.tags=this.getTags(way);var node_list=way.getElementsByTagName("nd");way_object.nodes=new Array(node_list.length);for(var j=0;j<node_list.length;j++){way_object.nodes[j]=node_list[j].getAttribute("ref");}
+return_ways.push(way_object);}
+return return_ways;},getTags:function(dom_node,interesting_tags){var tag_list=dom_node.getElementsByTagName("tag");var tags={};var interesting=false;for(var j=0;j<tag_list.length;j++){var key=tag_list[j].getAttribute("k");tags[key]=tag_list[j].getAttribute("v");if(interesting_tags){if(!this.interestingTagsExclude[key]){interesting=true;}}}
+return interesting_tags?[tags,interesting]:tags;},isWayArea:function(way){var poly_shaped=false;var poly_tags=false;if(way.nodes[0]==way.nodes[way.nodes.length-1]){poly_shaped=true;}
+if(this.checkTags){for(var key in way.tags){if(this.areaTags[key]){poly_tags=true;break;}}}
+return poly_shaped&&(this.checkTags?poly_tags:true);},write:function(features){if(!(OpenLayers.Util.isArray(features))){features=[features];}
+this.osm_id=1;this.created_nodes={};var root_node=this.createElementNS(null,"osm");root_node.setAttribute("version","0.5");root_node.setAttribute("generator","OpenLayers "+OpenLayers.VERSION_NUMBER);for(var i=features.length-1;i>=0;i--){var nodes=this.createFeatureNodes(features[i]);for(var j=0;j<nodes.length;j++){root_node.appendChild(nodes[j]);}}
+return OpenLayers.Format.XML.prototype.write.apply(this,[root_node]);},createFeatureNodes:function(feature){var nodes=[];var className=feature.geometry.CLASS_NAME;var type=className.substring(className.lastIndexOf(".")+1);type=type.toLowerCase();var builder=this.createXML[type];if(builder){nodes=builder.apply(this,[feature]);}
+return nodes;},createXML:{'point':function(point){var id=null;var geometry=point.geometry?point.geometry:point;if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
+var already_exists=false;if(point.osm_id){id=point.osm_id;if(this.created_nodes[id]){already_exists=true;}}else{id=-this.osm_id;this.osm_id++;}
+if(already_exists){node=this.created_nodes[id];}else{var node=this.createElementNS(null,"node");}
+this.created_nodes[id]=node;node.setAttribute("id",id);node.setAttribute("lon",geometry.x);node.setAttribute("lat",geometry.y);if(point.attributes){this.serializeTags(point,node);}
+this.setState(point,node);return already_exists?[]:[node];},linestring:function(feature){var id;var nodes=[];var geometry=feature.geometry;if(feature.osm_id){id=feature.osm_id;}else{id=-this.osm_id;this.osm_id++;}
+var way=this.createElementNS(null,"way");way.setAttribute("id",id);for(var i=0;i<geometry.components.length;i++){var node=this.createXML['point'].apply(this,[geometry.components[i]]);if(node.length){node=node[0];var node_ref=node.getAttribute("id");nodes.push(node);}else{node_ref=geometry.components[i].osm_id;node=this.created_nodes[node_ref];}
+this.setState(feature,node);var nd_dom=this.createElementNS(null,"nd");nd_dom.setAttribute("ref",node_ref);way.appendChild(nd_dom);}
+this.serializeTags(feature,way);nodes.push(way);return nodes;},polygon:function(feature){var attrs=OpenLayers.Util.extend({'area':'yes'},feature.attributes);var feat=new OpenLayers.Feature.Vector(feature.geometry.components[0],attrs);feat.osm_id=feature.osm_id;return this.createXML['linestring'].apply(this,[feat]);}},serializeTags:function(feature,node){for(var key in feature.attributes){var tag=this.createElementNS(null,"tag");tag.setAttribute("k",key);tag.setAttribute("v",feature.attributes[key]);node.appendChild(tag);}},setState:function(feature,node){if(feature.state){var state=null;switch(feature.state){case OpenLayers.State.UPDATE:state="modify";case OpenLayers.State.DELETE:state="delete";}
+if(state){node.setAttribute("action",state);}}},CLASS_NAME:"OpenLayers.Format.OSM"});OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:false,evt:null,initialize:function(control,callbacks,options){OpenLayers.Util.extend(this,options);this.control=control;this.callbacks=callbacks;var map=this.map||control.map;if(map){this.setMap(map);}
+this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},setMap:function(map){this.map=map;},checkModifiers:function(evt){if(this.keyMask==null){return true;}
+var keyModifiers=(evt.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(evt.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(evt.altKey?OpenLayers.Handler.MOD_ALT:0);return(keyModifiers==this.keyMask);},activate:function(){if(this.active){return false;}
+var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0,len=events.length;i<len;i++){if(this[events[i]]){this.register(events[i],this[events[i]]);}}
+this.active=true;return true;},deactivate:function(){if(!this.active){return false;}
+var events=OpenLayers.Events.prototype.BROWSER_EVENTS;for(var i=0,len=events.length;i<len;i++){if(this[events[i]]){this.unregister(events[i],this[events[i]]);}}
+this.active=false;return true;},callback:function(name,args){if(name&&this.callbacks[name]){this.callbacks[name].apply(this.control,args);}},register:function(name,method){this.map.events.registerPriority(name,this,method);this.map.events.registerPriority(name,this,this.setEvent);},unregister:function(name,method){this.map.events.unregister(name,this,method);this.map.events.unregister(name,this,this.setEvent);},setEvent:function(evt){this.evt=evt;return true;},destroy:function(){this.deactivate();this.control=this.map=null;},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,interval:0,delta:0,cumulative:true,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this);},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null;},onWheelEvent:function(e){if(!this.map||!this.checkModifiers(e)){return;}
+var overScrollableDiv=false;var overLayerDiv=false;var overMapDiv=false;var elem=OpenLayers.Event.element(e);while((elem!=null)&&!overMapDiv&&!overScrollableDiv){if(!overScrollableDiv){try{if(elem.currentStyle){overflow=elem.currentStyle["overflow"];}else{var style=document.defaultView.getComputedStyle(elem,null);var overflow=style.getPropertyValue("overflow");}
+overScrollableDiv=(overflow&&(overflow=="auto")||(overflow=="scroll"));}catch(err){}}
+if(!overLayerDiv){for(var i=0,len=this.map.layers.length;i<len;i++){if(elem==this.map.layers[i].div||elem==this.map.layers[i].pane){overLayerDiv=true;break;}}}
+overMapDiv=(elem==this.map.div);elem=elem.parentNode;}
+if(!overScrollableDiv&&overMapDiv){if(overLayerDiv){var delta=0;if(!e){e=window.event;}
+if(e.wheelDelta){delta=e.wheelDelta/120;if(window.opera&&window.opera.version()<9.2){delta=-delta;}}else if(e.detail){delta=-e.detail/3;}
+this.delta=this.delta+delta;if(this.interval){window.clearTimeout(this._timeoutId);this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(e);},this),this.interval);}else{this.wheelZoom(e);}}
+OpenLayers.Event.stop(e);}},wheelZoom:function(e){var delta=this.delta;this.delta=0;if(delta){if(this.mousePosition){e.xy=this.mousePosition;}
+if(!e.xy){e.xy=this.map.getPixelFromLonLat(this.map.getCenter());}
+if(delta<0){this.callback("down",[e,this.cumulative?delta:-1]);}else{this.callback("up",[e,this.cumulative?delta:1]);}}},mousemove:function(evt){this.mousePosition=evt.xy;},activate:function(evt){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.observe(window,"mousewheel",wheelListener);OpenLayers.Event.observe(document,"mousewheel",wheelListener);return true;}else{return false;}},deactivate:function(evt){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var wheelListener=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",wheelListener);OpenLayers.Event.stopObserving(window,"mousewheel",wheelListener);OpenLayers.Event.stopObserving(document,"mousewheel",wheelListener);return true;}else{return false;}},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Lang.en={'unhandledRequest':"Unhandled request return ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Base Layer",'noFID':"Can't update a feature for which there is no FID.",'browserNotSupported':"Your browser does not support vector rendering. Currently supported renderers are:\n${renderers}",'minZoomLevelError':"The minZoomLevel property is only intended for use "+"with the FixedZoomLevels-descendent layers. That this "+"wfs layer checks for minZoomLevel is a relic of the"+"past. We cannot, however, remove it without possibly "+"breaking OL based applications that may depend on it."+" Therefore we are deprecating it -- the minZoomLevel "+"check below will be removed at 3.0. Please instead "+"use min/max resolution setting as described here: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: SUCCESS ${response}",'commitFailed':"WFS Transaction: FAILED ${response}",'googleWarning':"The Google Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the Google Maps library "+"script was either not included, or does not contain the "+"correct API key for your site.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>click here</a>",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.<br><br>"+"To get rid of this message, select a new BaseLayer "+"in the layer switcher in the upper-right corner.<br><br>"+"Most likely, this is because the ${layerLib} library "+"script was not correctly included.<br><br>"+"Developers: For help getting this working correctly, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>click here</a>",'Scale = 1 : ${scaleDenom}':"Scale = 1 : ${scaleDenom}",'W':'W','E':'E','N':'N','S':'S','Graticule':'Graticule','reprojectDeprecated':"You are using the 'reproject' option "+"on the ${layerName} layer. This option is deprecated: "+"its use was designed to support displaying data over commercial "+"basemaps, but that functionality should now be achieved by using "+"Spherical Mercator support. More information is available from "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"This method has been deprecated and will be removed in 3.0. "+"Please use ${newMethod} instead.",'proxyNeeded':"You probably need to set OpenLayers.ProxyHost to access ${url}."+"See http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost",'end':''};OpenLayers.Lang['en-CA']=OpenLayers.Util.applyDefaults({},OpenLayers.Lang["en"]);OpenLayers.Geometry.MultiLineString=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LineString"],split:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,sourceLine,sourceLines,sourceSplit,targetSplit;var sourceParts=[];var targetParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){sourceLine=this.components[i];sourceSplit=false;for(var j=0;j<targetParts.length;++j){splits=sourceLine.split(targetParts[j],options);if(splits){if(mutual){sourceLines=splits[0];for(var k=0,klen=sourceLines.length;k<klen;++k){if(k===0&&sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLines[k]);}else{sourceParts.push(new OpenLayers.Geometry.MultiLineString([sourceLines[k]]));}}
+sourceSplit=true;splits=splits[1];}
+if(splits.length){splits.unshift(j,1);Array.prototype.splice.apply(targetParts,splits);break;}}}
+if(!sourceSplit){if(sourceParts.length){sourceParts[sourceParts.length-1].addComponent(sourceLine.clone());}else{sourceParts=[new OpenLayers.Geometry.MultiLineString(sourceLine.clone())];}}}
+if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
+if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
+if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
+return results;},splitWith:function(geometry,options){var results=null;var mutual=options&&options.mutual;var splits,targetLine,sourceLines,sourceSplit,targetSplit,sourceParts,targetParts;if(geometry instanceof OpenLayers.Geometry.LineString){targetParts=[];sourceParts=[geometry];for(var i=0,len=this.components.length;i<len;++i){targetSplit=false;targetLine=this.components[i];for(var j=0;j<sourceParts.length;++j){splits=sourceParts[j].split(targetLine,options);if(splits){if(mutual){sourceLines=splits[0];if(sourceLines.length){sourceLines.unshift(j,1);Array.prototype.splice.apply(sourceParts,sourceLines);j+=sourceLines.length-2;}
+splits=splits[1];if(splits.length===0){splits=[targetLine.clone()];}}
+for(var k=0,klen=splits.length;k<klen;++k){if(k===0&&targetParts.length){targetParts[targetParts.length-1].addComponent(splits[k]);}else{targetParts.push(new OpenLayers.Geometry.MultiLineString([splits[k]]));}}
+targetSplit=true;}}
+if(!targetSplit){if(targetParts.length){targetParts[targetParts.length-1].addComponent(targetLine.clone());}else{targetParts=[new OpenLayers.Geometry.MultiLineString([targetLine.clone()])];}}}}else{results=geometry.split(this);}
+if(sourceParts&&sourceParts.length>1){sourceSplit=true;}else{sourceParts=[];}
+if(targetParts&&targetParts.length>1){targetSplit=true;}else{targetParts=[];}
+if(sourceSplit||targetSplit){if(mutual){results=[sourceParts,targetParts];}else{results=targetParts;}}
+return results;},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:false,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:false,fixPadding:function(){if(typeof this.padding=="number"){this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding);}},panMapIfOutOfView:false,keepInMap:false,closeOnMove:false,map:null,initialize:function(id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback){if(id==null){id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");}
+this.id=id;this.lonlat=lonlat;this.contentSize=(contentSize!=null)?contentSize:new OpenLayers.Size(OpenLayers.Popup.WIDTH,OpenLayers.Popup.HEIGHT);if(contentHTML!=null){this.contentHTML=contentHTML;}
+this.backgroundColor=OpenLayers.Popup.COLOR;this.opacity=OpenLayers.Popup.OPACITY;this.border=OpenLayers.Popup.BORDER;this.div=OpenLayers.Util.createDiv(this.id,null,null,null,null,null,"hidden");this.div.className=this.displayClass;var groupDivId=this.id+"_GroupDiv";this.groupDiv=OpenLayers.Util.createDiv(groupDivId,null,null,null,"relative",null,"hidden");var id=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(id,null,this.contentSize.clone(),null,"relative");this.contentDiv.className=this.contentDisplayClass;this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);if(closeBox){this.addCloseBox(closeBoxCallback);}
+this.registerEvents();},destroy:function(){this.id=null;this.lonlat=null;this.size=null;this.contentHTML=null;this.backgroundColor=null;this.opacity=null;this.border=null;if(this.closeOnMove&&this.map){this.map.events.unregister("movestart",this,this.hide);}
+this.events.destroy();this.events=null;if(this.closeDiv){OpenLayers.Event.stopObservingElement(this.closeDiv);this.groupDiv.removeChild(this.closeDiv);}
+this.closeDiv=null;this.div.removeChild(this.groupDiv);this.groupDiv=null;if(this.map!=null){this.map.removePopup(this);}
+this.map=null;this.div=null;this.autoSize=null;this.minSize=null;this.maxSize=null;this.padding=null;this.panMapIfOutOfView=null;},draw:function(px){if(px==null){if((this.lonlat!=null)&&(this.map!=null)){px=this.map.getLayerPxFromLonLat(this.lonlat);}}
+if(this.closeOnMove){this.map.events.register("movestart",this,this.hide);}
+if(!this.disableFirefoxOverflowHack&&OpenLayers.BROWSER_NAME=='firefox'){this.map.events.register("movestart",this,function(){var style=document.defaultView.getComputedStyle(this.contentDiv,null);var currentOverflow=style.getPropertyValue("overflow");if(currentOverflow!="hidden"){this.contentDiv._oldOverflow=currentOverflow;this.contentDiv.style.overflow="hidden";}});this.map.events.register("moveend",this,function(){var oldOverflow=this.contentDiv._oldOverflow;if(oldOverflow){this.contentDiv.style.overflow=oldOverflow;this.contentDiv._oldOverflow=null;}});}
+this.moveTo(px);if(!this.autoSize&&!this.size){this.setSize(this.contentSize);}
+this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();if(this.panMapIfOutOfView){this.panIntoView();}
+return this.div;},updatePosition:function(){if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);if(px){this.moveTo(px);}}},moveTo:function(px){if((px!=null)&&(this.div!=null)){this.div.style.left=px.x+"px";this.div.style.top=px.y+"px";}},visible:function(){return OpenLayers.Element.visible(this.div);},toggle:function(){if(this.visible()){this.hide();}else{this.show();}},show:function(){this.div.style.display='';if(this.panMapIfOutOfView){this.panIntoView();}},hide:function(){this.div.style.display='none';},setSize:function(contentSize){this.size=contentSize.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;this.fixPadding();wPadding+=this.padding.left+this.padding.right;hPadding+=this.padding.top+this.padding.bottom;if(this.closeDiv){var closeDivWidth=parseInt(this.closeDiv.style.width);wPadding+=closeDivWidth+contentDivPadding.right;}
+this.size.w+=wPadding;this.size.h+=hPadding;if(OpenLayers.BROWSER_NAME=="msie"){this.contentSize.w+=contentDivPadding.left+contentDivPadding.right;this.contentSize.h+=contentDivPadding.bottom+contentDivPadding.top;}
+if(this.div!=null){this.div.style.width=this.size.w+"px";this.div.style.height=this.size.h+"px";}
+if(this.contentDiv!=null){this.contentDiv.style.width=contentSize.w+"px";this.contentDiv.style.height=contentSize.h+"px";}},updateSize:function(){var preparedHTML="<div class='"+this.contentDisplayClass+"'>"+
+this.contentDiv.innerHTML+"</div>";var containerElement=(this.map)?this.map.div:document.body;var realSize=OpenLayers.Util.getRenderedDimensions(preparedHTML,null,{displayClass:this.displayClass,containerElement:containerElement});var safeSize=this.getSafeContentSize(realSize);var newSize=null;if(safeSize.equals(realSize)){newSize=realSize;}else{var fixedSize={w:(safeSize.w<realSize.w)?safeSize.w:null,h:(safeSize.h<realSize.h)?safeSize.h:null};if(fixedSize.w&&fixedSize.h){newSize=safeSize;}else{var clippedSize=OpenLayers.Util.getRenderedDimensions(preparedHTML,fixedSize,{displayClass:this.contentDisplayClass,containerElement:containerElement});var currentOverflow=OpenLayers.Element.getStyle(this.contentDiv,"overflow");if((currentOverflow!="hidden")&&(clippedSize.equals(safeSize))){var scrollBar=OpenLayers.Util.getScrollbarWidth();if(fixedSize.w){clippedSize.h+=scrollBar;}else{clippedSize.w+=scrollBar;}}
+newSize=this.getSafeContentSize(clippedSize);}}
+this.setSize(newSize);},setBackgroundColor:function(color){if(color!=undefined){this.backgroundColor=color;}
+if(this.div!=null){this.div.style.backgroundColor=this.backgroundColor;}},setOpacity:function(opacity){if(opacity!=undefined){this.opacity=opacity;}
+if(this.div!=null){this.div.style.opacity=this.opacity;this.div.style.filter='alpha(opacity='+this.opacity*100+')';}},setBorder:function(border){if(border!=undefined){this.border=border;}
+if(this.div!=null){this.div.style.border=this.border;}},setContentHTML:function(contentHTML){if(contentHTML!=null){this.contentHTML=contentHTML;}
+if((this.contentDiv!=null)&&(this.contentHTML!=null)&&(this.contentHTML!=this.contentDiv.innerHTML)){this.contentDiv.innerHTML=this.contentHTML;if(this.autoSize){this.registerImageListeners();this.updateSize();}}},registerImageListeners:function(){var onImgLoad=function(){if(this.popup.id===null){return;}
+this.popup.updateSize();if(this.popup.visible()&&this.popup.panMapIfOutOfView){this.popup.panIntoView();}
+OpenLayers.Event.stopObserving(this.img,"load",this.img._onImageLoad);};var images=this.contentDiv.getElementsByTagName("img");for(var i=0,len=images.length;i<len;i++){var img=images[i];if(img.width==0||img.height==0){var context={'popup':this,'img':img};img._onImgLoad=OpenLayers.Function.bind(onImgLoad,context);OpenLayers.Event.observe(img,'load',img._onImgLoad);}}},getSafeContentSize:function(size){var safeContentSize=size.clone();var contentDivPadding=this.getContentDivPadding();var wPadding=contentDivPadding.left+contentDivPadding.right;var hPadding=contentDivPadding.top+contentDivPadding.bottom;this.fixPadding();wPadding+=this.padding.left+this.padding.right;hPadding+=this.padding.top+this.padding.bottom;if(this.closeDiv){var closeDivWidth=parseInt(this.closeDiv.style.width);wPadding+=closeDivWidth+contentDivPadding.right;}
+if(this.minSize){safeContentSize.w=Math.max(safeContentSize.w,(this.minSize.w-wPadding));safeContentSize.h=Math.max(safeContentSize.h,(this.minSize.h-hPadding));}
+if(this.maxSize){safeContentSize.w=Math.min(safeContentSize.w,(this.maxSize.w-wPadding));safeContentSize.h=Math.min(safeContentSize.h,(this.maxSize.h-hPadding));}
+if(this.map&&this.map.size){var extraX=0,extraY=0;if(this.keepInMap&&!this.panMapIfOutOfView){var px=this.map.getPixelFromLonLat(this.lonlat);switch(this.relativePosition){case"tr":extraX=px.x;extraY=this.map.size.h-px.y;break;case"tl":extraX=this.map.size.w-px.x;extraY=this.map.size.h-px.y;break;case"bl":extraX=this.map.size.w-px.x;extraY=px.y;break;case"br":extraX=px.x;extraY=px.y;break;default:extraX=px.x;extraY=this.map.size.h-px.y;break;}}
+var maxY=this.map.size.h-
+this.map.paddingForPopups.top-
+this.map.paddingForPopups.bottom-
+hPadding-extraY;var maxX=this.map.size.w-
+this.map.paddingForPopups.left-
+this.map.paddingForPopups.right-
+wPadding-extraX;safeContentSize.w=Math.min(safeContentSize.w,maxX);safeContentSize.h=Math.min(safeContentSize.h,maxY);}
+return safeContentSize;},getContentDivPadding:function(){var contentDivPadding=this._contentDivPadding;if(!contentDivPadding){if(this.div.parentNode==null){this.div.style.display="none";document.body.appendChild(this.div);}
+contentDivPadding=new OpenLayers.Bounds(OpenLayers.Element.getStyle(this.contentDiv,"padding-left"),OpenLayers.Element.getStyle(this.contentDiv,"padding-bottom"),OpenLayers.Element.getStyle(this.contentDiv,"padding-right"),OpenLayers.Element.getStyle(this.contentDiv,"padding-top"));this._contentDivPadding=contentDivPadding;if(this.div.parentNode==document.body){document.body.removeChild(this.div);this.div.style.display="";}}
+return contentDivPadding;},addCloseBox:function(callback){this.closeDiv=OpenLayers.Util.createDiv(this.id+"_close",null,{w:17,h:17});this.closeDiv.className="olPopupCloseBox";var contentDivPadding=this.getContentDivPadding();this.closeDiv.style.right=contentDivPadding.right+"px";this.closeDiv.style.top=contentDivPadding.top+"px";this.groupDiv.appendChild(this.closeDiv);var closePopup=callback||function(e){this.hide();OpenLayers.Event.stop(e);};OpenLayers.Event.observe(this.closeDiv,"touchend",OpenLayers.Function.bindAsEventListener(closePopup,this));OpenLayers.Event.observe(this.closeDiv,"click",OpenLayers.Function.bindAsEventListener(closePopup,this));},panIntoView:function(){var mapSize=this.map.getSize();var origTL=this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(parseInt(this.div.style.left),parseInt(this.div.style.top)));var newTL=origTL.clone();if(origTL.x<this.map.paddingForPopups.left){newTL.x=this.map.paddingForPopups.left;}else
+if((origTL.x+this.size.w)>(mapSize.w-this.map.paddingForPopups.right)){newTL.x=mapSize.w-this.map.paddingForPopups.right-this.size.w;}
+if(origTL.y<this.map.paddingForPopups.top){newTL.y=this.map.paddingForPopups.top;}else
+if((origTL.y+this.size.h)>(mapSize.h-this.map.paddingForPopups.bottom)){newTL.y=mapSize.h-this.map.paddingForPopups.bottom-this.size.h;}
+var dx=origTL.x-newTL.x;var dy=origTL.y-newTL.y;this.map.pan(dx,dy);},registerEvents:function(){this.events=new OpenLayers.Events(this,this.div,null,true);function onTouchstart(evt){OpenLayers.Event.stop(evt,true);}
+this.events.on({"mousedown":this.onmousedown,"mousemove":this.onmousemove,"mouseup":this.onmouseup,"click":this.onclick,"mouseout":this.onmouseout,"dblclick":this.ondblclick,"touchstart":onTouchstart,scope:this});},onmousedown:function(evt){this.mousedown=true;OpenLayers.Event.stop(evt,true);},onmousemove:function(evt){if(this.mousedown){OpenLayers.Event.stop(evt,true);}},onmouseup:function(evt){if(this.mousedown){this.mousedown=false;OpenLayers.Event.stop(evt,true);}},onclick:function(evt){OpenLayers.Event.stop(evt,true);},onmouseout:function(evt){this.mousedown=false;},ondblclick:function(evt){OpenLayers.Event.stop(evt,true);},CLASS_NAME:"OpenLayers.Popup"});OpenLayers.Popup.WIDTH=200;OpenLayers.Popup.HEIGHT=200;OpenLayers.Popup.COLOR="white";OpenLayers.Popup.OPACITY=1;OpenLayers.Popup.BORDER="0px";OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,keepInMap:true,anchor:null,initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){var newArguments=[id,lonlat,contentSize,contentHTML,closeBox,closeBoxCallback];OpenLayers.Popup.prototype.initialize.apply(this,newArguments);this.anchor=(anchor!=null)?anchor:{size:new OpenLayers.Size(0,0),offset:new OpenLayers.Pixel(0,0)};},destroy:function(){this.anchor=null;this.relativePosition=null;OpenLayers.Popup.prototype.destroy.apply(this,arguments);},show:function(){this.updatePosition();OpenLayers.Popup.prototype.show.apply(this,arguments);},moveTo:function(px){var oldRelativePosition=this.relativePosition;this.relativePosition=this.calculateRelativePosition(px);var newPx=this.calculateNewPx(px);var newArguments=new Array(newPx);OpenLayers.Popup.prototype.moveTo.apply(this,newArguments);if(this.relativePosition!=oldRelativePosition){this.updateRelativePosition();}},setSize:function(contentSize){OpenLayers.Popup.prototype.setSize.apply(this,arguments);if((this.lonlat)&&(this.map)){var px=this.map.getLayerPxFromLonLat(this.lonlat);this.moveTo(px);}},calculateRelativePosition:function(px){var lonlat=this.map.getLonLatFromLayerPx(px);var extent=this.map.getExtent();var quadrant=extent.determineQuadrant(lonlat);return OpenLayers.Bounds.oppositeQuadrant(quadrant);},updateRelativePosition:function(){},calculateNewPx:function(px){var newPx=px.offset(this.anchor.offset);var size=this.size||this.contentSize;var top=(this.relativePosition.charAt(0)=='t');newPx.y+=(top)?-size.h:this.anchor.size.h;var left=(this.relativePosition.charAt(1)=='l');newPx.x+=(left)?-size.w:this.anchor.size.w;return newPx;},CLASS_NAME:"OpenLayers.Popup.Anchored"});OpenLayers.Popup.Framed=OpenLayers.Class(OpenLayers.Popup.Anchored,{imageSrc:null,imageSize:null,isAlphaImage:false,positionBlocks:null,blocks:null,fixedRelativePosition:false,initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);if(this.fixedRelativePosition){this.updateRelativePosition();this.calculateRelativePosition=function(px){return this.relativePosition;};}
+this.contentDiv.style.position="absolute";this.contentDiv.style.zIndex=1;if(closeBox){this.closeDiv.style.zIndex=1;}
+this.groupDiv.style.position="absolute";this.groupDiv.style.top="0px";this.groupDiv.style.left="0px";this.groupDiv.style.height="100%";this.groupDiv.style.width="100%";},destroy:function(){this.imageSrc=null;this.imageSize=null;this.isAlphaImage=null;this.fixedRelativePosition=false;this.positionBlocks=null;for(var i=0;i<this.blocks.length;i++){var block=this.blocks[i];if(block.image){block.div.removeChild(block.image);}
+block.image=null;if(block.div){this.groupDiv.removeChild(block.div);}
+block.div=null;}
+this.blocks=null;OpenLayers.Popup.Anchored.prototype.destroy.apply(this,arguments);},setBackgroundColor:function(color){},setBorder:function(){},setOpacity:function(opacity){},setSize:function(contentSize){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.updateBlocks();},updateRelativePosition:function(){this.padding=this.positionBlocks[this.relativePosition].padding;if(this.closeDiv){var contentDivPadding=this.getContentDivPadding();this.closeDiv.style.right=contentDivPadding.right+
+this.padding.right+"px";this.closeDiv.style.top=contentDivPadding.top+
+this.padding.top+"px";}
+this.updateBlocks();},calculateNewPx:function(px){var newPx=OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(this,arguments);newPx=newPx.offset(this.positionBlocks[this.relativePosition].offset);return newPx;},createBlocks:function(){this.blocks=[];var firstPosition=null;for(var key in this.positionBlocks){firstPosition=key;break;}
+var position=this.positionBlocks[firstPosition];for(var i=0;i<position.blocks.length;i++){var block={};this.blocks.push(block);var divId=this.id+'_FrameDecorationDiv_'+i;block.div=OpenLayers.Util.createDiv(divId,null,null,null,"absolute",null,"hidden",null);var imgId=this.id+'_FrameDecorationImg_'+i;var imageCreator=(this.isAlphaImage)?OpenLayers.Util.createAlphaImageDiv:OpenLayers.Util.createImage;block.image=imageCreator(imgId,null,this.imageSize,this.imageSrc,"absolute",null,null,null);block.div.appendChild(block.image);this.groupDiv.appendChild(block.div);}},updateBlocks:function(){if(!this.blocks){this.createBlocks();}
+if(this.size&&this.relativePosition){var position=this.positionBlocks[this.relativePosition];for(var i=0;i<position.blocks.length;i++){var positionBlock=position.blocks[i];var block=this.blocks[i];var l=positionBlock.anchor.left;var b=positionBlock.anchor.bottom;var r=positionBlock.anchor.right;var t=positionBlock.anchor.top;var w=(isNaN(positionBlock.size.w))?this.size.w-(r+l):positionBlock.size.w;var h=(isNaN(positionBlock.size.h))?this.size.h-(b+t):positionBlock.size.h;block.div.style.width=(w<0?0:w)+'px';block.div.style.height=(h<0?0:h)+'px';block.div.style.left=(l!=null)?l+'px':'';block.div.style.bottom=(b!=null)?b+'px':'';block.div.style.right=(r!=null)?r+'px':'';block.div.style.top=(t!=null)?t+'px':'';block.image.style.left=positionBlock.position.x+'px';block.image.style.top=positionBlock.position.y+'px';}
+this.contentDiv.style.left=this.padding.left+"px";this.contentDiv.style.top=this.padding.top+"px";}},CLASS_NAME:"OpenLayers.Popup.Framed"});OpenLayers.Popup.FramedCloud=OpenLayers.Class(OpenLayers.Popup.Framed,{contentDisplayClass:"olFramedCloudPopupContent",autoSize:true,panMapIfOutOfView:true,imageSize:new OpenLayers.Size(1276,736),isAlphaImage:false,fixedRelativePosition:false,positionBlocks:{"tl":{'offset':new OpenLayers.Pixel(44,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,18),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-632)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(0,-688)}]},"tr":{'offset':new OpenLayers.Pixel(-45,0),'padding':new OpenLayers.Bounds(8,40,8,9),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,19),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-631)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(0,0,null,null),position:new OpenLayers.Pixel(-215,-687)}]},"bl":{'offset':new OpenLayers.Pixel(45,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(null,null,0,0),position:new OpenLayers.Pixel(-101,-674)}]},"br":{'offset':new OpenLayers.Pixel(-44,0),'padding':new OpenLayers.Bounds(8,9,8,40),'blocks':[{size:new OpenLayers.Size('auto','auto'),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,'auto'),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size('auto',21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(0,null,null,0),position:new OpenLayers.Pixel(-311,-674)}]}},minSize:new OpenLayers.Size(105,10),maxSize:new OpenLayers.Size(1200,660),initialize:function(id,lonlat,contentSize,contentHTML,anchor,closeBox,closeBoxCallback){this.imageSrc=OpenLayers.Util.getImageLocation('cloud-popup-relative.png');OpenLayers.Popup.Framed.prototype.initialize.apply(this,arguments);this.contentDiv.className=this.contentDisplayClass;},CLASS_NAME:"OpenLayers.Popup.FramedCloud"});OpenLayers.Lang["nb"]={'unhandledRequest':"Ubehandlet forespørsel returnerte ${statusText}",'Permalink':"Kobling til denne siden",'Overlays':"Kartlag",'Base Layer':"Bakgrunnskart",'noFID':"Kan ikke oppdatere et feature (et objekt) som ikke har FID.",'browserNotSupported':"Din nettleser støtter ikke vektortegning. Tegnemetodene som støttes er:\n${renderers}",'minZoomLevelError':"Egenskapen minZoomLevel er kun ment til bruk på lag "+"basert på FixedZoomLevels. At dette wfs-laget sjekker "+"minZoomLevel er en etterlevning fra tidligere versjoner. Det kan dog ikke "+"tas bort uten å risikere at OL-baserte applikasjoner "+"slutter å virke, så det er merket som foreldet: "+"minZoomLevel i sjekken nedenfor vil fjernes i 3.0. "+"Vennligst bruk innstillingene for min/maks oppløsning "+"som er beskrevet her: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-transaksjon: LYKTES ${response}",'commitFailed':"WFS-transaksjon: MISLYKTES ${response}",'googleWarning':"Google-laget kunne ikke lastes.<br><br>"+"Bytt til et annet bakgrunnslag i lagvelgeren i "+"øvre høyre hjørne for å slippe denne meldingen.<br><br>"+"Sannsynligvis forårsakes feilen av at Google Maps-biblioteket "+"ikke er riktig inkludert på nettsiden, eller at det ikke er "+"angitt riktig API-nøkkel for nettstedet.<br><br>"+"Utviklere: For hjelp til å få dette til å virke se "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>her</a>.",'getLayerWarning':"${layerType}-laget kunne ikke lastes.<br><br>"+"Bytt til et annet bakgrunnslag i lagvelgeren i "+"øvre høyre hjørne for å slippe denne meldingen.<br><br>"+"Sannsynligvis forårsakes feilen av at "+"${layerLib}-biblioteket ikke var riktig inkludert "+"på nettsiden.<br><br>"+"Utviklere: For hjelp til å få dette til å virke se "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>her</a>.",'Scale = 1 : ${scaleDenom}':"<strong>Skala</strong> 1 : ${scaleDenom}",'reprojectDeprecated':"Du bruker innstillingen 'reproject' på laget ${layerName}. "+"Denne innstillingen er foreldet, den var ment for å støtte "+"visning av kartdata over kommersielle bakgrunnskart, men det "+"bør nå gjøres med støtten for Spherical Mercator. Mer informasjon "+"finnes på http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Denne metoden er markert som foreldet og vil bli fjernet i 3.0. "+"Vennligst bruk ${newMethod} i stedet.",'end':''};OpenLayers.Lang["no"]=OpenLayers.Lang["nb"];OpenLayers.ElementsIndexer=OpenLayers.Class({maxZIndex:null,order:null,indices:null,compare:null,initialize:function(yOrdering){this.compare=yOrdering?OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER:OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;this.clear();},insert:function(newNode){if(this.exists(newNode)){this.remove(newNode);}
+var nodeId=newNode.id;this.determineZIndex(newNode);var leftIndex=-1;var rightIndex=this.order.length;var middle;while(rightIndex-leftIndex>1){middle=parseInt((leftIndex+rightIndex)/2);var placement=this.compare(this,newNode,OpenLayers.Util.getElement(this.order[middle]));if(placement>0){leftIndex=middle;}else{rightIndex=middle;}}
+this.order.splice(rightIndex,0,nodeId);this.indices[nodeId]=this.getZIndex(newNode);return this.getNextElement(rightIndex);},remove:function(node){var nodeId=node.id;var arrayIndex=OpenLayers.Util.indexOf(this.order,nodeId);if(arrayIndex>=0){this.order.splice(arrayIndex,1);delete this.indices[nodeId];if(this.order.length>0){var lastId=this.order[this.order.length-1];this.maxZIndex=this.indices[lastId];}else{this.maxZIndex=0;}}},clear:function(){this.order=[];this.indices={};this.maxZIndex=0;},exists:function(node){return(this.indices[node.id]!=null);},getZIndex:function(node){return node._style.graphicZIndex;},determineZIndex:function(node){var zIndex=node._style.graphicZIndex;if(zIndex==null){zIndex=this.maxZIndex;node._style.graphicZIndex=zIndex;}else if(zIndex>this.maxZIndex){this.maxZIndex=zIndex;}},getNextElement:function(index){var nextIndex=index+1;if(nextIndex<this.order.length){var nextElement=OpenLayers.Util.getElement(this.order[nextIndex]);if(nextElement==undefined){nextElement=this.getNextElement(nextIndex);}
+return nextElement;}else{return null;}},CLASS_NAME:"OpenLayers.ElementsIndexer"});OpenLayers.ElementsIndexer.IndexingMethods={Z_ORDER:function(indexer,newNode,nextNode){var newZIndex=indexer.getZIndex(newNode);var returnVal=0;if(nextNode){var nextZIndex=indexer.getZIndex(nextNode);returnVal=newZIndex-nextZIndex;}
+return returnVal;},Z_ORDER_DRAWING_ORDER:function(indexer,newNode,nextNode){var returnVal=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer,newNode,nextNode);if(nextNode&&returnVal==0){returnVal=1;}
+return returnVal;},Z_ORDER_Y_ORDER:function(indexer,newNode,nextNode){var returnVal=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer,newNode,nextNode);if(nextNode&&returnVal===0){var result=nextNode._boundsBottom-newNode._boundsBottom;returnVal=(result===0)?1:result;}
+return returnVal;}};OpenLayers.Renderer.Elements=OpenLayers.Class(OpenLayers.Renderer,{rendererRoot:null,root:null,vectorRoot:null,textRoot:null,xmlns:null,xOffset:0,indexer:null,BACKGROUND_ID_SUFFIX:"_background",LABEL_ID_SUFFIX:"_label",LABEL_OUTLINE_SUFFIX:"_outline",initialize:function(containerID,options){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.rendererRoot=this.createRenderRoot();this.root=this.createRoot("_root");this.vectorRoot=this.createRoot("_vroot");this.textRoot=this.createRoot("_troot");this.root.appendChild(this.vectorRoot);this.root.appendChild(this.textRoot);this.rendererRoot.appendChild(this.root);this.container.appendChild(this.rendererRoot);if(options&&(options.zIndexing||options.yOrdering)){this.indexer=new OpenLayers.ElementsIndexer(options.yOrdering);}},destroy:function(){this.clear();this.rendererRoot=null;this.root=null;this.xmlns=null;OpenLayers.Renderer.prototype.destroy.apply(this,arguments);},clear:function(){var child;var root=this.vectorRoot;if(root){while(child=root.firstChild){root.removeChild(child);}}
+root=this.textRoot;if(root){while(child=root.firstChild){root.removeChild(child);}}
+if(this.indexer){this.indexer.clear();}},setExtent:function(extent,resolutionChanged){var coordSysUnchanged=OpenLayers.Renderer.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var rightOfDateLine,ratio=extent.getWidth()/this.map.getExtent().getWidth(),extent=extent.scale(1/ratio),world=this.map.getMaxExtent();if(world.right>extent.left&&world.right<extent.right){rightOfDateLine=true;}else if(world.left>extent.left&&world.left<extent.right){rightOfDateLine=false;}
+if(rightOfDateLine!==this.rightOfDateLine||resolutionChanged){coordSysUnchanged=false;this.xOffset=rightOfDateLine===true?world.getWidth()/resolution:0;}
+this.rightOfDateLine=rightOfDateLine;}
+return coordSysUnchanged;},getNodeType:function(geometry,style){},drawGeometry:function(geometry,style,featureId){var className=geometry.CLASS_NAME;var rendered=true;if((className=="OpenLayers.Geometry.Collection")||(className=="OpenLayers.Geometry.MultiPoint")||(className=="OpenLayers.Geometry.MultiLineString")||(className=="OpenLayers.Geometry.MultiPolygon")){for(var i=0,len=geometry.components.length;i<len;i++){rendered=this.drawGeometry(geometry.components[i],style,featureId)&&rendered;}
+return rendered;}
+rendered=false;var removeBackground=false;if(style.display!="none"){if(style.backgroundGraphic){this.redrawBackgroundNode(geometry.id,geometry,style,featureId);}else{removeBackground=true;}
+rendered=this.redrawNode(geometry.id,geometry,style,featureId);}
+if(rendered==false){var node=document.getElementById(geometry.id);if(node){if(node._style.backgroundGraphic){removeBackground=true;}
+node.parentNode.removeChild(node);}}
+if(removeBackground){var node=document.getElementById(geometry.id+this.BACKGROUND_ID_SUFFIX);if(node){node.parentNode.removeChild(node);}}
+return rendered;},redrawNode:function(id,geometry,style,featureId){style=this.applyDefaultSymbolizer(style);var node=this.nodeFactory(id,this.getNodeType(geometry,style));node._featureId=featureId;node._boundsBottom=geometry.getBounds().bottom;node._geometryClass=geometry.CLASS_NAME;node._style=style;var drawResult=this.drawGeometryNode(node,geometry,style);if(drawResult===false){return false;}
+node=drawResult.node;if(this.indexer){var insert=this.indexer.insert(node);if(insert){this.vectorRoot.insertBefore(node,insert);}else{this.vectorRoot.appendChild(node);}}else{if(node.parentNode!==this.vectorRoot){this.vectorRoot.appendChild(node);}}
+this.postDraw(node);return drawResult.complete;},redrawBackgroundNode:function(id,geometry,style,featureId){var backgroundStyle=OpenLayers.Util.extend({},style);backgroundStyle.externalGraphic=backgroundStyle.backgroundGraphic;backgroundStyle.graphicXOffset=backgroundStyle.backgroundXOffset;backgroundStyle.graphicYOffset=backgroundStyle.backgroundYOffset;backgroundStyle.graphicZIndex=backgroundStyle.backgroundGraphicZIndex;backgroundStyle.graphicWidth=backgroundStyle.backgroundWidth||backgroundStyle.graphicWidth;backgroundStyle.graphicHeight=backgroundStyle.backgroundHeight||backgroundStyle.graphicHeight;backgroundStyle.backgroundGraphic=null;backgroundStyle.backgroundXOffset=null;backgroundStyle.backgroundYOffset=null;backgroundStyle.backgroundGraphicZIndex=null;return this.redrawNode(id+this.BACKGROUND_ID_SUFFIX,geometry,backgroundStyle,null);},drawGeometryNode:function(node,geometry,style){style=style||node._style;var options={'isFilled':style.fill===undefined?true:style.fill,'isStroked':style.stroke===undefined?!!style.strokeWidth:style.stroke};var drawn;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.graphic===false){options.isFilled=false;options.isStroked=false;}
+drawn=this.drawPoint(node,geometry);break;case"OpenLayers.Geometry.LineString":options.isFilled=false;drawn=this.drawLineString(node,geometry);break;case"OpenLayers.Geometry.LinearRing":drawn=this.drawLinearRing(node,geometry);break;case"OpenLayers.Geometry.Polygon":drawn=this.drawPolygon(node,geometry);break;case"OpenLayers.Geometry.Rectangle":drawn=this.drawRectangle(node,geometry);break;default:break;}
+node._options=options;if(drawn!=false){return{node:this.setStyle(node,style,options,geometry),complete:drawn};}else{return false;}},postDraw:function(node){},drawPoint:function(node,geometry){},drawLineString:function(node,geometry){},drawLinearRing:function(node,geometry){},drawPolygon:function(node,geometry){},drawRectangle:function(node,geometry){},drawCircle:function(node,geometry){},removeText:function(featureId){var label=document.getElementById(featureId+this.LABEL_ID_SUFFIX);if(label){this.textRoot.removeChild(label);}
+var outline=document.getElementById(featureId+this.LABEL_OUTLINE_SUFFIX);if(outline){this.textRoot.removeChild(outline);}},getFeatureIdFromEvent:function(evt){var target=evt.target;var useElement=target&&target.correspondingUseElement;var node=useElement?useElement:(target||evt.srcElement);return node._featureId;},eraseGeometry:function(geometry,featureId){if((geometry.CLASS_NAME=="OpenLayers.Geometry.MultiPoint")||(geometry.CLASS_NAME=="OpenLayers.Geometry.MultiLineString")||(geometry.CLASS_NAME=="OpenLayers.Geometry.MultiPolygon")||(geometry.CLASS_NAME=="OpenLayers.Geometry.Collection")){for(var i=0,len=geometry.components.length;i<len;i++){this.eraseGeometry(geometry.components[i],featureId);}}else{var element=OpenLayers.Util.getElement(geometry.id);if(element&&element.parentNode){if(element.geometry){element.geometry.destroy();element.geometry=null;}
+element.parentNode.removeChild(element);if(this.indexer){this.indexer.remove(element);}
+if(element._style.backgroundGraphic){var backgroundId=geometry.id+this.BACKGROUND_ID_SUFFIX;var bElem=OpenLayers.Util.getElement(backgroundId);if(bElem&&bElem.parentNode){bElem.parentNode.removeChild(bElem);}}}}},nodeFactory:function(id,type){var node=OpenLayers.Util.getElement(id);if(node){if(!this.nodeTypeCompare(node,type)){node.parentNode.removeChild(node);node=this.nodeFactory(id,type);}}else{node=this.createNode(type,id);}
+return node;},nodeTypeCompare:function(node,type){},createNode:function(type,id){},moveRoot:function(renderer){var root=this.root;if(renderer.root.parentNode==this.rendererRoot){root=renderer.root;}
+root.parentNode.removeChild(root);renderer.rendererRoot.appendChild(root);},getRenderLayerId:function(){return this.root.parentNode.parentNode.id;},isComplexSymbol:function(graphicName){return(graphicName!="circle")&&!!graphicName;},CLASS_NAME:"OpenLayers.Renderer.Elements"});OpenLayers.Lang["sv"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Ej hanterad fråga retur ${statusText}",'Permalink':"Permalänk",'Overlays':"Kartlager",'Base Layer':"Bakgrundskarta",'noFID':"Kan ej uppdatera feature (objekt) för vilket FID saknas.",'browserNotSupported':"Din webbläsare stöder inte vektorvisning. För närvarande stöds följande visning:\n${renderers}",'minZoomLevelError':"Egenskapen minZoomLevel är endast avsedd att användas med lager med FixedZoomLevels. Att detta WFS-lager kontrollerar minZoomLevel är en relik från äldre versioner. Vi kan dock inte ta bort det utan att riskera att OL-baserade tillämpningar som använder detta slutar fungera. Därför är det satt som deprecated, minZoomLevel kommer att tas bort i version 3.0. Använd i stället inställning av min/max resolution som beskrivs här: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-transaktion: LYCKADES ${response}",'commitFailed':"WFS-transaktion: MISSLYCKADES ${response}",'googleWarning':"Google-lagret kunde inte laddas korrekt.\x3cbr\x3e\x3cbr\x3eFör att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.\x3cbr\x3e\x3cbr\x3eSannolikt beror felet på att Google Maps-biblioteket inte är inkluderat på webbsidan eller på att sidan inte anger korrekt API-nyckel för webbplatsen.\x3cbr\x3e\x3cbr\x3eUtvecklare: hjälp för att åtgärda detta, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklicka här\x3c/a\x3e.",'getLayerWarning':"${layerType}-lagret kunde inte laddas korrekt.\x3cbr\x3e\x3cbr\x3eFör att slippa detta meddelande, välj en annan bakgrundskarta i lagerväljaren i övre högra hörnet.\x3cbr\x3e\x3cbr\x3eSannolikt beror felet på att ${layerLib}-biblioteket inte är inkluderat på webbsidan.\x3cbr\x3e\x3cbr\x3eUtvecklare: hjälp för att åtgärda detta, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklicka här\x3c/a\x3e.",'Scale = 1 : ${scaleDenom}':"\x3cstrong\x3eSkala\x3c/strong\x3e 1 : ${scaleDenom}",'reprojectDeprecated':"Du använder inställningen \'reproject\' på lagret ${layerName}. Denna inställning markerad som deprecated: den var avsedd att användas för att stödja visning av kartdata på kommersiella bakgrundskartor, men nu bör man i stället använda Spherical Mercator-stöd för den funktionaliteten. Mer information finns på http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Denna metod är markerad som deprecated och kommer att tas bort i 3.0. Använd ${newMethod} i stället."});OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:true,autoDestroy:true,initialize:function(options){OpenLayers.Util.extend(this,options);this.options=options;this.active=false;},destroy:function(){this.deactivate();this.layer=null;this.options=null;},setLayer:function(layer){this.layer=layer;},activate:function(){if(!this.active){this.active=true;return true;}
+return false;},deactivate:function(){if(this.active){this.active=false;return true;}
+return false;},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.Fixed=OpenLayers.Class(OpenLayers.Strategy,{preload:false,activate:function(){if(OpenLayers.Strategy.prototype.activate.apply(this,arguments)){this.layer.events.on({"refresh":this.load,scope:this});if(this.layer.visibility==true||this.preload){this.load();}else{this.layer.events.on({"visibilitychanged":this.load,scope:this});}
+return true;}
+return false;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.layer.events.un({"refresh":this.load,"visibilitychanged":this.load,scope:this});}
+return deactivated;},load:function(options){var layer=this.layer;layer.events.triggerEvent("loadstart");layer.protocol.read(OpenLayers.Util.applyDefaults({callback:OpenLayers.Function.bind(this.merge,this,layer.map.getProjectionObject()),filter:layer.filter},options));layer.events.un({"visibilitychanged":this.load,scope:this});},merge:function(mapProjection,resp){var layer=this.layer;layer.destroyFeatures();var features=resp.features;if(features&&features.length>0){if(!mapProjection.equals(layer.projection)){var geom;for(var i=0,len=features.length;i<len;++i){geom=features[i].geometry;if(geom){geom.transform(layer.projection,mapProjection);}}}
+layer.addFeatures(features);}
+layer.events.triggerEvent("loadend");},CLASS_NAME:"OpenLayers.Strategy.Fixed"});OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,markers:null,drawn:false,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[];},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},setOpacity:function(opacity){if(opacity!=this.opacity){this.opacity=opacity;for(var i=0,len=this.markers.length;i<len;i++){this.markers[i].setOpacity(this.opacity);}}},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);if(zoomChanged||!this.drawn){for(var i=0,len=this.markers.length;i<len;i++){this.drawMarker(this.markers[i]);}
+this.drawn=true;}},addMarker:function(marker){this.markers.push(marker);if(this.opacity<1){marker.setOpacity(this.opacity);}
+if(this.map&&this.map.getExtent()){marker.map=this.map;this.drawMarker(marker);}},removeMarker:function(marker){if(this.markers&&this.markers.length){OpenLayers.Util.removeItem(this.markers,marker);marker.erase();}},clearMarkers:function(){if(this.markers!=null){while(this.markers.length>0){this.removeMarker(this.markers[0]);}}},drawMarker:function(marker){var px=this.map.getLayerPxFromLonLat(marker.lonlat);if(px==null){marker.display(false);}else{if(!marker.isDrawn()){var markerImg=marker.draw(px);this.div.appendChild(markerImg);}else if(marker.icon){marker.icon.moveTo(px);}}},getDataExtent:function(){var maxExtent=null;if(this.markers&&(this.markers.length>0)){var maxExtent=new OpenLayers.Bounds();for(var i=0,len=this.markers.length;i<len;i++){var marker=this.markers[i];maxExtent.extend(marker.lonlat);}}
+return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Control.Zoom=OpenLayers.Class(OpenLayers.Control,{zoomInText:"+",zoomInId:"olZoomInLink",zoomOutText:"-",zoomOutId:"olZoomOutLink",draw:function(){var div=OpenLayers.Control.prototype.draw.apply(this),links=this.getOrCreateLinks(div),zoomIn=links.zoomIn,zoomOut=links.zoomOut,eventsInstance=this.map.events;if(zoomOut.parentNode!==div){eventsInstance=this.events;eventsInstance.attachToElement(zoomOut.parentNode);}
+eventsInstance.register("buttonclick",this,this.onZoomClick);this.zoomInLink=zoomIn;this.zoomOutLink=zoomOut;return div;},getOrCreateLinks:function(el){var zoomIn=document.getElementById(this.zoomInId),zoomOut=document.getElementById(this.zoomOutId);if(!zoomIn){zoomIn=document.createElement("a");zoomIn.href="#zoomIn";zoomIn.appendChild(document.createTextNode(this.zoomInText));zoomIn.className="olControlZoomIn";el.appendChild(zoomIn);}
+OpenLayers.Element.addClass(zoomIn,"olButton");if(!zoomOut){zoomOut=document.createElement("a");zoomOut.href="#zoomOut";zoomOut.appendChild(document.createTextNode(this.zoomOutText));zoomOut.className="olControlZoomOut";el.appendChild(zoomOut);}
+OpenLayers.Element.addClass(zoomOut,"olButton");return{zoomIn:zoomIn,zoomOut:zoomOut};},onZoomClick:function(evt){var button=evt.buttonElement;if(button===this.zoomInLink){this.map.zoomIn();}else if(button===this.zoomOutLink){this.map.zoomOut();}},destroy:function(){if(this.map){this.map.events.unregister("buttonclick",this,this.onZoomClick);}
+delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this);},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Lang.it={'unhandledRequest':"Codice di ritorno della richiesta ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Livello base",'noFID':"Impossibile aggiornare un elemento grafico che non abbia il FID.",'browserNotSupported':"Il tuo browser non supporta il rendering vettoriale. I renderizzatore attualemnte supportati sono:\n${renderers}",'minZoomLevelError':"La proprietà minZoomLevel è da utilizzare solamente "+"con livelli che abbiano FixedZoomLevels. Il fatto che "+"questo livello wfs controlli la proprietà minZoomLevel è "+"un retaggio del passato. Non possiamo comunque rimuoverla "+"senza rompere le vecchie applicazioni che dipendono su di essa."+"Quindi siamo costretti a deprecarla -- minZoomLevel "+"e sarà rimossa dalla vesione 3.0. Si prega di utilizzare i "+"settaggi di risoluzione min/max come descritto qui: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transazione WFS: SUCCESS ${response}",'commitFailed':"Transazione WFS: FAILED ${response}",'googleWarning':"Il livello Google non è riuscito a caricare correttamente.<br><br>"+"Per evitare questo messaggio, seleziona un nuovo BaseLayer "+"nel selettore di livelli nell'angolo in alto a destra.<br><br>"+"Più precisamente, ciò accade perchè la libreria Google Maps "+"non è stata inclusa nella pagina, oppure non contiene la "+"corretta API key per il tuo sito.<br><br>"+"Sviluppatori: Per aiuto su come farlo funzionare correttamente, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>clicca qui</a>",'getLayerWarning':"Il livello ${layerType} non è riuscito a caricare correttamente.<br><br>"+"Per evitare questo messaggio, seleziona un nuovo BaseLayer "+"nel selettore di livelli nell'angolo in alto a destra.<br><br>"+"Più precisamente, ciò accade perchè la libreria ${layerLib} "+"non è stata inclusa nella pagina.<br><br>"+"Sviluppatori: Per aiuto su come farlo funzionare correttamente, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>clicca qui</a>",'Scale = 1 : ${scaleDenom}':"Scala = 1 : ${scaleDenom}",'reprojectDeprecated':"Stai utilizzando l'opzione 'reproject' sul livello ${layerName}. "+"Questa opzione è deprecata: il suo utilizzo è stato introdotto per"+"supportare il disegno dei dati sopra mappe commerciali, ma tale "+"funzionalità dovrebbe essere ottenuta tramite l'utilizzo della proiezione "+"Spherical Mercator. Per maggiori informazioni consultare qui "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Questo metodo è stato deprecato e sarà rimosso dalla versione 3.0. "+"Si prega di utilizzare il metodo ${newMethod} in alternativa.",'end':''};OpenLayers.Lang["oc"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Requèsta pas gerida, retorna ${statusText}",'Permalink':"Permaligam",'Overlays':"Calques",'Base Layer':"Calc de basa",'noFID':"Impossible de metre a jorn un objècte sens identificant (fid).",'browserNotSupported':"Vòstre navegidor supòrta pas lo rendut vectorial. Los renderers actualament suportats son : \n${renderers}",'minZoomLevelError':"La proprietat minZoomLevel deu èsser utilizada solament per de jaces FixedZoomLevels-descendent. Lo fach qu\'aqueste jaç WFS verifique la preséncia de minZoomLevel es una relica del passat. Çaquelà, la podèm suprimir sens copar d\'aplicacions que ne poirián dependre. Es per aquò que la depreciam -- la verificacion del minZoomLevel serà suprimida en version 3.0. A la plaça, mercés d\'utilizar los paramètres de resolucions min/max tal coma descrich sus : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaccion WFS : SUCCES ${response}",'commitFailed':"Transaccion WFS : FRACAS ${response}",'googleWarning':"Lo jaç Google es pas estat en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat par la non-inclusion de la librariá Google Maps, o alara perque que la clau de l\'API correspond pas a vòstre site.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquò, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'getLayerWarning':"Lo jaç ${layerType} es pas en mesura de se cargar corrèctament.\x3cbr\x3e\x3cbr\x3ePer suprimir aqueste messatge, causissètz una  BaseLayer novèla dins lo selector de jaç en naut a drecha.\x3cbr\x3e\x3cbr\x3eAquò es possiblament causat per la non-inclusion de la librariá ${layerLib}.\x3cbr\x3e\x3cbr\x3eDesvolopaires : per saber cossí corregir aquí, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicatz aicí\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Escala ~ 1 : ${scaleDenom}",'W':"O",'E':"È",'N':"N",'S':"S",'reprojectDeprecated':"Utilizatz l\'opcion \'reproject\' sul jaç ${layerName}. Aquesta opcion es despreciada : Son usatge permetiá d\'afichar de donadas al dessús de jaces raster comercials. Aquesta foncionalitat ara es suportada en utilizant lo supòrt de la projeccion Mercator Esferica. Mai d\'informacion es disponibla sus http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Aqueste metòde es despreciada, e serà suprimida a la version 3.0. Mercés d\'utilizar ${newMethod} a la plaça."});OpenLayers.Lang["gsw"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nit behandleti Aafrogsruckmäldig ${statusText}",'Permalink':"Permalink",'Overlays':"Iberlagerige",'Base Layer':"Grundcharte",'noFID':"E Feature, wu s kei FID derfir git, cha nit aktualisiert wäre.",'browserNotSupported':"Dyy Browser unterstitzt kei Vektordarstellig. Aktuäll unterstitzti Renderer:\n${renderers}",'minZoomLevelError':"D minZoomLevel-Eigeschaft isch nume dänk fir d Layer, wu vu dr FixedZoomLevels abstamme. Ass dää wfs-Layer minZoomLevel prieft, scih e Relikt us dr Vergangeheit. Mir chenne s aber nit ändere ohni OL_basierti Aawändige villicht kaputt gehn, wu dervu abhänge.  Us däm Grund het die Funktion d Eigeschaft \'deprecated\' iberchuu. D minZoomLevel-Priefig unte wird in dr Version 3.0 usegnuu. Bitte verwänd statt däm e min/max-Uflesig wie s do bschriben isch: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transaktion: ERFOLGRYCH ${response}",'commitFailed':"WFS-Transaktion: FÄHLGSCHLAA ${response}",'googleWarning':"Dr Google-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr Google-Maps-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vum Google-Layer \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'getLayerWarning':"Dr ${layerType}-Layer het nit korräkt chenne glade wäre.\x3cbr\x3e\x3cbr\x3eGo die Mäldig nimi z kriege, wehl e andere Hintergrundlayer us em LayerSwitcher im rächte obere Ecke.\x3cbr\x3e\x3cbr\x3eDää Fähler git s seli hyfig, wel s Skript vu dr \'${layerLib}\'-Bibliothek nit yybunde woren isch oder wel s kei giltige API-Schlissel fir Dyy URL din het.\x3cbr\x3e\x3cbr\x3eEntwickler: Fir Hilf zum korräkte Yybinde vu Layer \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edoo drucke\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Maßstab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Du bruchsch d \'reproject\'-Option bim ${layerName}-Layer. Die Option isch nimi giltig: si isch aagleit wore go   Date iber kommerziälli Grundcharte lege, aber des sott mer jetz mache mit dr Unterstitzig vu Spherical Mercator. Meh Informatione git s uf http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Die Methode isch veraltet un wird us dr Version 3.0 usegnuu. Bitte verwäbnd statt däm ${newMethod}."});OpenLayers.Geometry.MultiPolygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Polygon"],CLASS_NAME:"OpenLayers.Geometry.MultiPolygon"});OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:false,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:false,propertyStyles:null,initialize:function(style,options){OpenLayers.Util.extend(this,options);this.rules=[];if(options&&options.rules){this.addRules(options.rules);}
+this.setDefaultStyle(style||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){for(var i=0,len=this.rules.length;i<len;i++){this.rules[i].destroy();this.rules[i]=null;}
+this.rules=null;this.defaultStyle=null;},createSymbolizer:function(feature){var style=this.defaultsPerSymbolizer?{}:this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),feature);var rules=this.rules;var rule,context;var elseRules=[];var appliedRules=false;for(var i=0,len=rules.length;i<len;i++){rule=rules[i];var applies=rule.evaluate(feature);if(applies){if(rule instanceof OpenLayers.Rule&&rule.elseFilter){elseRules.push(rule);}else{appliedRules=true;this.applySymbolizer(rule,style,feature);}}}
+if(appliedRules==false&&elseRules.length>0){appliedRules=true;for(var i=0,len=elseRules.length;i<len;i++){this.applySymbolizer(elseRules[i],style,feature);}}
+if(rules.length>0&&appliedRules==false){style.display="none";}
+if(style.label!=null&&typeof style.label!=="string"){style.label=String(style.label);}
+return style;},applySymbolizer:function(rule,style,feature){var symbolizerPrefix=feature.geometry?this.getSymbolizerPrefix(feature.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0];var symbolizer=rule.symbolizer[symbolizerPrefix]||rule.symbolizer;if(this.defaultsPerSymbolizer===true){var defaults=this.defaultStyle;OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:defaults.pointRadius});if(symbolizer.stroke===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{strokeWidth:defaults.strokeWidth,strokeColor:defaults.strokeColor,strokeOpacity:defaults.strokeOpacity,strokeDashstyle:defaults.strokeDashstyle,strokeLinecap:defaults.strokeLinecap});}
+if(symbolizer.fill===true||symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{fillColor:defaults.fillColor,fillOpacity:defaults.fillOpacity});}
+if(symbolizer.graphic===true){OpenLayers.Util.applyDefaults(symbolizer,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset,graphicYOffset:this.defaultStyle.graphicYOffset});}}
+return this.createLiterals(OpenLayers.Util.extend(style,symbolizer),feature);},createLiterals:function(style,feature){var context=OpenLayers.Util.extend({},feature.attributes||feature.data);OpenLayers.Util.extend(context,this.context);for(var i in this.propertyStyles){style[i]=OpenLayers.Style.createLiteral(style[i],context,feature,i);}
+return style;},findPropertyStyles:function(){var propertyStyles={};var style=this.defaultStyle;this.addPropertyStyles(propertyStyles,style);var rules=this.rules;var symbolizer,value;for(var i=0,len=rules.length;i<len;i++){symbolizer=rules[i].symbolizer;for(var key in symbolizer){value=symbolizer[key];if(typeof value=="object"){this.addPropertyStyles(propertyStyles,value);}else{this.addPropertyStyles(propertyStyles,symbolizer);break;}}}
+return propertyStyles;},addPropertyStyles:function(propertyStyles,symbolizer){var property;for(var key in symbolizer){property=symbolizer[key];if(typeof property=="string"&&property.match(/\$\{\w+\}/)){propertyStyles[key]=true;}}
+return propertyStyles;},addRules:function(rules){Array.prototype.push.apply(this.rules,rules);this.propertyStyles=this.findPropertyStyles();},setDefaultStyle:function(style){this.defaultStyle=style;this.propertyStyles=this.findPropertyStyles();},getSymbolizerPrefix:function(geometry){var prefixes=OpenLayers.Style.SYMBOLIZER_PREFIXES;for(var i=0,len=prefixes.length;i<len;i++){if(geometry.CLASS_NAME.indexOf(prefixes[i])!=-1){return prefixes[i];}}},clone:function(){var options=OpenLayers.Util.extend({},this);if(this.rules){options.rules=[];for(var i=0,len=this.rules.length;i<len;++i){options.rules.push(this.rules[i].clone());}}
+options.context=this.context&&OpenLayers.Util.extend({},this.context);var defaultStyle=OpenLayers.Util.extend({},this.defaultStyle);return new OpenLayers.Style(defaultStyle,options);},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(value,context,feature,property){if(typeof value=="string"&&value.indexOf("${")!=-1){value=OpenLayers.String.format(value,context,[feature,property]);value=(isNaN(value)||!value)?value:parseFloat(value);}
+return value;};OpenLayers.Style.SYMBOLIZER_PREFIXES=['Point','Line','Polygon','Text','Raster'];OpenLayers.Filter=OpenLayers.Class({initialize:function(options){OpenLayers.Util.extend(this,options);},destroy:function(){},evaluate:function(context){return true;},clone:function(){return null;},toString:function(){var string;if(OpenLayers.Format&&OpenLayers.Format.CQL){string=OpenLayers.Format.CQL.prototype.write(this);}else{string=Object.prototype.toString.call(this);}
+return string;},CLASS_NAME:"OpenLayers.Filter"});OpenLayers.Filter.Spatial=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,distance:null,distanceUnits:null,evaluate:function(feature){var intersect=false;switch(this.type){case OpenLayers.Filter.Spatial.BBOX:case OpenLayers.Filter.Spatial.INTERSECTS:if(feature.geometry){var geom=this.value;if(this.value.CLASS_NAME=="OpenLayers.Bounds"){geom=this.value.toGeometry();}
+if(feature.geometry.intersects(geom)){intersect=true;}}
+break;default:throw new Error('evaluate is not implemented for this filter type.');}
+return intersect;},clone:function(){var options=OpenLayers.Util.applyDefaults({value:this.value&&this.value.clone&&this.value.clone()},this);return new OpenLayers.Filter.Spatial(options);},CLASS_NAME:"OpenLayers.Filter.Spatial"});OpenLayers.Filter.Spatial.BBOX="BBOX";OpenLayers.Filter.Spatial.INTERSECTS="INTERSECTS";OpenLayers.Filter.Spatial.DWITHIN="DWITHIN";OpenLayers.Filter.Spatial.WITHIN="WITHIN";OpenLayers.Filter.Spatial.CONTAINS="CONTAINS";OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var activated=OpenLayers.Strategy.prototype.activate.call(this);if(activated){this.layer.events.on({"moveend":this.update,"refresh":this.update,"visibilitychanged":this.update,scope:this});this.update();}
+return activated;},deactivate:function(){var deactivated=OpenLayers.Strategy.prototype.deactivate.call(this);if(deactivated){this.layer.events.un({"moveend":this.update,"refresh":this.update,"visibilitychanged":this.update,scope:this});}
+return deactivated;},update:function(options){var mapBounds=this.getMapBounds();if(mapBounds!==null&&((options&&options.force)||(this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(mapBounds)))){this.calculateBounds(mapBounds);this.resolution=this.layer.map.getResolution();this.triggerRead(options);}},getMapBounds:function(){if(this.layer.map===null){return null;}
+var bounds=this.layer.map.getExtent();if(bounds&&!this.layer.projection.equals(this.layer.map.getProjectionObject())){bounds=bounds.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection);}
+return bounds;},invalidBounds:function(mapBounds){if(!mapBounds){mapBounds=this.getMapBounds();}
+var invalid=!this.bounds||!this.bounds.containsBounds(mapBounds);if(!invalid&&this.resFactor){var ratio=this.resolution/this.layer.map.getResolution();invalid=(ratio>=this.resFactor||ratio<=(1/this.resFactor));}
+return invalid;},calculateBounds:function(mapBounds){if(!mapBounds){mapBounds=this.getMapBounds();}
+var center=mapBounds.getCenterLonLat();var dataWidth=mapBounds.getWidth()*this.ratio;var dataHeight=mapBounds.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(center.lon-(dataWidth/2),center.lat-(dataHeight/2),center.lon+(dataWidth/2),center.lat+(dataHeight/2));},triggerRead:function(options){if(this.response&&!(options&&options.noAbort===true)){this.layer.protocol.abort(this.response);this.layer.events.triggerEvent("loadend");}
+this.layer.events.triggerEvent("loadstart");this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:this.createFilter(),callback:this.merge,scope:this},options));},createFilter:function(){var filter=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});if(this.layer.filter){filter=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.layer.filter,filter]});}
+return filter;},merge:function(resp){this.layer.destroyFeatures();if(resp.code==OpenLayers.Protocol.Response.SUCCESS){var features=resp.features;if(features&&features.length>0){var remote=this.layer.projection;var local=this.layer.map.getProjectionObject();if(!local.equals(remote)){var geom;for(var i=0,len=features.length;i<len;++i){geom=features[i].geometry;if(geom){geom.transform(remote,local);}}}
+this.layer.addFeatures(features);}}else{this.bounds=null;}
+this.response=null;this.layer.events.triggerEvent("loadend");},CLASS_NAME:"OpenLayers.Strategy.BBOX"});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{'click':{'in':'click','out':'clickout'},'mousemove':{'in':'over','out':'out'},'dblclick':{'in':'dblclick','out':null},'mousedown':{'in':null,'out':null},'mouseup':{'in':null,'out':null},'touchstart':{'in':'click','out':'clickout'}},feature:null,lastFeature:null,down:null,up:null,touch:false,clickTolerance:4,geometryTypes:null,stopClick:true,stopDown:true,stopUp:false,initialize:function(control,layer,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,[control,callbacks,options]);this.layer=layer;},touchstart:function(evt){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this});}
+return OpenLayers.Event.isMultiTouch(evt)?true:this.mousedown(evt);},touchmove:function(evt){OpenLayers.Event.stop(evt);},mousedown:function(evt){if(OpenLayers.Event.isLeftClick(evt)||OpenLayers.Event.isSingleTouch(evt)){this.down=evt.xy;}
+return this.handle(evt)?!this.stopDown:true;},mouseup:function(evt){this.up=evt.xy;return this.handle(evt)?!this.stopUp:true;},click:function(evt){return this.handle(evt)?!this.stopClick:true;},mousemove:function(evt){if(!this.callbacks['over']&&!this.callbacks['out']){return true;}
+this.handle(evt);return true;},dblclick:function(evt){return!this.handle(evt);},geometryTypeMatches:function(feature){return this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1;},handle:function(evt){if(this.feature&&!this.feature.layer){this.feature=null;}
+var type=evt.type;var handled=false;var previouslyIn=!!(this.feature);var click=(type=="click"||type=="dblclick"||type=="touchstart");this.feature=this.layer.getFeatureFromEvent(evt);if(this.feature&&!this.feature.layer){this.feature=null;}
+if(this.lastFeature&&!this.lastFeature.layer){this.lastFeature=null;}
+if(this.feature){if(type==="touchstart"){OpenLayers.Event.stop(evt);}
+var inNew=(this.feature!=this.lastFeature);if(this.geometryTypeMatches(this.feature)){if(previouslyIn&&inNew){if(this.lastFeature){this.triggerCallback(type,'out',[this.lastFeature]);}
+this.triggerCallback(type,'in',[this.feature]);}else if(!previouslyIn||click){this.triggerCallback(type,'in',[this.feature]);}
+this.lastFeature=this.feature;handled=true;}else{if(this.lastFeature&&(previouslyIn&&inNew||click)){this.triggerCallback(type,'out',[this.lastFeature]);}
+this.feature=null;}}else{if(this.lastFeature&&(previouslyIn||click)){this.triggerCallback(type,'out',[this.lastFeature]);}}
+return handled;},triggerCallback:function(type,mode,args){var key=this.EVENTMAP[type][mode];if(key){if(type=='click'&&this.up&&this.down){var dpx=Math.sqrt(Math.pow(this.up.x-this.down.x,2)+
+Math.pow(this.up.y-this.down.y,2));if(dpx<=this.clickTolerance){this.callback(key,args);}}else{this.callback(key,args);}}},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.moveLayerToTop();this.map.events.on({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.moveLayerBack();this.feature=null;this.lastFeature=null;this.down=null;this.up=null;this.touch=false;this.map.events.un({"removelayer":this.handleMapEvents,"changelayer":this.handleMapEvents,scope:this});deactivated=true;}
+return deactivated;},handleMapEvents:function(evt){if(evt.type=="removelayer"||evt.property=="order"){this.moveLayerToTop();}},moveLayerToTop:function(){var index=Math.max(this.map.Z_INDEX_BASE['Feature']-1,this.layer.getZIndex())+1;this.layer.setZIndex(index);},moveLayerBack:function(){var index=this.layer.getZIndex()-1;if(index>=this.map.Z_INDEX_BASE['Feature']){this.layer.setZIndex(index);}else{this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer));}},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:true,initialize:function(style,options){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),"select":new OpenLayers.Style(OpenLayers.Feature.Vector.style["select"]),"temporary":new OpenLayers.Style(OpenLayers.Feature.Vector.style["temporary"]),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(style instanceof OpenLayers.Style){this.styles["default"]=style;this.styles["select"]=style;this.styles["temporary"]=style;this.styles["delete"]=style;}else if(typeof style=="object"){for(var key in style){if(style[key]instanceof OpenLayers.Style){this.styles[key]=style[key];}else if(typeof style[key]=="object"){this.styles[key]=new OpenLayers.Style(style[key]);}else{this.styles["default"]=new OpenLayers.Style(style);this.styles["select"]=new OpenLayers.Style(style);this.styles["temporary"]=new OpenLayers.Style(style);this.styles["delete"]=new OpenLayers.Style(style);break;}}}
+OpenLayers.Util.extend(this,options);},destroy:function(){for(var key in this.styles){this.styles[key].destroy();}
+this.styles=null;},createSymbolizer:function(feature,intent){if(!feature){feature=new OpenLayers.Feature.Vector();}
+if(!this.styles[intent]){intent="default";}
+feature.renderIntent=intent;var defaultSymbolizer={};if(this.extendDefault&&intent!="default"){defaultSymbolizer=this.styles["default"].createSymbolizer(feature);}
+return OpenLayers.Util.extend(defaultSymbolizer,this.styles[intent].createSymbolizer(feature));},addUniqueValueRules:function(renderIntent,property,symbolizers,context){var rules=[];for(var value in symbolizers){rules.push(new OpenLayers.Rule({symbolizer:symbolizers[value],context:context,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:property,value:value})}));}
+this.styles[renderIntent].addRules(rules);},CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:false,isFixed:false,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:true,style:null,styleMap:null,strategies:null,protocol:null,renderers:['SVG','VML','Canvas'],renderer:null,rendererOptions:null,geometryType:null,drawn:false,ratio:1,initialize:function(name,options){OpenLayers.Layer.prototype.initialize.apply(this,arguments);if(!this.renderer||!this.renderer.supported()){this.assignRenderer();}
+if(!this.renderer||!this.renderer.supported()){this.renderer=null;this.displayError();}
+if(!this.styleMap){this.styleMap=new OpenLayers.StyleMap();}
+this.features=[];this.selectedFeatures=[];this.unrenderedFeatures={};if(this.strategies){for(var i=0,len=this.strategies.length;i<len;i++){this.strategies[i].setLayer(this);}}},destroy:function(){if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoDestroy){strategy.destroy();}}
+this.strategies=null;}
+if(this.protocol){if(this.protocol.autoDestroy){this.protocol.destroy();}
+this.protocol=null;}
+this.destroyFeatures();this.features=null;this.selectedFeatures=null;this.unrenderedFeatures=null;if(this.renderer){this.renderer.destroy();}
+this.renderer=null;this.geometryType=null;this.drawn=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments);},clone:function(obj){if(obj==null){obj=new OpenLayers.Layer.Vector(this.name,this.getOptions());}
+obj=OpenLayers.Layer.prototype.clone.apply(this,[obj]);var features=this.features;var len=features.length;var clonedFeatures=new Array(len);for(var i=0;i<len;++i){clonedFeatures[i]=features[i].clone();}
+obj.features=clonedFeatures;return obj;},refresh:function(obj){if(this.calculateInRange()&&this.visibility){this.events.triggerEvent("refresh",obj);}},assignRenderer:function(){for(var i=0,len=this.renderers.length;i<len;i++){var rendererClass=this.renderers[i];var renderer=(typeof rendererClass=="function")?rendererClass:OpenLayers.Renderer[rendererClass];if(renderer&&renderer.prototype.supported()){this.renderer=new renderer(this.div,this.rendererOptions);break;}}},displayError:function(){if(this.reportError){OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",{renderers:this.renderers.join('\n')}));}},setMap:function(map){OpenLayers.Layer.prototype.setMap.apply(this,arguments);if(!this.renderer){this.map.removeLayer(this);}else{this.renderer.map=this.map;var newSize=this.map.getSize();newSize.w=newSize.w*this.ratio;newSize.h=newSize.h*this.ratio;this.renderer.setSize(newSize);}},afterAdd:function(){if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoActivate){strategy.activate();}}}},removeMap:function(map){this.drawn=false;if(this.strategies){var strategy,i,len;for(i=0,len=this.strategies.length;i<len;i++){strategy=this.strategies[i];if(strategy.autoActivate){strategy.deactivate();}}}},onMapResize:function(){OpenLayers.Layer.prototype.onMapResize.apply(this,arguments);var newSize=this.map.getSize();newSize.w=newSize.w*this.ratio;newSize.h=newSize.h*this.ratio;this.renderer.setSize(newSize);},moveTo:function(bounds,zoomChanged,dragging){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var coordSysUnchanged=true;if(!dragging){this.renderer.root.style.visibility='hidden';var viewSize=this.map.getSize(),viewWidth=viewSize.w,viewHeight=viewSize.h,offsetLeft=(viewWidth/2*this.ratio)-viewWidth/2,offsetTop=(viewHeight/2*this.ratio)-viewHeight/2;offsetLeft+=parseInt(this.map.layerContainerDiv.style.left,10);offsetLeft=-Math.round(offsetLeft);offsetTop+=parseInt(this.map.layerContainerDiv.style.top,10);offsetTop=-Math.round(offsetTop);this.div.style.left=offsetLeft+'px';this.div.style.top=offsetTop+'px';var extent=this.map.getExtent().scale(this.ratio);coordSysUnchanged=this.renderer.setExtent(extent,zoomChanged);this.renderer.root.style.visibility='visible';if(OpenLayers.IS_GECKO===true){this.div.scrollLeft=this.div.scrollLeft;}
+if(!zoomChanged&&coordSysUnchanged){for(var i in this.unrenderedFeatures){var feature=this.unrenderedFeatures[i];this.drawFeature(feature);}}}
+if(!this.drawn||zoomChanged||!coordSysUnchanged){this.drawn=true;var feature;for(var i=0,len=this.features.length;i<len;i++){this.renderer.locked=(i!==(len-1));feature=this.features[i];this.drawFeature(feature);}}},display:function(display){OpenLayers.Layer.prototype.display.apply(this,arguments);var currentDisplay=this.div.style.display;if(currentDisplay!=this.renderer.root.style.display){this.renderer.root.style.display=currentDisplay;}},addFeatures:function(features,options){if(!(OpenLayers.Util.isArray(features))){features=[features];}
+var notify=!options||!options.silent;if(notify){var event={features:features};var ret=this.events.triggerEvent("beforefeaturesadded",event);if(ret===false){return;}
+features=event.features;}
+var featuresAdded=[];for(var i=0,len=features.length;i<len;i++){if(i!=(features.length-1)){this.renderer.locked=true;}else{this.renderer.locked=false;}
+var feature=features[i];if(this.geometryType&&!(feature.geometry instanceof this.geometryType)){throw new TypeError('addFeatures: component should be an '+
+this.geometryType.prototype.CLASS_NAME);}
+feature.layer=this;if(!feature.style&&this.style){feature.style=OpenLayers.Util.extend({},this.style);}
+if(notify){if(this.events.triggerEvent("beforefeatureadded",{feature:feature})===false){continue;}
+this.preFeatureInsert(feature);}
+featuresAdded.push(feature);this.features.push(feature);this.drawFeature(feature);if(notify){this.events.triggerEvent("featureadded",{feature:feature});this.onFeatureInsert(feature);}}
+if(notify){this.events.triggerEvent("featuresadded",{features:featuresAdded});}},removeFeatures:function(features,options){if(!features||features.length===0){return;}
+if(features===this.features){return this.removeAllFeatures(options);}
+if(!(OpenLayers.Util.isArray(features))){features=[features];}
+if(features===this.selectedFeatures){features=features.slice();}
+var notify=!options||!options.silent;if(notify){this.events.triggerEvent("beforefeaturesremoved",{features:features});}
+for(var i=features.length-1;i>=0;i--){if(i!=0&&features[i-1].geometry){this.renderer.locked=true;}else{this.renderer.locked=false;}
+var feature=features[i];delete this.unrenderedFeatures[feature.id];if(notify){this.events.triggerEvent("beforefeatureremoved",{feature:feature});}
+this.features=OpenLayers.Util.removeItem(this.features,feature);feature.layer=null;if(feature.geometry){this.renderer.eraseFeatures(feature);}
+if(OpenLayers.Util.indexOf(this.selectedFeatures,feature)!=-1){OpenLayers.Util.removeItem(this.selectedFeatures,feature);}
+if(notify){this.events.triggerEvent("featureremoved",{feature:feature});}}
+if(notify){this.events.triggerEvent("featuresremoved",{features:features});}},removeAllFeatures:function(options){var notify=!options||!options.silent;var features=this.features;if(notify){this.events.triggerEvent("beforefeaturesremoved",{features:features});}
+var feature;for(var i=features.length-1;i>=0;i--){feature=features[i];if(notify){this.events.triggerEvent("beforefeatureremoved",{feature:feature});}
+feature.layer=null;if(notify){this.events.triggerEvent("featureremoved",{feature:feature});}}
+this.renderer.clear();this.features=[];this.unrenderedFeatures={};this.selectedFeatures=[];if(notify){this.events.triggerEvent("featuresremoved",{features:features});}},destroyFeatures:function(features,options){var all=(features==undefined);if(all){features=this.features;}
+if(features){this.removeFeatures(features,options);for(var i=features.length-1;i>=0;i--){features[i].destroy();}}},drawFeature:function(feature,style){if(!this.drawn){return;}
+if(typeof style!="object"){if(!style&&feature.state===OpenLayers.State.DELETE){style="delete";}
+var renderIntent=style||feature.renderIntent;style=feature.style||this.style;if(!style){style=this.styleMap.createSymbolizer(feature,renderIntent);}}
+var drawn=this.renderer.drawFeature(feature,style);if(drawn===false||drawn===null){this.unrenderedFeatures[feature.id]=feature;}else{delete this.unrenderedFeatures[feature.id];}},eraseFeatures:function(features){this.renderer.eraseFeatures(features);},getFeatureFromEvent:function(evt){if(!this.renderer){throw new Error('getFeatureFromEvent called on layer with no '+'renderer. This usually means you destroyed a '+'layer, but not some handler which is associated '+'with it.');}
+var feature=null;var featureId=this.renderer.getFeatureIdFromEvent(evt);if(featureId){if(typeof featureId==="string"){feature=this.getFeatureById(featureId);}else{feature=featureId;}}
+return feature;},getFeatureBy:function(property,value){var feature=null;for(var i=0,len=this.features.length;i<len;++i){if(this.features[i][property]==value){feature=this.features[i];break;}}
+return feature;},getFeatureById:function(featureId){return this.getFeatureBy('id',featureId);},getFeatureByFid:function(featureFid){return this.getFeatureBy('fid',featureFid);},getFeaturesByAttribute:function(attrName,attrValue){var i,feature,len=this.features.length,foundFeatures=[];for(i=0;i<len;i++){feature=this.features[i];if(feature&&feature.attributes){if(feature.attributes[attrName]===attrValue){foundFeatures.push(feature);}}}
+return foundFeatures;},onFeatureInsert:function(feature){},preFeatureInsert:function(feature){},getDataExtent:function(){var maxExtent=null;var features=this.features;if(features&&(features.length>0)){var geometry=null;for(var i=0,len=features.length;i<len;i++){geometry=features[i].geometry;if(geometry){if(maxExtent===null){maxExtent=new OpenLayers.Bounds();}
+maxExtent.extend(geometry.getBounds());}}}
+return maxExtent;},CLASS_NAME:"OpenLayers.Layer.Vector"});OpenLayers.Layer.Vector.RootContainer=OpenLayers.Class(OpenLayers.Layer.Vector,{displayInLayerSwitcher:false,layers:null,display:function(){},getFeatureFromEvent:function(evt){var layers=this.layers;var feature;for(var i=0;i<layers.length;i++){feature=layers[i].getFeatureFromEvent(evt);if(feature){return feature;}}},setMap:function(map){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);this.collectRoots();map.events.register("changelayer",this,this.handleChangeLayer);},removeMap:function(map){map.events.unregister("changelayer",this,this.handleChangeLayer);this.resetRoots();OpenLayers.Layer.Vector.prototype.removeMap.apply(this,arguments);},collectRoots:function(){var layer;for(var i=0;i<this.map.layers.length;++i){layer=this.map.layers[i];if(OpenLayers.Util.indexOf(this.layers,layer)!=-1){layer.renderer.moveRoot(this.renderer);}}},resetRoots:function(){var layer;for(var i=0;i<this.layers.length;++i){layer=this.layers[i];if(this.renderer&&layer.renderer.getRenderLayerId()==this.id){this.renderer.moveRoot(layer.renderer);}}},handleChangeLayer:function(evt){var layer=evt.layer;if(evt.property=="order"&&OpenLayers.Util.indexOf(this.layers,layer)!=-1){this.resetRoots();this.collectRoots();}},CLASS_NAME:"OpenLayers.Layer.Vector.RootContainer"});OpenLayers.Control.SelectFeature=OpenLayers.Class(OpenLayers.Control,{multipleKey:null,toggleKey:null,multiple:false,clickout:true,toggle:false,hover:false,highlightOnly:false,box:false,onBeforeSelect:function(){},onSelect:function(){},onUnselect:function(){},scope:null,geometryTypes:null,layer:null,layers:null,callbacks:null,selectStyle:null,renderIntent:"select",handlers:null,initialize:function(layers,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);if(this.scope===null){this.scope=this;}
+this.initLayer(layers);var callbacks={click:this.clickFeature,clickout:this.clickoutFeature};if(this.hover){callbacks.over=this.overFeature;callbacks.out=this.outFeature;}
+this.callbacks=OpenLayers.Util.extend(callbacks,this.callbacks);this.handlers={feature:new OpenLayers.Handler.Feature(this,this.layer,this.callbacks,{geometryTypes:this.geometryTypes})};if(this.box){this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},{boxDivClassName:"olHandlerBoxSelectFeature"});}},initLayer:function(layers){if(OpenLayers.Util.isArray(layers)){this.layers=layers;this.layer=new OpenLayers.Layer.Vector.RootContainer(this.id+"_container",{layers:layers});}else{this.layer=layers;}},destroy:function(){if(this.active&&this.layers){this.map.removeLayer(this.layer);}
+OpenLayers.Control.prototype.destroy.apply(this,arguments);if(this.layers){this.layer.destroy();}},activate:function(){if(!this.active){if(this.layers){this.map.addLayer(this.layer);}
+this.handlers.feature.activate();if(this.box&&this.handlers.box){this.handlers.box.activate();}}
+return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){if(this.active){this.handlers.feature.deactivate();if(this.handlers.box){this.handlers.box.deactivate();}
+if(this.layers){this.map.removeLayer(this.layer);}}
+return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},unselectAll:function(options){var layers=this.layers||[this.layer];var layer,feature;for(var l=0;l<layers.length;++l){layer=layers[l];for(var i=layer.selectedFeatures.length-1;i>=0;--i){feature=layer.selectedFeatures[i];if(!options||options.except!=feature){this.unselect(feature);}}}},clickFeature:function(feature){if(!this.hover){var selected=(OpenLayers.Util.indexOf(feature.layer.selectedFeatures,feature)>-1);if(selected){if(this.toggleSelect()){this.unselect(feature);}else if(!this.multipleSelect()){this.unselectAll({except:feature});}}else{if(!this.multipleSelect()){this.unselectAll({except:feature});}
+this.select(feature);}}},multipleSelect:function(){return this.multiple||(this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]);},toggleSelect:function(){return this.toggle||(this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]);},clickoutFeature:function(feature){if(!this.hover&&this.clickout){this.unselectAll();}},overFeature:function(feature){var layer=feature.layer;if(this.hover){if(this.highlightOnly){this.highlight(feature);}else if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}},outFeature:function(feature){if(this.hover){if(this.highlightOnly){if(feature._lastHighlighter==this.id){if(feature._prevHighlighter&&feature._prevHighlighter!=this.id){delete feature._lastHighlighter;var control=this.map.getControl(feature._prevHighlighter);if(control){control.highlight(feature);}}else{this.unhighlight(feature);}}}else{this.unselect(feature);}}},highlight:function(feature){var layer=feature.layer;var cont=this.events.triggerEvent("beforefeaturehighlighted",{feature:feature});if(cont!==false){feature._prevHighlighter=feature._lastHighlighter;feature._lastHighlighter=this.id;var style=this.selectStyle||this.renderIntent;layer.drawFeature(feature,style);this.events.triggerEvent("featurehighlighted",{feature:feature});}},unhighlight:function(feature){var layer=feature.layer;if(feature._prevHighlighter==undefined){delete feature._lastHighlighter;}else if(feature._prevHighlighter==this.id){delete feature._prevHighlighter;}else{feature._lastHighlighter=feature._prevHighlighter;delete feature._prevHighlighter;}
+layer.drawFeature(feature,feature.style||feature.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:feature});},select:function(feature){var cont=this.onBeforeSelect.call(this.scope,feature);var layer=feature.layer;if(cont!==false){cont=layer.events.triggerEvent("beforefeatureselected",{feature:feature});if(cont!==false){layer.selectedFeatures.push(feature);this.highlight(feature);if(!this.handlers.feature.lastFeature){this.handlers.feature.lastFeature=layer.selectedFeatures[0];}
+layer.events.triggerEvent("featureselected",{feature:feature});this.onSelect.call(this.scope,feature);}}},unselect:function(feature){var layer=feature.layer;this.unhighlight(feature);OpenLayers.Util.removeItem(layer.selectedFeatures,feature);layer.events.triggerEvent("featureunselected",{feature:feature});this.onUnselect.call(this.scope,feature);},selectBox:function(position){if(position instanceof OpenLayers.Bounds){var minXY=this.map.getLonLatFromPixel({x:position.left,y:position.bottom});var maxXY=this.map.getLonLatFromPixel({x:position.right,y:position.top});var bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);if(!this.multipleSelect()){this.unselectAll();}
+var prevMultiple=this.multiple;this.multiple=true;var layers=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:layers});var layer;for(var l=0;l<layers.length;++l){layer=layers[l];for(var i=0,len=layer.features.length;i<len;++i){var feature=layer.features[i];if(!feature.getVisibility()){continue;}
+if(this.geometryTypes==null||OpenLayers.Util.indexOf(this.geometryTypes,feature.geometry.CLASS_NAME)>-1){if(bounds.toGeometry().intersects(feature.geometry)){if(OpenLayers.Util.indexOf(layer.selectedFeatures,feature)==-1){this.select(feature);}}}}}
+this.multiple=prevMultiple;this.events.triggerEvent("boxselectionend",{layers:layers});}},setMap:function(map){this.handlers.feature.setMap(map);if(this.box){this.handlers.box.setMap(map);}
+OpenLayers.Control.prototype.setMap.apply(this,arguments);},setLayer:function(layers){var isActive=this.active;this.unselectAll();this.deactivate();if(this.layers){this.layer.destroy();this.layers=null;}
+this.initLayer(layers);this.handlers.feature.layer=this.layer;if(isActive){this.activate();}},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({"removelayer":this.updateAttribution,"addlayer":this.updateAttribution,"changelayer":this.updateAttribution,"changebaselayer":this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments);},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({'changebaselayer':this.updateAttribution,'changelayer':this.updateAttribution,'addlayer':this.updateAttribution,'removelayer':this.updateAttribution,scope:this});this.updateAttribution();return this.div;},updateAttribution:function(){var attributions=[];if(this.map&&this.map.layers){for(var i=0,len=this.map.layers.length;i<len;i++){var layer=this.map.layers[i];if(layer.attribution&&layer.getVisibility()){if(OpenLayers.Util.indexOf(attributions,layer.attribution)===-1){attributions.push(layer.attribution);}}}
+this.div.innerHTML=OpenLayers.String.format(this.template,{layers:attributions.join(this.separator)});}},CLASS_NAME:"OpenLayers.Control.Attribution"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:false,citeCompliant:false,mouseDown:false,stoppedDown:null,lastDown:null,lastUp:null,persist:false,stopDown:false,stopUp:false,layerOptions:null,pixelTolerance:5,touch:false,lastTouchPx:null,initialize:function(control,callbacks,options){if(!(options&&options.layerOptions&&options.layerOptions.styleMap)){this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'],{});}
+OpenLayers.Handler.prototype.initialize.apply(this,arguments);},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,arguments)){return false;}
+var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);return true;},createFeature:function(pixel){var lonlat=this.layer.getLonLatFromViewPortPx(pixel);var geometry=new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);this.point=new OpenLayers.Feature.Vector(geometry);this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();this.layer.addFeatures([this.point],{silent:true});},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){return false;}
+this.cancel();if(this.layer.map!=null){this.destroyFeature(true);this.layer.destroy(false);}
+this.layer=null;this.touch=false;return true;},destroyFeature:function(force){if(this.layer&&(force||!this.persist)){this.layer.destroyFeatures();}
+this.point=null;},destroyPersistedFeature:function(){var layer=this.layer;if(layer&&layer.features.length>1){this.layer.features[0].destroy();}},finalize:function(cancel){var key=cancel?"cancel":"done";this.mouseDown=false;this.lastDown=null;this.lastUp=null;this.lastTouchPx=null;this.callback(key,[this.geometryClone()]);this.destroyFeature(cancel);},cancel:function(){this.finalize(true);},click:function(evt){OpenLayers.Event.stop(evt);return false;},dblclick:function(evt){OpenLayers.Event.stop(evt);return false;},modifyFeature:function(pixel){if(!this.point){this.createFeature(pixel);}
+var lonlat=this.layer.getLonLatFromViewPortPx(pixel);this.point.geometry.x=lonlat.lon;this.point.geometry.y=lonlat.lat;this.callback("modify",[this.point.geometry,this.point,false]);this.point.geometry.clearBounds();this.drawFeature();},drawFeature:function(){this.layer.drawFeature(this.point,this.style);},getGeometry:function(){var geometry=this.point&&this.point.geometry;if(geometry&&this.multi){geometry=new OpenLayers.Geometry.MultiPoint([geometry]);}
+return geometry;},geometryClone:function(){var geom=this.getGeometry();return geom&&geom.clone();},mousedown:function(evt){return this.down(evt);},touchstart:function(evt){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this});}
+this.lastTouchPx=evt.xy;return this.down(evt);},mousemove:function(evt){return this.move(evt);},touchmove:function(evt){this.lastTouchPx=evt.xy;return this.move(evt);},mouseup:function(evt){return this.up(evt);},touchend:function(evt){evt.xy=this.lastTouchPx;return this.up(evt);},down:function(evt){this.mouseDown=true;this.lastDown=evt.xy;if(!this.touch){this.modifyFeature(evt.xy);}
+this.stoppedDown=this.stopDown;return!this.stopDown;},move:function(evt){if(!this.touch&&(!this.mouseDown||this.stoppedDown)){this.modifyFeature(evt.xy);}
+return true;},up:function(evt){this.mouseDown=false;this.stoppedDown=this.stopDown;if(!this.checkModifiers(evt)){return true;}
+if(this.lastUp&&this.lastUp.equals(evt.xy)){return true;}
+if(this.lastDown&&this.passesTolerance(this.lastDown,evt.xy,this.pixelTolerance)){if(this.touch){this.modifyFeature(evt.xy);}
+if(this.persist){this.destroyPersistedFeature();}
+this.lastUp=evt.xy;this.finalize();return!this.stopUp;}else{return true;}},mouseout:function(evt){if(OpenLayers.Util.mouseLeft(evt,this.map.viewPortDiv)){this.stoppedDown=this.stopDown;this.mouseDown=false;}},passesTolerance:function(pixel1,pixel2,tolerance){var passes=true;if(tolerance!=null&&pixel1&&pixel2){var dist=pixel1.distanceTo(pixel2);if(dist>tolerance){passes=false;}}
+return passes;},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:false,stopDown:true,dragging:false,touch:false,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:false,documentEvents:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(this.documentDrag===true){var me=this;this._docMove=function(evt){me.mousemove({xy:{x:evt.clientX,y:evt.clientY},element:document});};this._docUp=function(evt){me.mouseup({xy:{x:evt.clientX,y:evt.clientY}});};}},dragstart:function(evt){var propagate=true;this.dragging=false;if(this.checkModifiers(evt)&&(OpenLayers.Event.isLeftClick(evt)||OpenLayers.Event.isSingleTouch(evt))){this.started=true;this.start=evt.xy;this.last=evt.xy;OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown");this.down(evt);this.callback("down",[evt.xy]);OpenLayers.Event.stop(evt);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True;}
+document.onselectstart=OpenLayers.Function.False;propagate=!this.stopDown;}else{this.started=false;this.start=null;this.last=null;}
+return propagate;},dragmove:function(evt){this.lastMoveEvt=evt;if(this.started&&!this.timeoutId&&(evt.xy.x!=this.last.x||evt.xy.y!=this.last.y)){if(this.documentDrag===true&&this.documentEvents){if(evt.element===document){this.adjustXY(evt);this.setEvent(evt);}else{this.removeDocumentEvents();}}
+if(this.interval>0){this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval);}
+this.dragging=true;this.move(evt);this.callback("move",[evt.xy]);if(!this.oldOnselectstart){this.oldOnselectstart=document.onselectstart;document.onselectstart=OpenLayers.Function.False;}
+this.last=evt.xy;}
+return true;},dragend:function(evt){if(this.started){if(this.documentDrag===true&&this.documentEvents){this.adjustXY(evt);this.removeDocumentEvents();}
+var dragged=(this.start!=this.last);this.started=false;this.dragging=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(evt);this.callback("up",[evt.xy]);if(dragged){this.callback("done",[evt.xy]);}
+document.onselectstart=this.oldOnselectstart;}
+return true;},down:function(evt){},move:function(evt){},up:function(evt){},out:function(evt){},mousedown:function(evt){return this.dragstart(evt);},touchstart:function(evt){if(!this.touch){this.touch=true;this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,scope:this});}
+return this.dragstart(evt);},mousemove:function(evt){return this.dragmove(evt);},touchmove:function(evt){return this.dragmove(evt);},removeTimeout:function(){this.timeoutId=null;if(this.dragging){this.mousemove(this.lastMoveEvt);}},mouseup:function(evt){return this.dragend(evt);},touchend:function(evt){evt.xy=this.last;return this.dragend(evt);},mouseout:function(evt){if(this.started&&OpenLayers.Util.mouseLeft(evt,this.map.viewPortDiv)){if(this.documentDrag===true){this.addDocumentEvents();}else{var dragged=(this.start!=this.last);this.started=false;this.dragging=false;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(evt);this.callback("out",[]);if(dragged){this.callback("done",[evt.xy]);}
+if(document.onselectstart){document.onselectstart=this.oldOnselectstart;}}}
+return true;},click:function(evt){return(this.start==this.last);},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragging=false;activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.touch=false;this.started=false;this.dragging=false;this.start=null;this.last=null;deactivated=true;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");}
+return deactivated;},adjustXY:function(evt){var pos=OpenLayers.Util.pagePosition(this.map.viewPortDiv);evt.xy.x-=pos[0];evt.xy.y-=pos[1];},addDocumentEvents:function(){OpenLayers.Element.addClass(document.body,"olDragDown");this.documentEvents=true;OpenLayers.Event.observe(document,"mousemove",this._docMove);OpenLayers.Event.observe(document,"mouseup",this._docUp);},removeDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents=false;OpenLayers.Event.stopObserving(document,"mousemove",this._docMove);OpenLayers.Event.stopObserving(document,"mouseup",this._docUp);},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(feature,pixel){},onDrag:function(feature,pixel){},onComplete:function(feature,pixel){},onEnter:function(feature){},onLeave:function(feature){},documentDrag:false,layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(layer,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.layer=layer;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature,up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks),{documentDrag:this.documentDrag}),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({click:this.clickFeature,clickout:this.clickoutFeature,over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})};},clickFeature:function(feature){if(this.handlers.feature.touch&&!this.over&&this.overFeature(feature)){this.handlers.drag.dragstart(this.handlers.feature.evt);this.handlers.drag.stopDown=false;}},clickoutFeature:function(feature){if(this.handlers.feature.touch&&this.over){this.outFeature(feature);this.handlers.drag.stopDown=true;}},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[]);},activate:function(){return(this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments));},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=false;this.lastPixel=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass+"Over");return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},overFeature:function(feature){var activated=false;if(!this.handlers.drag.dragging){this.feature=feature;this.handlers.drag.activate();activated=true;this.over=true;OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass+"Over");this.onEnter(feature);}else{if(this.feature.id==feature.id){this.over=true;}else{this.over=false;}}
+return activated;},downFeature:function(pixel){this.lastPixel=pixel;this.onStart(this.feature,pixel);},moveFeature:function(pixel){var res=this.map.getResolution();this.feature.geometry.move(res*(pixel.x-this.lastPixel.x),res*(this.lastPixel.y-pixel.y));this.layer.drawFeature(this.feature);this.lastPixel=pixel;this.onDrag(this.feature,pixel);},upFeature:function(pixel){if(!this.over){this.handlers.drag.deactivate();}},doneDragging:function(pixel){this.onComplete(this.feature,pixel);},outFeature:function(feature){if(!this.handlers.drag.dragging){this.over=false;this.handlers.drag.deactivate();OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass+"Over");this.onLeave(feature);this.feature=null;}else{if(this.feature.id==feature.id){this.over=false;}}},cancel:function(){this.handlers.drag.deactivate();this.over=false;},setMap:function(map){this.handlers.drag.setMap(map);this.handlers.feature.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.Control.TransformFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,layer:null,preserveAspectRatio:false,rotate:true,feature:null,renderIntent:"temporary",rotationHandleSymbolizer:null,box:null,center:null,scale:1,ratio:1,rotation:0,handles:null,rotationHandles:null,dragControl:null,irregular:false,initialize:function(layer,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.layer=layer;if(!this.rotationHandleSymbolizer){this.rotationHandleSymbolizer={stroke:false,pointRadius:10,fillOpacity:0,cursor:"pointer"};}
+this.createBox();this.createControl();},activate:function(){var activated=false;if(OpenLayers.Control.prototype.activate.apply(this,arguments)){this.dragControl.activate();this.layer.addFeatures([this.box]);this.rotate&&this.layer.addFeatures(this.rotationHandles);this.layer.addFeatures(this.handles);activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.layer.removeFeatures(this.handles);this.rotate&&this.layer.removeFeatures(this.rotationHandles);this.layer.removeFeatures([this.box]);this.dragControl.deactivate();deactivated=true;}
+return deactivated;},setMap:function(map){this.dragControl.setMap(map);OpenLayers.Control.prototype.setMap.apply(this,arguments);},setFeature:function(feature,initialParams){initialParams=OpenLayers.Util.applyDefaults(initialParams,{rotation:0,scale:1,ratio:1});var oldRotation=this.rotation;var oldCenter=this.center;OpenLayers.Util.extend(this,initialParams);var cont=this.events.triggerEvent("beforesetfeature",{feature:feature});if(cont===false){return;}
+this.feature=feature;this.activate();this._setfeature=true;var featureBounds=this.feature.geometry.getBounds();this.box.move(featureBounds.getCenterLonLat());this.box.geometry.rotate(-oldRotation,oldCenter);this._angle=0;var ll;if(this.rotation){var geom=feature.geometry.clone();geom.rotate(-this.rotation,this.center);var box=new OpenLayers.Feature.Vector(geom.getBounds().toGeometry());box.geometry.rotate(this.rotation,this.center);this.box.geometry.rotate(this.rotation,this.center);this.box.move(box.geometry.getBounds().getCenterLonLat());var llGeom=box.geometry.components[0].components[0];ll=llGeom.getBounds().getCenterLonLat();}else{ll=new OpenLayers.LonLat(featureBounds.left,featureBounds.bottom);}
+this.handles[0].move(ll);delete this._setfeature;this.events.triggerEvent("setfeature",{feature:feature});},unsetFeature:function(){if(this.active){this.deactivate();}else{this.feature=null;this.rotation=0;this.scale=1;this.ratio=1;}},createBox:function(){var control=this;this.center=new OpenLayers.Geometry.Point(0,0);this.box=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([new OpenLayers.Geometry.Point(-1,-1),new OpenLayers.Geometry.Point(0,-1),new OpenLayers.Geometry.Point(1,-1),new OpenLayers.Geometry.Point(1,0),new OpenLayers.Geometry.Point(1,1),new OpenLayers.Geometry.Point(0,1),new OpenLayers.Geometry.Point(-1,1),new OpenLayers.Geometry.Point(-1,0),new OpenLayers.Geometry.Point(-1,-1)]),null,typeof this.renderIntent=="string"?null:this.renderIntent);this.box.geometry.move=function(x,y){control._moving=true;OpenLayers.Geometry.LineString.prototype.move.apply(this,arguments);control.center.move(x,y);delete control._moving;};var vertexMoveFn=function(x,y){OpenLayers.Geometry.Point.prototype.move.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.move(x,y);this._handle.geometry.move(x,y);};var vertexResizeFn=function(scale,center,ratio){OpenLayers.Geometry.Point.prototype.resize.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.resize(scale,center,ratio);this._handle.geometry.resize(scale,center,ratio);};var vertexRotateFn=function(angle,center){OpenLayers.Geometry.Point.prototype.rotate.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.rotate(angle,center);this._handle.geometry.rotate(angle,center);};var handleMoveFn=function(x,y){var oldX=this.x,oldY=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,x,y);if(control._moving){return;}
+var evt=control.dragControl.handlers.drag.evt;var preserveAspectRatio=!control._setfeature&&control.preserveAspectRatio;var reshape=!preserveAspectRatio&&!(evt&&evt.shiftKey);var oldGeom=new OpenLayers.Geometry.Point(oldX,oldY);var centerGeometry=control.center;this.rotate(-control.rotation,centerGeometry);oldGeom.rotate(-control.rotation,centerGeometry);var dx1=this.x-centerGeometry.x;var dy1=this.y-centerGeometry.y;var dx0=dx1-(this.x-oldGeom.x);var dy0=dy1-(this.y-oldGeom.y);if(control.irregular&&!control._setfeature){dx1-=(this.x-oldGeom.x)/2;dy1-=(this.y-oldGeom.y)/2;}
+this.x=oldX;this.y=oldY;var scale,ratio=1;if(reshape){scale=Math.abs(dy0)<0.00001?1:dy1/dy0;ratio=(Math.abs(dx0)<0.00001?1:(dx1/dx0))/scale;}else{var l0=Math.sqrt((dx0*dx0)+(dy0*dy0));var l1=Math.sqrt((dx1*dx1)+(dy1*dy1));scale=l1/l0;}
+control._moving=true;control.box.geometry.rotate(-control.rotation,centerGeometry);delete control._moving;control.box.geometry.resize(scale,centerGeometry,ratio);control.box.geometry.rotate(control.rotation,centerGeometry);control.transformFeature({scale:scale,ratio:ratio});if(control.irregular&&!control._setfeature){var newCenter=centerGeometry.clone();newCenter.x+=Math.abs(oldX-centerGeometry.x)<0.00001?0:(this.x-oldX);newCenter.y+=Math.abs(oldY-centerGeometry.y)<0.00001?0:(this.y-oldY);control.box.geometry.move(this.x-oldX,this.y-oldY);control.transformFeature({center:newCenter});}};var rotationHandleMoveFn=function(x,y){var oldX=this.x,oldY=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,x,y);if(control._moving){return;}
+var evt=control.dragControl.handlers.drag.evt;var constrain=(evt&&evt.shiftKey)?45:1;var centerGeometry=control.center;var dx1=this.x-centerGeometry.x;var dy1=this.y-centerGeometry.y;var dx0=dx1-x;var dy0=dy1-y;this.x=oldX;this.y=oldY;var a0=Math.atan2(dy0,dx0);var a1=Math.atan2(dy1,dx1);var angle=a1-a0;angle*=180/Math.PI;control._angle=(control._angle+angle)%360;var diff=control.rotation%constrain;if(Math.abs(control._angle)>=constrain||diff!==0){angle=Math.round(control._angle/constrain)*constrain-
+diff;control._angle=0;control.box.geometry.rotate(angle,centerGeometry);control.transformFeature({rotation:angle});}};var handles=new Array(8);var rotationHandles=new Array(4);var geom,handle,rotationHandle;var positions=["sw","s","se","e","ne","n","nw","w"];for(var i=0;i<8;++i){geom=this.box.geometry.components[i];handle=new OpenLayers.Feature.Vector(geom.clone(),{role:positions[i]+"-resize"},typeof this.renderIntent=="string"?null:this.renderIntent);if(i%2==0){rotationHandle=new OpenLayers.Feature.Vector(geom.clone(),{role:positions[i]+"-rotate"},typeof this.rotationHandleSymbolizer=="string"?null:this.rotationHandleSymbolizer);rotationHandle.geometry.move=rotationHandleMoveFn;geom._rotationHandle=rotationHandle;rotationHandles[i/2]=rotationHandle;}
+geom.move=vertexMoveFn;geom.resize=vertexResizeFn;geom.rotate=vertexRotateFn;handle.geometry.move=handleMoveFn;geom._handle=handle;handles[i]=handle;}
+this.rotationHandles=rotationHandles;this.handles=handles;},createControl:function(){var control=this;this.dragControl=new OpenLayers.Control.DragFeature(this.layer,{documentDrag:true,moveFeature:function(pixel){if(this.feature===control.feature){this.feature=control.box;}
+OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this,arguments);},onDrag:function(feature,pixel){if(feature===control.box){control.transformFeature({center:control.center});}},onStart:function(feature,pixel){var eligible=!control.geometryTypes||OpenLayers.Util.indexOf(control.geometryTypes,feature.geometry.CLASS_NAME)!==-1;var i=OpenLayers.Util.indexOf(control.handles,feature);i+=OpenLayers.Util.indexOf(control.rotationHandles,feature);if(feature!==control.feature&&feature!==control.box&&i==-2&&eligible){control.setFeature(feature);}},onComplete:function(feature,pixel){control.events.triggerEvent("transformcomplete",{feature:control.feature});}});},drawHandles:function(){var layer=this.layer;for(var i=0;i<8;++i){if(this.rotate&&i%2===0){layer.drawFeature(this.rotationHandles[i/2],this.rotationHandleSymbolizer);}
+layer.drawFeature(this.handles[i],this.renderIntent);}},transformFeature:function(mods){if(!this._setfeature){this.scale*=(mods.scale||1);this.ratio*=(mods.ratio||1);var oldRotation=this.rotation;this.rotation=(this.rotation+(mods.rotation||0))%360;if(this.events.triggerEvent("beforetransform",mods)!==false){var feature=this.feature;var geom=feature.geometry;var center=this.center;geom.rotate(-oldRotation,center);if(mods.scale||mods.ratio){geom.resize(mods.scale,center,mods.ratio);}else if(mods.center){feature.move(mods.center.getBounds().getCenterLonLat());}
+geom.rotate(this.rotation,center);this.layer.drawFeature(feature);feature.toState(OpenLayers.State.UPDATE);this.events.triggerEvent("transform",mods);}}
+this.layer.drawFeature(this.box,this.renderIntent);this.drawHandles();},destroy:function(){var geom;for(var i=0;i<8;++i){geom=this.box.geometry.components[i];geom._handle.destroy();geom._handle=null;geom._rotationHandle&&geom._rotationHandle.destroy();geom._rotationHandle=null;}
+this.center=null;this.feature=null;this.handles=null;this.rotationHandleSymbolizer=null;this.rotationHandles=null;this.box.destroy();this.box=null;this.layer=null;this.dragControl.destroy();this.dragControl=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},CLASS_NAME:"OpenLayers.Control.TransformFeature"});OpenLayers.Filter.Logical=OpenLayers.Class(OpenLayers.Filter,{filters:null,type:null,initialize:function(options){this.filters=[];OpenLayers.Filter.prototype.initialize.apply(this,[options]);},destroy:function(){this.filters=null;OpenLayers.Filter.prototype.destroy.apply(this);},evaluate:function(context){var i,len;switch(this.type){case OpenLayers.Filter.Logical.AND:for(i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==false){return false;}}
+return true;case OpenLayers.Filter.Logical.OR:for(i=0,len=this.filters.length;i<len;i++){if(this.filters[i].evaluate(context)==true){return true;}}
+return false;case OpenLayers.Filter.Logical.NOT:return(!this.filters[0].evaluate(context));}
+return undefined;},clone:function(){var filters=[];for(var i=0,len=this.filters.length;i<len;++i){filters.push(this.filters[i].clone());}
+return new OpenLayers.Filter.Logical({type:this.type,filters:filters});},CLASS_NAME:"OpenLayers.Filter.Logical"});OpenLayers.Filter.Logical.AND="&&";OpenLayers.Filter.Logical.OR="||";OpenLayers.Filter.Logical.NOT="!";OpenLayers.Lang["ia"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Le responsa a un requesta non esseva maneate: ${statusText}",'Permalink':"Permaligamine",'Overlays':"Superpositiones",'Base Layer':"Strato de base",'noFID':"Non pote actualisar un elemento sin FID.",'browserNotSupported':"Tu navigator non supporta le rendition de vectores. Le renditores actualmente supportate es:\n${renderers}",'minZoomLevelError':"Le proprietate minZoomLevel es solmente pro uso con le stratos descendente de FixedZoomLevels. Le facto que iste strato WFS verifica minZoomLevel es un reliquia del passato. Nonobstante, si nos lo remove immediatemente, nos pote rumper applicationes a base de OL que depende de illo. Ergo nos lo declara obsolete; le verification de minZoomLevel in basso essera removite in version 3.0. Per favor usa in su loco le configuration de resolutiones min/max como describite a: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaction WFS: SUCCESSO ${response}",'commitFailed':"Transaction WFS: FALLEVA ${response}",'googleWarning':"Le strato Google non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de Google Maps non esseva includite o non contine le clave API correcte pro tu sito.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclicca hic\x3c/a",'getLayerWarning':"Le strato ${layerType} non poteva esser cargate correctemente.\x3cbr\x3e\x3cbr\x3ePro disfacer te de iste message, selige un nove BaseLayer in le selector de strato in alto a dextra.\x3cbr\x3e\x3cbr\x3eMulto probabilemente, isto es proque le script del libreria de ${layerLib} non esseva correctemente includite.\x3cbr\x3e\x3cbr\x3eDisveloppatores: Pro adjuta de corriger isto, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclicca hic\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Scala = 1 : ${scaleDenom}",'W':"W",'E':"E",'N':"N",'S':"S",'reprojectDeprecated':"Tu usa le option \'reproject\' in le strato ${layerName} layer. Iste option es obsolescente: illo esseva pro poter monstrar datos super cartas de base commercial, ma iste functionalitate pote ora esser attingite con le uso de Spherical Mercator. Ulterior information es disponibile a http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Iste methodo ha essite declarate obsolescente e essera removite in version 3.0. Per favor usa ${newMethod} in su loco."});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:'olHandlerBoxZoomBox',boxOffsets:null,initialize:function(control,callbacks,options){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.dragHandler=new OpenLayers.Handler.Drag(this,{down:this.startBox,move:this.moveBox,out:this.removeBox,up:this.endBox},{keyMask:this.keyMask});},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);if(this.dragHandler){this.dragHandler.destroy();this.dragHandler=null;}},setMap:function(map){OpenLayers.Handler.prototype.setMap.apply(this,arguments);if(this.dragHandler){this.dragHandler.setMap(map);}},startBox:function(xy){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv('zoomBox',{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE["Popup"]-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox");},moveBox:function(xy){var startX=this.dragHandler.start.x;var startY=this.dragHandler.start.y;var deltaX=Math.abs(startX-xy.x);var deltaY=Math.abs(startY-xy.y);var offset=this.getBoxOffsets();this.zoomBox.style.width=(deltaX+offset.width+1)+"px";this.zoomBox.style.height=(deltaY+offset.height+1)+"px";this.zoomBox.style.left=(xy.x<startX?startX-deltaX-offset.left:startX-offset.left)+"px";this.zoomBox.style.top=(xy.y<startY?startY-deltaY-offset.top:startY-offset.top)+"px";},endBox:function(end){var result;if(Math.abs(this.dragHandler.start.x-end.x)>5||Math.abs(this.dragHandler.start.y-end.y)>5){var start=this.dragHandler.start;var top=Math.min(start.y,end.y);var bottom=Math.max(start.y,end.y);var left=Math.min(start.x,end.x);var right=Math.max(start.x,end.x);result=new OpenLayers.Bounds(left,bottom,right,top);}else{result=this.dragHandler.start.clone();}
+this.removeBox();this.callback("done",[result]);},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.zoomBox=null;this.boxOffsets=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox");},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.dragHandler.activate();return true;}else{return false;}},deactivate:function(){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){if(this.dragHandler.deactivate()){if(this.zoomBox){this.removeBox();}}
+return true;}else{return false;}},getBoxOffsets:function(){if(!this.boxOffsets){var testDiv=document.createElement("div");testDiv.style.position="absolute";testDiv.style.border="1px solid black";testDiv.style.width="3px";document.body.appendChild(testDiv);var w3cBoxModel=testDiv.clientWidth==3;document.body.removeChild(testDiv);var left=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width"));var right=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width"));var top=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-top-width"));var bottom=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:left,right:right,top:top,bottom:bottom,width:w3cBoxModel===false?left+right:0,height:w3cBoxModel===false?top+bottom:0};}
+return this.boxOffsets;},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:false,keyMask:null,alwaysZoom:false,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask});},zoomBox:function(position){if(position instanceof OpenLayers.Bounds){var bounds;if(!this.out){var minXY=this.map.getLonLatFromPixel({x:position.left,y:position.bottom});var maxXY=this.map.getLonLatFromPixel({x:position.right,y:position.top});bounds=new OpenLayers.Bounds(minXY.lon,minXY.lat,maxXY.lon,maxXY.lat);}else{var pixWidth=Math.abs(position.right-position.left);var pixHeight=Math.abs(position.top-position.bottom);var zoomFactor=Math.min((this.map.size.h/pixHeight),(this.map.size.w/pixWidth));var extent=this.map.getExtent();var center=this.map.getLonLatFromPixel(position.getCenterPixel());var xmin=center.lon-(extent.getWidth()/2)*zoomFactor;var xmax=center.lon+(extent.getWidth()/2)*zoomFactor;var ymin=center.lat-(extent.getHeight()/2)*zoomFactor;var ymax=center.lat+(extent.getHeight()/2)*zoomFactor;bounds=new OpenLayers.Bounds(xmin,ymin,xmax,ymax);}
+var lastZoom=this.map.getZoom();this.map.zoomToExtent(bounds);if(lastZoom==this.map.getZoom()&&this.alwaysZoom==true){this.map.zoomTo(lastZoom+(this.out?-1:1));}}else{if(!this.out){this.map.setCenter(this.map.getLonLatFromPixel(position),this.map.getZoom()+1);}else{this.map.setCenter(this.map.getLonLatFromPixel(position),this.map.getZoom()-1);}}},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:false,interval:1,documentDrag:false,kinetic:null,enableKinetic:false,kineticInterval:10,draw:function(){if(this.enableKinetic){var config={interval:this.kineticInterval};if(typeof this.enableKinetic==="object"){config=OpenLayers.Util.extend(config,this.enableKinetic);}
+this.kinetic=new OpenLayers.Kinetic(config);}
+this.handler=new OpenLayers.Handler.Drag(this,{"move":this.panMap,"done":this.panMapDone,"down":this.panMapStart},{interval:this.interval,documentDrag:this.documentDrag});},panMapStart:function(){if(this.kinetic){this.kinetic.begin();}},panMap:function(xy){if(this.kinetic){this.kinetic.update(xy);}
+this.panned=true;this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:true,animate:false});},panMapDone:function(xy){if(this.panned){var res=null;if(this.kinetic){res=this.kinetic.end(xy);}
+this.map.pan(this.handler.last.x-xy.x,this.handler.last.y-xy.y,{dragging:!!res,animate:false});if(res){var self=this;this.kinetic.move(res,function(x,y,end){self.map.pan(x,y,{dragging:!end,animate:false});});}
+this.panned=false;}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:true,'double':false,pixelTolerance:0,dblclickTolerance:13,stopSingle:false,stopDouble:false,timerId:null,touch:false,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(evt){if(!this.touch){this.unregisterMouseListeners();this.touch=true;}
+this.down=this.getEventInfo(evt);this.last=this.getEventInfo(evt);return true;},touchmove:function(evt){this.last=this.getEventInfo(evt);return true;},touchend:function(evt){if(this.down){evt.xy=this.last.xy;evt.lastTouches=this.last.touches;this.handleSingle(evt);this.down=null;}
+return true;},unregisterMouseListeners:function(){this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,click:this.click,dblclick:this.dblclick,scope:this});},mousedown:function(evt){this.down=this.getEventInfo(evt);this.last=this.getEventInfo(evt);return true;},mouseup:function(evt){var propagate=true;if(this.checkModifiers(evt)&&this.control.handleRightClicks&&OpenLayers.Event.isRightClick(evt)){propagate=this.rightclick(evt);}
+return propagate;},rightclick:function(evt){if(this.passesTolerance(evt)){if(this.rightclickTimerId!=null){this.clearTimer();this.callback('dblrightclick',[evt]);return!this.stopDouble;}else{var clickEvent=this['double']?OpenLayers.Util.extend({},evt):this.callback('rightclick',[evt]);var delayedRightCall=OpenLayers.Function.bind(this.delayedRightCall,this,clickEvent);this.rightclickTimerId=window.setTimeout(delayedRightCall,this.delay);}}
+return!this.stopSingle;},delayedRightCall:function(evt){this.rightclickTimerId=null;if(evt){this.callback('rightclick',[evt]);}},click:function(evt){if(!this.last){this.last=this.getEventInfo(evt);}
+this.handleSingle(evt);return!this.stopSingle;},dblclick:function(evt){this.handleDouble(evt);return!this.stopDouble;},handleDouble:function(evt){if(this.passesDblclickTolerance(evt)){if(this["double"]){this.callback("dblclick",[evt]);}
+this.clearTimer();}},handleSingle:function(evt){if(this.passesTolerance(evt)){if(this.timerId!=null){if(this.last.touches&&this.last.touches.length===1){if(this["double"]){OpenLayers.Event.stop(evt);}
+this.handleDouble(evt);}
+if(!this.last.touches||this.last.touches.length!==2){this.clearTimer();}}else{this.first=this.getEventInfo(evt);var clickEvent=this.single?OpenLayers.Util.extend({},evt):null;this.queuePotentialClick(clickEvent);}}},queuePotentialClick:function(evt){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,evt),this.delay);},passesTolerance:function(evt){var passes=true;if(this.pixelTolerance!=null&&this.down&&this.down.xy){passes=this.pixelTolerance>=this.down.xy.distanceTo(evt.xy);if(passes&&this.touch&&this.down.touches.length===this.last.touches.length){for(var i=0,ii=this.down.touches.length;i<ii;++i){if(this.getTouchDistance(this.down.touches[i],this.last.touches[i])>this.pixelTolerance){passes=false;break;}}}}
+return passes;},getTouchDistance:function(from,to){return Math.sqrt(Math.pow(from.clientX-to.clientX,2)+
+Math.pow(from.clientY-to.clientY,2));},passesDblclickTolerance:function(evt){var passes=true;if(this.down&&this.first){passes=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance;}
+return passes;},clearTimer:function(){if(this.timerId!=null){window.clearTimeout(this.timerId);this.timerId=null;}
+if(this.rightclickTimerId!=null){window.clearTimeout(this.rightclickTimerId);this.rightclickTimerId=null;}},delayedCall:function(evt){this.timerId=null;if(evt){this.callback("click",[evt]);}},getEventInfo:function(evt){var touches;if(evt.touches){var len=evt.touches.length;touches=new Array(len);var touch;for(var i=0;i<len;i++){touch=evt.touches[i];touches[i]={clientX:touch.clientX,clientY:touch.clientY};}}
+return{xy:evt.xy,touches:touches};},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.clearTimer();this.down=null;this.first=null;this.last=null;this.touch=false;deactivated=true;}
+return deactivated;},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,documentDrag:false,zoomBox:null,zoomBoxEnabled:true,zoomWheelEnabled:true,mouseWheelOptions:null,handleRightClicks:false,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:true,initialize:function(options){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments);},destroy:function(){this.deactivate();if(this.dragPan){this.dragPan.destroy();}
+this.dragPan=null;if(this.zoomBox){this.zoomBox.destroy();}
+this.zoomBox=null;if(this.pinchZoom){this.pinchZoom.destroy();}
+this.pinchZoom=null;OpenLayers.Control.prototype.destroy.apply(this,arguments);},activate:function(){this.dragPan.activate();if(this.zoomWheelEnabled){this.handlers.wheel.activate();}
+this.handlers.click.activate();if(this.zoomBoxEnabled){this.zoomBox.activate();}
+if(this.pinchZoom){this.pinchZoom.activate();}
+return OpenLayers.Control.prototype.activate.apply(this,arguments);},deactivate:function(){if(this.pinchZoom){this.pinchZoom.deactivate();}
+this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments);},draw:function(){if(this.handleRightClicks){this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False;}
+var clickCallbacks={'click':this.defaultClick,'dblclick':this.defaultDblClick,'dblrightclick':this.defaultDblRightClick};var clickOptions={'double':true,'stopDouble':true};this.handlers.click=new OpenLayers.Handler.Click(this,clickCallbacks,clickOptions);this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,documentDrag:this.documentDrag},this.dragPanOptions));this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:this.zoomBoxKeyMask});this.dragPan.draw();this.zoomBox.draw();this.handlers.wheel=new OpenLayers.Handler.MouseWheel(this,{"up":this.wheelUp,"down":this.wheelDown},this.mouseWheelOptions);if(OpenLayers.Control.PinchZoom){this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions));}},defaultClick:function(evt){if(evt.lastTouches&&evt.lastTouches.length==2){this.map.zoomOut();}},defaultDblClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom+1);},defaultDblRightClick:function(evt){var newCenter=this.map.getLonLatFromViewPortPx(evt.xy);this.map.setCenter(newCenter,this.map.zoom-1);},wheelChange:function(evt,deltaZ){var currentZoom=this.map.getZoom();var newZoom=this.map.getZoom()+Math.round(deltaZ);newZoom=Math.max(newZoom,0);newZoom=Math.min(newZoom,this.map.getNumZoomLevels());if(newZoom===currentZoom){return;}
+var size=this.map.getSize();var deltaX=size.w/2-evt.xy.x;var deltaY=evt.xy.y-size.h/2;var newRes=this.map.baseLayer.getResolutionForZoom(newZoom);var zoomPoint=this.map.getLonLatFromPixel(evt.xy);var newCenter=new OpenLayers.LonLat(zoomPoint.lon+deltaX*newRes,zoomPoint.lat+deltaY*newRes);this.map.setCenter(newCenter,newZoom);},wheelUp:function(evt,delta){this.wheelChange(evt,delta||1);},wheelDown:function(evt,delta){this.wheelChange(evt,delta||-1);},disableZoomBox:function(){this.zoomBoxEnabled=false;this.zoomBox.deactivate();},enableZoomBox:function(){this.zoomBoxEnabled=true;if(this.active){this.zoomBox.activate();}},disableZoomWheel:function(){this.zoomWheelEnabled=false;this.handlers.wheel.deactivate();},enableZoomWheel:function(){this.zoomWheelEnabled=true;if(this.active){this.handlers.wheel.activate();}},CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Lang["sk"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Neobslúžené požiadavky vracajú ${statusText}",'Permalink':"Trvalý odkaz",'Overlays':"Prekrytia",'Base Layer':"Základná vrstva",'noFID':"Nie je možné aktualizovať vlastnosť, pre ktorú neexistuje FID.",'browserNotSupported':"Váš prehliadač nepodporuje vykresľovanie vektorov. Momentálne podporované vykresľovače sú:\n${renderers}",'minZoomLevelError':"Vlastnosť minZoomLevel je určený iba na použitie s vrstvami odvodenými od FixedZoomLevels. To, že táto wfs vrstva kontroluje minZoomLevel je pozostatok z minulosti. Nemôžeme ho však odstrániť, aby sme sa vyhli možnému porušeniu aplikácií založených na Open Layers, ktoré na tomto môže závisieť. Preto ho označujeme ako zavrhovaný - dolu uvedená kontrola minZoomLevel bude odstránená vo verzii 3.0. Použite prosím namiesto toho kontrolu min./max. rozlíšenia podľa tu uvedeného popisu: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transakcia WFS: ÚSPEŠNÁ ${response}",'commitFailed':"Transakcia WFS: ZLYHALA ${response}",'googleWarning':"Vrstvu Google nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice Google Maps buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e",'getLayerWarning':"Vrstvu ${layerType} nebolo možné správne načítať.\x3cbr\x3e\x3cbr\x3eAby ste sa tejto správy zbavili vyberte novú BaseLayer v prepínači vrstiev v pravom hornom rohu.\x3cbr\x3e\x3cbr\x3eToto sa stalo pravdepodobne preto, že skript knižnice ${layerType} buď nebol načítaný alebo neobsahuje správny kľúč API pre vašu lokalitu.\x3cbr\x3e\x3cbr\x3eVývojári: Tu môžete získať \x3ca href=\'http://trac.openlayers.org/wiki/${layerType}\' target=\'_blank\'\x3epomoc so sfunkčnením\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Mierka = 1 : ${scaleDenom}",'reprojectDeprecated':"Používate voľby „reproject“ vrstvy ${layerType}. Táto voľba je zzavrhovaná: jej použitie bolo navrhnuté na podporu zobrazovania údajov nad komerčnými základovými mapami, ale túto funkcionalitu je teraz možné dosiahnuť pomocou Spherical Mercator. Ďalšie informácie získate na stránke http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Táto metóda je zavrhovaná a bude odstránená vo verzii 3.0. Použite prosím namiesto nej metódu ${newMethod}."});OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15000,translationParameters:null,symbolMetrics:null,initialize:function(containerID){if(!this.supported()){return;}
+OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);this.translationParameters={x:0,y:0};this.symbolMetrics={};},supported:function(){var svgFeature="http://www.w3.org/TR/SVG11/feature#";return(document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature(svgFeature+"SVG","1.1")||document.implementation.hasFeature(svgFeature+"BasicStructure","1.1")));},inValidRange:function(x,y,xyOnly){var left=x+(xyOnly?0:this.translationParameters.x);var top=y+(xyOnly?0:this.translationParameters.y);return(left>=-this.MAX_PIXEL&&left<=this.MAX_PIXEL&&top>=-this.MAX_PIXEL&&top<=this.MAX_PIXEL);},setExtent:function(extent,resolutionChanged){var coordSysUnchanged=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution(),left=-extent.left/resolution,top=extent.top/resolution;if(resolutionChanged){this.left=left;this.top=top;var extentString="0 0 "+this.size.w+" "+this.size.h;this.rendererRoot.setAttributeNS(null,"viewBox",extentString);this.translate(this.xOffset,0);return true;}else{var inRange=this.translate(left-this.left+this.xOffset,top-this.top);if(!inRange){this.setExtent(extent,true);}
+return coordSysUnchanged&&inRange;}},translate:function(x,y){if(!this.inValidRange(x,y,true)){return false;}else{var transformString="";if(x||y){transformString="translate("+x+","+y+")";}
+this.root.setAttributeNS(null,"transform",transformString);this.translationParameters={x:x,y:y};return true;}},setSize:function(size){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null,"width",this.size.w);this.rendererRoot.setAttributeNS(null,"height",this.size.h);},getNodeType:function(geometry,style){var nodeType=null;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.externalGraphic){nodeType="image";}else if(this.isComplexSymbol(style.graphicName)){nodeType="svg";}else{nodeType="circle";}
+break;case"OpenLayers.Geometry.Rectangle":nodeType="rect";break;case"OpenLayers.Geometry.LineString":nodeType="polyline";break;case"OpenLayers.Geometry.LinearRing":nodeType="polygon";break;case"OpenLayers.Geometry.Polygon":case"OpenLayers.Geometry.Curve":nodeType="path";break;default:break;}
+return nodeType;},setStyle:function(node,style,options){style=style||node._style;options=options||node._options;var r=parseFloat(node.getAttributeNS(null,"r"));var widthFactor=1;var pos;if(node._geometryClass=="OpenLayers.Geometry.Point"&&r){node.style.visibility="";if(style.graphic===false){node.style.visibility="hidden";}else if(style.externalGraphic){pos=this.getPosition(node);if(style.graphicTitle){node.setAttributeNS(null,"title",style.graphicTitle);var titleNode=node.getElementsByTagName("title");if(titleNode.length>0){titleNode[0].firstChild.textContent=style.graphicTitle;}else{var label=this.nodeFactory(null,"title");label.textContent=style.graphicTitle;node.appendChild(label);}}
+if(style.graphicWidth&&style.graphicHeight){node.setAttributeNS(null,"preserveAspectRatio","none");}
+var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);var opacity=style.graphicOpacity||style.fillOpacity;node.setAttributeNS(null,"x",(pos.x+xOffset).toFixed());node.setAttributeNS(null,"y",(pos.y+yOffset).toFixed());node.setAttributeNS(null,"width",width);node.setAttributeNS(null,"height",height);node.setAttributeNS(this.xlinkns,"href",style.externalGraphic);node.setAttributeNS(null,"style","opacity: "+opacity);node.onclick=OpenLayers.Renderer.SVG.preventDefault;}else if(this.isComplexSymbol(style.graphicName)){var offset=style.pointRadius*3;var size=offset*2;var src=this.importSymbol(style.graphicName);pos=this.getPosition(node);widthFactor=this.symbolMetrics[src.id][0]*3/size;var parent=node.parentNode;var nextSibling=node.nextSibling;if(parent){parent.removeChild(node);}
+node.firstChild&&node.removeChild(node.firstChild);node.appendChild(src.firstChild.cloneNode(true));node.setAttributeNS(null,"viewBox",src.getAttributeNS(null,"viewBox"));node.setAttributeNS(null,"width",size);node.setAttributeNS(null,"height",size);node.setAttributeNS(null,"x",pos.x-offset);node.setAttributeNS(null,"y",pos.y-offset);if(nextSibling){parent.insertBefore(node,nextSibling);}else if(parent){parent.appendChild(node);}}else{node.setAttributeNS(null,"r",style.pointRadius);}
+var rotation=style.rotation;if((rotation!==undefined||node._rotation!==undefined)&&pos){node._rotation=rotation;rotation|=0;if(node.nodeName!=="svg"){node.setAttributeNS(null,"transform","rotate("+rotation+" "+pos.x+" "+
+pos.y+")");}else{var metrics=this.symbolMetrics[src.id];node.firstChild.setAttributeNS(null,"transform","rotate("
++rotation+" "
++metrics[1]+" "
++metrics[2]+")");}}}
+if(options.isFilled){node.setAttributeNS(null,"fill",style.fillColor);node.setAttributeNS(null,"fill-opacity",style.fillOpacity);}else{node.setAttributeNS(null,"fill","none");}
+if(options.isStroked){node.setAttributeNS(null,"stroke",style.strokeColor);node.setAttributeNS(null,"stroke-opacity",style.strokeOpacity);node.setAttributeNS(null,"stroke-width",style.strokeWidth*widthFactor);node.setAttributeNS(null,"stroke-linecap",style.strokeLinecap||"round");node.setAttributeNS(null,"stroke-linejoin","round");style.strokeDashstyle&&node.setAttributeNS(null,"stroke-dasharray",this.dashStyle(style,widthFactor));}else{node.setAttributeNS(null,"stroke","none");}
+if(style.pointerEvents){node.setAttributeNS(null,"pointer-events",style.pointerEvents);}
+if(style.cursor!=null){node.setAttributeNS(null,"cursor",style.cursor);}
+return node;},dashStyle:function(style,widthFactor){var w=style.strokeWidth*widthFactor;var str=style.strokeDashstyle;switch(str){case'solid':return'none';case'dot':return[1,4*w].join();case'dash':return[4*w,4*w].join();case'dashdot':return[4*w,4*w,1,4*w].join();case'longdash':return[8*w,4*w].join();case'longdashdot':return[8*w,4*w,1,4*w].join();default:return OpenLayers.String.trim(str).replace(/\s+/g,",");}},createNode:function(type,id){var node=document.createElementNS(this.xmlns,type);if(id){node.setAttributeNS(null,"id",id);}
+return node;},nodeTypeCompare:function(node,type){return(type==node.nodeName);},createRenderRoot:function(){var svg=this.nodeFactory(this.container.id+"_svgRoot","svg");svg.style.display="block";return svg;},createRoot:function(suffix){return this.nodeFactory(this.container.id+suffix,"g");},createDefs:function(){var defs=this.nodeFactory(this.container.id+"_defs","defs");this.rendererRoot.appendChild(defs);return defs;},drawPoint:function(node,geometry){return this.drawCircle(node,geometry,1);},drawCircle:function(node,geometry,radius){var resolution=this.getResolution();var x=((geometry.x-this.featureDx)/resolution+this.left);var y=(this.top-geometry.y/resolution);if(this.inValidRange(x,y)){node.setAttributeNS(null,"cx",x);node.setAttributeNS(null,"cy",y);node.setAttributeNS(null,"r",radius);return node;}else{return false;}},drawLineString:function(node,geometry){var componentsResult=this.getComponentsString(geometry.components);if(componentsResult.path){node.setAttributeNS(null,"points",componentsResult.path);return(componentsResult.complete?node:null);}else{return false;}},drawLinearRing:function(node,geometry){var componentsResult=this.getComponentsString(geometry.components);if(componentsResult.path){node.setAttributeNS(null,"points",componentsResult.path);return(componentsResult.complete?node:null);}else{return false;}},drawPolygon:function(node,geometry){var d="";var draw=true;var complete=true;var linearRingResult,path;for(var j=0,len=geometry.components.length;j<len;j++){d+=" M";linearRingResult=this.getComponentsString(geometry.components[j].components," ");path=linearRingResult.path;if(path){d+=" "+path;complete=linearRingResult.complete&&complete;}else{draw=false;}}
+d+=" z";if(draw){node.setAttributeNS(null,"d",d);node.setAttributeNS(null,"fill-rule","evenodd");return complete?node:null;}else{return false;}},drawRectangle:function(node,geometry){var resolution=this.getResolution();var x=((geometry.x-this.featureDx)/resolution+this.left);var y=(this.top-geometry.y/resolution);if(this.inValidRange(x,y)){node.setAttributeNS(null,"x",x);node.setAttributeNS(null,"y",y);node.setAttributeNS(null,"width",geometry.width/resolution);node.setAttributeNS(null,"height",geometry.height/resolution);return node;}else{return false;}},drawText:function(featureId,style,location){var drawOutline=(!!style.labelOutlineWidth);if(drawOutline){var outlineStyle=OpenLayers.Util.extend({},style);outlineStyle.fontColor=outlineStyle.labelOutlineColor;outlineStyle.fontStrokeColor=outlineStyle.labelOutlineColor;outlineStyle.fontStrokeWidth=style.labelOutlineWidth;delete outlineStyle.labelOutlineWidth;this.drawText(featureId,outlineStyle,location);}
+var resolution=this.getResolution();var x=((location.x-this.featureDx)/resolution+this.left);var y=(location.y/resolution-this.top);var suffix=(drawOutline)?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX;var label=this.nodeFactory(featureId+suffix,"text");label.setAttributeNS(null,"x",x);label.setAttributeNS(null,"y",-y);if(style.fontColor){label.setAttributeNS(null,"fill",style.fontColor);}
+if(style.fontStrokeColor){label.setAttributeNS(null,"stroke",style.fontStrokeColor);}
+if(style.fontStrokeWidth){label.setAttributeNS(null,"stroke-width",style.fontStrokeWidth);}
+if(style.fontOpacity){label.setAttributeNS(null,"opacity",style.fontOpacity);}
+if(style.fontFamily){label.setAttributeNS(null,"font-family",style.fontFamily);}
+if(style.fontSize){label.setAttributeNS(null,"font-size",style.fontSize);}
+if(style.fontWeight){label.setAttributeNS(null,"font-weight",style.fontWeight);}
+if(style.fontStyle){label.setAttributeNS(null,"font-style",style.fontStyle);}
+if(style.labelSelect===true){label.setAttributeNS(null,"pointer-events","visible");label._featureId=featureId;}else{label.setAttributeNS(null,"pointer-events","none");}
+var align=style.labelAlign||OpenLayers.Renderer.defaultSymbolizer.labelAlign;label.setAttributeNS(null,"text-anchor",OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]]||"middle");if(OpenLayers.IS_GECKO===true){label.setAttributeNS(null,"dominant-baseline",OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]]||"central");}
+var labelRows=style.label.split('\n');var numRows=labelRows.length;while(label.childNodes.length>numRows){label.removeChild(label.lastChild);}
+for(var i=0;i<numRows;i++){var tspan=this.nodeFactory(featureId+suffix+"_tspan_"+i,"tspan");if(style.labelSelect===true){tspan._featureId=featureId;tspan._geometry=location;tspan._geometryClass=location.CLASS_NAME;}
+if(OpenLayers.IS_GECKO===false){tspan.setAttributeNS(null,"baseline-shift",OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]]||"-35%");}
+tspan.setAttribute("x",x);if(i==0){var vfactor=OpenLayers.Renderer.SVG.LABEL_VFACTOR[align[1]];if(vfactor==null){vfactor=-.5;}
+tspan.setAttribute("dy",(vfactor*(numRows-1))+"em");}else{tspan.setAttribute("dy","1em");}
+tspan.textContent=(labelRows[i]==='')?' ':labelRows[i];if(!tspan.parentNode){label.appendChild(tspan);}}
+if(!label.parentNode){this.textRoot.appendChild(label);}},getComponentsString:function(components,separator){var renderCmp=[];var complete=true;var len=components.length;var strings=[];var str,component;for(var i=0;i<len;i++){component=components[i];renderCmp.push(component);str=this.getShortString(component);if(str){strings.push(str);}else{if(i>0){if(this.getShortString(components[i-1])){strings.push(this.clipLine(components[i],components[i-1]));}}
+if(i<len-1){if(this.getShortString(components[i+1])){strings.push(this.clipLine(components[i],components[i+1]));}}
+complete=false;}}
+return{path:strings.join(separator||","),complete:complete};},clipLine:function(badComponent,goodComponent){if(goodComponent.equals(badComponent)){return"";}
+var resolution=this.getResolution();var maxX=this.MAX_PIXEL-this.translationParameters.x;var maxY=this.MAX_PIXEL-this.translationParameters.y;var x1=(goodComponent.x-this.featureDx)/resolution+this.left;var y1=this.top-goodComponent.y/resolution;var x2=(badComponent.x-this.featureDx)/resolution+this.left;var y2=this.top-badComponent.y/resolution;var k;if(x2<-maxX||x2>maxX){k=(y2-y1)/(x2-x1);x2=x2<0?-maxX:maxX;y2=y1+(x2-x1)*k;}
+if(y2<-maxY||y2>maxY){k=(x2-x1)/(y2-y1);y2=y2<0?-maxY:maxY;x2=x1+(y2-y1)*k;}
+return x2+","+y2;},getShortString:function(point){var resolution=this.getResolution();var x=((point.x-this.featureDx)/resolution+this.left);var y=(this.top-point.y/resolution);if(this.inValidRange(x,y)){return x+","+y;}else{return false;}},getPosition:function(node){return({x:parseFloat(node.getAttributeNS(null,"cx")),y:parseFloat(node.getAttributeNS(null,"cy"))});},importSymbol:function(graphicName){if(!this.defs){this.defs=this.createDefs();}
+var id=this.container.id+"-"+graphicName;var existing=document.getElementById(id);if(existing!=null){return existing;}
+var symbol=OpenLayers.Renderer.symbol[graphicName];if(!symbol){throw new Error(graphicName+' is not a valid symbol name');}
+var symbolNode=this.nodeFactory(id,"symbol");var node=this.nodeFactory(null,"polygon");symbolNode.appendChild(node);var symbolExtent=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);var points=[];var x,y;for(var i=0;i<symbol.length;i=i+2){x=symbol[i];y=symbol[i+1];symbolExtent.left=Math.min(symbolExtent.left,x);symbolExtent.bottom=Math.min(symbolExtent.bottom,y);symbolExtent.right=Math.max(symbolExtent.right,x);symbolExtent.top=Math.max(symbolExtent.top,y);points.push(x,",",y);}
+node.setAttributeNS(null,"points",points.join(" "));var width=symbolExtent.getWidth();var height=symbolExtent.getHeight();var viewBox=[symbolExtent.left-width,symbolExtent.bottom-height,width*3,height*3];symbolNode.setAttributeNS(null,"viewBox",viewBox.join(" "));this.symbolMetrics[id]=[Math.max(width,height),symbolExtent.getCenterLonLat().lon,symbolExtent.getCenterLonLat().lat];this.defs.appendChild(symbolNode);return symbolNode;},getFeatureIdFromEvent:function(evt){var featureId=OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this,arguments);if(!featureId){var target=evt.target;featureId=target.parentNode&&target!=this.rendererRoot?target.parentNode._featureId:undefined;}
+return featureId;},CLASS_NAME:"OpenLayers.Renderer.SVG"});OpenLayers.Renderer.SVG.LABEL_ALIGN={"l":"start","r":"end","b":"bottom","t":"hanging"};OpenLayers.Renderer.SVG.LABEL_VSHIFT={"t":"-70%","b":"0"};OpenLayers.Renderer.SVG.LABEL_VFACTOR={"t":0,"b":-1};OpenLayers.Renderer.SVG.preventDefault=function(e){e.preventDefault&&e.preventDefault();};OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,geodesic:false,draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.eTop){this.eTop=document.createElement("div");this.eTop.className=this.displayClass+"Top";var theLen=this.topInUnits.length;this.div.appendChild(this.eTop);if((this.topOutUnits=="")||(this.topInUnits=="")){this.eTop.style.visibility="hidden";}else{this.eTop.style.visibility="visible";}
+this.eBottom=document.createElement("div");this.eBottom.className=this.displayClass+"Bottom";this.div.appendChild(this.eBottom);if((this.bottomOutUnits=="")||(this.bottomInUnits=="")){this.eBottom.style.visibility="hidden";}else{this.eBottom.style.visibility="visible";}}
+this.map.events.register('moveend',this,this.update);this.update();return this.div;},getBarLen:function(maxLen){var digits=parseInt(Math.log(maxLen)/Math.log(10));var pow10=Math.pow(10,digits);var firstChar=parseInt(maxLen/pow10);var barLen;if(firstChar>5){barLen=5;}else if(firstChar>2){barLen=2;}else{barLen=1;}
+return barLen*pow10;},update:function(){var res=this.map.getResolution();if(!res){return;}
+var curMapUnits=this.map.getUnits();var inches=OpenLayers.INCHES_PER_UNIT;var maxSizeData=this.maxWidth*res*inches[curMapUnits];var geodesicRatio=1;if(this.geodesic===true){var maxSizeGeodesic=(this.map.getGeodesicPixelSize().w||0.000001)*this.maxWidth;var maxSizeKilometers=maxSizeData/inches["km"];geodesicRatio=maxSizeGeodesic/maxSizeKilometers;maxSizeData*=geodesicRatio;}
+var topUnits;var bottomUnits;if(maxSizeData>100000){topUnits=this.topOutUnits;bottomUnits=this.bottomOutUnits;}else{topUnits=this.topInUnits;bottomUnits=this.bottomInUnits;}
+var topMax=maxSizeData/inches[topUnits];var bottomMax=maxSizeData/inches[bottomUnits];var topRounded=this.getBarLen(topMax);var bottomRounded=this.getBarLen(bottomMax);topMax=topRounded/inches[curMapUnits]*inches[topUnits];bottomMax=bottomRounded/inches[curMapUnits]*inches[bottomUnits];var topPx=topMax/res/geodesicRatio;var bottomPx=bottomMax/res/geodesicRatio;if(this.eBottom.style.visibility=="visible"){this.eBottom.style.width=Math.round(bottomPx)+"px";this.eBottom.innerHTML=bottomRounded+" "+bottomUnits;}
+if(this.eTop.style.visibility=="visible"){this.eTop.style.width=Math.round(topPx)+"px";this.eTop.innerHTML=topRounded+" "+topUnits;}},CLASS_NAME:"OpenLayers.Control.ScaleLine"});OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(url,size,offset,calculateOffset){this.url=url;this.size=size||{w:20,h:20};this.offset=offset||{x:-(this.size.w/2),y:-(this.size.h/2)};this.calculateOffset=calculateOffset;var id=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(id);},destroy:function(){this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null;},clone:function(){return new OpenLayers.Icon(this.url,this.size,this.offset,this.calculateOffset);},setSize:function(size){if(size!=null){this.size=size;}
+this.draw();},setUrl:function(url){if(url!=null){this.url=url;}
+this.draw();},draw:function(px){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(px);return this.imageDiv;},erase:function(){if(this.imageDiv!=null&&this.imageDiv.parentNode!=null){OpenLayers.Element.remove(this.imageDiv);}},setOpacity:function(opacity){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,null,null,null,opacity);},moveTo:function(px){if(px!=null){this.px=px;}
+if(this.imageDiv!=null){if(this.px==null){this.display(false);}else{if(this.calculateOffset){this.offset=this.calculateOffset(this.size);}
+OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x:this.px.x+this.offset.x,y:this.px.y+this.offset.y});}}},display:function(display){this.imageDiv.style.display=(display)?"":"none";},isDrawn:function(){var isDrawn=(this.imageDiv&&this.imageDiv.parentNode&&(this.imageDiv.parentNode.nodeType!=11));return isDrawn;},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(lonlat,icon){this.lonlat=lonlat;var newIcon=(icon)?icon:OpenLayers.Marker.defaultIcon();if(this.icon==null){this.icon=newIcon;}else{this.icon.url=newIcon.url;this.icon.size=newIcon.size;this.icon.offset=newIcon.offset;this.icon.calculateOffset=newIcon.calculateOffset;}
+this.events=new OpenLayers.Events(this,this.icon.imageDiv);},destroy:function(){this.erase();this.map=null;this.events.destroy();this.events=null;if(this.icon!=null){this.icon.destroy();this.icon=null;}},draw:function(px){return this.icon.draw(px);},erase:function(){if(this.icon!=null){this.icon.erase();}},moveTo:function(px){if((px!=null)&&(this.icon!=null)){this.icon.moveTo(px);}
+this.lonlat=this.map.getLonLatFromLayerPx(px);},isDrawn:function(){var isDrawn=(this.icon&&this.icon.isDrawn());return isDrawn;},onScreen:function(){var onScreen=false;if(this.map){var screenBounds=this.map.getExtent();onScreen=screenBounds.containsLonLat(this.lonlat);}
+return onScreen;},inflate:function(inflate){if(this.icon){this.icon.setSize({w:this.icon.size.w*inflate,h:this.icon.size.h*inflate});}},setOpacity:function(opacity){this.icon.setOpacity(opacity);},setUrl:function(url){this.icon.setUrl(url);},display:function(display){this.icon.display(display);},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),{w:21,h:25},{x:-10.5,y:-25});};OpenLayers.Format.JSON=OpenLayers.Class(OpenLayers.Format,{indent:"    ",space:" ",newline:"\n",level:0,pretty:false,nativeJSON:(function(){return!!(window.JSON&&typeof JSON.parse=="function"&&typeof JSON.stringify=="function");})(),read:function(json,filter){var object;if(this.nativeJSON){object=JSON.parse(json,filter);}else try{if(/^[\],:{}\s]*$/.test(json.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){object=eval('('+json+')');if(typeof filter==='function'){function walk(k,v){if(v&&typeof v==='object'){for(var i in v){if(v.hasOwnProperty(i)){v[i]=walk(i,v[i]);}}}
+return filter(k,v);}
+object=walk('',object);}}}catch(e){}
+if(this.keepData){this.data=object;}
+return object;},write:function(value,pretty){this.pretty=!!pretty;var json=null;var type=typeof value;if(this.serialize[type]){try{json=(!this.pretty&&this.nativeJSON)?JSON.stringify(value):this.serialize[type].apply(this,[value]);}catch(err){OpenLayers.Console.error("Trouble serializing: "+err);}}
+return json;},writeIndent:function(){var pieces=[];if(this.pretty){for(var i=0;i<this.level;++i){pieces.push(this.indent);}}
+return pieces.join('');},writeNewline:function(){return(this.pretty)?this.newline:'';},writeSpace:function(){return(this.pretty)?this.space:'';},serialize:{'object':function(object){if(object==null){return"null";}
+if(object.constructor==Date){return this.serialize.date.apply(this,[object]);}
+if(object.constructor==Array){return this.serialize.array.apply(this,[object]);}
+var pieces=['{'];this.level+=1;var key,keyJSON,valueJSON;var addComma=false;for(key in object){if(object.hasOwnProperty(key)){keyJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[key,this.pretty]);valueJSON=OpenLayers.Format.JSON.prototype.write.apply(this,[object[key],this.pretty]);if(keyJSON!=null&&valueJSON!=null){if(addComma){pieces.push(',');}
+pieces.push(this.writeNewline(),this.writeIndent(),keyJSON,':',this.writeSpace(),valueJSON);addComma=true;}}}
+this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),'}');return pieces.join('');},'array':function(array){var json;var pieces=['['];this.level+=1;for(var i=0,len=array.length;i<len;++i){json=OpenLayers.Format.JSON.prototype.write.apply(this,[array[i],this.pretty]);if(json!=null){if(i>0){pieces.push(',');}
+pieces.push(this.writeNewline(),this.writeIndent(),json);}}
+this.level-=1;pieces.push(this.writeNewline(),this.writeIndent(),']');return pieces.join('');},'string':function(string){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};if(/["\\\x00-\x1f]/.test(string)){return'"'+string.replace(/([\x00-\x1f\\"])/g,function(a,b){var c=m[b];if(c){return c;}
+c=b.charCodeAt();return'\\u00'+
+Math.floor(c/16).toString(16)+
+(c%16).toString(16);})+'"';}
+return'"'+string+'"';},'number':function(number){return isFinite(number)?String(number):"null";},'boolean':function(bool){return String(bool);},'date':function(date){function format(number){return(number<10)?'0'+number:number;}
+return'"'+date.getFullYear()+'-'+
+format(date.getMonth()+1)+'-'+
+format(date.getDate())+'T'+
+format(date.getHours())+':'+
+format(date.getMinutes())+':'+
+format(date.getSeconds())+'"';}},CLASS_NAME:"OpenLayers.Format.JSON"});OpenLayers.Format.GeoJSON=OpenLayers.Class(OpenLayers.Format.JSON,{ignoreExtraDims:false,read:function(json,type,filter){type=(type)?type:"FeatureCollection";var results=null;var obj=null;if(typeof json=="string"){obj=OpenLayers.Format.JSON.prototype.read.apply(this,[json,filter]);}else{obj=json;}
+if(!obj){OpenLayers.Console.error("Bad JSON: "+json);}else if(typeof(obj.type)!="string"){OpenLayers.Console.error("Bad GeoJSON - no type: "+json);}else if(this.isValidType(obj,type)){switch(type){case"Geometry":try{results=this.parseGeometry(obj);}catch(err){OpenLayers.Console.error(err);}
+break;case"Feature":try{results=this.parseFeature(obj);results.type="Feature";}catch(err){OpenLayers.Console.error(err);}
+break;case"FeatureCollection":results=[];switch(obj.type){case"Feature":try{results.push(this.parseFeature(obj));}catch(err){results=null;OpenLayers.Console.error(err);}
+break;case"FeatureCollection":for(var i=0,len=obj.features.length;i<len;++i){try{results.push(this.parseFeature(obj.features[i]));}catch(err){results=null;OpenLayers.Console.error(err);}}
+break;default:try{var geom=this.parseGeometry(obj);results.push(new OpenLayers.Feature.Vector(geom));}catch(err){results=null;OpenLayers.Console.error(err);}}
+break;}}
+return results;},isValidType:function(obj,type){var valid=false;switch(type){case"Geometry":if(OpenLayers.Util.indexOf(["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon","Box","GeometryCollection"],obj.type)==-1){OpenLayers.Console.error("Unsupported geometry type: "+
+obj.type);}else{valid=true;}
+break;case"FeatureCollection":valid=true;break;default:if(obj.type==type){valid=true;}else{OpenLayers.Console.error("Cannot convert types from "+
+obj.type+" to "+type);}}
+return valid;},parseFeature:function(obj){var feature,geometry,attributes,bbox;attributes=(obj.properties)?obj.properties:{};bbox=(obj.geometry&&obj.geometry.bbox)||obj.bbox;try{geometry=this.parseGeometry(obj.geometry);}catch(err){throw err;}
+feature=new OpenLayers.Feature.Vector(geometry,attributes);if(bbox){feature.bounds=OpenLayers.Bounds.fromArray(bbox);}
+if(obj.id){feature.fid=obj.id;}
+return feature;},parseGeometry:function(obj){if(obj==null){return null;}
+var geometry,collection=false;if(obj.type=="GeometryCollection"){if(!(OpenLayers.Util.isArray(obj.geometries))){throw"GeometryCollection must have geometries array: "+obj;}
+var numGeom=obj.geometries.length;var components=new Array(numGeom);for(var i=0;i<numGeom;++i){components[i]=this.parseGeometry.apply(this,[obj.geometries[i]]);}
+geometry=new OpenLayers.Geometry.Collection(components);collection=true;}else{if(!(OpenLayers.Util.isArray(obj.coordinates))){throw"Geometry must have coordinates array: "+obj;}
+if(!this.parseCoords[obj.type.toLowerCase()]){throw"Unsupported geometry type: "+obj.type;}
+try{geometry=this.parseCoords[obj.type.toLowerCase()].apply(this,[obj.coordinates]);}catch(err){throw err;}}
+if(this.internalProjection&&this.externalProjection&&!collection){geometry.transform(this.externalProjection,this.internalProjection);}
+return geometry;},parseCoords:{"point":function(array){if(this.ignoreExtraDims==false&&array.length!=2){throw"Only 2D points are supported: "+array;}
+return new OpenLayers.Geometry.Point(array[0],array[1]);},"multipoint":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
+points.push(p);}
+return new OpenLayers.Geometry.MultiPoint(points);},"linestring":function(array){var points=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["point"].apply(this,[array[i]]);}catch(err){throw err;}
+points.push(p);}
+return new OpenLayers.Geometry.LineString(points);},"multilinestring":function(array){var lines=[];var l=null;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
+lines.push(l);}
+return new OpenLayers.Geometry.MultiLineString(lines);},"polygon":function(array){var rings=[];var r,l;for(var i=0,len=array.length;i<len;++i){try{l=this.parseCoords["linestring"].apply(this,[array[i]]);}catch(err){throw err;}
+r=new OpenLayers.Geometry.LinearRing(l.components);rings.push(r);}
+return new OpenLayers.Geometry.Polygon(rings);},"multipolygon":function(array){var polys=[];var p=null;for(var i=0,len=array.length;i<len;++i){try{p=this.parseCoords["polygon"].apply(this,[array[i]]);}catch(err){throw err;}
+polys.push(p);}
+return new OpenLayers.Geometry.MultiPolygon(polys);},"box":function(array){if(array.length!=2){throw"GeoJSON box coordinates must have 2 elements";}
+return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(array[0][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[0][1]),new OpenLayers.Geometry.Point(array[1][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[1][1]),new OpenLayers.Geometry.Point(array[0][0],array[0][1])])]);}},write:function(obj,pretty){var geojson={"type":null};if(OpenLayers.Util.isArray(obj)){geojson.type="FeatureCollection";var numFeatures=obj.length;geojson.features=new Array(numFeatures);for(var i=0;i<numFeatures;++i){var element=obj[i];if(!element instanceof OpenLayers.Feature.Vector){var msg="FeatureCollection only supports collections "+"of features: "+element;throw msg;}
+geojson.features[i]=this.extract.feature.apply(this,[element]);}}else if(obj.CLASS_NAME.indexOf("OpenLayers.Geometry")==0){geojson=this.extract.geometry.apply(this,[obj]);}else if(obj instanceof OpenLayers.Feature.Vector){geojson=this.extract.feature.apply(this,[obj]);if(obj.layer&&obj.layer.projection){geojson.crs=this.createCRSObject(obj);}}
+return OpenLayers.Format.JSON.prototype.write.apply(this,[geojson,pretty]);},createCRSObject:function(object){var proj=object.layer.projection.toString();var crs={};if(proj.match(/epsg:/i)){var code=parseInt(proj.substring(proj.indexOf(":")+1));if(code==4326){crs={"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}};}else{crs={"type":"name","properties":{"name":"EPSG:"+code}};}}
+return crs;},extract:{'feature':function(feature){var geom=this.extract.geometry.apply(this,[feature.geometry]);var json={"type":"Feature","properties":feature.attributes,"geometry":geom};if(feature.fid!=null){json.id=feature.fid;}
+return json;},'geometry':function(geometry){if(geometry==null){return null;}
+if(this.internalProjection&&this.externalProjection){geometry=geometry.clone();geometry.transform(this.internalProjection,this.externalProjection);}
+var geometryType=geometry.CLASS_NAME.split('.')[2];var data=this.extract[geometryType.toLowerCase()].apply(this,[geometry]);var json;if(geometryType=="Collection"){json={"type":"GeometryCollection","geometries":data};}else{json={"type":geometryType,"coordinates":data};}
+return json;},'point':function(point){return[point.x,point.y];},'multipoint':function(multipoint){var array=[];for(var i=0,len=multipoint.components.length;i<len;++i){array.push(this.extract.point.apply(this,[multipoint.components[i]]));}
+return array;},'linestring':function(linestring){var array=[];for(var i=0,len=linestring.components.length;i<len;++i){array.push(this.extract.point.apply(this,[linestring.components[i]]));}
+return array;},'multilinestring':function(multilinestring){var array=[];for(var i=0,len=multilinestring.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[multilinestring.components[i]]));}
+return array;},'polygon':function(polygon){var array=[];for(var i=0,len=polygon.components.length;i<len;++i){array.push(this.extract.linestring.apply(this,[polygon.components[i]]));}
+return array;},'multipolygon':function(multipolygon){var array=[];for(var i=0,len=multipolygon.components.length;i<len;++i){array.push(this.extract.polygon.apply(this,[multipolygon.components[i]]));}
+return array;},'collection':function(collection){var len=collection.components.length;var array=new Array(len);for(var i=0;i<len;++i){array[i]=this.extract.geometry.apply(this,[collection.components[i]]);}
+return array;}},CLASS_NAME:"OpenLayers.Format.GeoJSON"});OpenLayers.Lang["nn"]=OpenLayers.Util.applyDefaults({'Scale = 1 : ${scaleDenom}':"Skala = 1 : ${scaleDenom}"});OpenLayers.Lang["fi"]=OpenLayers.Util.applyDefaults({'Permalink':"Ikilinkki",'Overlays':"Kerrokset",'Base Layer':"Peruskerros",'W':"L",'E':"I",'N':"P",'S':"E"});OpenLayers.Lang["pl"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nieobsługiwane żądanie zwróciło ${statusText}",'Permalink':"Permalink",'Overlays':"Nakładki",'Base Layer':"Warstwa podstawowa",'noFID':"Nie można zaktualizować funkcji, dla których nie ma FID.",'browserNotSupported':"Twoja przeglądarka nie obsługuje renderowania wektorów. Obecnie obsługiwane renderowanie to:\n${renderers}",'minZoomLevelError':"Właściwość minZoomLevel jest przeznaczona tylko do użytku "+"z warstwami FixedZoomLevels-descendent."+"Warstwa wfs, która sprawdza minZoomLevel jest reliktem przeszłości."+"Nie możemy jej jednak usunąc bez mozliwości łamania OL aplikacji, "+"które mogą być od niej zależne. "+"Dlatego jesteśmy za deprecjację -- minZoomLevel "+"zostanie usunięta w wersji 3.0. W zamian prosze użyj "+"min/max rozdzielczości w sposób opisany tutaj: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transakcja WFS: SUKCES ${response}",'commitFailed':"Transakcja WFS: FAILED ${response}",'googleWarning':"Warstwa Google nie był w stanie załadować się poprawnie.<br><br>"+"Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową "+"w przełączniku warstw w górnym prawym rogu mapy.<br><br>"+"Najprawdopodobniej jest to spowodowane tym, że biblioteka Google Maps "+"nie jest załadowana, lub nie zawiera poprawnego klucza do API dla twojej strony<br><br>"+"Programisto: Aby uzyskać pomoc , "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>kliknij tutaj</a>",'getLayerWarning':"Warstwa ${layerType} nie mogła zostać załadowana poprawnie.<br><br>"+"Aby pozbyć się tej wiadomości, wybierz nową Warstwe podstawową "+"w przełączniku warstw w górnym prawym rogu mapy.<br><br>"+"Najprawdopodobniej jest to spowodowane tym, że biblioteka ${layerLib} "+"nie jest załadowana, lub może(o ile biblioteka tego wymaga) "+"byc potrzebny klucza do API dla twojej strony<br><br>"+"Programisto: Aby uzyskać pomoc , "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>kliknij tutaj</a>",'Scale = 1 : ${scaleDenom}':"Skala = 1 : ${scaleDenom}",'W':'ZACH','E':'WSCH','N':'PN','S':'PD','Graticule':'Siatka','reprojectDeprecated':"w warstwie ${layerName} używasz opcji 'reproject'. "+"Ta opcja jest przestarzała: "+"jej zastosowanie został zaprojektowany, aby wspierać wyświetlania danych przez komercyjne mapy, "+"jednak obecnie ta funkcjonalność powinien zostać osiągnięty za pomocą Spherical Mercator "+"its use was designed to support displaying data over commercial. Więcje informacji na ten temat możesz znaleźć na stronie "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Ta metoda jest przestarzała i będzie usunięta od wersji 3.0. "+"W zamian użyj ${newMethod}.",'proxyNeeded':"Prawdopodobnie musisz ustawić OpenLayers.ProxyHost aby otrzymać dostęp do ${url}."+"See http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost"});OpenLayers.Lang.es={'unhandledRequest':"Respuesta a petición no gestionada ${statusText}",'Permalink':"Enlace permanente",'Overlays':"Capas superpuestas",'Base Layer':"Capa Base",'noFID':"No se puede actualizar un elemento para el que no existe FID.",'browserNotSupported':"Su navegador no soporta renderización vectorial. Los renderizadores soportados actualmente son:\n${renderers}",'minZoomLevelError':"La propiedad minZoomLevel debe sólo utilizarse "+"con las capas que tienen FixedZoomLevels. El hecho de que "+"una capa wfs compruebe minZoomLevel es una reliquia del "+"pasado. Sin embargo, no podemos eliminarla sin discontinuar "+"probablemente las aplicaciones OL que puedan depender de ello. "+"Así pues estamos haciéndolo obsoleto --la comprobación "+"minZoomLevel se eliminará en la versión 3.0. Utilice el ajuste "+"de resolution min/max en su lugar, tal como se describe aquí: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacción WFS: ÉXITO ${response}",'commitFailed':"Transacción WFS: FALLÓ ${response}",'googleWarning':"La capa Google no pudo ser cargada correctamente.<br><br>"+"Para evitar este mensaje, seleccione una nueva Capa Base "+"en el selector de capas en la esquina superior derecha.<br><br>"+"Probablemente, esto se debe a que el script de la biblioteca de "+"Google Maps no fue correctamente incluido en su página, o no "+"contiene la clave del API correcta para su sitio.<br><br>"+"Desarrolladores: Para ayudar a hacer funcionar esto correctamente, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>haga clic aquí</a>",'getLayerWarning':"La capa ${layerType} no pudo ser cargada correctamente.<br><br>"+"Para evitar este mensaje, seleccione una nueva Capa Base "+"en el selector de capas en la esquina superior derecha.<br><br>"+"Probablemente, esto se debe a que el script de "+"la biblioteca ${layerLib} "+"no fue correctamente incluido en su página.<br><br>"+"Desarrolladores: Para ayudar a hacer funcionar esto correctamente, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>haga clic aquí</a>",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':'O','E':'E','N':'N','S':'S','Graticule':'Retícula','reprojectDeprecated':"Está usando la opción 'reproject' en la capa "+"${layerName}. Esta opción es obsoleta: su uso fue diseñado "+"para soportar la visualización de datos sobre mapas base comerciales, "+"pero ahora esa funcionalidad debería conseguirse mediante el soporte "+"de la proyección Spherical Mercator. Más información disponible en "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Este método es obsoleto y se eliminará en la versión 3.0. "+"Por favor utilice el método ${newMethod} en su lugar.",'end':''};OpenLayers.Layer.SphericalMercator={getExtent:function(){var extent=null;if(this.sphericalMercator){extent=this.map.calculateBounds();}else{extent=OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);}
+return extent;},getLonLatFromViewPortPx:function(viewPortPx){return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this,arguments);},getViewPortPxFromLonLat:function(lonlat){return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this,arguments);},initMercatorParameters:function(){this.RESOLUTIONS=[];var maxResolution=156543.03390625;for(var zoom=0;zoom<=this.MAX_ZOOM_LEVEL;++zoom){this.RESOLUTIONS[zoom]=maxResolution/Math.pow(2,zoom);}
+this.units="m";this.projection=this.projection||"EPSG:900913";},forwardMercator:(function(){var gg=new OpenLayers.Projection("EPSG:4326");var sm=new OpenLayers.Projection("EPSG:900913");return function(lon,lat){var point=OpenLayers.Projection.transform({x:lon,y:lat},gg,sm);return new OpenLayers.LonLat(point.x,point.y);};})(),inverseMercator:(function(){var gg=new OpenLayers.Projection("EPSG:4326");var sm=new OpenLayers.Projection("EPSG:900913");return function(x,y){var point=OpenLayers.Projection.transform({x:x,y:y},sm,gg);return new OpenLayers.LonLat(point.x,point.y);};})()};OpenLayers.Lang["ru"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Необработанный запрос вернул ${statusText}",'Permalink':"Постоянная ссылка",'Overlays':"Слои",'Base Layer':"Основной слой",'noFID':"Невозможно обновить объект, для которого нет FID.",'browserNotSupported':"Ваш браузер не поддерживает векторную графику. На данный момент поддерживаются:\n${renderers}",'minZoomLevelError':"Свойство minZoomLevel предназначено только для использования со слоями, являющимися потомками FixedZoomLevels. То, что этот WFS-слой проверяется на minZoomLevel — реликт прошлого. Однако мы не можем удалить эту функцию, так как, возможно, от неё зависят некоторые основанные на OpenLayers приложения. Функция объявлена устаревшей — проверка minZoomLevel будет удалена в 3.0. Пожалуйста, используйте вместо неё настройку мин/макс разрешения, описанную здесь: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Транзакция WFS: УСПЕШНО ${response}",'commitFailed':"Транзакция WFS: ОШИБКА ${response}",'googleWarning':"Слой Google не удалось нормально загрузить.\x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека Google Maps не была включена или не содержит корректного API-ключа для вашего сайта.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'getLayerWarning':"Слой ${layerType} не удалось нормально загрузить. \x3cbr\x3e\x3cbr\x3eЧтобы избавиться от этого сообщения, выбите другой основной слой в переключателе в правом верхнем углу.\x3cbr\x3e\x3cbr\x3eСкорее всего, причина в том, что библиотека ${layerLib} не была включена или была включена некорректно.\x3cbr\x3e\x3cbr\x3eРазработчикам: чтобы узнать, как сделать, чтобы всё заработало, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eщёлкните тут\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Масштаб = 1 : ${scaleDenom}",'W':"З",'E':"В",'N':"С",'S':"Ю",'reprojectDeprecated':"Вы используете опцию \'reproject\' для слоя ${layerName}. Эта опция является устаревшей: ее использование предполагалось для поддержки показа данных поверх коммерческих базовых карт, но теперь этот функционал несёт встроенная поддержка сферической проекции Меркатора. Больше сведений доступно на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Этот метод считается устаревшим и будет удалён в версии 3.0. Пожалуйста, пользуйтесь ${newMethod}."});OpenLayers.Lang["hsb"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Wotmołwa njewobdźěłaneho naprašowanja ${statusText}",'Permalink':"Trajny wotkaz",'Overlays':"Naworštowanja",'Base Layer':"Zakładna runina",'noFID':"Funkcija, za kotruž FID njeje, njeda so aktualizować.",'browserNotSupported':"Twój wobhladowak wektorowe rysowanje njepodpěruje. Tuchwilu podpěrowane rysowaki su:\n${renderers}",'minZoomLevelError':"Kajkosć minZoomLevel je jenož za wužiwanje z worštami myslena, kotrež wot FixedZoomLevels pochadźeja. Zo tuta woršta wfs za minZoomLevel přepruwuje, je relikt zańdźenosće. Njemóžemy wšak ju wotstronić, bjeztoho zo aplikacije, kotrež na OpenLayers bazěruja a snano tutu kajkosć wužiwaja, hižo njefunguja. Tohodla smy ju jako zestarjenu woznamjenili -- přepruwowanje za minZoomLevel budu so we wersiji 3.0 wotstronjeć. Prošu wužij město toho nastajenje min/max, kaž je tu wopisane: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-Transakcija: WUSPĚŠNA ${response}",'commitFailed':"WFS-Transakcija: NJEPORADŹENA ${response}",'googleWarning':"Woršta Google njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki Google Maps pak njebu zapřijaty pak njewobsahuje korektny kluč API za twoje sydło.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'getLayerWarning':"Woršta ${layerType} njemóžeše so korektnje začitać.\x3cbr\x3e\x3cbr\x3eZo by tutu zdźělenku wotbył, wubjer nowy BaseLayer z wuběra worštow horjeka naprawo.\x3cbr\x3e\x3cbr\x3eNajskerje so to stawa, dokelž skript biblioteki ${layerLib} njebu korektnje zapřijaty.\x3cbr\x3e\x3cbr\x3eWuwiwarjo: Za pomoc ke korektnemu fungowanju worštow\n\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3etu kliknyć\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Měritko = 1 : ${scaleDenom}",'W':"Z",'E':"W",'N':"S",'S':"J",'reprojectDeprecated':"Wužiwaš opciju \"reproject\" wořšty ${layerName}. Tuta opcija je zestarjena: jeje wužiwanje bě myslene, zo by zwobraznjenje datow nad komercielnymi bazowymi kartami podpěrało, ale funkcionalnosć měła so nětko z pomocu Sperical Mercator docpěć. Dalše informacije steja na http://trac.openlayers.org/wiki/SphericalMercator k dispoziciji.",'methodDeprecated':"Tuta metoda je so njeschwaliła a budźe so w 3.0 wotstronjeć. Prošu wužij ${newMethod} město toho."});OpenLayers.Lang["de"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Unbehandelte Anfragerückmeldung ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Grundkarte",'noFID':"Ein Feature, für das keine FID existiert, kann nicht aktualisiert werden.",'browserNotSupported':"Ihr Browser unterstützt keine Vektordarstellung. Aktuell unterstützte Renderer:\n${renderers}",'minZoomLevelError':"Die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft ist nur für die Verwendung mit \x3ccode\x3eFixedZoomLevels\x3c/code\x3e-untergeordneten Layers vorgesehen. Das dieser \x3ctt\x3ewfs\x3c/tt\x3e-Layer die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Eigenschaft überprüft ist ein Relikt der Vergangenheit. Wir können diese Überprüfung nicht entfernen, ohne das OL basierende Applikationen nicht mehr funktionieren. Daher markieren wir es als veraltet - die \x3ccode\x3eminZoomLevel\x3c/code\x3e-Überprüfung wird in Version 3.0 entfernt werden. Bitte verwenden Sie stattdessen die Min-/Max-Lösung, wie sie unter http://trac.openlayers.org/wiki/SettingZoomLevels beschrieben ist.",'commitSuccess':"WFS-Transaktion: Erfolgreich ${response}",'commitFailed':"WFS-Transaktion: Fehlgeschlagen ${response}",'googleWarning':"Der Google-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der Google-Maps-Bibliothek nicht eingebunden wurde oder keinen gültigen API-Schlüssel für Ihre URL enthält.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden des Google-Layers",'getLayerWarning':"Der ${layerType}-Layer konnte nicht korrekt geladen werden.\x3cbr\x3e\x3cbr\x3eUm diese Meldung nicht mehr zu erhalten, wählen Sie einen anderen Hintergrundlayer aus dem LayerSwitcher in der rechten oberen Ecke.\x3cbr\x3e\x3cbr\x3eSehr wahrscheinlich tritt dieser Fehler auf, weil das Skript der \'${layerLib}\'-Bibliothek nicht eingebunden wurde.\x3cbr\x3e\x3cbr\x3eEntwickler: Besuche \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3edas Wiki\x3c/a\x3e für Hilfe zum korrekten Einbinden von Layern",'Scale = 1 : ${scaleDenom}':"Maßstab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Sie verwenden die „Reproject“-Option des Layers ${layerName}. Diese Option ist veraltet: Sie wurde entwickelt um die Anzeige von Daten auf kommerziellen Basiskarten zu unterstützen, aber diese Funktion sollte jetzt durch Unterstützung der „Spherical Mercator“ erreicht werden. Weitere Informationen sind unter http://trac.openlayers.org/wiki/SphericalMercator verfügbar.",'methodDeprecated':"Die Methode ist veraltet und wird in 3.0 entfernt. Bitte verwende stattdessen ${newMethod}."});OpenLayers.ProxyHost="";OpenLayers.Request={DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:true,user:undefined,password:undefined,params:null,proxy:OpenLayers.ProxyHost,headers:{},data:null,callback:function(){},success:null,failure:null,scope:null},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(url,proxy){var sameOrigin=url.indexOf("http")!==0;var urlParts=!sameOrigin&&url.match(this.URL_SPLIT_REGEX);if(urlParts){var location=window.location;sameOrigin=urlParts[1]==location.protocol&&urlParts[3]==location.hostname;var uPort=urlParts[4],lPort=location.port;if(uPort!=80&&uPort!=""||lPort!="80"&&lPort!=""){sameOrigin=sameOrigin&&uPort==lPort;}}
+if(!sameOrigin){if(proxy){if(typeof proxy=="function"){url=proxy(url);}else{url=proxy+encodeURIComponent(url);}}else{OpenLayers.Console.warn(OpenLayers.i18n("proxyNeeded"),{url:url});}}
+return url;},issue:function(config){var defaultConfig=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost});config=OpenLayers.Util.applyDefaults(config,defaultConfig);var customRequestedWithHeader=false,headerKey;for(headerKey in config.headers){if(config.headers.hasOwnProperty(headerKey)){if(headerKey.toLowerCase()==='x-requested-with'){customRequestedWithHeader=true;}}}
+if(customRequestedWithHeader===false){config.headers['X-Requested-With']='XMLHttpRequest';}
+var request=new OpenLayers.Request.XMLHttpRequest();var url=OpenLayers.Util.urlAppend(config.url,OpenLayers.Util.getParameterString(config.params||{}));url=OpenLayers.Request.makeSameOrigin(url,config.proxy);request.open(config.method,url,config.async,config.user,config.password);for(var header in config.headers){request.setRequestHeader(header,config.headers[header]);}
+var events=this.events;var self=this;request.onreadystatechange=function(){if(request.readyState==OpenLayers.Request.XMLHttpRequest.DONE){var proceed=events.triggerEvent("complete",{request:request,config:config,requestUrl:url});if(proceed!==false){self.runCallbacks({request:request,config:config,requestUrl:url});}}};if(config.async===false){request.send(config.data);}else{window.setTimeout(function(){if(request.readyState!==0){request.send(config.data);}},0);}
+return request;},runCallbacks:function(options){var request=options.request;var config=options.config;var complete=(config.scope)?OpenLayers.Function.bind(config.callback,config.scope):config.callback;var success;if(config.success){success=(config.scope)?OpenLayers.Function.bind(config.success,config.scope):config.success;}
+var failure;if(config.failure){failure=(config.scope)?OpenLayers.Function.bind(config.failure,config.scope):config.failure;}
+if(OpenLayers.Util.createUrlObject(config.url).protocol=="file:"&&request.responseText){request.status=200;}
+complete(request);if(!request.status||(request.status>=200&&request.status<300)){this.events.triggerEvent("success",options);if(success){success(request);}}
+if(request.status&&(request.status<200||request.status>=300)){this.events.triggerEvent("failure",options);if(failure){failure(request);}}},GET:function(config){config=OpenLayers.Util.extend(config,{method:"GET"});return OpenLayers.Request.issue(config);},POST:function(config){config=OpenLayers.Util.extend(config,{method:"POST"});config.headers=config.headers?config.headers:{};if(!("CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(config.headers))){config.headers["Content-Type"]="application/xml";}
+return OpenLayers.Request.issue(config);},PUT:function(config){config=OpenLayers.Util.extend(config,{method:"PUT"});config.headers=config.headers?config.headers:{};if(!("CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(config.headers))){config.headers["Content-Type"]="application/xml";}
+return OpenLayers.Request.issue(config);},DELETE:function(config){config=OpenLayers.Util.extend(config,{method:"DELETE"});return OpenLayers.Request.issue(config);},HEAD:function(config){config=OpenLayers.Util.extend(config,{method:"HEAD"});return OpenLayers.Request.issue(config);},OPTIONS:function(config){config=OpenLayers.Util.extend(config,{method:"OPTIONS"});return OpenLayers.Request.issue(config);}};OpenLayers.Lang['da-DK']={'unhandledRequest':"En ikke håndteret forespørgsel returnerede ${statusText}",'Permalink':"Permalink",'Overlays':"Kortlag",'Base Layer':"Baggrundslag",'noFID':"Kan ikke opdateret en feature (et objekt) der ikke har et FID.",'browserNotSupported':"Din browser understøtter ikke vektor visning. Følgende vektor visninger understøttes:\n${renderers}",'minZoomLevelError':"Egenskaben minZoomLevel er kun beregnet til brug "+"med FixedZoomLevels. At dette WFS lag kontrollerer "+"minZoomLevel egenskaben, er et levn fra en tidligere "+"version. Vi kan desværre ikke fjerne dette uden at risikere "+"at ødelægge eksisterende OL baserede programmer der "+" benytter denne funktionalitet. "+"Egenskaben bør derfor ikke anvendes, og minZoomLevel "+"kontrollen herunder vil blive fjernet i version 3.0. "+"Benyt istedet min/max opløsnings indstillingerne, som "+"er beskrevet her: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS transaktion: LYKKEDES ${response}",'commitFailed':"WFS transaktion: MISLYKKEDES ${response}",'googleWarning':"Google laget kunne ikke indlæses.<br><br>"+"For at fjerne denne besked, vælg et nyt bagrundskort i "+"lagskifteren i øverste højre hjørne.<br><br>"+"Fejlen skyldes formentlig at Google Maps bibliotekts "+"scriptet ikke er inkluderet, eller ikke indeholder den "+"korrkte API nøgle for dit site.<br><br>"+"Udviklere: For hjælp til at få dette til at fungere, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>klik her</a>",'getLayerWarning':"${layerType}-laget kunne ikke indlæses.<br><br>"+"For at fjerne denne besked, vælg et nyt bagrundskort i "+"lagskifteren i øverste højre hjørne.<br><br>"+"Fejlen skyldes formentlig at ${layerLib} bibliotekts "+"scriptet ikke er inkluderet.<br><br>"+"Udviklere: For hjælp til at få dette til at fungere, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>klik her</a>",'Scale = 1 : ${scaleDenom}':"Målforhold = 1 : ${scaleDenom}",'reprojectDeprecated':"Du anvender indstillingen 'reproject' på laget ${layerName}."+"Denne indstilling bør ikke længere anvendes. Den var beregnet "+"til at vise data ovenpå kommercielle grundkort, men den funktionalitet "+"bør nu opnås ved at anvende Spherical Mercator understøttelsen. "+"Mere information er tilgængelig her: "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Denne funktion bør ikke længere anvendes, og vil blive fjernet i version 3.0. "+"Anvend venligst funktionen ${newMethod} istedet."};OpenLayers.Lang["hu"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nem kezelt kérés visszatérése ${statusText}",'Permalink':"Permalink",'Overlays':"Rávetítések",'Base Layer':"Alapréteg",'noFID':"Nem frissíthető olyan jellemző, amely nem rendelkezik FID-del.",'browserNotSupported':"A böngészője nem támogatja a vektoros renderelést. A jelenleg támogatott renderelők:\n${renderers}",'minZoomLevelError':"A minZoomLevel tulajdonságot csak a következővel való használatra szánták: FixedZoomLevels-leszármazott fóliák. Ez azt jelenti, hogy a minZoomLevel wfs fólia jelölőnégyzetei már a múlté. Mi azonban nem távolíthatjuk el annak a veszélye nélkül, hogy az esetlegesen ettől függő OL alapú alkalmazásokat tönkretennénk. Ezért ezt érvénytelenítjük -- a minZoomLevel az alul levő jelölőnégyzet a 3.0-s verzióból el lesz távolítva. Kérjük, helyette használja a  min/max felbontás beállítást, amelyről az alábbi helyen talál leírást: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS tranzakció: SIKERES ${response}",'commitFailed':"WFS tranzakció: SIKERTELEN ${response}",'googleWarning':"A Google fólia betöltése sikertelen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a Google Maps könyvtár parancsfájlja nem található, vagy nem tartalmazza az Ön oldalához tartozó megfelelő API-kulcsot.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e",'getLayerWarning':"A(z) ${layerType} fólia nem töltődött be helyesen.\x3cbr\x3e\x3cbr\x3eAhhoz, hogy ez az üzenet eltűnjön, válasszon egy új BaseLayer fóliát a jobb felső sarokban található fóliakapcsoló segítségével.\x3cbr\x3e\x3cbr\x3eNagy valószínűséggel ez azért van, mert a(z) ${layerLib} könyvtár parancsfájlja helytelen.\x3cbr\x3e\x3cbr\x3eFejlesztőknek: A helyes működtetésre vonatkozó segítség az alábbi helyen érhető el, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ekattintson ide\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Lépték = 1 : ${scaleDenom}",'W':"Ny",'E':"K",'N':"É",'S':"D",'reprojectDeprecated':"Ön a \'reproject\' beállítást használja a(z) ${layerName} fólián. Ez a beállítás érvénytelen: használata az üzleti alaptérképek fölötti adatok megjelenítésének támogatására szolgált, de ezt a funkció ezentúl a Gömbi Mercator használatával érhető el. További információ az alábbi helyen érhető el: http://trac.openlayers.org/wiki/SphericalMercator",'methodDeprecated':"Ez a módszer érvénytelenítve lett és a 3.0-s verzióból el lesz távolítva. Használja a(z) ${newMethod} módszert helyette."});OpenLayers.Lang["zh-TW"]={'unhandledRequest':"未處理的請求,傳回值為 ${statusText}。",'Permalink':"永久連結",'Overlays':"額外圖層",'Base Layer':"基礎圖層",'noFID':"因為沒有 FID 所以無法更新 feature。",'browserNotSupported':"您的瀏覽器未支援向量渲染. 目前支援的渲染方式是:\n${renderers}",'minZoomLevelError':"minZoomLevel 屬性僅適合用在 "+"FixedZoomLevels-descendent 類型的圖層. 這個"+"wfs layer 的 minZoomLevel 是過去所遺留下來的,"+"然而我們不能移除它而不讓它將"+"過去的程式相容性給破壞掉。"+"因此我們將會迴避使用它 -- minZoomLevel "+"會在3.0被移除,請改"+"用在這邊描述的 min/max resolution 設定: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: 成功 ${response}",'commitFailed':"WFS Transaction: 失敗 ${response}",'googleWarning':"The Google Layer 圖層無法被正確的載入。<br><br>"+"要迴避這個訊息, 請在右上角的圖層改變器裡,"+"選一個新的基礎圖層。<br><br>"+"很有可能是因為 Google Maps 的函式庫"+"腳本沒有被正確的置入,或沒有包含 "+"您網站上正確的 API key <br><br>"+"開發者: 要幫助這個行為正確完成,"+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>請按這裡</a>",'getLayerWarning':"${layerType} 圖層無法被正確的載入。<br><br>"+"要迴避這個訊息, 請在右上角的圖層改變器裡,"+"選一個新的基礎圖層。<br><br>"+"很有可能是因為 ${layerLib} 的函式庫"+"腳本沒有被正確的置入。<br><br>"+"開發者: 要幫助這個行為正確完成,"+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>請按這裡</a>",'Scale = 1 : ${scaleDenom}':"Scale = 1 : ${scaleDenom}",'reprojectDeprecated':"你正使用 'reproject' 這個選項 "+"在 ${layerName} 層。這個選項已經不再使用:"+"它的使用原本是設計用來支援在商業地圖上秀出資料,"+"但這個功能已經被"+"Spherical Mercator所取代。更多的資訊可以在 "+"http://trac.openlayers.org/wiki/SphericalMercator 找到。",'methodDeprecated':"這個方法已經不再使用且在3.0將會被移除,"+"請使用 ${newMethod} 來代替。",'end':''};OpenLayers.Control.DrawFeature=OpenLayers.Class(OpenLayers.Control,{layer:null,callbacks:null,multi:false,featureAdded:function(){},handlerOptions:null,initialize:function(layer,handler,options){OpenLayers.Control.prototype.initialize.apply(this,[options]);this.callbacks=OpenLayers.Util.extend({done:this.drawFeature,modify:function(vertex,feature){this.layer.events.triggerEvent("sketchmodified",{vertex:vertex,feature:feature});},create:function(vertex,feature){this.layer.events.triggerEvent("sketchstarted",{vertex:vertex,feature:feature});}},this.callbacks);this.layer=layer;this.handlerOptions=this.handlerOptions||{};this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{renderers:layer.renderers,rendererOptions:layer.rendererOptions});if(!("multi"in this.handlerOptions)){this.handlerOptions.multi=this.multi;}
+var sketchStyle=this.layer.styleMap&&this.layer.styleMap.styles.temporary;if(sketchStyle){this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":sketchStyle})});}
+this.handler=new handler(this,this.callbacks,this.handlerOptions);},drawFeature:function(geometry){var feature=new OpenLayers.Feature.Vector(geometry);var proceed=this.layer.events.triggerEvent("sketchcomplete",{feature:feature});if(proceed!==false){feature.state=OpenLayers.State.INSERT;this.layer.addFeatures([feature]);this.featureAdded(feature);this.events.triggerEvent("featureadded",{feature:feature});}},insertXY:function(x,y){if(this.handler&&this.handler.line){this.handler.insertXY(x,y);}},insertDeltaXY:function(dx,dy){if(this.handler&&this.handler.line){this.handler.insertDeltaXY(dx,dy);}},insertDirectionLength:function(direction,length){if(this.handler&&this.handler.line){this.handler.insertDirectionLength(direction,length);}},insertDeflectionLength:function(deflection,length){if(this.handler&&this.handler.line){this.handler.insertDeflectionLength(deflection,length);}},undo:function(){return this.handler.undo&&this.handler.undo();},redo:function(){return this.handler.redo&&this.handler.redo();},finishSketch:function(){this.handler.finishGeometry();},cancel:function(){this.handler.cancel();},CLASS_NAME:"OpenLayers.Control.DrawFeature"});OpenLayers.Lang["pt-br"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"A requisição retornou um erro não tratado: ${statusText}",'Permalink':"Link para essa página",'Overlays':"Camadas de Sobreposição",'Base Layer':"Camada Base",'noFID':"Não é possível atualizar uma feição que não tenha um FID.",'browserNotSupported':"Seu navegador não suporta renderização de vetores. Os renderizadores suportados atualmente são:\n${renderers}",'minZoomLevelError':"A propriedade minZoomLevel é de uso restrito das camadas descendentes de FixedZoomLevels. A verificação dessa propriedade pelas camadas wfs é um resíduo do passado. Não podemos, entretanto não é possível removê-la sem possívelmente quebrar o funcionamento de aplicações OL que possuem depência com ela. Portanto estamos tornando seu uso obsoleto -- a verificação desse atributo será removida na versão 3.0. Ao invés, use as opções de resolução min/max como descrito em: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transação WFS : SUCESSO ${response}",'commitFailed':"Transação WFS : ERRO ${response}",'googleWarning':"Não foi possível carregar a camada Google corretamente.\x3cbr\x3e\x3cbr\x3ePara se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.\x3cbr\x3e\x3cbr\x3eMuito provavelmente, isso foi causado porque o script da biblioteca do Google Maps não foi incluído, ou porque ele não contém a chave correta da API para o seu site.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: Para obter ajuda em solucionar esse problema \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquem aqui\x3c/a\x3e",'getLayerWarning':"Não foi possível carregar a camada ${layerType} corretamente.\x3cbr\x3e\x3cbr\x3ePara se livrar dessa mensagem, selecione uma nova Camada Base, na ferramenta de alternação de camadas localização do canto superior direito.\x3cbr\x3e\x3cbr\x3eMuito provavelmente, isso foi causado porque o script da biblioteca ${layerLib} não foi incluído corretamente.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: Para obter ajuda em solucionar esse problema \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquem aqui\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':"O",'E':"L",'N':"N",'S':"S",'reprojectDeprecated':"Você está usando a opção \'reproject\' na camada ${layerName}. Essa opção está obsoleta: seu uso foi projetado para suportar a visualização de dados sobre bases de mapas comerciais, entretanto essa funcionalidade deve agora ser alcançada usando o suporte à projeção Mercator. Mais informação está disponível em: http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Esse método está obsoleto e será removido na versão 3.0. Ao invés, por favor use ${newMethod}."});OpenLayers.Lang["zh-CN"]={'unhandledRequest':"未处理的请求,返回值为 ${statusText}",'Permalink':"永久链接",'Overlays':"叠加层",'Base Layer':"基础图层",'noFID':"无法更新feature,缺少FID。",'browserNotSupported':"你使用的浏览器不支持矢量渲染。当前支持的渲染方式包括:\n${renderers}",'minZoomLevelError':"minZoomLevel属性仅适合用于"+"使用了固定缩放级别的图层。这个 "+"wfs 图层检查 minZoomLevel 是过去遗留下来的。"+"然而,我们不能移除它,"+"而破坏依赖于它的基于OL的应用程序。"+"因此,我们废除了它 -- minZoomLevel "+"将会在3.0中被移除。请改用 "+"min/max resolution 设置,参考:"+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: 成功。 ${response}",'commitFailed':"WFS Transaction: 失败。 ${response}",'googleWarning':"Google图层不能正确加载。<br><br>"+"要消除这个信息,请在右上角的"+"图层控制面板中选择其他的基础图层。<br><br>"+"这种情况很可能是没有正确的包含Google地图脚本库,"+"或者是没有包含在你的站点上"+"使用的正确的Google Maps API密匙。<br><br>"+"开发者:获取使其正确工作的帮助信息,"+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>点击这里</a>",'getLayerWarning':"${layerType} 图层不能正确加载。<br><br>"+"要消除这个信息,请在右上角的"+"图层控制面板中选择其他的基础图层。<br><br>"+"这种情况很可能是没有正确的包含"+"${layerLib} 脚本库。<br><br>"+"开发者:获取使其正确工作的帮助信息,"+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>点击这里</a>",'Scale = 1 : ${scaleDenom}':"比例尺 = 1 : ${scaleDenom}",'reprojectDeprecated':"你正在使用 ${layerName} 图层上的'reproject'选项。"+"这个选项已经不再使用:"+"它是被设计用来支持显示商业的地图数据,"+"不过现在该功能可以通过使用Spherical Mercator来实现。"+"更多信息可以参阅"+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"该方法已经不再被支持,并且将在3.0中被移除。"+"请使用 ${newMethod} 方法来替代。",'end':''};OpenLayers.Lang["pt"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Servidor devolveu erro não contemplado ${statusText}",'Permalink':"Ligação permanente",'Overlays':"Sobreposições",'Base Layer':"Camada Base",'noFID':"Não é possível atualizar um elemento para a qual não há FID.",'browserNotSupported':"O seu navegador não suporta renderização vetorial. Actualmente os renderizadores suportados são:\n${renderers}",'minZoomLevelError':"A propriedade minZoomLevel só deve ser usada com as camadas descendentes da FixedZoomLevels. A verificação da propriedade por esta camada wfs é uma relíquia do passado. No entanto, não podemos removê-la sem correr o risco de afectar aplicações OL que dependam dela. Portanto, estamos a torná-la obsoleta -- a verificação minZoomLevel será removida na versão 3.0. Em vez dela, por favor, use as opções de resolução min/max descritas aqui: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacção WFS: SUCESSO ${response}",'commitFailed':"Transacção WFS: FALHOU ${response}",'googleWarning':"A Camada Google não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara deixar de receber esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca do Google Maps não foi incluído ou não contém a chave API correcta para o seu sítio.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .",'getLayerWarning':"A camada ${layerType} não foi correctamente carregada.\x3cbr\x3e\x3cbr\x3ePara desactivar esta mensagem, seleccione uma nova Camada-Base no \'\'switcher\'\' de camadas no canto superior direito.\x3cbr\x3e\x3cbr\x3eProvavelmente, isto acontece porque o \'\'script\'\' da biblioteca ${layerLib} não foi incluído correctamente.\x3cbr\x3e\x3cbr\x3eProgramadores: Para ajuda sobre como solucionar o problema \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclique aqui\x3c/a\x3e .",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S",'reprojectDeprecated':"Está usando a opção \'reproject\' na camada ${layerName}. Esta opção é obsoleta: foi concebida para permitir a apresentação de dados sobre mapas-base comerciais, mas esta funcionalidade é agora suportada pelo Mercator Esférico. Mais informação está disponível em http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Este método foi declarado obsoleto e será removido na versão 3.0. Por favor, use ${newMethod} em vez disso."});OpenLayers.Rule=OpenLayers.Class({id:null,name:null,title:null,description:null,context:null,filter:null,elseFilter:false,symbolizer:null,symbolizers:null,minScaleDenominator:null,maxScaleDenominator:null,initialize:function(options){this.symbolizer={};OpenLayers.Util.extend(this,options);if(this.symbolizers){delete this.symbolizer;}
+this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_");},destroy:function(){for(var i in this.symbolizer){this.symbolizer[i]=null;}
+this.symbolizer=null;delete this.symbolizers;},evaluate:function(feature){var context=this.getContext(feature);var applies=true;if(this.minScaleDenominator||this.maxScaleDenominator){var scale=feature.layer.map.getScale();}
+if(this.minScaleDenominator){applies=scale>=OpenLayers.Style.createLiteral(this.minScaleDenominator,context);}
+if(applies&&this.maxScaleDenominator){applies=scale<OpenLayers.Style.createLiteral(this.maxScaleDenominator,context);}
+if(applies&&this.filter){if(this.filter.CLASS_NAME=="OpenLayers.Filter.FeatureId"){applies=this.filter.evaluate(feature);}else{applies=this.filter.evaluate(context);}}
+return applies;},getContext:function(feature){var context=this.context;if(!context){context=feature.attributes||feature.data;}
+if(typeof this.context=="function"){context=this.context(feature);}
+return context;},clone:function(){var options=OpenLayers.Util.extend({},this);if(this.symbolizers){var len=this.symbolizers.length;options.symbolizers=new Array(len);for(var i=0;i<len;++i){options.symbolizers[i]=this.symbolizers[i].clone();}}else{options.symbolizer={};var value,type;for(var key in this.symbolizer){value=this.symbolizer[key];type=typeof value;if(type==="object"){options.symbolizer[key]=OpenLayers.Util.extend({},value);}else if(type==="string"){options.symbolizer[key]=value;}}}
+options.filter=this.filter&&this.filter.clone();options.context=this.context&&OpenLayers.Util.extend({},this.context);return new OpenLayers.Rule(options);},CLASS_NAME:"OpenLayers.Rule"});OpenLayers.Lang["gl"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Solicitude non xerada; a resposta foi: ${statusText}",'Permalink':"Ligazón permanente",'Overlays':"Capas superpostas",'Base Layer':"Capa base",'noFID':"Non se pode actualizar a funcionalidade para a que non hai FID.",'browserNotSupported':"O seu navegador non soporta a renderización de vectores. Os renderizadores soportados actualmente son:\n${renderers}",'minZoomLevelError':"A propiedade minZoomLevel é só para uso conxuntamente coas capas FixedZoomLevels-descendent. O feito de que esa capa wfs verifique o minZoomLevel é unha reliquia do pasado. Non podemos, con todo, eliminala sen a posibilidade de non romper as aplicacións baseadas en OL que poidan depender dela. Por iso a estamos deixando obsoleta (a comprobación minZoomLevel de embaixo será eliminada na versión 3.0). Por favor, no canto diso use o axuste de resolución mín/máx tal e como está descrito aquí: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacción WFS: ÉXITO ${response}",'commitFailed':"Transacción WFS: FALLIDA ${response}",'googleWarning':"A capa do Google non puido cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría do Google Maps ou ben non foi incluída ou ben non contén a clave API correcta para o seu sitio.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e",'getLayerWarning':"A capa ${layerType} foi incapaz de cargarse correctamente.\x3cbr\x3e\x3cbr\x3ePara evitar esta mensaxe, escolla unha nova capa base no seleccionador de capas na marxe superior dereita.\x3cbr\x3e\x3cbr\x3eProbablemente, isto acontece porque a escritura da libraría ${layerLib} non foi ben incluída.\x3cbr\x3e\x3cbr\x3eDesenvolvedores: para axudar a facer funcionar isto correctamente, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3epremede aquí\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':"O",'E':"L",'N':"N",'S':"S",'reprojectDeprecated':"Está usando a opción \"reproject\" na capa ${layerName}. Esta opción está obsoleta: o seu uso foi deseñado para a visualización de datos sobre mapas base comerciais, pero esta funcionalidade debera agora ser obtida utilizando a proxección Spherical Mercator. Hai dispoñible máis información en http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Este método está obsoleto e será eliminado na versión 3.0. Por favor, no canto deste use ${newMethod}."});OpenLayers.Lang["ar"]=OpenLayers.Util.applyDefaults({'Permalink':"وصلة دائمة",'Base Layer':"الطبقة الاساسية",'Scale = 1 : ${scaleDenom}':"النسبة = 1 : ${scaleDenom}",'W':"غ",'E':"شر",'N':"شم",'S':"ج"});OpenLayers.Handler.Pinch=OpenLayers.Class(OpenLayers.Handler,{started:false,stopDown:false,pinching:false,last:null,start:null,touchstart:function(evt){var propagate=true;this.pinching=false;if(OpenLayers.Event.isMultiTouch(evt)){this.started=true;this.last=this.start={distance:this.getDistance(evt.touches),delta:0,scale:1};this.callback("start",[evt,this.start]);propagate=!this.stopDown;}else{this.started=false;this.start=null;this.last=null;}
+OpenLayers.Event.stop(evt);return propagate;},touchmove:function(evt){if(this.started&&OpenLayers.Event.isMultiTouch(evt)){this.pinching=true;var current=this.getPinchData(evt);this.callback("move",[evt,current]);this.last=current;OpenLayers.Event.stop(evt);}
+return true;},touchend:function(evt){if(this.started){this.started=false;this.pinching=false;this.callback("done",[evt,this.start,this.last]);this.start=null;this.last=null;}
+return true;},activate:function(){var activated=false;if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){this.pinching=false;activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){this.started=false;this.pinching=false;this.start=null;this.last=null;deactivated=true;}
+return deactivated;},getDistance:function(touches){var t0=touches[0];var t1=touches[1];return Math.sqrt(Math.pow(t0.clientX-t1.clientX,2)+
+Math.pow(t0.clientY-t1.clientY,2));},getPinchData:function(evt){var distance=this.getDistance(evt.touches);var scale=distance/this.start.distance;return{distance:distance,delta:this.last.distance-distance,scale:scale};},CLASS_NAME:"OpenLayers.Handler.Pinch"});OpenLayers.Lang['lt']=OpenLayers.Util.applyDefaults({'unhandledRequest':"Neapdorota užklausa gražino ${statusText}",'Permalink':"Pastovi nuoroda",'Overlays':"Papildomi sluoksniai",'Base Layer':"Pagrindinis sluoksnis",'noFID':"Negaliu atnaujinti objekto, kuris neturi FID.",'browserNotSupported':"Jūsų naršyklė nemoka parodyti vektorių. Šiuo metu galima naudotis tokiais rodymo varikliais:\n{renderers}",'commitSuccess':"WFS Tranzakcija: PAVYKO ${response}",'commitFailed':"WFS Tranzakcija: ŽLUGO ${response}",'Scale = 1 : ${scaleDenom}':"Mastelis = 1 : ${scaleDenom}",'W':'V','E':'R','N':'Š','S':'P','Graticule':'Tinklelis','methodDeprecated':"Šis metodas yra pasenęs ir 3.0 versijoje bus pašalintas. "+"Prašome naudoti ${newMethod}.",'end':''});OpenLayers.Lang.ca={'unhandledRequest':"Resposta a petició no gestionada ${statusText}",'Permalink':"Enllaç permanent",'Overlays':"Capes addicionals",'Base Layer':"Capa Base",'noFID':"No es pot actualitzar un element per al que no existeix FID.",'browserNotSupported':"El seu navegador no suporta renderització vectorial. Els renderitzadors suportats actualment són:\n${renderers}",'minZoomLevelError':"La propietat minZoomLevel s'ha d'utilitzar només "+"amb les capes que tenen FixedZoomLevels. El fet que "+"una capa wfs comprovi minZoomLevel és una relíquia del "+"passat. No podem, però, eliminar-la sense trencar "+"les aplicacions d'OpenLayers que en puguin dependre. "+"Així doncs estem fent-la obsoleta -- la comprovació "+"minZoomLevel s'eliminarà a la versió 3.0. Feu servir "+"els paràmetres min/max resolution en substitució, tal com es descriu aquí: "+"http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transacció WFS: CORRECTA ${response}",'commitFailed':"Transacció WFS: HA FALLAT ${response}",'googleWarning':"La capa Google no s'ha pogut carregar correctament.<br><br>"+"Per evitar aquest missatge, seleccioneu una nova Capa Base "+"al gestor de capes de la cantonada superior dreta.<br><br>"+"Probablement això és degut a que l'script de la biblioteca de "+"Google Maps no ha estat inclòs a la vostra pàgina, o no "+"conté la clau de l'API correcta per a la vostra adreça.<br><br>"+"Desenvolupadors: Per obtenir consells sobre com fer anar això, "+"<a href='http://trac.openlayers.org/wiki/Google' "+"target='_blank'>féu clic aquí</a>",'getLayerWarning':"Per evitar aquest missatge, seleccioneu una nova Capa Base "+"al gestor de capes de la cantonada superior dreta.<br><br>"+"Probablement això és degut a que l'script de la biblioteca "+"${layerLib} "+"no ha estat inclòs a la vostra pàgina.<br><br>"+"Desenvolupadors: Per obtenir consells sobre com fer anar això, "+"<a href='http://trac.openlayers.org/wiki/${layerLib}' "+"target='_blank'>féu clic aquí</a>",'Scale = 1 : ${scaleDenom}':"Escala = 1 : ${scaleDenom}",'W':'O','E':'E','N':'N','S':'S','Graticule':'Retícula','reprojectDeprecated':"Esteu fent servir l'opció 'reproject' a la capa "+"${layerName}. Aquesta opció és obsoleta: el seu ús fou concebut "+"per suportar la visualització de dades sobre mapes base comercials, "+"però ara aquesta funcionalitat s'hauria d'assolir mitjançant el suport "+"de la projecció Spherical Mercator. Més informació disponible a "+"http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Aquest mètode és obsolet i s'eliminarà a la versió 3.0. "+"Si us plau feu servir em mètode alternatiu ${newMethod}.",'end':''};OpenLayers.Lang["id"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Permintaan yang tak tertangani menghasilkan ${statusText}",'Permalink':"Pranala permanen",'Overlays':"Hamparan",'Base Layer':"Lapisan Dasar",'noFID':"Tidak dapat memperbarui fitur yang tidak memiliki FID.",'browserNotSupported':"Peramban Anda tidak mendukung penggambaran vektor. Penggambar yang didukung saat ini adalah:\n${renderers}",'minZoomLevelError':"Properti minZoomLevel hanya ditujukan bekerja dengan lapisan FixedZoomLevels-descendent. Pengecekan minZoomLevel oleh lapisan wfs adalah peninggalan masa lalu. Kami tidak dapat menghapusnya tanpa kemungkinan merusak aplikasi berbasis OL yang mungkin bergantung padanya. Karenanya, kami menganggapnya tidak berlaku -- Cek minZoomLevel di bawah ini akan dihapus pada 3.0. Silakan gunakan penyetelan resolusi min/maks seperti dijabarkan di sini: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaksi: BERHASIL ${respon}",'commitFailed':"WFS Transaksi: GAGAL ${respon}",'googleWarning':"Lapisan Google tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan atau tidak mengandung kunci API yang tepat untuk situs Anda.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'getLayerWarning':"Lapisan ${layerType} tidak dapat dimuat dengan benar.\x3cbr\x3e\x3cbr\x3eUntuk menghilangkan pesan ini, pilih suatu BaseLayer baru melalui penukar lapisan (layer switcher) di ujung kanan atas.\x3cbr\x3e\x3cbr\x3eKemungkinan besar ini karena pustaka skrip Google Maps tidak disertakan dengan benar.\x3cbr\x3e\x3cbr\x3ePengembang: Untuk bantuan mengatasi masalah ini, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik di sini\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Sekala = 1 : ${scaleDenom}",'W':"B",'E':"T",'N':"U",'S':"S",'reprojectDeprecated':"Anda menggunakan opsi \'reproject\' pada lapisan ${layerName}. Opsi ini telah ditinggalkan: penggunaannya dirancang untuk mendukung tampilan data melalui peta dasar komersial, tapi fungsionalitas tersebut saat ini harus dilakukan dengan menggunakan dukungan Spherical Mercator. Informasi lebih lanjut tersedia di http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Metode ini telah usang dan akan dihapus di 3.0. Sebaliknya, harap gunakan ${newMethod}."});OpenLayers.Filter.Comparison=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,matchCase:true,lowerBoundary:null,upperBoundary:null,initialize:function(options){OpenLayers.Filter.prototype.initialize.apply(this,[options]);if(this.type===OpenLayers.Filter.Comparison.LIKE&&options.matchCase===undefined){this.matchCase=null;}},evaluate:function(context){if(context instanceof OpenLayers.Feature.Vector){context=context.attributes;}
+var result=false;var got=context[this.property];var exp;switch(this.type){case OpenLayers.Filter.Comparison.EQUAL_TO:exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()==exp.toUpperCase());}else{result=(got==exp);}
+break;case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:exp=this.value;if(!this.matchCase&&typeof got=="string"&&typeof exp=="string"){result=(got.toUpperCase()!=exp.toUpperCase());}else{result=(got!=exp);}
+break;case OpenLayers.Filter.Comparison.LESS_THAN:result=got<this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN:result=got>this.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:result=got<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:result=got>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:result=(got>=this.lowerBoundary)&&(got<=this.upperBoundary);break;case OpenLayers.Filter.Comparison.LIKE:var regexp=new RegExp(this.value,"gi");result=regexp.test(got);break;}
+return result;},value2regex:function(wildCard,singleChar,escapeChar){if(wildCard=="."){throw new Error("'.' is an unsupported wildCard character for "+"OpenLayers.Filter.Comparison");}
+wildCard=wildCard?wildCard:"*";singleChar=singleChar?singleChar:".";escapeChar=escapeChar?escapeChar:"!";this.value=this.value.replace(new RegExp("\\"+escapeChar+"(.|$)","g"),"\\$1");this.value=this.value.replace(new RegExp("\\"+singleChar,"g"),".");this.value=this.value.replace(new RegExp("\\"+wildCard,"g"),".*");this.value=this.value.replace(new RegExp("\\\\.\\*","g"),"\\"+wildCard);this.value=this.value.replace(new RegExp("\\\\\\.","g"),"\\"+singleChar);return this.value;},regex2value:function(){var value=this.value;value=value.replace(/!/g,"!!");value=value.replace(/(\\)?\\\./g,function($0,$1){return $1?$0:"!.";});value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"!*";});value=value.replace(/\\\\/g,"\\");value=value.replace(/\.\*/g,"*");return value;},clone:function(){return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison(),this);},CLASS_NAME:"OpenLayers.Filter.Comparison"});OpenLayers.Filter.Comparison.EQUAL_TO="==";OpenLayers.Filter.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Filter.Comparison.LESS_THAN="<";OpenLayers.Filter.Comparison.GREATER_THAN=">";OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Filter.Comparison.BETWEEN="..";OpenLayers.Filter.Comparison.LIKE="~";OpenLayers.Format.QueryStringFilter=(function(){var cmpToStr={};cmpToStr[OpenLayers.Filter.Comparison.EQUAL_TO]="eq";cmpToStr[OpenLayers.Filter.Comparison.NOT_EQUAL_TO]="ne";cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN]="lt";cmpToStr[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO]="lte";cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN]="gt";cmpToStr[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO]="gte";cmpToStr[OpenLayers.Filter.Comparison.LIKE]="ilike";function regex2value(value){value=value.replace(/%/g,"\\%");value=value.replace(/\\\\\.(\*)?/g,function($0,$1){return $1?$0:"\\\\_";});value=value.replace(/\\\\\.\*/g,"\\\\%");value=value.replace(/(\\)?\.(\*)?/g,function($0,$1,$2){return $1||$2?$0:"_";});value=value.replace(/(\\)?\.\*/g,function($0,$1){return $1?$0:"%";});value=value.replace(/\\\./g,".");value=value.replace(/(\\)?\\\*/g,function($0,$1){return $1?$0:"*";});return value;}
+return OpenLayers.Class(OpenLayers.Format,{wildcarded:false,srsInBBOX:false,write:function(filter,params){params=params||{};var className=filter.CLASS_NAME;var filterType=className.substring(className.lastIndexOf(".")+1);switch(filterType){case"Spatial":switch(filter.type){case OpenLayers.Filter.Spatial.BBOX:params.bbox=filter.value.toArray();if(this.srsInBBOX&&filter.projection){params.bbox.push(filter.projection.getCode());}
+break;case OpenLayers.Filter.Spatial.DWITHIN:params.tolerance=filter.distance;case OpenLayers.Filter.Spatial.WITHIN:params.lon=filter.value.x;params.lat=filter.value.y;break;default:OpenLayers.Console.warn("Unknown spatial filter type "+filter.type);}
+break;case"Comparison":var op=cmpToStr[filter.type];if(op!==undefined){var value=filter.value;if(filter.type==OpenLayers.Filter.Comparison.LIKE){value=regex2value(value);if(this.wildcarded){value="%"+value+"%";}}
+params[filter.property+"__"+op]=value;params.queryable=params.queryable||[];params.queryable.push(filter.property);}else{OpenLayers.Console.warn("Unknown comparison filter type "+filter.type);}
+break;case"Logical":if(filter.type===OpenLayers.Filter.Logical.AND){for(var i=0,len=filter.filters.length;i<len;i++){params=this.write(filter.filters[i],params);}}else{OpenLayers.Console.warn("Unsupported logical filter type "+filter.type);}
+break;default:OpenLayers.Console.warn("Unknown filter type "+filterType);}
+return params;},CLASS_NAME:"OpenLayers.Format.QueryStringFilter"});})();OpenLayers.Lang["km"]=OpenLayers.Util.applyDefaults({'Permalink':"តំណភ្ជាប់អចិន្ត្រៃយ៍",'Base Layer':"ស្រទាប់បាត​",'Scale = 1 : ${scaleDenom}':"មាត្រដ្ឋាន = ១ ៖ ${scaleDenom}"});OpenLayers.Lang["nl"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Het verzoek is niet afgehandeld met de volgende melding: ${statusText}",'Permalink':"Permanente verwijzing",'Overlays':"Overlays",'Base Layer':"Achtergrondkaart",'noFID':"Een optie die geen FID heeft kan niet bijgewerkt worden.",'browserNotSupported':"Uw browser ondersteunt het weergeven van vectoren niet.\nMomenteel ondersteunde weergavemogelijkheden:\n${renderers}",'minZoomLevelError':"De eigenschap minZoomLevel is alleen bedoeld voor gebruik lagen met die afstammen van FixedZoomLevels-lagen.\nDat deze WFS-laag minZoomLevel controleert, is een overblijfsel uit het verleden.\nWe kunnen deze controle echter niet verwijderen zonder op OL gebaseerde applicaties die hervan afhankelijk zijn stuk te maken.\nDaarom heeft deze functionaliteit de eigenschap \'deprecated\' gekregen - de minZoomLevel wordt verwijderd in versie 3.0.\nGebruik in plaats van deze functie de mogelijkheid om min/max voor resolutie in te stellen zoals op de volgende pagina wordt beschreven:\nhttp://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-transactie: succesvol ${response}",'commitFailed':"WFS-transactie: mislukt ${response}",'googleWarning':"De Google-Layer kon niet correct geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct ingevoegd is.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.",'getLayerWarning':"De laag ${layerType} kon niet goed geladen worden.\x3cbr /\x3e\x3cbr /\x3e\nOm deze melding niet meer te krijgen, moet u een andere achtergrondkaart kiezen in de laagwisselaar in de rechterbovenhoek.\x3cbr /\x3e\x3cbr /\x3e\nDit komt waarschijnlijk doordat de bibliotheek ${layerLib} niet correct is ingevoegd.\x3cbr /\x3e\x3cbr /\x3e\nOntwikkelaars: \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eklik hier\x3c/a\x3e om dit werkend te krijgen.",'Scale = 1 : ${scaleDenom}':"Schaal = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"Z",'reprojectDeprecated':"U gebruikt de optie \'reproject\' op de laag ${layerName}.\nDeze optie is vervallen: deze optie was ontwikkeld om gegevens over commerciële basiskaarten weer te geven, maar deze functionaliteit wordt nu bereikt door ondersteuning van Spherical Mercator.\nMeer informatie is beschikbaar op http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Deze methode is verouderd en wordt verwijderd in versie 3.0.\nGebruik ${newMethod}."});OpenLayers.Lang["fr"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Requête non gérée, retournant ${statusText}",'Permalink':"Permalien",'Overlays':"Calques",'Base Layer':"Calque de base",'noFID':"Impossible de mettre à jour un objet sans identifiant (fid).",'browserNotSupported':"Votre navigateur ne supporte pas le rendu vectoriel. Les renderers actuellement supportés sont : \n${renderers}",'minZoomLevelError':"La propriété minZoomLevel doit seulement être utilisée pour des couches FixedZoomLevels-descendent. Le fait que cette couche WFS vérifie la présence de minZoomLevel est une relique du passé. Nous ne pouvons toutefois la supprimer sans casser des applications qui pourraient en dépendre. C\'est pourquoi nous la déprécions -- la vérification du minZoomLevel sera supprimée en version 3.0. A la place, merci d\'utiliser les paramètres de résolutions min/max tel que décrit sur : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Transaction WFS : SUCCES ${response}",'commitFailed':"Transaction WFS : ECHEC ${response}",'googleWarning':"La couche Google n\'a pas été en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie Google Maps, ou alors parce que la clé de l\'API ne correspond pas à votre site.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e",'getLayerWarning':"La couche ${layerType} n\'est pas en mesure de se charger correctement.\x3cbr\x3e\x3cbr\x3ePour supprimer ce message, choisissez une nouvelle BaseLayer dans le sélecteur de couche en haut à droite.\x3cbr\x3e\x3cbr\x3eCela est possiblement causé par la non-inclusion de la librairie ${layerLib}.\x3cbr\x3e\x3cbr\x3eDéveloppeurs : pour savoir comment corriger ceci, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3ecliquez ici\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Echelle ~ 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S",'reprojectDeprecated':"Vous utilisez l\'option \'reproject\' sur la couche ${layerName}. Cette option est dépréciée : Son usage permettait d\'afficher des données au dessus de couches raster commerciales.Cette fonctionalité est maintenant supportée en utilisant le support de la projection Mercator Sphérique. Plus d\'information est disponible sur http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Cette méthode est dépréciée, et sera supprimée à la version 3.0. Merci d\'utiliser ${newMethod} à la place.",'proxyNeeded':"Vous avez très probablement besoin de renseigner OpenLayers.ProxyHost pour accéder à ${url}. Voir http://trac.osgeo.org/openlayers/wiki/FrequentlyAskedQuestions#ProxyHost"});OpenLayers.Lang["ksh"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Met dä Antwoot op en Aanfrooch ham_mer nix aanjefange: ${statusText}",'Permalink':"Lengk op Duuer",'Overlays':"Drövver jelaat",'Base Layer':"Jrund-Nivoh",'noFID':"En Saach, woh kein \x3ci lang=\"en\"\x3eFID\x3c/i\x3e för doh es, löht sesch nit ändere.",'browserNotSupported':"Dinge Brauser kann kein Väktore ußjävve. De Zoote Ußjaabe, di em Momang jon, sen:\n${renderers}",'minZoomLevelError':"De Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ es bloß doför jedaach, dat mer se met dä Nivvohß bruch, di vun \x3ccode lang=\"en\"\x3eFixedZoomLevels\x3c/code\x3e affhange don. Dat dat \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Nivvoh övverhoup de Eijeschaff „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“ pröhfe deiht, es noch övveresch vun fröhjer. Mer künne dat ävver jez nit fott lohße, oohne dat mer Jevaa loufe, dat Aanwendunge vun OpenLayers nit mieh loufe, di sesch doh velleijsch noch drop am verlohße sin. Dröm sare mer, dat mer et nit mieh han welle, un de „\x3ccode lang=\"en\"\x3eminZoomLevel\x3c/code\x3e“-Eijeschaff weed hee vun de Version 3.0 af nit mieh jeprööf wäde. Nemm doför de Enstellung för de hühßte un de kleinßte Oplöhsung, esu wi et en http://trac.openlayers.org/wiki/SettingZoomLevels opjeschrevve es.",'commitSuccess':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es joot jeloufe: ${response}",'commitFailed':"Dä \x3ci lang=\"en\"\x3eWFS\x3c/i\x3e-Vörjang es scheif jejange: ${response}",'googleWarning':"Dat Nivvoh \x3ccode lang=\"en\"\x3eGoogle\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhke, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat wiel dat \x3ci lang=\"en\"\x3eGoogle-Maps\x3c/i\x3e-Skrepp entweeder nit reschtesch enjebonge wood, udder nit dä reschtejje \x3ci lang=\"en\"\x3eAPI\x3c/i\x3e-Schlößel för Ding Web-ßait scheke deiht.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/Google\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'getLayerWarning':"Dat Nivvoh \x3ccode\x3e${layerType}\x3c/code\x3e kunnt nit reschtesch jelaade wääde.\x3cbr /\x3e\x3cbr /\x3eÖm hee di Nohreesch loß ze krijje, donn en ander Jrund-Nivvoh ußsöhkre, rähß bovve en de Äk.\x3cbr /\x3e\x3cbr /\x3eWascheinlesch es dat, wiel dat Skrepp \x3ccode\x3e${layerLib}\x3c/code\x3e nit reschtesch enjebonge wood.\x3cbr /\x3e\x3cbr /\x3eFör Projrammierer jidd_Et Hölp do_drövver, \x3ca href=\"http://trac.openlayers.org/wiki/${layerLib}\" target=\"_blank\"\x3ewi mer dat aan et Loufe brengk\x3c/a\x3e.",'Scale = 1 : ${scaleDenom}':"Mohßshtaab = 1 : ${scaleDenom}",'W':"W",'E':"O",'N':"N",'S':"S",'reprojectDeprecated':"Do bruchs de Ußwahl \x3ccode\x3ereproject\x3c/code\x3e op däm Nivvoh \x3ccode\x3e${layerName}\x3c/code\x3e. Di Ußwahl es nit mieh jähn jesinn. Se wohr doför jedaach, öm Date op jeschääfsmäßesch eruß jejovve Kaate bovve drop ze moole, wat ävver enzwesche besser met dä Öngershtözung för de ßfääresche Mäkaator Beldscher jeiht. Doh kanns De mieh drövver fenge op dä Sigg: http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Hee di Metood es nim_mih aktoäll un et weed se en dä Version 3.0 nit mieh jävve. Nemm \x3ccode\x3e${newMethod}\x3c/code\x3e doföör."});OpenLayers.Lang["fur"]=OpenLayers.Util.applyDefaults({'Permalink':"Leam Permanent",'Overlays':"Livei parsore",'Base Layer':"Livel di base",'browserNotSupported':"Il to sgarfadôr nol supuarte la renderizazion vetoriâl. Al moment a son supuartâts:\n${renderers}",'Scale = 1 : ${scaleDenom}':"Scjale = 1 : ${scaleDenom}",'W':"O",'E':"E",'N':"N",'S':"S"});OpenLayers.Lang["ja"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"未処理の要求は ${statusText} を返します",'Permalink':"パーマリンク",'Overlays':"オーバーレイ",'Base Layer':"基底レイヤー",'noFID':"FID のない地物は更新できません。",'browserNotSupported':"あなたのブラウザはベクターグラフィックスの描写に対応していません。現時点で対応しているソフトウェアは以下のものです。\n${renderers}",'minZoomLevelError':"minZoomLevel プロパティは FixedZoomLevels を継承するレイヤーでの使用のみを想定しています。この minZoomLevel に対する WFS レイヤーの検査は歴史的なものです。しかしながら、この検査を除去するとそれに依存する OpenLayers ベースのアプリケーションを破壊してしまう可能性があります。よって廃止が予定されており、この minZoomLevel 検査はバージョン3.0で除去されます。代わりに、http://trac.openlayers.org/wiki/SettingZoomLevels で解説されている、最小および最大解像度設定を使用してください。",'commitSuccess':"WFS トランザクション: 成功 ${response}",'commitFailed':"WFS トランザクション: 失敗 ${response}",'googleWarning':"Google レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは Google マップ用ライブラリのスクリプトが組み込まれていないか、あなたのサイトに対応する正しい API キーが設定されていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'getLayerWarning':"${layerType} レイヤーが正しく読み込みを行えませんでした。\x3cbr\x3e\x3cbr\x3eこのメッセージを消すには、右上の隅にあるレイヤー切り替え部分で新しい基底レイヤーを選んでください。\x3cbr\x3e\x3cbr\x3eおそらく、これは ${layerLib} ライブラリのスクリプトが正しく組み込まれていないためです。\x3cbr\x3e\x3cbr\x3e開発者の方へ: 正しい動作をさせるために\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eこちらのウィキ\x3c/a\x3eを参照してください。",'Scale = 1 : ${scaleDenom}':"縮尺 = 1 : ${scaleDenom}",'W':"西",'E':"東",'N':"北",'S':"南",'reprojectDeprecated':"あなたは「${layerName}」レイヤーで reproject オプションを使っています。このオプションは商用の基底地図上に情報を表示する目的で設計されましたが、現在ではその機能は Spherical Mercator サポートを利用して実現されており、このオプションの使用は非推奨です。追加の情報は http://trac.openlayers.org/wiki/SphericalMercator で入手できます。",'methodDeprecated':"このメソッドは廃止が予定されており、バージョン3.0で除去されます。代わりに ${newMethod} を使用してください。"});(function(){var oXMLHttpRequest=window.XMLHttpRequest;var bGecko=!!window.controllers,bIE=window.document.all&&!window.opera,bIE7=bIE&&window.navigator.userAgent.match(/MSIE 7.0/);function fXMLHttpRequest(){this._object=oXMLHttpRequest&&!bIE7?new oXMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[];};function cXMLHttpRequest(){return new fXMLHttpRequest;};cXMLHttpRequest.prototype=fXMLHttpRequest.prototype;if(bGecko&&oXMLHttpRequest.wrapped)
+cXMLHttpRequest.wrapped=oXMLHttpRequest.wrapped;cXMLHttpRequest.UNSENT=0;cXMLHttpRequest.OPENED=1;cXMLHttpRequest.HEADERS_RECEIVED=2;cXMLHttpRequest.LOADING=3;cXMLHttpRequest.DONE=4;cXMLHttpRequest.prototype.readyState=cXMLHttpRequest.UNSENT;cXMLHttpRequest.prototype.responseText='';cXMLHttpRequest.prototype.responseXML=null;cXMLHttpRequest.prototype.status=0;cXMLHttpRequest.prototype.statusText='';cXMLHttpRequest.prototype.priority="NORMAL";cXMLHttpRequest.prototype.onreadystatechange=null;cXMLHttpRequest.onreadystatechange=null;cXMLHttpRequest.onopen=null;cXMLHttpRequest.onsend=null;cXMLHttpRequest.onabort=null;cXMLHttpRequest.prototype.open=function(sMethod,sUrl,bAsync,sUser,sPassword){delete this._headers;if(arguments.length<3)
+bAsync=true;this._async=bAsync;var oRequest=this,nState=this.readyState,fOnUnload;if(bIE&&bAsync){fOnUnload=function(){if(nState!=cXMLHttpRequest.DONE){fCleanTransport(oRequest);oRequest.abort();}};window.attachEvent("onunload",fOnUnload);}
+if(cXMLHttpRequest.onopen)
+cXMLHttpRequest.onopen.apply(this,arguments);if(arguments.length>4)
+this._object.open(sMethod,sUrl,bAsync,sUser,sPassword);else
+if(arguments.length>3)
+this._object.open(sMethod,sUrl,bAsync,sUser);else
+this._object.open(sMethod,sUrl,bAsync);this.readyState=cXMLHttpRequest.OPENED;fReadyStateChange(this);this._object.onreadystatechange=function(){if(bGecko&&!bAsync)
+return;oRequest.readyState=oRequest._object.readyState;fSynchronizeValues(oRequest);if(oRequest._aborted){oRequest.readyState=cXMLHttpRequest.UNSENT;return;}
+if(oRequest.readyState==cXMLHttpRequest.DONE){delete oRequest._data;fCleanTransport(oRequest);if(bIE&&bAsync)
+window.detachEvent("onunload",fOnUnload);}
+if(nState!=oRequest.readyState)
+fReadyStateChange(oRequest);nState=oRequest.readyState;}};function fXMLHttpRequest_send(oRequest){oRequest._object.send(oRequest._data);if(bGecko&&!oRequest._async){oRequest.readyState=cXMLHttpRequest.OPENED;fSynchronizeValues(oRequest);while(oRequest.readyState<cXMLHttpRequest.DONE){oRequest.readyState++;fReadyStateChange(oRequest);if(oRequest._aborted)
+return;}}};cXMLHttpRequest.prototype.send=function(vData){if(cXMLHttpRequest.onsend)
+cXMLHttpRequest.onsend.apply(this,arguments);if(!arguments.length)
+vData=null;if(vData&&vData.nodeType){vData=window.XMLSerializer?new window.XMLSerializer().serializeToString(vData):vData.xml;if(!this._headers["Content-Type"])
+this._object.setRequestHeader("Content-Type","application/xml");}
+this._data=vData;fXMLHttpRequest_send(this);};cXMLHttpRequest.prototype.abort=function(){if(cXMLHttpRequest.onabort)
+cXMLHttpRequest.onabort.apply(this,arguments);if(this.readyState>cXMLHttpRequest.UNSENT)
+this._aborted=true;this._object.abort();fCleanTransport(this);this.readyState=cXMLHttpRequest.UNSENT;delete this._data;};cXMLHttpRequest.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders();};cXMLHttpRequest.prototype.getResponseHeader=function(sName){return this._object.getResponseHeader(sName);};cXMLHttpRequest.prototype.setRequestHeader=function(sName,sValue){if(!this._headers)
+this._headers={};this._headers[sName]=sValue;return this._object.setRequestHeader(sName,sValue);};cXMLHttpRequest.prototype.addEventListener=function(sName,fHandler,bUseCapture){for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
+if(oListener[0]==sName&&oListener[1]==fHandler&&oListener[2]==bUseCapture)
+return;this._listeners.push([sName,fHandler,bUseCapture]);};cXMLHttpRequest.prototype.removeEventListener=function(sName,fHandler,bUseCapture){for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
+if(oListener[0]==sName&&oListener[1]==fHandler&&oListener[2]==bUseCapture)
+break;if(oListener)
+this._listeners.splice(nIndex,1);};cXMLHttpRequest.prototype.dispatchEvent=function(oEvent){var oEventPseudo={'type':oEvent.type,'target':this,'currentTarget':this,'eventPhase':2,'bubbles':oEvent.bubbles,'cancelable':oEvent.cancelable,'timeStamp':oEvent.timeStamp,'stopPropagation':function(){},'preventDefault':function(){},'initEvent':function(){}};if(oEventPseudo.type=="readystatechange"&&this.onreadystatechange)
+(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[oEventPseudo]);for(var nIndex=0,oListener;oListener=this._listeners[nIndex];nIndex++)
+if(oListener[0]==oEventPseudo.type&&!oListener[2])
+(oListener[1].handleEvent||oListener[1]).apply(this,[oEventPseudo]);};cXMLHttpRequest.prototype.toString=function(){return'['+"object"+' '+"XMLHttpRequest"+']';};cXMLHttpRequest.toString=function(){return'['+"XMLHttpRequest"+']';};function fReadyStateChange(oRequest){if(cXMLHttpRequest.onreadystatechange)
+cXMLHttpRequest.onreadystatechange.apply(oRequest);oRequest.dispatchEvent({'type':"readystatechange",'bubbles':false,'cancelable':false,'timeStamp':new Date+0});};function fGetDocument(oRequest){var oDocument=oRequest.responseXML,sResponse=oRequest.responseText;if(bIE&&sResponse&&oDocument&&!oDocument.documentElement&&oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)){oDocument=new window.ActiveXObject("Microsoft.XMLDOM");oDocument.async=false;oDocument.validateOnParse=false;oDocument.loadXML(sResponse);}
+if(oDocument)
+if((bIE&&oDocument.parseError!=0)||!oDocument.documentElement||(oDocument.documentElement&&oDocument.documentElement.tagName=="parsererror"))
+return null;return oDocument;};function fSynchronizeValues(oRequest){try{oRequest.responseText=oRequest._object.responseText;}catch(e){}
+try{oRequest.responseXML=fGetDocument(oRequest._object);}catch(e){}
+try{oRequest.status=oRequest._object.status;}catch(e){}
+try{oRequest.statusText=oRequest._object.statusText;}catch(e){}};function fCleanTransport(oRequest){oRequest._object.onreadystatechange=new window.Function;};if(!window.Function.prototype.apply){window.Function.prototype.apply=function(oRequest,oArguments){if(!oArguments)
+oArguments=[];oRequest.__func=this;oRequest.__func(oArguments[0],oArguments[1],oArguments[2],oArguments[3],oArguments[4]);delete oRequest.__func;};};OpenLayers.Request.XMLHttpRequest=cXMLHttpRequest;})();OpenLayers.Lang["nds"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Unbehannelt Trüchmellels för de Anfraag ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Achtergrundkoort",'noFID':"En Feature, dat keen FID hett, kann nich aktuell maakt warrn.",'browserNotSupported':"Dien Browser ünnerstütt keen Vektorbiller. Ünnerstütt Renderers:\n${renderers}",'commitSuccess':"WFS-Transakschoon: hett klappt ${response}",'commitFailed':"WFS-Transakschoon: hett nich klappt ${response}",'Scale = 1 : ${scaleDenom}':"Skaal = 1 : ${scaleDenom}",'methodDeprecated':"Disse Methood is oold un schall dat in 3.0 nich mehr geven. Bruuk dor man beter ${newMethod} för."});OpenLayers.Handler.RegularPolygon=OpenLayers.Class(OpenLayers.Handler.Drag,{sides:4,radius:null,snapAngle:null,snapToggle:'shiftKey',layerOptions:null,persist:false,irregular:false,citeCompliant:false,angle:null,fixedRadius:false,feature:null,layer:null,origin:null,initialize:function(control,callbacks,options){if(!(options&&options.layerOptions&&options.layerOptions.styleMap)){this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'],{});}
+OpenLayers.Handler.Drag.prototype.initialize.apply(this,[control,callbacks,options]);this.options=(options)?options:{};},setOptions:function(newOptions){OpenLayers.Util.extend(this.options,newOptions);OpenLayers.Util.extend(this,newOptions);},activate:function(){var activated=false;if(OpenLayers.Handler.Drag.prototype.activate.apply(this,arguments)){var options=OpenLayers.Util.extend({displayInLayerSwitcher:false,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,options);this.map.addLayer(this.layer);activated=true;}
+return activated;},deactivate:function(){var deactivated=false;if(OpenLayers.Handler.Drag.prototype.deactivate.apply(this,arguments)){if(this.dragging){this.cancel();}
+if(this.layer.map!=null){this.layer.destroy(false);if(this.feature){this.feature.destroy();}}
+this.layer=null;this.feature=null;deactivated=true;}
+return deactivated;},down:function(evt){this.fixedRadius=!!(this.radius);var maploc=this.layer.getLonLatFromViewPortPx(evt.xy);this.origin=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(!this.fixedRadius||this.irregular){this.radius=this.map.getResolution();}
+if(this.persist){this.clear();}
+this.feature=new OpenLayers.Feature.Vector();this.createGeometry();this.callback("create",[this.origin,this.feature]);this.layer.addFeatures([this.feature],{silent:true});this.layer.drawFeature(this.feature,this.style);},move:function(evt){var maploc=this.layer.getLonLatFromViewPortPx(evt.xy);var point=new OpenLayers.Geometry.Point(maploc.lon,maploc.lat);if(this.irregular){var ry=Math.sqrt(2)*Math.abs(point.y-this.origin.y)/2;this.radius=Math.max(this.map.getResolution()/2,ry);}else if(this.fixedRadius){this.origin=point;}else{this.calculateAngle(point,evt);this.radius=Math.max(this.map.getResolution()/2,point.distanceTo(this.origin));}
+this.modifyGeometry();if(this.irregular){var dx=point.x-this.origin.x;var dy=point.y-this.origin.y;var ratio;if(dy==0){ratio=dx/(this.radius*Math.sqrt(2));}else{ratio=dx/dy;}
+this.feature.geometry.resize(1,this.origin,ratio);this.feature.geometry.move(dx/2,dy/2);}
+this.layer.drawFeature(this.feature,this.style);},up:function(evt){this.finalize();if(this.start==this.last){this.callback("done",[evt.xy]);}},out:function(evt){this.finalize();},createGeometry:function(){this.angle=Math.PI*((1/this.sides)-(1/2));if(this.snapAngle){this.angle+=this.snapAngle*(Math.PI/180);}
+this.feature.geometry=OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin,this.radius,this.sides,this.snapAngle);},modifyGeometry:function(){var angle,point;var ring=this.feature.geometry.components[0];if(ring.components.length!=(this.sides+1)){this.createGeometry();ring=this.feature.geometry.components[0];}
+for(var i=0;i<this.sides;++i){point=ring.components[i];angle=this.angle+(i*2*Math.PI/this.sides);point.x=this.origin.x+(this.radius*Math.cos(angle));point.y=this.origin.y+(this.radius*Math.sin(angle));point.clearBounds();}},calculateAngle:function(point,evt){var alpha=Math.atan2(point.y-this.origin.y,point.x-this.origin.x);if(this.snapAngle&&(this.snapToggle&&!evt[this.snapToggle])){var snapAngleRad=(Math.PI/180)*this.snapAngle;this.angle=Math.round(alpha/snapAngleRad)*snapAngleRad;}else{this.angle=alpha;}},cancel:function(){this.callback("cancel",null);this.finalize();},finalize:function(){this.origin=null;this.radius=this.options.radius;},clear:function(){if(this.layer){this.layer.renderer.clear();this.layer.destroyFeatures();}},callback:function(name,args){if(this.callbacks[name]){this.callbacks[name].apply(this.control,[this.feature.geometry.clone()]);}
+if(!this.persist&&(name=="done"||name=="cancel")){this.clear();}},CLASS_NAME:"OpenLayers.Handler.RegularPolygon"});OpenLayers.Renderer.VML=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"urn:schemas-microsoft-com:vml",symbolCache:{},offset:null,initialize:function(containerID){if(!this.supported()){return;}
+if(!document.namespaces.olv){document.namespaces.add("olv",this.xmlns);var style=document.createStyleSheet();var shapes=['shape','rect','oval','fill','stroke','imagedata','group','textbox'];for(var i=0,len=shapes.length;i<len;i++){style.addRule('olv\\:'+shapes[i],"behavior: url(#default#VML); "+"position: absolute; display: inline-block;");}}
+OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments);},supported:function(){return!!(document.namespaces);},setExtent:function(extent,resolutionChanged){var coordSysUnchanged=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments);var resolution=this.getResolution();var left=(extent.left/resolution)|0;var top=(extent.top/resolution-this.size.h)|0;if(resolutionChanged||!this.offset){this.offset={x:left,y:top};left=0;top=0;}else{left=left-this.offset.x;top=top-this.offset.y;}
+var org=(left-this.xOffset)+" "+top;this.root.coordorigin=org;var roots=[this.root,this.vectorRoot,this.textRoot];var root;for(var i=0,len=roots.length;i<len;++i){root=roots[i];var size=this.size.w+" "+this.size.h;root.coordsize=size;}
+this.root.style.flip="y";return coordSysUnchanged;},setSize:function(size){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);var roots=[this.rendererRoot,this.root,this.vectorRoot,this.textRoot];var w=this.size.w+"px";var h=this.size.h+"px";var root;for(var i=0,len=roots.length;i<len;++i){root=roots[i];root.style.width=w;root.style.height=h;}},getNodeType:function(geometry,style){var nodeType=null;switch(geometry.CLASS_NAME){case"OpenLayers.Geometry.Point":if(style.externalGraphic){nodeType="olv:rect";}else if(this.isComplexSymbol(style.graphicName)){nodeType="olv:shape";}else{nodeType="olv:oval";}
+break;case"OpenLayers.Geometry.Rectangle":nodeType="olv:rect";break;case"OpenLayers.Geometry.LineString":case"OpenLayers.Geometry.LinearRing":case"OpenLayers.Geometry.Polygon":case"OpenLayers.Geometry.Curve":nodeType="olv:shape";break;default:break;}
+return nodeType;},setStyle:function(node,style,options,geometry){style=style||node._style;options=options||node._options;var fillColor=style.fillColor;if(node._geometryClass==="OpenLayers.Geometry.Point"){if(style.externalGraphic){options.isFilled=true;if(style.graphicTitle){node.title=style.graphicTitle;}
+var width=style.graphicWidth||style.graphicHeight;var height=style.graphicHeight||style.graphicWidth;width=width?width:style.pointRadius*2;height=height?height:style.pointRadius*2;var resolution=this.getResolution();var xOffset=(style.graphicXOffset!=undefined)?style.graphicXOffset:-(0.5*width);var yOffset=(style.graphicYOffset!=undefined)?style.graphicYOffset:-(0.5*height);node.style.left=((((geometry.x-this.featureDx)/resolution-this.offset.x)+xOffset)|0)+"px";node.style.top=(((geometry.y/resolution-this.offset.y)-(yOffset+height))|0)+"px";node.style.width=width+"px";node.style.height=height+"px";node.style.flip="y";fillColor="none";options.isStroked=false;}else if(this.isComplexSymbol(style.graphicName)){var cache=this.importSymbol(style.graphicName);node.path=cache.path;node.coordorigin=cache.left+","+cache.bottom;var size=cache.size;node.coordsize=size+","+size;this.drawCircle(node,geometry,style.pointRadius);node.style.flip="y";}else{this.drawCircle(node,geometry,style.pointRadius);}}
+if(options.isFilled){node.fillcolor=fillColor;}else{node.filled="false";}
+var fills=node.getElementsByTagName("fill");var fill=(fills.length==0)?null:fills[0];if(!options.isFilled){if(fill){node.removeChild(fill);}}else{if(!fill){fill=this.createNode('olv:fill',node.id+"_fill");}
+fill.opacity=style.fillOpacity;if(node._geometryClass==="OpenLayers.Geometry.Point"&&style.externalGraphic){if(style.graphicOpacity){fill.opacity=style.graphicOpacity;}
+fill.src=style.externalGraphic;fill.type="frame";if(!(style.graphicWidth&&style.graphicHeight)){fill.aspect="atmost";}}
+if(fill.parentNode!=node){node.appendChild(fill);}}
+var rotation=style.rotation;if((rotation!==undefined||node._rotation!==undefined)){node._rotation=rotation;if(style.externalGraphic){this.graphicRotate(node,xOffset,yOffset,style);fill.opacity=0;}else if(node._geometryClass==="OpenLayers.Geometry.Point"){node.style.rotation=rotation||0;}}
+var strokes=node.getElementsByTagName("stroke");var stroke=(strokes.length==0)?null:strokes[0];if(!options.isStroked){node.stroked=false;if(stroke){stroke.on=false;}}else{if(!stroke){stroke=this.createNode('olv:stroke',node.id+"_stroke");node.appendChild(stroke);}
+stroke.on=true;stroke.color=style.strokeColor;stroke.weight=style.strokeWidth+"px";stroke.opacity=style.strokeOpacity;stroke.endcap=style.strokeLinecap=='butt'?'flat':(style.strokeLinecap||'round');if(style.strokeDashstyle){stroke.dashstyle=this.dashStyle(style);}}
+if(style.cursor!="inherit"&&style.cursor!=null){node.style.cursor=style.cursor;}
+return node;},graphicRotate:function(node,xOffset,yOffset,style){var style=style||node._style;var rotation=style.rotation||0;var aspectRatio,size;if(!(style.graphicWidth&&style.graphicHeight)){var img=new Image();img.onreadystatechange=OpenLayers.Function.bind(function(){if(img.readyState=="complete"||img.readyState=="interactive"){aspectRatio=img.width/img.height;size=Math.max(style.pointRadius*2,style.graphicWidth||0,style.graphicHeight||0);xOffset=xOffset*aspectRatio;style.graphicWidth=size*aspectRatio;style.graphicHeight=size;this.graphicRotate(node,xOffset,yOffset,style);}},this);img.src=style.externalGraphic;return;}else{size=Math.max(style.graphicWidth,style.graphicHeight);aspectRatio=style.graphicWidth/style.graphicHeight;}
+var width=Math.round(style.graphicWidth||size*aspectRatio);var height=Math.round(style.graphicHeight||size);node.style.width=width+"px";node.style.height=height+"px";var image=document.getElementById(node.id+"_image");if(!image){image=this.createNode("olv:imagedata",node.id+"_image");node.appendChild(image);}
+image.style.width=width+"px";image.style.height=height+"px";image.src=style.externalGraphic;image.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader("+"src='', sizingMethod='scale')";var rot=rotation*Math.PI/180;var sintheta=Math.sin(rot);var costheta=Math.cos(rot);var filter="progid:DXImageTransform.Microsoft.Matrix(M11="+costheta+",M12="+(-sintheta)+",M21="+sintheta+",M22="+costheta+",SizingMethod='auto expand')\n";var opacity=style.graphicOpacity||style.fillOpacity;if(opacity&&opacity!=1){filter+="progid:DXImageTransform.Microsoft.BasicImage(opacity="+
+opacity+")\n";}
+node.style.filter=filter;var centerPoint=new OpenLayers.Geometry.Point(-xOffset,-yOffset);var imgBox=new OpenLayers.Bounds(0,0,width,height).toGeometry();imgBox.rotate(style.rotation,centerPoint);var imgBounds=imgBox.getBounds();node.style.left=Math.round(parseInt(node.style.left)+imgBounds.left)+"px";node.style.top=Math.round(parseInt(node.style.top)-imgBounds.bottom)+"px";},postDraw:function(node){node.style.visibility="visible";var fillColor=node._style.fillColor;var strokeColor=node._style.strokeColor;if(fillColor=="none"&&node.fillcolor!=fillColor){node.fillcolor=fillColor;}
+if(strokeColor=="none"&&node.strokecolor!=strokeColor){node.strokecolor=strokeColor;}},setNodeDimension:function(node,geometry){var bbox=geometry.getBounds();if(bbox){var resolution=this.getResolution();var scaledBox=new OpenLayers.Bounds(((bbox.left-this.featureDx)/resolution-this.offset.x)|0,(bbox.bottom/resolution-this.offset.y)|0,((bbox.right-this.featureDx)/resolution-this.offset.x)|0,(bbox.top/resolution-this.offset.y)|0);node.style.left=scaledBox.left+"px";node.style.top=scaledBox.top+"px";node.style.width=scaledBox.getWidth()+"px";node.style.height=scaledBox.getHeight()+"px";node.coordorigin=scaledBox.left+" "+scaledBox.top;node.coordsize=scaledBox.getWidth()+" "+scaledBox.getHeight();}},dashStyle:function(style){var dash=style.strokeDashstyle;switch(dash){case'solid':case'dot':case'dash':case'dashdot':case'longdash':case'longdashdot':return dash;default:var parts=dash.split(/[ ,]/);if(parts.length==2){if(1*parts[0]>=2*parts[1]){return"longdash";}
+return(parts[0]==1||parts[1]==1)?"dot":"dash";}else if(parts.length==4){return(1*parts[0]>=2*parts[1])?"longdashdot":"dashdot";}
+return"solid";}},createNode:function(type,id){var node=document.createElement(type);if(id){node.id=id;}
+node.unselectable='on';node.onselectstart=OpenLayers.Function.False;return node;},nodeTypeCompare:function(node,type){var subType=type;var splitIndex=subType.indexOf(":");if(splitIndex!=-1){subType=subType.substr(splitIndex+1);}
+var nodeName=node.nodeName;splitIndex=nodeName.indexOf(":");if(splitIndex!=-1){nodeName=nodeName.substr(splitIndex+1);}
+return(subType==nodeName);},createRenderRoot:function(){return this.nodeFactory(this.container.id+"_vmlRoot","div");},createRoot:function(suffix){return this.nodeFactory(this.container.id+suffix,"olv:group");},drawPoint:function(node,geometry){return this.drawCircle(node,geometry,1);},drawCircle:function(node,geometry,radius){if(!isNaN(geometry.x)&&!isNaN(geometry.y)){var resolution=this.getResolution();node.style.left=((((geometry.x-this.featureDx)/resolution-this.offset.x)|0)-radius)+"px";node.style.top=(((geometry.y/resolution-this.offset.y)|0)-radius)+"px";var diameter=radius*2;node.style.width=diameter+"px";node.style.height=diameter+"px";return node;}
+return false;},drawLineString:function(node,geometry){return this.drawLine(node,geometry,false);},drawLinearRing:function(node,geometry){return this.drawLine(node,geometry,true);},drawLine:function(node,geometry,closeLine){this.setNodeDimension(node,geometry);var resolution=this.getResolution();var numComponents=geometry.components.length;var parts=new Array(numComponents);var comp,x,y;for(var i=0;i<numComponents;i++){comp=geometry.components[i];x=((comp.x-this.featureDx)/resolution-this.offset.x)|0;y=(comp.y/resolution-this.offset.y)|0;parts[i]=" "+x+","+y+" l ";}
+var end=(closeLine)?" x e":" e";node.path="m"+parts.join("")+end;return node;},drawPolygon:function(node,geometry){this.setNodeDimension(node,geometry);var resolution=this.getResolution();var path=[];var j,jj,points,area,first,second,i,ii,comp,pathComp,x,y;for(j=0,jj=geometry.components.length;j<jj;j++){path.push("m");points=geometry.components[j].components;area=(j===0);first=null;second=null;for(i=0,ii=points.length;i<ii;i++){comp=points[i];x=((comp.x-this.featureDx)/resolution-this.offset.x)|0;y=(comp.y/resolution-this.offset.y)|0;pathComp=" "+x+","+y;path.push(pathComp);if(i==0){path.push(" l");}
+if(!area){if(!first){first=pathComp;}else if(first!=pathComp){if(!second){second=pathComp;}else if(second!=pathComp){area=true;}}}}
+path.push(area?" x ":" ");}
+path.push("e");node.path=path.join("");return node;},drawRectangle:function(node,geometry){var resolution=this.getResolution();node.style.left=(((geometry.x-this.featureDx)/resolution-this.offset.x)|0)+"px";node.style.top=((geometry.y/resolution-this.offset.y)|0)+"px";node.style.width=((geometry.width/resolution)|0)+"px";node.style.height=((geometry.height/resolution)|0)+"px";return node;},drawText:function(featureId,style,location){var label=this.nodeFactory(featureId+this.LABEL_ID_SUFFIX,"olv:rect");var textbox=this.nodeFactory(featureId+this.LABEL_ID_SUFFIX+"_textbox","olv:textbox");var resolution=this.getResolution();label.style.left=(((location.x-this.featureDx)/resolution-this.offset.x)|0)+"px";label.style.top=((location.y/resolution-this.offset.y)|0)+"px";label.style.flip="y";textbox.innerText=style.label;if(style.cursor!="inherit"&&style.cursor!=null){textbox.style.cursor=style.cursor;}
+if(style.fontColor){textbox.style.color=style.fontColor;}
+if(style.fontOpacity){textbox.style.filter='alpha(opacity='+(style.fontOpacity*100)+')';}
+if(style.fontFamily){textbox.style.fontFamily=style.fontFamily;}
+if(style.fontSize){textbox.style.fontSize=style.fontSize;}
+if(style.fontWeight){textbox.style.fontWeight=style.fontWeight;}
+if(style.fontStyle){textbox.style.fontStyle=style.fontStyle;}
+if(style.labelSelect===true){label._featureId=featureId;textbox._featureId=featureId;textbox._geometry=location;textbox._geometryClass=location.CLASS_NAME;}
+textbox.style.whiteSpace="nowrap";textbox.inset="1px,0px,0px,0px";if(!label.parentNode){label.appendChild(textbox);this.textRoot.appendChild(label);}
+var align=style.labelAlign||"cm";if(align.length==1){align+="m";}
+var xshift=textbox.clientWidth*(OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0,1)]);var yshift=textbox.clientHeight*(OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);label.style.left=parseInt(label.style.left)-xshift-1+"px";label.style.top=parseInt(label.style.top)+yshift+"px";},moveRoot:function(renderer){var layer=this.map.getLayer(renderer.container.id);if(layer instanceof OpenLayers.Layer.Vector.RootContainer){layer=this.map.getLayer(this.container.id);}
+layer&&layer.renderer.clear();OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this,arguments);layer&&layer.redraw();},importSymbol:function(graphicName){var id=this.container.id+"-"+graphicName;var cache=this.symbolCache[id];if(cache){return cache;}
+var symbol=OpenLayers.Renderer.symbol[graphicName];if(!symbol){throw new Error(graphicName+' is not a valid symbol name');}
+var symbolExtent=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0);var pathitems=["m"];for(var i=0;i<symbol.length;i=i+2){var x=symbol[i];var y=symbol[i+1];symbolExtent.left=Math.min(symbolExtent.left,x);symbolExtent.bottom=Math.min(symbolExtent.bottom,y);symbolExtent.right=Math.max(symbolExtent.right,x);symbolExtent.top=Math.max(symbolExtent.top,y);pathitems.push(x);pathitems.push(y);if(i==0){pathitems.push("l");}}
+pathitems.push("x e");var path=pathitems.join(" ");var diff=(symbolExtent.getWidth()-symbolExtent.getHeight())/2;if(diff>0){symbolExtent.bottom=symbolExtent.bottom-diff;symbolExtent.top=symbolExtent.top+diff;}else{symbolExtent.left=symbolExtent.left+diff;symbolExtent.right=symbolExtent.right-diff;}
+cache={path:path,size:symbolExtent.getWidth(),left:symbolExtent.left,bottom:symbolExtent.bottom};this.symbolCache[id]=cache;return cache;},CLASS_NAME:"OpenLayers.Renderer.VML"});OpenLayers.Renderer.VML.LABEL_SHIFT={"l":0,"c":.5,"r":1,"t":0,"m":.5,"b":1};OpenLayers.Lang["vi"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Không xử lý được phản hồi ${statusText} cho yêu cầu",'Permalink':"Liên kết thường trực",'Overlays':"Lấp bản đồ",'Base Layer':"Lớp nền",'noFID':"Không thể cập nhật tính năng thiếu FID.",'browserNotSupported':"Trình duyệt của bạn không hỗ trợ chức năng vẽ bằng vectơ. Hiện hỗ trợ các bộ kết xuất:\n${renderers}",'minZoomLevelError':"Chỉ nên sử dụng thuộc tính minZoomLevel với các lớp FixedZoomLevels-descendent. Việc lớp wfs này tìm cho minZoomLevel là di tích còn lại từ xưa. Tuy nhiên, nếu chúng tôi dời nó thì sẽ vỡ các chương trình OpenLayers mà dựa trên nó. Bởi vậy chúng tôi phản đối sử dụng nó\x26nbsp;– bước tìm cho minZoomLevel sẽ được dời vào phiên bản 3.0. Xin sử dụng thiết lập độ phân tích tối thiểu / tối đa thay thế, theo hướng dẫn này: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Giao dịch WFS: THÀNH CÔNG ${response}",'commitFailed':"Giao dịch WFS: THẤT BẠI ${response}",'googleWarning':"Không thể tải lớp Google đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện Google Maps hoặc không được bao gồm hoặc không chứa khóa API hợp với website của bạn.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.",'getLayerWarning':"Không thể tải lớp ${layerType} đúng đắn.\x3cbr\x3e\x3cbr\x3eĐể tránh thông báo này lần sau, hãy chọn BaseLayer mới dùng điều khiển chọn lớp ở góc trên phải.\x3cbr\x3e\x3cbr\x3eChắc script thư viện ${layerLib} không được bao gồm đúng kiểu.\x3cbr\x3e\x3cbr\x3e\x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eTrợ giúp về tính năng này\x3c/a\x3e cho người phát triển.",'Scale = 1 : ${scaleDenom}':"Tỷ lệ = 1 : ${scaleDenom}",'W':"T",'E':"Đ",'N':"B",'S':"N",'reprojectDeprecated':"Bạn đang áp dụng chế độ “reproject” vào lớp ${layerName}. Chế độ này đã bị phản đối: nó có mục đích hỗ trợ lấp dữ liệu trên các nền bản đồ thương mại; nên thực hiện hiệu ứng đó dùng tính năng Mercator Hình cầu. Có sẵn thêm chi tiết tại http://trac.openlayers.org/wiki/SphericalMercator .",'methodDeprecated':"Phương thức này đã bị phản đối và sẽ bị dời vào phiên bản 3.0. Xin hãy sử dụng ${newMethod} thay thế."});OpenLayers.Protocol=OpenLayers.Class({format:null,options:null,autoDestroy:true,defaultFilter:null,initialize:function(options){options=options||{};OpenLayers.Util.extend(this,options);this.options=options;},mergeWithDefaultFilter:function(filter){var merged;if(filter&&this.defaultFilter){merged=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.defaultFilter,filter]});}else{merged=filter||this.defaultFilter||undefined;}
+return merged;},destroy:function(){this.options=null;this.format=null;},read:function(options){options=options||{};options.filter=this.mergeWithDefaultFilter(options.filter);},create:function(){},update:function(){},"delete":function(){},commit:function(){},abort:function(response){},createCallback:function(method,response,options){return OpenLayers.Function.bind(function(){method.apply(this,[response,options]);},this);},CLASS_NAME:"OpenLayers.Protocol"});OpenLayers.Protocol.Response=OpenLayers.Class({code:null,requestType:null,last:true,features:null,data:null,reqFeatures:null,priv:null,error:null,initialize:function(options){OpenLayers.Util.extend(this,options);},success:function(){return this.code>0;},CLASS_NAME:"OpenLayers.Protocol.Response"});OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Protocol.HTTP=OpenLayers.Class(OpenLayers.Protocol,{url:null,headers:null,params:null,callback:null,scope:null,readWithPOST:false,updateWithPOST:false,deleteWithPOST:false,wildcarded:false,srsInBBOX:false,initialize:function(options){options=options||{};this.params={};this.headers={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var format=new OpenLayers.Format.QueryStringFilter({wildcarded:this.wildcarded,srsInBBOX:this.srsInBBOX});this.filterToParams=function(filter,params){return format.write(filter,params);};}},destroy:function(){this.params=null;this.headers=null;OpenLayers.Protocol.prototype.destroy.apply(this);},read:function(options){OpenLayers.Protocol.prototype.read.apply(this,arguments);options=options||{};options.params=OpenLayers.Util.applyDefaults(options.params,this.options.params);options=OpenLayers.Util.applyDefaults(options,this.options);if(options.filter&&this.filterToParams){options.params=this.filterToParams(options.filter,options.params);}
+var readWithPOST=(options.readWithPOST!==undefined)?options.readWithPOST:this.readWithPOST;var resp=new OpenLayers.Protocol.Response({requestType:"read"});if(readWithPOST){var headers=options.headers||{};headers["Content-Type"]="application/x-www-form-urlencoded";resp.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleRead,resp,options),data:OpenLayers.Util.getParameterString(options.params),headers:headers});}else{resp.priv=OpenLayers.Request.GET({url:options.url,callback:this.createCallback(this.handleRead,resp,options),params:options.params,headers:options.headers});}
+return resp;},handleRead:function(resp,options){this.handleResponse(resp,options);},create:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:features,requestType:"create"});resp.priv=OpenLayers.Request.POST({url:options.url,callback:this.createCallback(this.handleCreate,resp,options),headers:options.headers,data:this.format.write(features)});return resp;},handleCreate:function(resp,options){this.handleResponse(resp,options);},update:function(feature,options){options=options||{};var url=options.url||feature.url||this.options.url+"/"+feature.fid;options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:feature,requestType:"update"});var method=this.updateWithPOST?"POST":"PUT";resp.priv=OpenLayers.Request[method]({url:url,callback:this.createCallback(this.handleUpdate,resp,options),headers:options.headers,data:this.format.write(feature)});return resp;},handleUpdate:function(resp,options){this.handleResponse(resp,options);},"delete":function(feature,options){options=options||{};var url=options.url||feature.url||this.options.url+"/"+feature.fid;options=OpenLayers.Util.applyDefaults(options,this.options);var resp=new OpenLayers.Protocol.Response({reqFeatures:feature,requestType:"delete"});var method=this.deleteWithPOST?"POST":"DELETE";var requestOptions={url:url,callback:this.createCallback(this.handleDelete,resp,options),headers:options.headers};if(this.deleteWithPOST){requestOptions.data=this.format.write(feature);}
+resp.priv=OpenLayers.Request[method](requestOptions);return resp;},handleDelete:function(resp,options){this.handleResponse(resp,options);},handleResponse:function(resp,options){var request=resp.priv;if(options.callback){if(request.status>=200&&request.status<300){if(resp.requestType!="delete"){resp.features=this.parseFeatures(request);}
+resp.code=OpenLayers.Protocol.Response.SUCCESS;}else{resp.code=OpenLayers.Protocol.Response.FAILURE;}
+options.callback.call(options.scope,resp);}},parseFeatures:function(request){var doc=request.responseXML;if(!doc||!doc.documentElement){doc=request.responseText;}
+if(!doc||doc.length<=0){return null;}
+return this.format.read(doc);},commit:function(features,options){options=OpenLayers.Util.applyDefaults(options,this.options);var resp=[],nResponses=0;var types={};types[OpenLayers.State.INSERT]=[];types[OpenLayers.State.UPDATE]=[];types[OpenLayers.State.DELETE]=[];var feature,list,requestFeatures=[];for(var i=0,len=features.length;i<len;++i){feature=features[i];list=types[feature.state];if(list){list.push(feature);requestFeatures.push(feature);}}
+var nRequests=(types[OpenLayers.State.INSERT].length>0?1:0)+
+types[OpenLayers.State.UPDATE].length+
+types[OpenLayers.State.DELETE].length;var success=true;var finalResponse=new OpenLayers.Protocol.Response({reqFeatures:requestFeatures});function insertCallback(response){var len=response.features?response.features.length:0;var fids=new Array(len);for(var i=0;i<len;++i){fids[i]=response.features[i].fid;}
+finalResponse.insertIds=fids;callback.apply(this,[response]);}
+function callback(response){this.callUserCallback(response,options);success=success&&response.success();nResponses++;if(nResponses>=nRequests){if(options.callback){finalResponse.code=success?OpenLayers.Protocol.Response.SUCCESS:OpenLayers.Protocol.Response.FAILURE;options.callback.apply(options.scope,[finalResponse]);}}}
+var queue=types[OpenLayers.State.INSERT];if(queue.length>0){resp.push(this.create(queue,OpenLayers.Util.applyDefaults({callback:insertCallback,scope:this},options.create)));}
+queue=types[OpenLayers.State.UPDATE];for(var i=queue.length-1;i>=0;--i){resp.push(this.update(queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options.update)));}
+queue=types[OpenLayers.State.DELETE];for(var i=queue.length-1;i>=0;--i){resp.push(this["delete"](queue[i],OpenLayers.Util.applyDefaults({callback:callback,scope:this},options["delete"])));}
+return resp;},abort:function(response){if(response){response.priv.abort();}},callUserCallback:function(resp,options){var opt=options[resp.requestType];if(opt&&opt.callback){opt.callback.call(opt.scope,resp);}},CLASS_NAME:"OpenLayers.Protocol.HTTP"});OpenLayers.Lang["bg"]=OpenLayers.Util.applyDefaults({'Permalink':"Постоянна препратка",'Base Layer':"Основен слой",'Scale = 1 : ${scaleDenom}':"Мащаб = 1 : ${scaleDenom}",'methodDeprecated':"Този метод е остарял и ще бъде премахват в 3.0. Вместо него използвайте ${newMethod}."});OpenLayers.Lang["hr"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nepodržani zahtjev ${statusText}",'Permalink':"Permalink",'Overlays':"Overlays",'Base Layer':"Osnovna karta",'noFID':"Ne mogu ažurirati značajku za koju ne postoji FID.",'browserNotSupported':"Vaš preglednik ne podržava vektorsko renderiranje. Trenutno podržani rendereri su: ${renderers}",'commitSuccess':"WFS Transakcija: USPJEŠNA ${response}",'commitFailed':"WFS Transakcija: NEUSPJEŠNA ${response}",'Scale = 1 : ${scaleDenom}':"Mjerilo = 1 : ${scaleDenom}",'methodDeprecated':"Ova metoda nije odobrena i biti će maknuta u 3.0. Koristite ${newMethod}."});OpenLayers.Lang["be-tarask"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Неапрацаваны вынік запыту ${statusText}",'Permalink':"Сталая спасылка",'Overlays':"Слаі",'Base Layer':"Базавы слой",'noFID':"Немагчыма абнавіць магчымасьць, для якога не існуе FID.",'browserNotSupported':"Ваш браўзэр не падтрымлівае вэктарную графіку. У цяперашні момант падтрымліваюцца: ${renderers}",'minZoomLevelError':"Уласьцівасьць minZoomLevel прызначана толькі для выкарыстаньня са слаямі вытворнымі ад FixedZoomLevels. Тое, што  гэты wfs-слой правяраецца на minZoomLevel — рэха прошлага. Але мы ня можам выдаліць гэтую магчымасьць, таму што ад яе залежаць некаторыя заснаваныя на OL дастасаваньні. Тым ня менш, праверка minZoomLevel будзе выдаленая ў вэрсіі 3.0. Калі ласка, выкарыстоўваеце замест яе ўстаноўкі мінімальнага/максымальнага памераў, як апісана тут: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS-транзакцыя: ПОСЬПЕХ ${response}",'commitFailed':"WFS-транзакцыя: ПАМЫЛКА ${response}",'googleWarning':"Не атрымалася загрузіць слой Google. \x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3e Хутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі Google Maps ня быў уключаныя альбо не ўтрымлівае слушны API-ключ для Вашага сайта.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'getLayerWarning':"Немагчыма загрузіць слой ${layerType}.\x3cbr\x3e\x3cbr\x3eКаб пазбавіцца гэтага паведамленьня, выберыце новы базавы слой у сьпісе ў верхнім правым куце.\x3cbr\x3e\x3cbr\x3eХутчэй за ўсё, прычына ў тым, што скрыпт бібліятэкі ${layerLib} ня быў слушна ўключаны.\x3cbr\x3e\x3cbr\x3eРаспрацоўшчыкам: Для таго, каб даведацца як зрабіць так, каб усё працавала, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eнацісьніце тут\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Маштаб = 1 : ${scaleDenom}",'W':"З",'E':"У",'N':"Пн",'S':"Пд",'reprojectDeprecated':"Вы выкарыстоўваеце ўстаноўку \'reproject\' для слоя ${layerName}. Гэтая ўстаноўка зьяўляецца састарэлай: яна выкарыстоўвалася для падтрымкі паказу зьвестак на камэрцыйных базавых мапах, але гэта функцыя цяпер рэалізаваная ў убудаванай падтрымцы сфэрычнай праекцыі Мэркатара. Дадатковая інфармацыя ёсьць на http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Гэты мэтад састарэлы і будзе выдалены ў вэрсіі 3.0. Калі ласка, замест яго выкарыстоўвайце ${newMethod}."});OpenLayers.Lang["cs-CZ"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Nezpracovaná návratová hodnota ${statusText}",'Permalink':"Trvalý odkaz",'Overlays':"Překryvné vrstvy",'Base Layer':"Podkladové vrstvy",'noFID':"Nelze aktualizovat prvek, pro který neexistuje FID.",'browserNotSupported':"Váš prohlížeč nepodporuje vykreslování vektorů. Momentálně podporované nástroje jsou::\n${renderers}",'minZoomLevelError':"Vlastnost minZoomLevel by se měla používat pouze s potomky FixedZoomLevels vrstvami. To znamená, že vrstva wfs kontroluje, zda-li minZoomLevel není zbytek z minulosti.Nelze to ovšem vyjmout bez možnosti, že bychom rozbili aplikace postavené na OL, které by na tom mohly záviset. Proto tuto vlastnost nedoporučujeme používat --  kontrola minZoomLevel bude odstraněna ve verzi 3.0. Použijte prosím raději nastavení min/max podle příkaldu popsaného na: http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"WFS Transaction: ÚSPĚCH ${response}",'commitFailed':"WFS Transaction: CHYBA ${response}",'googleWarning':"Nepodařilo se správně načíst vrstvu Google.\x3cbr\x3e\x3cbr\x3eAbyste se zbavili této zprávy, zvolte jinou základní vrstvu v přepínači vrstev.\x3cbr\x3e\x3cbr\x3eTo se většinou stává, pokud nebyl načten skript, nebo neobsahuje správný klíč pro API pro tuto stránku.\x3cbr\x3e\x3cbr\x3eVývojáři: Pro pomoc, aby tohle fungovalo , \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eklikněte sem\x3c/a\x3e",'getLayerWarning':"The ${layerType} Layer was unable to load correctly.\x3cbr\x3e\x3cbr\x3eTo get rid of this message, select a new BaseLayer in the layer switcher in the upper-right corner.\x3cbr\x3e\x3cbr\x3eMost likely, this is because the ${layerLib} library script was either not correctly included.\x3cbr\x3e\x3cbr\x3eDevelopers: For help getting this working correctly, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Měřítko = 1 : ${scaleDenom}",'reprojectDeprecated':"Použil jste volbu \'reproject\' ve vrstvě ${layerName}. Tato volba není doporučená: byla zde proto, aby bylo možno zobrazovat data z okomerčních serverů, ale tato funkce je nyní zajištěna pomocí podpory Spherical Mercator. Více informací naleznete na http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Tato metoda je zavržená a bude ve verzi 3.0 odstraněna. Prosím, použijte raději ${newMethod}."});OpenLayers.Lang["br"]=OpenLayers.Util.applyDefaults({'unhandledRequest':"Distro evel reked anveret ${statusText}",'Permalink':"Peurliamm",'Overlays':"Gwiskadoù",'Base Layer':"Gwiskad diazez",'noFID':"N\'haller ket hizivaat un elfenn ma n\'eus ket a niverenn-anaout (FID) eviti.",'browserNotSupported':"N\'eo ket skoret an daskor vektorel gant ho merdeer. Setu aze an daskorerioù skoret evit ar poent :\n${renderers}",'minZoomLevelError':"Ne zleer implijout ar perzh minZoomLevel nemet evit gwiskadoù FixedZoomLevels-descendent. Ar fed ma wiria ar gwiskad WHS-se hag-eñ ez eus eus minZoomLevel zo un aspadenn gozh. Koulskoude n\'omp ket evit e ziverkañ kuit da derriñ arloadoù diazezet war OL a c\'hallfe bezañ stag outañ. Setu perak eo dispredet -- Lamet kuit e vo ar gwiriañ minZoomLevel a-is er stumm 3.0. Ober gant an arventennoù bihanañ/brasañ evel deskrivet amañ e plas : http://trac.openlayers.org/wiki/SettingZoomLevels",'commitSuccess':"Treuzgread WFS : MAT EO ${response}",'commitFailed':"Treuzgread WFS Transaction: C\'HWITET ${response}",'googleWarning':"N\'eus ket bet gallet kargañ ar gwiskad Google ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het levraoueg Google Maps pe neuze ne glot ket an alc\'hwez API gant ho lec\'hienn.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/Google\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'getLayerWarning':"N\'haller ket kargañ ar gwiskad ${layerType} ent reizh.\x3cbr\x3e\x3cbr\x3eEvit en em zizober eus ar c\'hemenn-mañ, dibabit ur BaseLayer nevez en diuzer gwiskadoù er c\'horn dehoù el laez.\x3cbr\x3e\x3cbr\x3eSur a-walc\'h eo peogwir n\'eo ket bet ensoc\'het mat al levraoueg ${layerLib}.\x3cbr\x3e\x3cbr\x3eDiorroerien : Evit gouzout penaos reizhañ an dra-se, \x3ca href=\'http://trac.openlayers.org/wiki/${layerLib}\' target=\'_blank\'\x3eclick here\x3c/a\x3e",'Scale = 1 : ${scaleDenom}':"Skeul = 1 : ${scaleDenom}",'W':"K",'E':"R",'N':"N",'S':"S",'reprojectDeprecated':"Emaoc\'h oc\'h implijout an dibarzh \'reproject\' war ar gwiskad ${layerName}. Dispredet eo an dibarzh-mañ : bet eo hag e talveze da ziskwel roadennoù war-c\'horre kartennoù diazez kenwerzhel, un dra hag a c\'haller ober bremañ gant an arc\'hwel dre skor banndres boullek Mercator. Muioc\'h a ditouroù a c\'haller da gaout war http://trac.openlayers.org/wiki/SphericalMercator.",'methodDeprecated':"Dispredet eo an daore-se ha tennet e vo kuit eus ar stumm 3.0. Grit gant ${newMethod} e plas."});OpenLayers.Control.PinchZoom=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,containerCenter:null,pinchOrigin:null,currentCenter:null,autoActivate:true,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.handler=new OpenLayers.Handler.Pinch(this,{start:this.pinchStart,move:this.pinchMove,done:this.pinchDone},this.handlerOptions);},activate:function(){var activated=OpenLayers.Control.prototype.activate.apply(this,arguments);if(activated){this.map.events.on({moveend:this.updateContainerCenter,scope:this});this.updateContainerCenter();}
+return activated;},deactivate:function(){var deactivated=OpenLayers.Control.prototype.deactivate.apply(this,arguments);if(this.map&&this.map.events){this.map.events.un({moveend:this.updateContainerCenter,scope:this});}
+return deactivated;},updateContainerCenter:function(){var container=this.map.layerContainerDiv;this.containerCenter={x:parseInt(container.style.left,10)+50,y:parseInt(container.style.top,10)+50};},pinchStart:function(evt,pinchData){this.pinchOrigin=evt.xy;this.currentCenter=evt.xy;},pinchMove:function(evt,pinchData){var scale=pinchData.scale;var containerCenter=this.containerCenter;var pinchOrigin=this.pinchOrigin;var current=evt.xy;var dx=Math.round((current.x-pinchOrigin.x)+(scale-1)*(containerCenter.x-pinchOrigin.x));var dy=Math.round((current.y-pinchOrigin.y)+(scale-1)*(containerCenter.y-pinchOrigin.y));this.applyTransform("translate("+dx+"px, "+dy+"px) scale("+scale+")");this.currentCenter=current;},applyTransform:function(transform){var style=this.map.layerContainerDiv.style;style['-webkit-transform']=transform;style['-moz-transform']=transform;},pinchDone:function(evt,start,last){this.applyTransform("");var zoom=this.map.getZoomForResolution(this.map.getResolution()/last.scale,true);if(zoom!==this.map.getZoom()||!this.currentCenter.equals(this.pinchOrigin)){var resolution=this.map.getResolutionForZoom(zoom);var location=this.map.getLonLatFromPixel(this.pinchOrigin);var zoomPixel=this.currentCenter;var size=this.map.getSize();location.lon+=resolution*((size.w/2)-zoomPixel.x);location.lat-=resolution*((size.h/2)-zoomPixel.y);this.map.div.clientWidth=this.map.div.clientWidth;this.map.setCenter(location,zoom);}},CLASS_NAME:"OpenLayers.Control.PinchZoom"});OpenLayers.Lang["io"]=OpenLayers.Util.applyDefaults({'Scale = 1 : ${scaleDenom}':"Skalo = 1 : ${scaleDenom}"});OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{roundedCorner:false,roundedCornerColor:"darkblue",layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:true,initialize:function(options){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[];if(this.roundedCorner){OpenLayers.Console.warn('roundedCorner option is deprecated');}},destroy:function(){this.clearLayersArray("base");this.clearLayersArray("data");this.map.events.un({buttonclick:this.onButtonClick,addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments);},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});if(this.outsideViewport){this.events.attachToElement(this.div);this.events.register("buttonclick",this,this.onButtonClick);}else{this.map.events.register("buttonclick",this,this.onButtonClick);}},draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();if(!this.outsideViewport){this.minimizeControl();}
+this.redraw();return this.div;},onButtonClick:function(evt){var button=evt.buttonElement;if(button===this.minimizeDiv){this.minimizeControl();}else if(button===this.maximizeDiv){this.maximizeControl();}else if(button._layerSwitcher===this.id){if(button["for"]){button=document.getElementById(button["for"]);}
+if(!button.disabled){if(button.type=="radio"){button.checked=true;this.map.setBaseLayer(this.map.getLayer(button._layer));}else{button.checked=!button.checked;this.updateMap();}}}},clearLayersArray:function(layersType){this[layersType+"LayersDiv"].innerHTML="";this[layersType+"Layers"]=[];},checkRedraw:function(){var redraw=false;if(!this.layerStates.length||(this.map.layers.length!=this.layerStates.length)){redraw=true;}else{for(var i=0,len=this.layerStates.length;i<len;i++){var layerState=this.layerStates[i];var layer=this.map.layers[i];if((layerState.name!=layer.name)||(layerState.inRange!=layer.inRange)||(layerState.id!=layer.id)||(layerState.visibility!=layer.visibility)){redraw=true;break;}}}
+return redraw;},redraw:function(){if(!this.checkRedraw()){return this.div;}
+this.clearLayersArray("base");this.clearLayersArray("data");var containsOverlays=false;var containsBaseLayers=false;var len=this.map.layers.length;this.layerStates=new Array(len);for(var i=0;i<len;i++){var layer=this.map.layers[i];this.layerStates[i]={'name':layer.name,'visibility':layer.visibility,'inRange':layer.inRange,'id':layer.id};}
+var layers=this.map.layers.slice();if(!this.ascending){layers.reverse();}
+for(var i=0,len=layers.length;i<len;i++){var layer=layers[i];var baseLayer=layer.isBaseLayer;if(layer.displayInLayerSwitcher){if(baseLayer){containsBaseLayers=true;}else{containsOverlays=true;}
+var checked=(baseLayer)?(layer==this.map.baseLayer):layer.getVisibility();var inputElem=document.createElement("input");inputElem.id=this.id+"_input_"+layer.name;inputElem.name=(baseLayer)?this.id+"_baseLayers":layer.name;inputElem.type=(baseLayer)?"radio":"checkbox";inputElem.value=layer.name;inputElem.checked=checked;inputElem.defaultChecked=checked;inputElem.className="olButton";inputElem._layer=layer.id;inputElem._layerSwitcher=this.id;if(!baseLayer&&!layer.inRange){inputElem.disabled=true;}
+var labelSpan=document.createElement("label");labelSpan["for"]=inputElem.id;OpenLayers.Element.addClass(labelSpan,"labelSpan olButton");labelSpan._layer=layer.id;labelSpan._layerSwitcher=this.id;if(!baseLayer&&!layer.inRange){labelSpan.style.color="gray";}
+labelSpan.innerHTML=layer.name;labelSpan.style.verticalAlign=(baseLayer)?"bottom":"baseline";var br=document.createElement("br");var groupArray=(baseLayer)?this.baseLayers:this.dataLayers;groupArray.push({'layer':layer,'inputElem':inputElem,'labelSpan':labelSpan});var groupDiv=(baseLayer)?this.baseLayersDiv:this.dataLayersDiv;groupDiv.appendChild(inputElem);groupDiv.appendChild(labelSpan);groupDiv.appendChild(br);}}
+this.dataLbl.style.display=(containsOverlays)?"":"none";this.baseLbl.style.display=(containsBaseLayers)?"":"none";return this.div;},updateMap:function(){for(var i=0,len=this.baseLayers.length;i<len;i++){var layerEntry=this.baseLayers[i];if(layerEntry.inputElem.checked){this.map.setBaseLayer(layerEntry.layer,false);}}
+for(var i=0,len=this.dataLayers.length;i<len;i++){var layerEntry=this.dataLayers[i];layerEntry.layer.setVisibility(layerEntry.inputElem.checked);}},maximizeControl:function(e){this.div.style.width="";this.div.style.height="";this.showControls(false);if(e!=null){OpenLayers.Event.stop(e);}},minimizeControl:function(e){this.div.style.width="0px";this.div.style.height="0px";this.showControls(true);if(e!=null){OpenLayers.Event.stop(e);}},showControls:function(minimize){this.maximizeDiv.style.display=minimize?"":"none";this.minimizeDiv.style.display=minimize?"none":"";this.layersDiv.style.display=minimize?"none":"";},loadContents:function(){this.layersDiv=document.createElement("div");this.layersDiv.id=this.id+"_layersDiv";OpenLayers.Element.addClass(this.layersDiv,"layersDiv");this.baseLbl=document.createElement("div");this.baseLbl.innerHTML=OpenLayers.i18n("Base Layer");OpenLayers.Element.addClass(this.baseLbl,"baseLbl");this.baseLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.baseLayersDiv,"baseLayersDiv");this.dataLbl=document.createElement("div");this.dataLbl.innerHTML=OpenLayers.i18n("Overlays");OpenLayers.Element.addClass(this.dataLbl,"dataLbl");this.dataLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.dataLayersDiv,"dataLayersDiv");if(this.ascending){this.layersDiv.appendChild(this.baseLbl);this.layersDiv.appendChild(this.baseLayersDiv);this.layersDiv.appendChild(this.dataLbl);this.layersDiv.appendChild(this.dataLayersDiv);}else{this.layersDiv.appendChild(this.dataLbl);this.layersDiv.appendChild(this.dataLayersDiv);this.layersDiv.appendChild(this.baseLbl);this.layersDiv.appendChild(this.baseLayersDiv);}
+this.div.appendChild(this.layersDiv);if(this.roundedCorner){OpenLayers.Rico.Corner.round(this.div,{corners:"tl bl",bgColor:"transparent",color:this.roundedCornerColor,blend:false});OpenLayers.Rico.Corner.changeOpacity(this.layersDiv,0.75);}
+var img=OpenLayers.Util.getImageLocation('layer-switcher-maximize.png');this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv",null,null,img,"absolute");OpenLayers.Element.addClass(this.maximizeDiv,"maximizeDiv olButton");this.maximizeDiv.style.display="none";this.div.appendChild(this.maximizeDiv);var img=OpenLayers.Util.getImageLocation('layer-switcher-minimize.png');this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv",null,null,img,"absolute");OpenLayers.Element.addClass(this.minimizeDiv,"minimizeDiv olButton");this.minimizeDiv.style.display="none";this.div.appendChild(this.minimizeDiv);},CLASS_NAME:"OpenLayers.Control.LayerSwitcher"});OpenLayers.Lang["el"]=OpenLayers.Util.applyDefaults({'Scale = 1 : ${scaleDenom}':"Κλίμακα ~ 1 : ${scaleDenom}"});OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,displayProjection:null,getParameters:function(url){url=url||window.location.href;var parameters=OpenLayers.Util.getParameters(url);var index=url.indexOf('#');if(index>0){url='?'+url.substring(index+1,url.length);OpenLayers.Util.extend(parameters,OpenLayers.Util.getParameters(url));}
+return parameters;},setMap:function(map){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var i=0,len=this.map.controls.length;i<len;i++){var control=this.map.controls[i];if((control!=this)&&(control.CLASS_NAME=="OpenLayers.Control.ArgParser")){if(control.displayProjection!=this.displayProjection){this.displayProjection=control.displayProjection;}
+break;}}
+if(i==this.map.controls.length){var args=this.getParameters();if(args.layers){this.layers=args.layers;this.map.events.register('addlayer',this,this.configureLayers);this.configureLayers();}
+if(args.lat&&args.lon){this.center=new OpenLayers.LonLat(parseFloat(args.lon),parseFloat(args.lat));if(args.zoom){this.zoom=parseFloat(args.zoom);}
+this.map.events.register('changebaselayer',this,this.setCenter);this.setCenter();}}},setCenter:function(){if(this.map.baseLayer){this.map.events.unregister('changebaselayer',this,this.setCenter);if(this.displayProjection){this.center.transform(this.displayProjection,this.map.getProjectionObject());}
+this.map.setCenter(this.center,this.zoom);}},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister('addlayer',this,this.configureLayers);for(var i=0,len=this.layers.length;i<len;i++){var layer=this.map.layers[i];var c=this.layers.charAt(i);if(c=="B"){this.map.setBaseLayer(layer);}else if((c=="T")||(c=="F")){layer.setVisibility(c=="T");}}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});
\ No newline at end of file
diff --git a/cookbooks/web/files/default/static/openlayers/OpenStreetMap.js b/cookbooks/web/files/default/static/openlayers/OpenStreetMap.js
new file mode 100644 (file)
index 0000000..44e338b
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * Class: OpenLayers.Layer.OSM.Mapnik
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.OSM>
+ */
+OpenLayers.Layer.OSM.Mapnik = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.Mapnik
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+            "https://a.tile.openstreetmap.org/${z}/${x}/${y}.png",
+            "https://b.tile.openstreetmap.org/${z}/${x}/${y}.png",
+            "https://c.tile.openstreetmap.org/${z}/${x}/${y}.png"
+        ];
+        options = OpenLayers.Util.extend({
+            numZoomLevels: 20,
+            attribution: "&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",
+            buffer: 0,
+            transitionEffect: "resize"
+        }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.Mapnik"
+});
+
+/**
+ * Class: OpenLayers.Layer.OSM.CycleMap
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.OSM>
+ */
+OpenLayers.Layer.OSM.CycleMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.CycleMap
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+            "http://a.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
+            "http://b.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png",
+            "http://c.tile.opencyclemap.org/cycle/${z}/${x}/${y}.png"
+        ];
+        options = OpenLayers.Util.extend({
+            numZoomLevels: 19,
+            attribution: "&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors, Tiles courtesy of <a href='http://www.opencyclemap.org'>Andy Allan</a>",
+            buffer: 0,
+            transitionEffect: "resize"
+        }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.CycleMap"
+});
+
+/**
+ * Class: OpenLayers.Layer.OSM.TransportMap
+ *
+ * Inherits from:
+ *  - <OpenLayers.Layer.OSM>
+ */
+OpenLayers.Layer.OSM.TransportMap = OpenLayers.Class(OpenLayers.Layer.OSM, {
+    /**
+     * Constructor: OpenLayers.Layer.OSM.TransportMap
+     *
+     * Parameters:
+     * name - {String}
+     * options - {Object} Hashtable of extra options to tag onto the layer
+     */
+    initialize: function(name, options) {
+        var url = [
+            "http://a.tile2.opencyclemap.org/transport/${z}/${x}/${y}.png",
+            "http://b.tile2.opencyclemap.org/transport/${z}/${x}/${y}.png",
+            "http://c.tile2.opencyclemap.org/transport/${z}/${x}/${y}.png"
+        ];
+        options = OpenLayers.Util.extend({
+            numZoomLevels: 19,
+            attribution: "&copy; <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors, Tiles courtesy of <a href='http://www.opencyclemap.org'>Andy Allan</a>",
+            buffer: 0,
+            transitionEffect: "resize"
+        }, options);
+        var newArguments = [name, url, options];
+        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
+    },
+
+    CLASS_NAME: "OpenLayers.Layer.OSM.TransportMap"
+});
diff --git a/cookbooks/web/files/default/static/openlayers/img/404.png b/cookbooks/web/files/default/static/openlayers/img/404.png
new file mode 100644 (file)
index 0000000..df0f967
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/404.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/blank.gif b/cookbooks/web/files/default/static/openlayers/img/blank.gif
new file mode 100644 (file)
index 0000000..4bcc753
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/blank.gif differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/cloud-popup-relative.png b/cookbooks/web/files/default/static/openlayers/img/cloud-popup-relative.png
new file mode 100644 (file)
index 0000000..c9fd4c4
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/cloud-popup-relative.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/drag-rectangle-off.png b/cookbooks/web/files/default/static/openlayers/img/drag-rectangle-off.png
new file mode 100644 (file)
index 0000000..382a81d
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/drag-rectangle-off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/drag-rectangle-on.png b/cookbooks/web/files/default/static/openlayers/img/drag-rectangle-on.png
new file mode 100644 (file)
index 0000000..2ed2d5b
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/drag-rectangle-on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/east-mini.png b/cookbooks/web/files/default/static/openlayers/img/east-mini.png
new file mode 100644 (file)
index 0000000..ecedc5e
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/east-mini.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/layer-switcher-maximize.png b/cookbooks/web/files/default/static/openlayers/img/layer-switcher-maximize.png
new file mode 100644 (file)
index 0000000..f346086
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/layer-switcher-maximize.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/layer-switcher-minimize.png b/cookbooks/web/files/default/static/openlayers/img/layer-switcher-minimize.png
new file mode 100644 (file)
index 0000000..b4aab0b
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/layer-switcher-minimize.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/marker-blue.png b/cookbooks/web/files/default/static/openlayers/img/marker-blue.png
new file mode 100644 (file)
index 0000000..f5b4efc
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/marker-blue.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/marker-gold.png b/cookbooks/web/files/default/static/openlayers/img/marker-gold.png
new file mode 100644 (file)
index 0000000..0b62f96
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/marker-gold.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/marker-green.png b/cookbooks/web/files/default/static/openlayers/img/marker-green.png
new file mode 100644 (file)
index 0000000..c36b164
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/marker-green.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/marker.png b/cookbooks/web/files/default/static/openlayers/img/marker.png
new file mode 100644 (file)
index 0000000..ea3e59a
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/marker.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/measuring-stick-off.png b/cookbooks/web/files/default/static/openlayers/img/measuring-stick-off.png
new file mode 100644 (file)
index 0000000..efbf63f
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/measuring-stick-off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/measuring-stick-on.png b/cookbooks/web/files/default/static/openlayers/img/measuring-stick-on.png
new file mode 100644 (file)
index 0000000..2d41c84
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/measuring-stick-on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/north-mini.png b/cookbooks/web/files/default/static/openlayers/img/north-mini.png
new file mode 100644 (file)
index 0000000..dfd7211
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/north-mini.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/panning-hand-off.png b/cookbooks/web/files/default/static/openlayers/img/panning-hand-off.png
new file mode 100644 (file)
index 0000000..d1c593e
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/panning-hand-off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/panning-hand-on.png b/cookbooks/web/files/default/static/openlayers/img/panning-hand-on.png
new file mode 100644 (file)
index 0000000..9b7e064
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/panning-hand-on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/slider.png b/cookbooks/web/files/default/static/openlayers/img/slider.png
new file mode 100644 (file)
index 0000000..4335364
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/slider.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/south-mini.png b/cookbooks/web/files/default/static/openlayers/img/south-mini.png
new file mode 100644 (file)
index 0000000..2970875
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/south-mini.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/west-mini.png b/cookbooks/web/files/default/static/openlayers/img/west-mini.png
new file mode 100644 (file)
index 0000000..363cd3d
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/west-mini.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/zoom-minus-mini.png b/cookbooks/web/files/default/static/openlayers/img/zoom-minus-mini.png
new file mode 100644 (file)
index 0000000..8f0d77f
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/zoom-minus-mini.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/zoom-plus-mini.png b/cookbooks/web/files/default/static/openlayers/img/zoom-plus-mini.png
new file mode 100644 (file)
index 0000000..a73ab4e
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/zoom-plus-mini.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/zoom-world-mini.png b/cookbooks/web/files/default/static/openlayers/img/zoom-world-mini.png
new file mode 100644 (file)
index 0000000..aebf22d
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/zoom-world-mini.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/img/zoombar.png b/cookbooks/web/files/default/static/openlayers/img/zoombar.png
new file mode 100644 (file)
index 0000000..47110ab
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/img/zoombar.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/google.css b/cookbooks/web/files/default/static/openlayers/theme/default/google.css
new file mode 100644 (file)
index 0000000..3ee757c
--- /dev/null
@@ -0,0 +1,17 @@
+.olLayerGoogleCopyright {
+    right: 3px;
+    bottom: 2px;
+    left: auto;  
+}
+.olLayerGoogleV3.olLayerGoogleCopyright {
+    bottom: 0px;
+    right: 0px !important;
+}
+.olLayerGooglePoweredBy {
+    left: 2px;
+    bottom: 2px;   
+}
+.olLayerGoogleV3.olLayerGooglePoweredBy {
+    bottom: 0px !important;
+}
+
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/ie6-style.css b/cookbooks/web/files/default/static/openlayers/theme/default/ie6-style.css
new file mode 100755 (executable)
index 0000000..a0fd7c6
--- /dev/null
@@ -0,0 +1,10 @@
+.olControlZoomPanel div {
+    background-image: url(img/zoom-panel-NOALPHA.png);
+}
+.olControlPanPanel div {
+    background-image: url(img/pan-panel-NOALPHA.png);
+}
+.olControlEditingToolbar {
+    width: 200px;
+}
+
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_off.png
new file mode 100644 (file)
index 0000000..26c0233
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_on.png
new file mode 100644 (file)
index 0000000..1294a2c
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/add_point_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/blank.gif b/cookbooks/web/files/default/static/openlayers/theme/default/img/blank.gif
new file mode 100644 (file)
index 0000000..4bcc753
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/blank.gif differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/close.gif b/cookbooks/web/files/default/static/openlayers/theme/default/img/close.gif
new file mode 100644 (file)
index 0000000..a8958de
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/close.gif differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-off.png
new file mode 100644 (file)
index 0000000..382a81d
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-on.png
new file mode 100644 (file)
index 0000000..2ed2d5b
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/drag-rectangle-on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_off.png
new file mode 100644 (file)
index 0000000..a4d67b3
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_on.png
new file mode 100644 (file)
index 0000000..90dcf3e
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_line_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_off.png
new file mode 100644 (file)
index 0000000..5633407
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_on.png
new file mode 100644 (file)
index 0000000..fff50b7
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_point_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_off.png
new file mode 100644 (file)
index 0000000..917af35
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_on.png
new file mode 100644 (file)
index 0000000..05a2cc5
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/draw_polygon_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/editing_tool_bar.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/editing_tool_bar.png
new file mode 100644 (file)
index 0000000..5977856
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/editing_tool_bar.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_off.png
new file mode 100644 (file)
index 0000000..ed4472d
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_on.png
new file mode 100644 (file)
index 0000000..62226a2
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/move_feature_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/navigation_history.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/navigation_history.png
new file mode 100644 (file)
index 0000000..84e3489
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/navigation_history.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/overview_replacement.gif b/cookbooks/web/files/default/static/openlayers/theme/default/img/overview_replacement.gif
new file mode 100644 (file)
index 0000000..a82cf5f
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/overview_replacement.gif differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel-NOALPHA.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel-NOALPHA.png
new file mode 100644 (file)
index 0000000..6987268
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel-NOALPHA.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel.png
new file mode 100644 (file)
index 0000000..dfe6748
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan-panel.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/pan_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan_off.png
new file mode 100644 (file)
index 0000000..30b2aed
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/pan_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan_on.png
new file mode 100644 (file)
index 0000000..e3953a8
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/pan_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-off.png
new file mode 100644 (file)
index 0000000..d1c593e
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-on.png
new file mode 100644 (file)
index 0000000..9b7e064
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/panning-hand-on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_off.png
new file mode 100644 (file)
index 0000000..76c8606
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_on.png
new file mode 100644 (file)
index 0000000..cc8d7b2
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/remove_point_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/ruler.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/ruler.png
new file mode 100644 (file)
index 0000000..aa4883b
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/ruler.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_off.png
new file mode 100644 (file)
index 0000000..3d305b6
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_on.png
new file mode 100644 (file)
index 0000000..5640ae8
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/save_features_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_off.png
new file mode 100644 (file)
index 0000000..9149a24
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_on.png
new file mode 100644 (file)
index 0000000..e41fb7b
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_next_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_off.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_off.png
new file mode 100644 (file)
index 0000000..8a9ef21
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_off.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_on.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_on.png
new file mode 100644 (file)
index 0000000..c009c25
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/view_previous_on.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel-NOALPHA.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel-NOALPHA.png
new file mode 100644 (file)
index 0000000..cdde6fc
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel-NOALPHA.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel.png b/cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel.png
new file mode 100644 (file)
index 0000000..c91a4ef
Binary files /dev/null and b/cookbooks/web/files/default/static/openlayers/theme/default/img/zoom-panel.png differ
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/style.css b/cookbooks/web/files/default/static/openlayers/theme/default/style.css
new file mode 100644 (file)
index 0000000..8e0abb7
--- /dev/null
@@ -0,0 +1,484 @@
+div.olMap {
+    z-index: 0;
+    padding: 0 !important;
+    margin: 0 !important;
+    cursor: default;
+}
+
+div.olMapViewport {
+    text-align: left;
+}
+
+div.olLayerDiv {
+   -moz-user-select: none;
+   -khtml-user-select: none;
+}
+
+.olLayerGoogleCopyright {
+    left: 2px;
+    bottom: 2px;
+}
+.olLayerGoogleV3.olLayerGoogleCopyright {
+    right: auto !important;
+}
+.olLayerGooglePoweredBy {
+    left: 2px;
+    bottom: 15px;
+}
+.olLayerGoogleV3.olLayerGooglePoweredBy {
+    bottom: 15px !important;
+}
+.olControlAttribution {
+    font-size: smaller;
+    right: 3px;
+    bottom: 4.5em;
+    position: absolute;
+    display: block;
+}
+.olControlScale {
+    right: 3px;
+    bottom: 3em;
+    display: block;
+    position: absolute;
+    font-size: smaller;
+}
+.olControlScaleLine {
+   display: block;
+   position: absolute;
+   left: 10px;
+   bottom: 15px;
+   font-size: xx-small;
+}
+.olControlScaleLineBottom {
+   border: solid 2px black;
+   border-bottom: none;
+   margin-top:-2px;
+   text-align: center;
+}
+.olControlScaleLineTop {
+   border: solid 2px black;
+   border-top: none;
+   text-align: center;
+}
+
+.olControlPermalink {
+    right: 3px;
+    bottom: 1.5em;
+    display: block;
+    position: absolute;
+    font-size: smaller;
+}
+
+div.olControlMousePosition {
+    bottom: 0;
+    right: 3px;
+    display: block;
+    position: absolute;
+    font-family: Arial;
+    font-size: smaller;
+}
+
+.olControlOverviewMapContainer {
+    position: absolute;
+    bottom: 0;
+    right: 0;
+}
+
+.olControlOverviewMapElement {
+    padding: 10px 18px 10px 10px;
+    background-color: #00008B;
+    -moz-border-radius: 1em 0 0 0;
+}
+
+.olControlOverviewMapMinimizeButton,
+.olControlOverviewMapMaximizeButton {
+    height: 18px;
+    width: 18px;
+    right: 0;
+    bottom: 80px;
+    cursor: pointer;
+}
+
+.olControlOverviewMapExtentRectangle {
+    overflow: hidden;
+    background-image: url("img/blank.gif");
+    cursor: move;
+    border: 2px dotted red;
+}
+.olControlOverviewMapRectReplacement {
+    overflow: hidden;
+    cursor: move;
+    background-image: url("img/overview_replacement.gif");
+    background-repeat: no-repeat;
+    background-position: center;
+}
+
+.olLayerGeoRSSDescription {
+    float:left;
+    width:100%;
+    overflow:auto;
+    font-size:1.0em;
+}
+.olLayerGeoRSSClose {
+    float:right;
+    color:gray;
+    font-size:1.2em;
+    margin-right:6px;
+    font-family:sans-serif;
+}
+.olLayerGeoRSSTitle {
+    float:left;font-size:1.2em;
+}
+
+.olPopupContent {
+    padding:5px;
+    overflow: auto;
+}
+
+.olControlNavigationHistory {
+   background-image: url("img/navigation_history.png");
+   background-repeat: no-repeat;
+   width:  24px;
+   height: 24px;
+
+}
+.olControlNavigationHistoryPreviousItemActive {
+  background-position: 0 0;
+}
+.olControlNavigationHistoryPreviousItemInactive {
+   background-position: 0 -24px;
+}
+.olControlNavigationHistoryNextItemActive {
+   background-position: -24px 0;
+}
+.olControlNavigationHistoryNextItemInactive {
+   background-position: -24px -24px;
+}
+
+div.olControlSaveFeaturesItemActive {
+    background-image: url(img/save_features_on.png);
+    background-repeat: no-repeat;
+    background-position: 0 1px;
+}
+div.olControlSaveFeaturesItemInactive {
+    background-image: url(img/save_features_off.png);
+    background-repeat: no-repeat;
+    background-position: 0 1px;
+}
+
+.olHandlerBoxZoomBox {
+    border: 2px solid red;
+    position: absolute;
+    background-color: white;
+    opacity: 0.50;
+    font-size: 1px;
+    filter: alpha(opacity=50);
+}
+.olHandlerBoxSelectFeature {
+    border: 2px solid blue;
+    position: absolute;
+    background-color: white;
+    opacity: 0.50;
+    font-size: 1px;
+    filter: alpha(opacity=50);
+}
+
+.olControlPanPanel {
+    top: 10px;
+    left: 5px;
+}
+
+.olControlPanPanel div {
+    background-image: url(img/pan-panel.png);
+    height: 18px;
+    width: 18px;
+    cursor: pointer;
+    position: absolute;
+}
+
+.olControlPanPanel .olControlPanNorthItemInactive {
+    top: 0;
+    left: 9px;
+    background-position: 0 0;
+}
+.olControlPanPanel .olControlPanSouthItemInactive {
+    top: 36px;
+    left: 9px;
+    background-position: 18px 0;
+}
+.olControlPanPanel .olControlPanWestItemInactive {
+    position: absolute;
+    top: 18px;
+    left: 0;
+    background-position: 0 18px;
+}
+.olControlPanPanel .olControlPanEastItemInactive {
+    top: 18px;
+    left: 18px;
+    background-position: 18px 18px;
+}
+
+.olControlZoomPanel {
+    top: 71px;
+    left: 14px;
+}
+
+.olControlZoomPanel div {
+    background-image: url(img/zoom-panel.png);
+    position: absolute;
+    height: 18px;
+    width: 18px;
+    cursor: pointer;
+}
+
+.olControlZoomPanel .olControlZoomInItemInactive {
+    top: 0;
+    left: 0;
+    background-position: 0 0;
+}
+
+.olControlZoomPanel .olControlZoomToMaxExtentItemInactive {
+    top: 18px;
+    left: 0;
+    background-position: 0 -18px;
+}
+
+.olControlZoomPanel .olControlZoomOutItemInactive {
+    top: 36px;
+    left: 0;
+    background-position: 0 18px;
+}
+
+/*
+ * When a potential text is bigger than the image it move the image
+ * with some headers (closes #3154)
+ */
+.olControlPanZoomBar div {
+    font-size: 1px;
+}
+
+.olPopupCloseBox {
+  background: url("img/close.gif") no-repeat;
+  cursor: pointer;
+}
+
+.olFramedCloudPopupContent {
+    padding: 5px;
+    overflow: auto;
+}
+
+.olControlNoSelect {
+ -moz-user-select: none;
+ -khtml-user-select: none;
+}
+
+.olImageLoadError {
+    background-color: pink;
+    opacity: 0.5;
+    filter: alpha(opacity=50); /* IE */
+}
+
+/**
+ * Cursor styles
+ */
+
+.olCursorWait {
+    cursor: wait;
+}
+.olDragDown {
+    cursor: move;
+}
+.olDrawBox {
+    cursor: crosshair;
+}
+.olControlDragFeatureOver {
+    cursor: move;
+}
+.olControlDragFeatureActive.olControlDragFeatureOver.olDragDown {
+    cursor: -moz-grabbing;
+}
+
+/**
+ * Layer switcher
+ */
+.olControlLayerSwitcher {
+    position: absolute;
+    top: 25px;
+    right: 0;
+    width: 20em;
+    font-family: sans-serif;
+    font-weight: bold;
+    margin-top: 3px;
+    margin-left: 3px;
+    margin-bottom: 3px;
+    font-size: smaller;
+    color: white;
+    background-color: transparent;
+}
+
+.olControlLayerSwitcher .layersDiv {
+    padding-top: 5px;
+    padding-left: 10px;
+    padding-bottom: 5px;
+    padding-right: 10px;
+    background-color: darkblue;
+}
+
+.olControlLayerSwitcher .layersDiv .baseLbl,
+.olControlLayerSwitcher .layersDiv .dataLbl {
+    margin-top: 3px;
+    margin-left: 3px;
+    margin-bottom: 3px;
+}
+
+.olControlLayerSwitcher .layersDiv .baseLayersDiv,
+.olControlLayerSwitcher .layersDiv .dataLayersDiv {
+    padding-left: 10px;
+}
+
+.olControlLayerSwitcher .maximizeDiv,
+.olControlLayerSwitcher .minimizeDiv {
+    width: 18px;
+    height: 18px;
+    top: 5px;
+    right: 0;
+    cursor: pointer;
+}
+
+.olBingAttribution {
+    color: #DDD;
+}
+.olBingAttribution.road {
+    color: #333;
+}
+
+.olGoogleAttribution.hybrid, .olGoogleAttribution.satellite {
+    color: #EEE;
+}
+.olGoogleAttribution {
+    color: #333;
+}
+span.olGoogleAttribution a {
+    color: #77C;
+}
+span.olGoogleAttribution.hybrid a, span.olGoogleAttribution.satellite a {
+    color: #EEE;
+}
+
+/**
+ * Editing and navigation icons.
+ * (using the editing_tool_bar.png sprint image)
+ */
+.olControlNavToolbar ,
+.olControlEditingToolbar {
+    margin: 5px 5px 0 0;
+}
+.olControlNavToolbar div,
+.olControlEditingToolbar div {
+    background-image: url("img/editing_tool_bar.png");
+    background-repeat: no-repeat;
+    margin: 0 0 5px 5px;
+    width: 24px;
+    height: 22px;
+    cursor: pointer
+}
+/* positions */
+.olControlEditingToolbar {
+    right: 0;
+    top: 0;
+}
+.olControlNavToolbar {
+    top: 295px;
+    left: 9px;
+}
+/* layouts */
+.olControlEditingToolbar div {
+    float: right;
+}
+/* individual controls */
+.olControlNavToolbar .olControlNavigationItemInactive,
+.olControlEditingToolbar .olControlNavigationItemInactive {
+    background-position: -103px -1px;
+}
+.olControlNavToolbar .olControlNavigationItemActive ,
+.olControlEditingToolbar .olControlNavigationItemActive  {
+    background-position: -103px -24px;
+}
+.olControlNavToolbar .olControlZoomBoxItemInactive {
+    background-position: -128px -1px;
+}
+.olControlNavToolbar .olControlZoomBoxItemActive  {
+    background-position: -128px -24px;
+}
+.olControlEditingToolbar .olControlDrawFeaturePointItemInactive {
+    background-position: -77px -1px;
+}
+.olControlEditingToolbar .olControlDrawFeaturePointItemActive {
+    background-position: -77px -24px;
+}
+.olControlEditingToolbar .olControlDrawFeaturePathItemInactive {
+    background-position: -51px -1px;
+}
+.olControlEditingToolbar .olControlDrawFeaturePathItemActive {
+    background-position: -51px -24px;
+}
+.olControlEditingToolbar .olControlDrawFeaturePolygonItemInactive{
+    background-position: -26px -1px;
+}
+.olControlEditingToolbar .olControlDrawFeaturePolygonItemActive {
+    background-position: -26px -24px;
+}
+
+div.olControlZoom {
+    position: absolute;
+    top: 8px;
+    left: 8px;
+    background: rgba(255,255,255,0.4);
+    border-radius: 4px;
+    padding: 2px;
+}
+div.olControlZoom a {
+    display: block;
+    margin: 1px;
+    padding: 0;
+    color: white;
+    font-size: 18px;
+    font-family: 'Lucida Grande', Verdana, Geneva, Lucida, Arial, Helvetica, sans-serif;
+    font-weight: bold;
+    text-decoration: none;
+    text-align: center;
+    height: 22px;
+    width:22px;
+    line-height: 19px;
+    background: #130085; /* fallback for IE - IE6 requires background shorthand*/
+    background: rgba(0, 60, 136, 0.5);
+    filter: alpha(opacity=80);
+}
+div.olControlZoom a:hover {
+    background: #130085; /* fallback for IE */
+    background: rgba(0, 60, 136, 0.7);
+    filter: alpha(opacity=100);
+}
+@media only screen and (max-width: 600px) {
+    div.olControlZoom a:hover {
+        background: rgba(0, 60, 136, 0.5);
+    }
+}
+a.olControlZoomIn {
+    border-radius: 4px 4px 0 0;
+}
+a.olControlZoomOut {
+    border-radius: 0 0 4px 4px;
+}
+
+
+/**
+ * Animations
+ */
+
+.olLayerGrid .olTileImage {
+    -webkit-transition: opacity 0.2s linear;
+    -moz-transition: opacity 0.2s linear;
+    -o-transition: opacity 0.2s linear;
+    transition: opacity 0.2s linear;
+}
diff --git a/cookbooks/web/files/default/static/openlayers/theme/default/style.mobile.css b/cookbooks/web/files/default/static/openlayers/theme/default/style.mobile.css
new file mode 100644 (file)
index 0000000..2d4d392
--- /dev/null
@@ -0,0 +1,63 @@
+div.olControlZoom {
+    position: absolute;
+    top: 8px;
+    left: 8px;
+    background: rgba(255,255,255,0.4);
+    border-radius: 4px;
+    padding: 2px;
+}
+* {
+    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+div.olControlZoom a {
+    display: block;
+    margin: 1px;
+    padding: 0;
+    color: white;
+    font-size: 28px;
+    font-family: sans-serif;
+    font-weight: bold;
+    text-decoration: none;
+    text-align: center;
+    height: 32px;
+    width: 32px;
+    line-height: 28px;
+    text-shadow: 0 0 3px rgba(0,0,0,0.8);
+    background: #130085; /* fallback for IE - IE6 requires background shorthand*/
+    background: rgba(0, 60, 136, 0.5);
+    filter: alpha(opacity=80);
+}
+a.olControlZoomIn {
+    border-radius: 4px 4px 0 0;
+}
+a.olControlZoomOut {
+    border-radius: 0 0 4px 4px;
+}
+div.olControlZoom a:hover {
+    background: #130085; /* fallback for IE */
+    background: rgba(0, 60, 136, 0.7);
+    filter: alpha(opacity=100);
+}
+@media only screen and (max-width: 600px) {
+    div.olControlZoom a:hover {
+        background: rgba(0, 60, 136, 0.5);
+    }
+}
+.olLayerGrid .olTileImage {
+    -webkit-transition: opacity 0.2s linear;
+    -moz-transition: opacity 0.2s linear;
+    -o-transition: opacity 0.2s linear;
+    transition: opacity 0.2s linear;
+}
+/* Enable 3d acceleration when operating on tiles, this is
+   known to yield better performance on IOS Safari.
+   http://osgeo-org.1803224.n2.nabble.com/Harware-accelerated-CSS3-animations-for-iOS-td6255560.html
+
+   It also prevents tile blinking effects in iOS 5.
+   See https://github.com/openlayers/openlayers/issues/511
+*/
+@media (-webkit-transform-3d) {
+img.olTileImage {
+    -webkit-transform: translate3d(0, 0, 0);
+}
+}
index 47b0dd678fe1bcb01968a26ae5f70938d63e3896..004e5f320f4d1beddafe81b5c5ce1b2d2ee44814 100644 (file)
@@ -6,13 +6,16 @@ description       "Installs and configures www.openstreetmap.org servers"
 
 version           "1.0.1"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
-depends           "passenger"
+depends           "apt"
+depends           "chef"
+depends           "fail2ban"
+depends           "geoipupdate"
 depends           "git"
 depends           "memcached"
 depends           "nodejs"
-depends           "tools"
-depends           "nfs"
-depends           "accounts"
-depends           "apt"
+depends           "passenger"
+depends           "ruby"
 depends           "systemd"
+depends           "tools"
diff --git a/cookbooks/web/recipes/backend.rb b/cookbooks/web/recipes/backend.rb
deleted file mode 100644 (file)
index 97bab57..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# Cookbook:: web
-# Recipe:: backend
-#
-# Copyright:: 2011, OpenStreetMap Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-include_recipe "memcached"
-include_recipe "apache"
-include_recipe "web::rails"
-include_recipe "web::cgimap"
-
-web_passwords = data_bag_item("web", "passwords")
-
-apache_module "remoteip"
-apache_module "rewrite"
-apache_module "proxy"
-apache_module "proxy_fcgi"
-apache_module "setenvif"
-
-apache_site "default" do
-  action [:disable]
-end
-
-apache_site "www.openstreetmap.org" do
-  template "apache.backend.erb"
-  variables :status => node[:web][:status],
-            :secret_key_base => web_passwords["secret_key_base"]
-end
-
-node.normal[:memcached][:ip_address] = node.internal_ipaddress
-
-service "rails-jobs@storage" do
-  action [:enable, :start]
-  supports :restart => true
-  subscribes :restart, "rails_port[www.openstreetmap.org]"
-  subscribes :restart, "systemd_service[rails-jobs]"
-end
-
-if node[:web][:primary_cluster]
-  service "rails-jobs@traces" do
-    action [:enable, :start]
-    supports :restart => true
-    subscribes :restart, "rails_port[www.openstreetmap.org]"
-    subscribes :restart, "systemd_service[rails-jobs]"
-  end
-end
index 00f77af6cae7525a4d5fa283ab2f07b22652f33a..6fe8c7f5d6b939441de070efc4649db9048d7e04 100644 (file)
 # limitations under the License.
 #
 
-node.default[:nfs]["/store/rails"] = {
-  :host => node[:web][:fileserver],
-  :path => "/store/rails"
-}
-
-include_recipe "nfs"
+include_recipe "accounts"
 
 directory node[:web][:base_directory] do
   group "rails"
-  mode 0o2775
+  mode "2775"
 end
 
 systemd_tmpfile node[:web][:pid_directory] do
@@ -39,12 +34,12 @@ end
 directory node[:web][:log_directory] do
   owner "rails"
   group "rails"
-  mode 0o775
+  mode "775"
 end
 
 template "/etc/logrotate.d/web" do
   source "logrotate.web.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
 end
index 22d6d02f0f21fb8af090311b85d6204c4861d8cb..d3655068431971c0ee9b2b6802ed0fd9079b1689 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "apt"
 include_recipe "tools"
 include_recipe "web::base"
 
 db_passwords = data_bag_item("db", "passwords")
 
 package "openstreetmap-cgimap-bin" do
-  action :upgrade
+  action :install
 end
 
-if node[:web][:readonly_database_host]
-  database_host = node[:web][:readonly_database_host]
-  database_readonly = true
-else
-  database_host = node[:web][:database_host]
-  database_readonly = node[:web][:status] == "database_readonly"
-end
+database_host = node[:web][:readonly_database_host] || node[:web][:database_host]
 
 memcached_servers = node[:web][:memcached_servers] || []
 
-switches = database_readonly ? " --readonly" : ""
+cgimap_options = {
+  "CGIMAP_SOCKET" => "/run/cgimap/socket",
+  "CGIMAP_HOST" => database_host,
+  "CGIMAP_DBNAME" => "openstreetmap",
+  "CGIMAP_USERNAME" => "cgimap",
+  "CGIMAP_PASSWORD" => db_passwords["cgimap"],
+  "CGIMAP_OAUTH_HOST" => node[:web][:database_host],
+  "CGIMAP_UPDATE_HOST" => node[:web][:database_host],
+  "CGIMAP_PIDFILE" => "#{node[:web][:pid_directory]}/cgimap.pid",
+  "CGIMAP_LOGFILE" => "#{node[:web][:log_directory]}/cgimap.log",
+  "CGIMAP_MEMCACHE" => memcached_servers.join(","),
+  "CGIMAP_RATELIMIT" => "204800",
+  "CGIMAP_MAXDEBT" => "250",
+  "CGIMAP_MODERATOR_RATELIMIT" => "1048576",
+  "CGIMAP_MODERATOR_MAXDEBT" => "1280",
+  "CGIMAP_MAP_AREA" => node[:web][:max_request_area],
+  "CGIMAP_MAP_NODES" => node[:web][:max_number_of_nodes],
+  "CGIMAP_MAX_WAY_NODES" => node[:web][:max_number_of_way_nodes],
+  "CGIMAP_MAX_RELATION_MEMBERS" => node[:web][:max_number_of_relation_members],
+  "CGIMAP_RATELIMIT_UPLOAD" => "true"
+}
+
+if %w[database_readonly api_readonly].include?(node[:web][:status])
+  cgimap_options["CGIMAP_DISABLE_API_WRITE"] = "true"
+end
 
 systemd_service "cgimap" do
   description "OpenStreetMap API Server"
   type "forking"
-  environment_file "CGIMAP_HOST" => database_host,
-                   "CGIMAP_DBNAME" => "openstreetmap",
-                   "CGIMAP_USERNAME" => "cgimap",
-                   "CGIMAP_PASSWORD" => db_passwords["cgimap"],
-                   "CGIMAP_OAUTH_HOST" => node[:web][:database_host],
-                   "CGIMAP_UPDATE_HOST" => node[:web][:database_host],
-                   "CGIMAP_PIDFILE" => "#{node[:web][:pid_directory]}/cgimap.pid",
-                   "CGIMAP_LOGFILE" => "#{node[:web][:log_directory]}/cgimap.log",
-                   "CGIMAP_MEMCACHE" => memcached_servers.join(","),
-                   "CGIMAP_RATELIMIT" => "204800",
-                   "CGIMAP_MAXDEBT" => "250"
+  environment_file cgimap_options
   user "rails"
-  exec_start "/usr/bin/openstreetmap-cgimap --daemon --port 8000 --instances 30#{switches}"
+  group "www-data"
+  umask "0002"
+  exec_start "/usr/bin/openstreetmap-cgimap --daemon --instances 30"
   exec_reload "/bin/kill -HUP $MAINPID"
+  runtime_directory "cgimap"
   private_tmp true
   private_devices true
   protect_system "full"
index 7c3240152b779e079280a6d87f6ad7a15417d4bf..9ce886114de825b4595793e3d3d60c23d247b879 100644 (file)
 
 include_recipe "web::base"
 
-ruby = "ruby#{node[:passenger][:ruby_version]}"
+ruby = "ruby#{node[:ruby][:version]}"
 rails_directory = "#{node[:web][:base_directory]}/rails"
 
 template "/etc/cron.daily/web-cleanup" do
   source "cleanup.cron.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   variables :ruby => ruby, :directory => rails_directory
 end
index 947b7583b1a38b5781e123e778416fcba3dd60c8..ec7ce92f533ea7426483151b3a9ac3fa310b6006 100644 (file)
 # limitations under the License.
 #
 
+node.default[:memcached][:ip_address] = node.internal_ipaddress || "127.0.0.1"
+
+include_recipe "memcached"
 include_recipe "apache"
+include_recipe "fail2ban"
 include_recipe "web::rails"
+include_recipe "web::cgimap"
 
 web_passwords = data_bag_item("web", "passwords")
 
 apache_module "alias"
 apache_module "expires"
 apache_module "headers"
-apache_module "proxy_http"
-apache_module "proxy_balancer"
+apache_module "proxy"
+apache_module "proxy_fcgi"
 apache_module "lbmethod_byrequests"
 apache_module "lbmethod_bybusyness"
+apache_module "reqtimeout"
 apache_module "rewrite"
 apache_module "unique_id"
 
@@ -36,6 +42,16 @@ apache_site "default" do
   action [:disable]
 end
 
+remote_directory "#{node[:web][:base_directory]}/static" do
+  source "static"
+  owner "root"
+  group "root"
+  mode "755"
+  files_owner "root"
+  files_group "root"
+  files_mode "644"
+end
+
 apache_site "www.openstreetmap.org" do
   template "apache.frontend.erb"
   variables :status => node[:web][:status],
@@ -46,12 +62,80 @@ template "/etc/logrotate.d/apache2" do
   source "logrotate.apache.erb"
   owner "root"
   group "root"
-  mode 0o644
+  mode "644"
+end
+
+fail2ban_filter "apache-request-timeout" do
+  failregex '^<ADDR> .* "-" 408 .*$'
+end
+
+fail2ban_jail "apache-request-timeout" do
+  filter "apache-request-timeout"
+  logpath "/var/log/apache2/access.log"
+  ports [80, 443]
+end
+
+fail2ban_filter "apache-trackpoints-timeout" do
+  failregex '^<ADDR> .* "GET /api/0\.6/trackpoints\?.*" 408 .*$'
+end
+
+fail2ban_jail "apache-trackpoints-timeout" do
+  filter "apache-trackpoints-timeout"
+  logpath "/var/log/apache2/access.log"
+  ports [80, 443]
+  bantime "12h"
+  findtime "30m"
+end
+
+fail2ban_filter "apache-notes-search" do
+  failregex '^<ADDR> .* "GET /api/0\.6/notes/search\?q=abcde&.*$'
+end
+
+fail2ban_jail "apache-notes-search" do
+  filter "apache-notes-search"
+  logpath "/var/log/apache2/access.log"
+  ports [80, 443]
+end
+
+if %w[database_offline database_readonly].include?(node[:web][:status])
+  service "rails-jobs@mailers" do
+    action :stop
+  end
+
+  service "rails-jobs@storage" do
+    action :stop
+  end
+
+  service "rails-jobs@traces" do
+    action :stop
+  end
+else
+  service "rails-jobs@mailers" do
+    action [:enable, :start]
+    supports :restart => true
+    subscribes :restart, "rails_port[www.openstreetmap.org]"
+    subscribes :restart, "systemd_service[rails-jobs@]"
+  end
+
+  service "rails-jobs@storage" do
+    action [:enable, :start]
+    supports :restart => true
+    subscribes :restart, "rails_port[www.openstreetmap.org]"
+    subscribes :restart, "systemd_service[rails-jobs@]"
+  end
+
+  service "rails-jobs@traces" do
+    action [:enable, :start]
+    supports :restart => true
+    subscribes :restart, "rails_port[www.openstreetmap.org]"
+    subscribes :restart, "systemd_service[rails-jobs@]"
+  end
 end
 
-service "rails-jobs@mailers" do
-  action [:enable, :start]
-  supports :restart => true
-  subscribes :restart, "rails_port[www.openstreetmap.org]"
-  subscribes :restart, "systemd_service[rails-jobs]"
+template "/usr/local/bin/deliver-message" do
+  source "deliver-message.erb"
+  owner "rails"
+  group "rails"
+  mode "0700"
+  variables :secret_key_base => web_passwords["secret_key_base"]
 end
index d46c09ee126c9a78d167d0a5ee031292fea2c568..ee24dbd8da207273ed82d0f0b0bf3dabf1928058 100644 (file)
 # limitations under the License.
 #
 
-include_recipe "tools"
-include_recipe "web::base"
-
 include_recipe "apache"
-include_recipe "passenger"
+include_recipe "apt"
 include_recipe "git"
+include_recipe "geoipupdate"
 include_recipe "nodejs"
+include_recipe "passenger"
+include_recipe "ruby"
+include_recipe "tools"
+include_recipe "web::base"
 
 web_passwords = data_bag_item("web", "passwords")
 db_passwords = data_bag_item("db", "passwords")
 
 ssl_certificate "www.openstreetmap.org" do
-  domains ["www.openstreetmap.org", "www.osm.org",
+  domains ["www.openstreetmap.org", "www.osm.org", "www.openstreetmap.com",
            "api.openstreetmap.org", "api.osm.org",
            "maps.openstreetmap.org", "maps.osm.org",
            "mapz.openstreetmap.org", "mapz.osm.org",
-           "openstreetmap.org", "osm.org"]
+           "openstreetmap.org", "osm.org", "openstreetmap.com"]
   notifies :reload, "service[apache2]"
 end
 
 nodejs_package "svgo"
 
-template "/etc/cron.hourly/passenger" do
-  cookbook "web"
-  source "passenger.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o755
-end
-
-ruby_version = node[:passenger][:ruby_version]
 rails_directory = "#{node[:web][:base_directory]}/rails"
 
-piwik = data_bag_item("web", "piwik")
+matomo = data_bag_item("web", "matomo")
 
 storage = {
-  "aws" => {
+  "avatars" => {
     "service" => "S3",
     "access_key_id" => "AKIASQUXHPE7AMJQRFOS",
     "secret_access_key" => web_passwords["aws_key"],
@@ -64,68 +57,129 @@ storage = {
       "acl" => "public-read",
       "cache_control" => "public, max-age=31536000, immutable"
     }
+  },
+  "gps_traces" => {
+    "service" => "S3",
+    "access_key_id" => "AKIASQUXHPE7AMJQRFOS",
+    "secret_access_key" => web_passwords["aws_key"],
+    "region" => "eu-west-1",
+    "bucket" => "openstreetmap-gps-traces",
+    "use_dualstack_endpoint" => true,
+    "upload" => {
+      "acl" => "public-read",
+      "cache_control" => "public, max-age=31536000, immutable"
+    }
+  },
+  "gps_images" => {
+    "service" => "S3",
+    "access_key_id" => "AKIASQUXHPE7AMJQRFOS",
+    "secret_access_key" => web_passwords["aws_key"],
+    "region" => "eu-west-1",
+    "bucket" => "openstreetmap-gps-images",
+    "use_dualstack_endpoint" => true,
+    "upload" => {
+      "acl" => "public-read",
+      "cache_control" => "public, max-age=31536000, immutable"
+    }
   }
 }
 
+db_host = if node[:web][:status] == "database_readonly"
+            node[:web][:readonly_database_host]
+          else
+            node[:web][:database_host]
+          end
+
 rails_port "www.openstreetmap.org" do
-  ruby ruby_version
   directory rails_directory
   user "rails"
   group "rails"
   repository "https://git.openstreetmap.org/public/rails.git"
   revision "live"
-  database_host node[:web][:database_host]
+  database_host db_host
   database_name "openstreetmap"
   database_username "rails"
   database_password db_passwords["rails"]
   email_from "OpenStreetMap <web@noreply.openstreetmap.org>"
   status node[:web][:status]
   messages_domain "messages.openstreetmap.org"
-  gpx_dir "/store/rails/gpx"
-  attachments_dir "/store/rails/attachments"
   log_path "#{node[:web][:log_directory]}/rails.log"
   logstash_path "#{node[:web][:log_directory]}/rails-logstash.log"
   memcache_servers node[:web][:memcached_servers]
   potlatch2_key web_passwords["potlatch2_key"]
   id_key web_passwords["id_key"]
+  id_application web_passwords["id_application"]
   oauth_key web_passwords["oauth_key"]
-  piwik_configuration "location" => piwik[:location],
-                      "site" => piwik[:site],
-                      "goals" => piwik[:goals].to_hash
+  oauth_application web_passwords["oauth_application"]
+  matomo_configuration "location" => matomo[:location],
+                       "site" => matomo[:site],
+                       "visitor_cookie_timeout" => matomo[:visitor_cookie_timeout],
+                       "referral_cookie_timeout" => matomo[:referral_cookie_timeout],
+                       "session_cookie_timeout" => matomo[:session_cookie_timeout],
+                       "goals" => matomo[:goals].to_hash
   google_auth_id "651529786092-6c5ahcu0tpp95emiec8uibg11asmk34t.apps.googleusercontent.com"
   google_auth_secret web_passwords["google_auth_secret"]
   google_openid_realm "https://www.openstreetmap.org"
   facebook_auth_id "427915424036881"
   facebook_auth_secret web_passwords["facebook_auth_secret"]
-  windowslive_auth_id "0000000040153C51"
-  windowslive_auth_secret web_passwords["windowslive_auth_secret"]
+  microsoft_auth_id "e34f14f1-f790-40f3-9fa4-3c5f1a027c38"
+  microsoft_auth_secret web_passwords["microsoft_auth_secret"]
   github_auth_id "acf7da34edee99e35499"
   github_auth_secret web_passwords["github_auth_secret"]
   wikipedia_auth_id "e4fe0c2c5855d23ed7e1f1c0fa1f1c58"
   wikipedia_auth_secret web_passwords["wikipedia_auth_secret"]
   thunderforest_key web_passwords["thunderforest_key"]
+  tracestrack_key web_passwords["tracestrack_key"]
   totp_key web_passwords["totp_key"]
   csp_enforce true
   trace_use_job_queue true
   diary_feed_delay 12
   storage_configuration storage
-  storage_service "aws"
-  storage_url "https://openstreetmap-user-avatars.s3.dualstack.eu-west-1.amazonaws.com"
+  avatar_storage "avatars"
+  trace_file_storage "gps_traces"
+  trace_image_storage "gps_images"
+  trace_icon_storage "gps_images"
+  avatar_storage_url "https://openstreetmap-user-avatars.s3.dualstack.eu-west-1.amazonaws.com"
+  trace_image_storage_url "https://openstreetmap-gps-images.s3.dualstack.eu-west-1.amazonaws.com"
+  overpass_url "https://query.openstreetmap.org/query-features"
+  overpass_credentials true
+  signup_ip_per_day 24
+  signup_ip_max_burst 48
+  signup_email_per_day 1
+  signup_email_max_burst 2
+  doorkeeper_signing_key web_passwords["openid_connect_key"].join("\n")
+  user_account_deletion_delay 7 * 24
+  # Requests to modify the imagery blacklist should come from the DWG only
+  imagery_blacklist [
+    # Current Google imagery URLs have google or googleapis in the domain
+    ".*\\.google(apis)?\\..*/.*",
+    # Blacklist VWorld
+    "http://xdworld\\.vworld\\.kr:8080/.*",
+    # Blacklist here
+    ".*\\.here\\.com[/:].*",
+    # Blacklist Mapy.cz
+    ".*\\.mapy\\.cz.*",
+    # Blacklist Yandex
+    ".*\\.api-maps\\.yandex\\.ru/.*",
+    ".*\\.maps\\.yandex\\.net/.*"
+  ]
 end
 
 systemd_service "rails-jobs@" do
   description "Rails job queue runner"
   type "simple"
-  environment "RAILS_ENV" => "production", "QUEUE" => "%I"
+  environment "RAILS_ENV" => "production",
+              "QUEUE" => "%I",
+              "SLEEP_DELAY" => "60",
+              "SECRET_KEY_BASE" => web_passwords["secret_key_base"]
   user "rails"
   working_directory rails_directory
-  exec_start "/usr/local/bin/bundle#{ruby_version} exec rake jobs:work"
+  exec_start "#{node[:ruby][:bundle]} exec rails jobs:work"
   restart "on-failure"
-  private_tmp true
-  private_devices true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  nice 10
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  read_write_paths "/var/log/web"
 end
 
 package "libjson-xs-perl"
@@ -134,17 +188,22 @@ template "/usr/local/bin/cleanup-rails-assets" do
   source "cleanup-assets.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
-gem_package "apachelogregex"
-gem_package "file-tail"
+gem_package "apachelogregex" do
+  gem_binary node[:ruby][:gem]
+end
+
+gem_package "file-tail" do
+  gem_binary node[:ruby][:gem]
+end
 
 template "/usr/local/bin/api-statistics" do
   source "api-statistics.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
 end
 
 systemd_service "api-statistics" do
@@ -152,12 +211,12 @@ systemd_service "api-statistics" do
   user "rails"
   group "adm"
   exec_start "/usr/local/bin/api-statistics"
-  private_tmp true
-  private_devices true
-  private_network true
-  protect_system "full"
-  protect_home true
-  no_new_privileges true
+  nice 10
+  sandbox true
+  read_write_paths [
+    "/srv/www.openstreetmap.org/rails/tmp",
+    "/var/lib/prometheus/node-exporter"
+  ]
   restart "on-failure"
 end
 
@@ -168,15 +227,6 @@ service "api-statistics" do
   subscribes :restart, "systemd_service[api-statistics]"
 end
 
-gem_package "hpricot"
-
-munin_plugin "api_calls_status"
-munin_plugin "api_calls_num"
-
-munin_plugin "api_calls_#{node[:hostname]}" do
-  target "api_calls_"
-end
-
-munin_plugin "api_waits_#{node[:hostname]}" do
-  target "api_waits_"
+gem_package "hpricot" do
+  gem_binary node[:ruby][:gem]
 end
index c2f7d9b147ea8fa13ee8590bf3d01f509dc6685a..84848b0030eb2f67437b0aded36782fc2d1ae60c 100644 (file)
 
 include_recipe "web::base"
 
-ruby = "ruby#{node[:passenger][:ruby_version]}"
+ruby = "ruby#{node[:ruby][:version]}"
 rails_directory = "#{node[:web][:base_directory]}/rails"
 
 template "/usr/local/bin/statistics" do
   source "statistics.erb"
   owner "root"
   group "root"
-  mode 0o755
+  mode "755"
   variables :ruby => ruby, :directory => rails_directory
 end
 
-template "/etc/cron.d/statistics" do
-  source "statistics.cron.erb"
-  owner "root"
-  group "root"
-  mode 0o644
+systemd_service "web-statistics" do
+  description "Generate web statistics"
+  environment "RAILS_ENV" => "production",
+              "SECRET_KEY_BASE_DUMMY" => "1"
+  user "rails"
+  working_directory rails_directory
+  exec_start "/usr/local/bin/statistics"
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  read_write_paths ["#{rails_directory}/tmp", "/var/log/web"]
+end
+
+systemd_timer "web-statistics" do
+  description "Generate web statistics"
+  on_calendar "00:00:00"
+end
+
+service "web-statistics.timer" do
+  action [:enable, :start]
 end
index 0a37afe89f7ec5cc143d6c640da3d107d6505096..3f5078d3487354899d71d1448ea8bbda89f4b750 100644 (file)
 require "yaml"
 
 resource_name :rails_port
+provides :rails_port
+
+unified_mode true
 
 default_action :create
 
-property :site, String, :name_attribute => true
-property :ruby, String, :default => "2.3"
+property :site, String, :name_property => true
 property :directory, String
 property :user, String
 property :group, String
 property :repository, String, :default => "https://git.openstreetmap.org/public/rails.git"
 property :revision, String, :default => "live"
-property :run_migrations, [TrueClass, FalseClass], :default => false
+property :run_migrations, [true, false], :default => false
+property :build_assets, [true, false], :default => true
 property :email_from, String, :default => "OpenStreetMap <support@openstreetmap.org>"
 property :status, String, :default => "online"
 property :database_host, String
@@ -47,42 +50,61 @@ property :logstash_path, String
 property :memcache_servers, Array
 property :potlatch2_key, String
 property :id_key, String
+property :id_application, String
 property :oauth_key, String
+property :oauth_application, String
 property :nominatim_url, String
-property :osrm_url, String
+property :overpass_url, String
+property :overpass_credentials, [true, false], :default => false
 property :google_auth_id, String
 property :google_auth_secret, String
 property :google_openid_realm, String
 property :facebook_auth_id, String
 property :facebook_auth_secret, String
-property :windowslive_auth_id, String
-property :windowslive_auth_secret, String
+property :microsoft_auth_id, String
+property :microsoft_auth_secret, String
 property :github_auth_id, String
 property :github_auth_secret, String
 property :wikipedia_auth_id, String
 property :wikipedia_auth_secret, String
 property :thunderforest_key, String
+property :tracestrack_key, String
 property :totp_key, String
-property :csp_enforce, [TrueClass, FalseClass], :default => false
+property :csp_enforce, [true, false], :default => false
 property :csp_report_url, String
-property :piwik_configuration, Hash
-property :trace_use_job_queue, [TrueClass, FalseClass], :default => false
-property :diary_feed_delay, Integer
-property :storage_configuration, Hash, :default => {}
+property :matomo_configuration, Hash
 property :storage_service, String, :default => "local"
 property :storage_url, String
+property :trace_use_job_queue, [true, false], :default => false
+property :diary_feed_delay, Integer
+property :storage_configuration, Hash, :default => {}
+property :avatar_storage, String
+property :trace_file_storage, String
+property :trace_image_storage, String
+property :trace_icon_storage, String
+property :avatar_storage_url, String
+property :trace_image_storage_url, String
+property :trace_icon_storage_url, String
+property :tile_cdn_url, String
+property :imagery_blacklist, Array
+property :signup_ip_per_day, Integer
+property :signup_ip_max_burst, Integer
+property :signup_email_per_day, Integer
+property :signup_email_max_burst, Integer
+property :doorkeeper_signing_key, String
+property :user_account_deletion_delay, Integer
 
 action :create do
   package %W[
-    ruby#{new_resource.ruby}
-    ruby#{new_resource.ruby}-dev
     imagemagick
+    libvips42
     nodejs
-    geoip-database
+    tzdata
   ]
 
   package %w[
     g++
+    make
     pkg-config
     libpq-dev
     libsasl2-dev
@@ -93,6 +115,7 @@ action :create do
     libgd-dev
     libarchive-dev
     libbz2-dev
+    libyaml-dev
   ]
 
   package %w[
@@ -106,35 +129,19 @@ action :create do
     libjpeg-turbo-progs
   ]
 
-  gem_package "bundler#{new_resource.ruby}" do
-    package_name "bundler"
-    version "1.16.2"
-    gem_binary "gem#{new_resource.ruby}"
-    options "--format-executable"
-  end
-
-  gem_package "bundler#{new_resource.ruby}" do
-    package_name "pkg-config"
-    gem_binary "gem#{new_resource.ruby}"
-  end
-
   declare_resource :directory, rails_directory do
     owner new_resource.user
     group new_resource.group
-    mode 0o2775
+    mode "2775"
   end
 
   git rails_directory do
     action :sync
     repository new_resource.repository
     revision new_resource.revision
+    depth 1
     user new_resource.user
     group new_resource.group
-    notifies :run, "execute[#{rails_directory}/Gemfile]"
-    notifies :run, "execute[#{rails_directory}/app/assets/javascripts/i18n]"
-    notifies :run, "execute[#{rails_directory}/public/assets]"
-    notifies :delete, "file[#{rails_directory}/public/export/embed.html]"
-    notifies :restart, "passenger_application[#{rails_directory}]"
   end
 
   declare_resource :directory, "#{rails_directory}/tmp" do
@@ -152,13 +159,12 @@ action :create do
     source "database.yml.erb"
     owner new_resource.user
     group new_resource.group
-    mode 0o664
+    mode "664"
     variables :host => new_resource.database_host,
               :port => new_resource.database_port,
               :name => new_resource.database_name,
               :username => new_resource.database_username,
               :password => new_resource.database_password
-    notifies :restart, "passenger_application[#{rails_directory}]"
   end
 
   application_yml = edit_file "#{rails_directory}/config/example.application.yml" do |line|
@@ -181,7 +187,7 @@ action :create do
 
     line.gsub!(/^( *)#geonames_username:.*$/, "\\1geonames_username: \"openstreetmap\"")
 
-    line.gsub!(/^( *)#geoip_database:.*$/, "\\1geoip_database: \"/usr/share/GeoIP/GeoIPv6.dat\"")
+    line.gsub!(/^( *)#maxmind_database:.*$/, "\\1maxmind_database: \"#{node[:geoipupdate][:directory]}/GeoLite2-Country.mmdb\"")
 
     if new_resource.gpx_dir
       line.gsub!(/^( *)gpx_trace_dir:.*$/, "\\1gpx_trace_dir: \"#{new_resource.gpx_dir}/traces\"")
@@ -212,16 +218,24 @@ action :create do
       line.gsub!(/^( *)#id_key:.*$/, "\\1id_key: \"#{new_resource.id_key}\"")
     end
 
+    if new_resource.id_application
+      line.gsub!(/^( *)#id_application:.*$/, "\\1id_application: \"#{new_resource.id_application}\"")
+    end
+
     if new_resource.oauth_key
       line.gsub!(/^( *)#oauth_key:.*$/, "\\1oauth_key: \"#{new_resource.oauth_key}\"")
     end
 
+    if new_resource.oauth_application
+      line.gsub!(/^( *)#oauth_application:.*$/, "\\1oauth_application: \"#{new_resource.oauth_application}\"")
+    end
+
     if new_resource.nominatim_url
       line.gsub!(/^( *)nominatim_url:.*$/, "\\1nominatim_url: \"#{new_resource.nominatim_url}\"")
     end
 
-    if new_resource.osrm_url
-      line.gsub!(/^( *)osrm_url:.*$/, "\\1osrm_url: \"#{new_resource.osrm_url}\"")
+    if new_resource.overpass_url
+      line.gsub!(/^( *)overpass_url:.*$/, "\\1overpass_url: \"#{new_resource.overpass_url}\"")
     end
 
     if new_resource.google_auth_id
@@ -235,9 +249,9 @@ action :create do
       line.gsub!(/^( *)#facebook_auth_secret:.*$/, "\\1facebook_auth_secret: \"#{new_resource.facebook_auth_secret}\"")
     end
 
-    if new_resource.windowslive_auth_id
-      line.gsub!(/^( *)#windowslive_auth_id:.*$/, "\\1windowslive_auth_id: \"#{new_resource.windowslive_auth_id}\"")
-      line.gsub!(/^( *)#windowslive_auth_secret:.*$/, "\\1windowslive_auth_secret: \"#{new_resource.windowslive_auth_secret}\"")
+    if new_resource.microsoft_auth_id
+      line.gsub!(/^( *)#microsoft_auth_id:.*$/, "\\1microsoft_auth_id: \"#{new_resource.microsoft_auth_id}\"")
+      line.gsub!(/^( *)#microsoft_auth_secret:.*$/, "\\1microsoft_auth_secret: \"#{new_resource.microsoft_auth_secret}\"")
     end
 
     if new_resource.github_auth_id
@@ -277,9 +291,8 @@ action :create do
     path "#{rails_directory}/config/application.yml"
     owner new_resource.user
     group new_resource.group
-    mode 0o664
+    mode "664"
     content application_yml
-    notifies :run, "execute[#{rails_directory}/public/assets]"
     only_if { ::File.exist?("#{rails_directory}/config/example.application.yml") }
   end
 
@@ -298,35 +311,60 @@ action :create do
     "logstash_path",
     "potlatch2_key",
     "id_key",
+    "id_application",
     "oauth_key",
+    "oauth_application",
     "nominatim_url",
-    "osrm_url",
+    "overpass_url",
+    "overpass_credentials",
     "google_auth_id",
     "google_auth_secret",
     "google_openid_realm",
     "facebook_auth_id",
     "facebook_auth_secret",
-    "windowslive_auth_id",
-    "windowslive_auth_secret",
+    "microsoft_auth_id",
+    "microsoft_auth_secret",
     "github_auth_id",
     "github_auth_secret",
     "wikipedia_auth_id",
     "wikipedia_auth_secret",
     "thunderforest_key",
+    "tracestrack_key",
     "totp_key",
     "csp_enforce",
     "csp_report_url",
     "trace_use_job_queue",
     "diary_feed_delay",
     "storage_service",
-    "storage_url"
-  ).reject { |_k, v| v.nil? }.merge(
+    "storage_url",
+    "avatar_storage",
+    "trace_file_storage",
+    "trace_image_storage",
+    "trace_icon_storage",
+    "avatar_storage_url",
+    "trace_image_storage_url",
+    "trace_icon_storage_url",
+    "tile_cdn_url",
+    "imagery_blacklist",
+    "signup_ip_per_day",
+    "signup_ip_max_burst",
+    "signup_email_per_day",
+    "signup_email_max_burst",
+    "doorkeeper_signing_key",
+    "user_account_deletion_delay"
+  ).compact.merge(
     "server_protocol" => "https",
     "server_url" => new_resource.site,
     "support_email" => "support@openstreetmap.org",
     "email_return_path" => "bounces@openstreetmap.org",
     "geonames_username" => "openstreetmap",
-    "geoip_database" => "/usr/share/GeoIP/GeoIPv6.dat"
+    "maxmind_database" => "#{node[:geoipupdate][:directory]}/GeoLite2-Country.mmdb",
+    "max_request_area" => node[:web][:max_request_area],
+    "max_number_of_nodes" => node[:web][:max_number_of_nodes],
+    "max_number_of_way_nodes" => node[:web][:max_number_of_way_nodes],
+    "max_number_of_relation_members" => node[:web][:max_number_of_relation_members],
+    "oauth_10_support" => false,
+    "oauth_10_registration" => false
   )
 
   if new_resource.memcache_servers
@@ -338,12 +376,15 @@ action :create do
     settings["gpx_image_dir"] = "#{new_resource.gpx_dir}/images"
   end
 
+  if new_resource.matomo_configuration
+    settings["matomo"] = new_resource.matomo_configuration.to_h
+  end
+
   file "#{rails_directory}/config/settings.local.yml" do
     owner new_resource.user
     group new_resource.group
-    mode 0o664
+    mode "664"
     content YAML.dump(settings)
-    notifies :run, "execute[#{rails_directory}/public/assets]"
     only_if { ::File.exist?("#{rails_directory}/config/settings.yml") }
   end
 
@@ -357,74 +398,94 @@ action :create do
   file "#{rails_directory}/config/storage.yml" do
     owner new_resource.user
     group new_resource.group
-    mode 0o664
+    mode "664"
     content YAML.dump(storage_configuration)
-    notifies :run, "execute[#{rails_directory}/public/assets]"
   end
 
-  if new_resource.piwik_configuration
-    file "#{rails_directory}/config/piwik.yml" do
-      owner new_resource.user
-      group new_resource.group
-      mode 0o664
-      content YAML.dump(new_resource.piwik_configuration)
-      notifies :run, "execute[#{rails_directory}/public/assets]"
-    end
-  else
-    file "#{rails_directory}/config/piwik.yml" do
-      action :delete
-      notifies :run, "execute[#{rails_directory}/public/assets]"
-    end
+  file "#{rails_directory}/config/piwik.yml" do
+    action :delete
   end
 
-  execute "#{rails_directory}/Gemfile" do
+  bundle_install "#{rails_directory}" do
     action :nothing
-    command "bundle#{new_resource.ruby} install"
-    cwd rails_directory
     user "root"
     group "root"
     environment "NOKOGIRI_USE_SYSTEM_LIBRARIES" => "yes"
-    subscribes :run, "gem_package[bundler#{new_resource.ruby}]"
-    notifies :restart, "passenger_application[#{rails_directory}]"
+    subscribes :run, "git[#{rails_directory}]"
   end
 
-  execute "#{rails_directory}/db/migrate" do
+  bundle_exec "#{rails_directory}/db/migrate" do
     action :nothing
-    command "bundle#{new_resource.ruby} exec rake db:migrate"
-    cwd rails_directory
+    directory rails_directory
+    command "rails db:migrate"
     user new_resource.user
     group new_resource.group
     subscribes :run, "git[#{rails_directory}]"
-    notifies :restart, "passenger_application[#{rails_directory}]"
     only_if { new_resource.run_migrations }
   end
 
-  execute "#{rails_directory}/app/assets/javascripts/i18n" do
+  bundle_exec "#{rails_directory}/package.json" do
     action :nothing
-    command "bundle#{new_resource.ruby} exec rake i18n:js:export"
-    environment "RAILS_ENV" => "production"
-    cwd rails_directory
+    directory rails_directory
+    command "rails yarn:install"
+    environment "HOME" => rails_directory,
+                "RAILS_ENV" => "production",
+                "SECRET_KEY_BASE_DUMMY" => "1"
     user new_resource.user
     group new_resource.group
-    notifies :run, "execute[#{rails_directory}/public/assets]"
+    subscribes :run, "git[#{rails_directory}]"
+    only_if { new_resource.build_assets }
   end
 
-  execute "#{rails_directory}/public/assets" do
+  bundle_exec "#{rails_directory}/app/assets/javascripts/i18n" do
     action :nothing
-    command "bundle#{new_resource.ruby} exec rake assets:precompile"
-    environment "RAILS_ENV" => "production"
-    cwd rails_directory
+    directory rails_directory
+    command "rails i18n:js:export"
+    environment "HOME" => rails_directory,
+                "RAILS_ENV" => "production",
+                "SECRET_KEY_BASE_DUMMY" => "1"
     user new_resource.user
     group new_resource.group
-    notifies :restart, "passenger_application[#{rails_directory}]"
+    subscribes :run, "git[#{rails_directory}]"
+    only_if { new_resource.build_assets }
+  end
+
+  bundle_exec "#{rails_directory}/public/assets" do
+    action :nothing
+    directory rails_directory
+    command "rails assets:precompile"
+    environment "HOME" => rails_directory,
+                "RAILS_ENV" => "production",
+                "SECRET_KEY_BASE_DUMMY" => "1"
+    user new_resource.user
+    group new_resource.group
+    subscribes :run, "git[#{rails_directory}]"
+    subscribes :run, "file[create:#{rails_directory}/config/application.yml]"
+    subscribes :run, "file[#{rails_directory}/config/settings.local.yml]"
+    subscribes :run, "file[#{rails_directory}/config/storage.yml]"
+    subscribes :run, "bundle_exec[#{rails_directory}/package.json]"
+    subscribes :run, "bundle_exec[#{rails_directory}/app/assets/javascripts/i18n]"
+    only_if { new_resource.build_assets }
   end
 
   file "#{rails_directory}/public/export/embed.html" do
     action :nothing
+    subscribes :delete, "git[#{rails_directory}]"
+    subscribes :delete, "file[#{rails_directory}/config/settings.local.yml]"
   end
 
   passenger_application rails_directory do
     action :nothing
+    subscribes :restart, "git[#{rails_directory}]"
+    subscribes :restart, "file[#{rails_directory}/config/database.yml]"
+    subscribes :restart, "file[create:#{rails_directory}/config/application.yml]"
+    subscribes :restart, "file[#{rails_directory}/config/settings.local.yml]"
+    subscribes :restart, "file[#{rails_directory}/config/storage.yml]"
+    subscribes :restart, "bundle_installl[#{rails_directory}]"
+    subscribes :restart, "bundle_exec[#{rails_directory}/db/migrate]"
+    subscribes :restart, "bundle_exec[#{rails_directory}/package.json]"
+    subscribes :restart, "bundle_exec[#{rails_directory}/app/assets/javascripts/i18n]"
+    subscribes :restart, "bundle_exec[#{rails_directory}/public/assets]"
     only_if { ::File.exist?("/usr/bin/passenger-config") }
   end
 
@@ -433,7 +494,7 @@ action :create do
     source "rails.cron.erb"
     owner "root"
     group "root"
-    mode 0o755
+    mode "755"
     variables :directory => rails_directory
   end
 end
@@ -445,7 +506,7 @@ action :restart do
 end
 
 action_class do
-  include Chef::Mixin::EditFile
+  include OpenStreetMap::Mixin::EditFile
 
   def rails_directory
     new_resource.directory || "/srv/#{new_resource.site}"
diff --git a/cookbooks/web/templates/default/apache.backend.erb b/cookbooks/web/templates/default/apache.backend.erb
deleted file mode 100644 (file)
index b69b3f0..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-<VirtualHost *:443>
-  #
-  # Basic server configuration
-  #
-  ServerName <%= node[:fqdn] %>
-  ServerAlias api.openstreetmap.org www.openstreetmap.org
-  ServerAdmin webmaster@openstreetmap.org
-
-  #
-  # Enable SSL
-  #
-  SSLEngine on
-  SSLCertificateFile /etc/ssl/certs/www.openstreetmap.org.pem
-  SSLCertificateKeyFile /etc/ssl/private/www.openstreetmap.org.key
-
-  #
-  # Setup logging
-  #
-  LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %Dus %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x" combined_with_time
-  CustomLog /var/log/apache2/access.log combined_with_time
-  ErrorLog /var/log/apache2/error.log
-
-  #
-  # Turn on the rewrite engine
-  #
-  RewriteEngine on
-
-  #
-  # Recover the unique ID from the request headers
-  #
-  SetEnvIf X-Request-Id ^(.*)$ UNIQUE_ID=$1
-
-  #
-  # Configure rails
-  #
-  DocumentRoot <%= node[:web][:base_directory] %>/rails/public
-  RailsEnv production
-  PassengerMinInstances 3
-  PassengerMaxRequests 500
-  PassengerPreStart https://www.openstreetmap.org/
-  PassengerAppGroupName rails
-  SetEnv OPENSTREETMAP_STATUS <%= @status %>
-  SetEnv SECRET_KEY_BASE <%= @secret_key_base %>
-
-  #
-  # Get the real remote IP for requests via a trusted proxy
-  #
-  RemoteIPHeader X-Forwarded-For
-  RemoteIPTrustedProxy 10.0.32.0/24
-  RemoteIPTrustedProxy 10.0.48.0/24
-
-  #
-  # Pass authentication related headers to cgimap
-  #
-  <Location />
-    CGIPassAuth On
-  </Location>
-
-  #
-  # Pass supported calls to cgimap
-  #
-  RewriteRule ^/api/0\.6/map$ fcgi://127.0.0.1:8000$0 [P]
-  RewriteCond %{REQUEST_METHOD} ^(HEAD|GET)$
-  RewriteRule ^/api/0\.6/(node|way|relation|changeset)/[0-9]+$ fcgi://127.0.0.1:8000$0 [P]
-  RewriteRule ^/api/0\.6/(node|way|relation)/[0-9]+/history$ fcgi://127.0.0.1:8000$0 [P]
-  RewriteRule ^/api/0\.6/(way|relation)/[0-9]+/full$ fcgi://127.0.0.1:8000$0 [P]
-  RewriteRule ^/api/0\.6/(nodes|ways|relations)$ fcgi://127.0.0.1:8000$0 [P]
-  RewriteRule ^/api/0\.6/changeset/[0-9]+/download$ fcgi://127.0.0.1:8000$0 [P]
-  RewriteRule ^/api/0\.6/changeset/[0-9]+/upload$ fcgi://127.0.0.1:8000$0 [P]
-</VirtualHost>
-
-<Directory <%= node[:web][:base_directory] %>/rails/public>
-  Require all granted
-</Directory>
index 4c283299b2f8cedc2b866834fa227b0aac595ffe..4ee4c459cf769eef7dc17cab194eb154d5e9e09c 100644 (file)
@@ -1,5 +1,16 @@
 # DO NOT EDIT - This file is being maintained by Chef
 
+#
+# Setup logging
+# 
+SetEnvIfNoCase Authorization "^Basic " AUTH_METHOD=basic
+SetEnvIfNoCase Authorization "^OAuth " AUTH_METHOD=oauth1
+SetEnvIfNoCase Authorization "^Bearer " AUTH_METHOD=oauth2
+SetEnvIfExpr "%{QUERY_STRING} =~ /(^|&)oauth_signature=/" AUTH_METHOD=oauth1
+LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %Dus %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{AUTH_METHOD}e" combined_with_time
+CustomLog /var/log/apache2/access.log combined_with_time
+ErrorLog /var/log/apache2/error.log
+
 <VirtualHost *:443>
   #
   # Basic server configuration
   # Enable SSL
   #
   SSLEngine on
-  SSLProxyEngine on
   SSLCertificateFile /etc/ssl/certs/www.openstreetmap.org.pem
   SSLCertificateKeyFile /etc/ssl/private/www.openstreetmap.org.key
 
-  #
-  # Setup logging
-  #
-  LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %Dus %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x" combined_with_time
-  CustomLog /var/log/apache2/access.log combined_with_time
-  ErrorLog /var/log/apache2/error.log
-
   #
   # Turn on various features
   #
   ExpiresActive On
   RewriteEngine on
 
+  #
+  # Configure timeouts
+  #
+  TimeOut 10
+  RequestReadTimeout handshake=10-20,MinRate=500 header=10-20,MinRate=500 body=10-120,MinRate=500
+  LogLevel reqtimeout:info
+
   #
   # Add the unique ID to the request headers
   #
   RewriteRule . - [F,L]
 
   #
-  # Block requests for the old 404 map tile
-  # and force cache headers on response
+  # Block trace scraper
   #
-  <Location /openlayers/img/404.png>
-    Header always set Cache-Control "public, max-age=31536000, immutable"
-    Header always set Expires "Tue, 19 Jan 2038 03:14:07 GMT"
-    RewriteRule ^ - [G,L]
-  </Location>
+  RewriteCond %{HTTP_USER_AGENT} "python-httpx/0.24.1"
+  RewriteRule . - [F,L]
+
+  #
+  # Block out of control spider
+  #
+  RewriteCond %{HTTP_USER_AGENT} "Bytespider"
+  RewriteRule . - [F,L]
 
   #
   # Block attempts to access old API versions
   #
   RewriteRule ^/api/0.6/changeset/6823497/download$ - [F,L]
 
+  #
+  # Ignore Vicon Valerus "online" status pings
+  # https://gist.github.com/Firefishy/86ed5b86991b225179b54bbafbcd769e
+  #
+  RewriteCond "%{QUERY_STRING}" "^q=abcde&t=20"
+  RewriteRule "^/api/0\.6/notes/search$" - [R=429,L]
+
   #
   # Force special MIME type for crossdomain.xml files
   #
     ExpiresDefault "access plus 10 years"
   </Location>
   <Location /openlayers/>
-    ExpiresDefault "access plus 7 days"
+    Header unset Last-Modified
+    FileETag Size
+
+    Header always set Cache-Control "public, max-age=31536000, immutable"
+    Header always set Expires "Tue, 19 Jan 2038 03:14:07 GMT"
   </Location>
 
   #
   SetEnv OPENSTREETMAP_STATUS <%= @status %>
   SetEnv SECRET_KEY_BASE <%= @secret_key_base %>
   Alias /favicon.ico <%= node[:web][:base_directory] %>/rails/app/assets/favicons/favicon.ico
-  Alias /openlayers <%= node[:web][:base_directory] %>/rails/vendor/assets/openlayers
-  Alias /stats /store/rails/stats
-  Alias /user/image /store/rails/user/image
-  Alias /attachments /store/rails/attachments
-
-  #
-  # Preserve the host name when forwarding to the proxy
-  #
-  ProxyPreserveHost on
-
-  #
-  # Set a long timeout - changeset uploads can take a long time
-  #
-  ProxyTimeout 3600
+  Alias /openlayers <%= node[:web][:base_directory] %>/static/openlayers
+  RedirectPermanent /stats https://planet.openstreetmap.org/statistics
 
   #
-  # Allow all proxy requests
+  # Pass authentication related headers to cgimap
   #
-  <Proxy *>
-    Require all granted
-  </Proxy>
+  <Location />
+    CGIPassAuth On
+  </Location>
 
   #
-  # Pass some other API calls to the backends via a load balancer
+  # Pass supported calls to cgimap
   #
-  ProxyPass /api/0.6/map balancer://backend/api/0.6/map
-  ProxyPass /api/0.6/tracepoints balancer://backend/api/0.6/tracepoints
-  ProxyPass /api/0.6/amf/read balancer://backend/api/0.6/amf/read
-  ProxyPass /api/0.6/swf/trackpoints balancer://backend/api/0.6/swf/trackpoints
-  ProxyPassMatch ^(/api/0\.6/changeset/[0-9]+)$ balancer://backend$1
-  ProxyPassMatch ^(/api/0\.6/changeset/[0-9]+/upload)$ balancer://amsterdam$1
-  ProxyPassMatch ^(/api/0\.6/changeset/[0-9]+/download)$ balancer://backend$1
-  ProxyPassMatch ^(/api/0\.6/(node|way|relation)/[0-9]+)$ balancer://backend$1
-  ProxyPassMatch ^(/api/0\.6/(node|way|relation)/[0-9]+/(full|history|search|ways))$ balancer://backend$1
-  ProxyPass /api/0.6/nodes balancer://backend/api/0.6/nodes
-  ProxyPass /api/0.6/ways balancer://backend/api/0.6/ways
-  ProxyPass /api/0.6/relations balancer://backend/api/0.6/relations
-  ProxyPassMatch ^(/trace/[0-9]+/data(|/|.xml))$ balancer://backend$1
+  RewriteRule ^/api/0\.6/map(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
+  RewriteCond %{REQUEST_METHOD} ^(HEAD|GET)$
+  RewriteRule ^/api/0\.6/(node|way|relation|changeset)/[0-9]+(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
+  RewriteRule ^/api/0\.6/(node|way|relation)/[0-9]+/history(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
+  RewriteRule ^/api/0\.6/(node|way|relation)/[0-9]+/relations(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
+  RewriteRule ^/api/0\.6/node/[0-9]+/ways(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
+  RewriteRule ^/api/0\.6/(way|relation)/[0-9]+/full(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
+  RewriteRule ^/api/0\.6/(nodes|ways|relations)(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
+  RewriteRule ^/api/0\.6/changeset/[0-9]+/(upload|download)(\.json|\.xml)?$ unix:/run/cgimap/socket|fcgi://127.0.0.1$0 [P]
 
   #
   # Redirect trac and wiki requests to the right places
   RedirectPermanent /images/cc_button.png https://www.openstreetmap.org/assets/cc_button.png
 
   #
-  # Define a load balancer for the local backends
-  #
-  <Proxy balancer://backend>
-    ProxySet lbmethod=bybusyness
-<% node[:web][:backends].each do |backend| -%>
-    BalancerMember https://<%= backend %> disablereuse=on
-<% end -%>
-  </Proxy>
-
-  #
-  # Define a load balancer for the Amsterdam backends
-  #
-  <Proxy balancer://amsterdam>
-    ProxySet lbmethod=bybusyness
-<% ["rails1.ams", "rails2.ams", "rails3.ams"].each do |backend| -%>
-    BalancerMember https://<%= backend %> disablereuse=on
-<% end -%>
-  </Proxy>
-
-  #
-  # Define a load balancer for the Bytemark backends
-  #
-  <Proxy balancer://bytemark>
-    ProxySet lbmethod=bybusyness
-<% ["rails4.bm", "rails5.bm"].each do |backend| -%>
-    BalancerMember https://<%= backend %> disablereuse=on
-<% end -%>
-  </Proxy>
-
-  #
-  # Redirect api requests made to www.osm.org to api.osm.org
+  # Redirect api requests made to www.openstreetmap.org to api.openstreetmap.org
   #
 #  RewriteCond %{HTTP_HOST} =www.openstreetmap.org
 #  RewriteRule ^/api/(.*)$ https://api.openstreetmap.org/api/$1 [L,NE,R=permanent]
 
   #
-  # Redirect non-api requests made to api.osm.org to www.osm.org
+  # Redirect non-api requests made to api.openstreetmap.org to www.openstreetmap.org
   #
   RewriteCond %{HTTP_HOST} =api.openstreetmap.org
   RewriteCond %{REQUEST_URI} !^/api/
   RedirectPermanent / https://www.openstreetmap.org/
 </VirtualHost>
 
+<VirtualHost *:80>
+  ServerName osm.org
+
+  Header always set Cache-Control "max-age=31536000"
+  Header always set Expires "Tue, 19 Jan 2038 03:14:07 GMT"
+
+  RewriteEngine on
+
+  RewriteRule ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 [R=permanent,L]
+
+  RewriteCond %{REQUEST_URI} !^/server-status$
+  RewriteRule ^(.*)$ https://osm.org$1 [L,NE,R=permanent]
+</VirtualHost>
+
+<VirtualHost *:80>
+  ServerName www.osm.org
+
+  Header always set Cache-Control "max-age=31536000"
+  Header always set Expires "Tue, 19 Jan 2038 03:14:07 GMT"
+
+  RewriteEngine on
+
+  RewriteRule ^/\.well-known/acme-challenge/(.*)$ http://acme.openstreetmap.org/.well-known/acme-challenge/$1 [R=permanent,L]
+
+  RewriteCond %{REQUEST_URI} !^/server-status$
+  RewriteRule ^(.*)$ https://www.osm.org$1 [L,NE,R=permanent]
+</VirtualHost>
+
 <VirtualHost *:80>
   ServerName openstreetmap.org
 
 <Directory <%= node[:web][:base_directory] %>/rails/public>
   Require all granted
 
+  RewriteCond "%{HTTP:Accept-encoding}" "br"
+  RewriteCond "%{REQUEST_FILENAME}\.br" -s
+  RewriteRule "^(.*)\.(css|ico|js|json|svg|xml)$" "$1\.$2\.br" [QSA]
+
   RewriteCond "%{HTTP:Accept-encoding}" "gzip"
   RewriteCond "%{REQUEST_FILENAME}\.gz" -s
   RewriteRule "^(.*)\.(css|ico|js|json|svg|xml)$" "$1\.$2\.gz" [QSA]
 
-  RewriteRule "\.css\.gz$" "-" [T=text/css,E=no-gzip:1]
-  RewriteRule "\.ico\.gz$"  "-" [T=image/vnd.microsoft.icon,E=no-gzip:1]
-  RewriteRule "\.js\.gz$"  "-" [T=text/javascript,E=no-gzip:1]
-  RewriteRule "\.json\.gz$"  "-" [T=application/json,E=no-gzip:1]
-  RewriteRule "\.svg\.gz$"  "-" [T=image/svg+xml,E=no-gzip:1]
-  RewriteRule "\.xml\.gz$"  "-" [T=application/xml,E=no-gzip:1]
+  RewriteRule "\.css\.(br|gz)$" "-" [T=text/css,E=no-gzip:1,E=no-brotli:1]
+  RewriteRule "\.ico\.(br|gz)$"  "-" [T=image/vnd.microsoft.icon,E=no-gzip:1,E=no-brotli:1]
+  RewriteRule "\.js\.(br|gz)$"  "-" [T=text/javascript,E=no-gzip:1,E=no-brotli:1]
+  RewriteRule "\.json\.(br|gz)$"  "-" [T=application/json,E=no-gzip:1,E=no-brotli:1]
+  RewriteRule "\.svg\.(br|gz)$"  "-" [T=image/svg+xml,E=no-gzip:1,E=no-brotli:1]
+  RewriteRule "\.xml\.(br|gz)$"  "-" [T=application/xml,E=no-gzip:1,E=no-brotli:1]
+
+  <FilesMatch "\.(css|ico|js|json|svg|xml)\.br$">
+    Header append Content-Encoding br
+    Header append Vary Accept-Encoding
+  </FilesMatch>
 
   <FilesMatch "\.(css|ico|js|json|svg|xml)\.gz$">
     Header append Content-Encoding gzip
   </FilesMatch>
 </Directory>
 
-<Directory /srv/www.openstreetmap.org/rails/app/assets>
+<Directory /srv/www.openstreetmap.org/static>
   Require all granted
 </Directory>
 
-<Directory /srv/www.openstreetmap.org/rails/vendor/assets>
-  Require all granted
-</Directory>
-
-<Directory /store/rails/stats>
-  Require all granted
-</Directory>
-
-<Directory /store/rails/user/image>
+<Directory /srv/www.openstreetmap.org/rails/app/assets>
   Require all granted
 </Directory>
 
-<Directory /store/rails/attachments>
+<Directory /srv/www.openstreetmap.org/rails/vendor/assets>
   Require all granted
 </Directory>
index b4c4174476f48824cac2f3d6ca827a0d255ef364..ce3af0b3430275a258e413236220ea0680dfaa96 100644 (file)
@@ -19,24 +19,92 @@ def categorise_uri(line)
   end
 end
 
-parser = ApacheLogRegex.new('%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %Dus %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x')
+parser = ApacheLogRegex.new('%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %Dus %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x %{AUTH_METHOD}e')
 last_write = Time.now
-statistics = { :status => Hash.new(0), :uri => Hash.new(0) }
+
+statistics = {
+  :status => Hash.new(0),
+  :uri => Hash.new(0),
+  :count => Hash.new(0),
+  :bytes => Hash.new(0),
+  :seconds => Hash.new(0.0),
+  :ssl => Hash.new(0),
+  :auth => Hash.new(0)
+}
 
 File::Tail::Logfile.tail("/var/log/apache2/access.log") do |line|
   begin
-    hash = parser.parse(line)
-    status = hash["%>s"]
+    hash = parser.parse!(line)
+
     uri = categorise_uri(hash["%r"])
+    status = hash["%>s"]
+    bytes = hash["%O"].to_i
+    seconds = hash["%Dus"].to_f / 1000000
+    protocol = hash["%{SSL_PROTOCOL}x"]
+    cipher = hash["%{SSL_CIPHER}x"]
+    auth = hash["%{AUTH_METHOD}e"]
 
     statistics[:status][status] += 1
     statistics[:uri][uri] += 1
-  rescue ApacheLogRegex::ParseError
-    # nil
+    statistics[:count][[uri, status]] += 1
+    statistics[:bytes][[uri, status]] += bytes
+    statistics[:seconds][[uri, status]] += seconds
+    statistics[:ssl][[protocol, cipher]] += 1 unless protocol == "-"
+    statistics[:auth][auth] += 1 unless auth == "-"
+  rescue ApacheLogRegex::ParseError => ex
+    STDERR.puts ex.to_s
   end
 
   if Time.now - last_write > 10
-    File.write("/srv/www.openstreetmap.org/rails/tmp/statistics.json", statistics.to_json)
+    File.write("/srv/www.openstreetmap.org/rails/tmp/statistics.json", statistics.slice(:status, :uri).to_json)
+
+    File.open("/var/lib/prometheus/node-exporter/api.tmp", "w") do |file|
+      file.puts "# HELP api_call_count_total Number of calls by type and status"
+      file.puts "# TYPE api_call_count_total counter"
+
+      statistics[:count].each do |key, value|
+        uri, status = key
+
+        file.puts "api_call_count_total{uri=\"#{uri}\",status=\"#{status}\"} #{value}"
+      end
+
+      file.puts "# HELP api_call_bytes_total Number of bytes returned by type and status"
+      file.puts "# TYPE api_call_bytes_total counter"
+
+      statistics[:bytes].each do |key, value|
+        uri, status = key
+
+        file.puts "api_call_bytes_total{uri=\"#{uri}\",status=\"#{status}\"} #{value}"
+      end
+
+      file.puts "# HELP api_call_seconds_total Number of seconds returned by type and status"
+      file.puts "# TYPE api_call_seconds_total counter"
+
+      statistics[:seconds].each do |key, value|
+        uri, status = key
+
+        file.puts "api_call_seconds_total{uri=\"#{uri}\",status=\"#{status}\"} #{value}"
+      end
+
+      file.puts "# HELP api_call_ssl_total Number of calls by SSL protocol and cipher"
+      file.puts "# TYPE api_call_ssl_total counter"
+
+      statistics[:ssl].each do |key, value|
+        protocol, cipher = key
+
+        file.puts "api_call_ssl_total{protocol=\"#{protocol}\",cipher=\"#{cipher}\"} #{value}"
+      end
+
+      file.puts "# HELP api_call_auth_method_total Number of calls by authentication method"
+      file.puts "# TYPE api_call_auth_method_total counter"
+
+      statistics[:auth].each do |method, value|
+        file.puts "api_call_auth_method_total{method=\"#{method}\"} #{value}"
+      end
+    end
+
+    File.rename("/var/lib/prometheus/node-exporter/api.tmp", "/var/lib/prometheus/node-exporter/api.prom")
+
     last_write = Time.now
   end
 end
diff --git a/cookbooks/web/templates/default/deliver-message.erb b/cookbooks/web/templates/default/deliver-message.erb
new file mode 100644 (file)
index 0000000..7653818
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+export RAILS_ENV="production"
+export SECRET_KEY_BASE="<%= @secret_key_base %>"
+
+exec /usr/local/bin/passenger-ruby /srv/www.openstreetmap.org/rails/script/deliver-message "$@"
index 7f9e1de77e20a55e7130c8678b3986f12135d687..608fd4d38699234f2ac76e06f9cff083612f35f4 100644 (file)
   create 0660 rails rails
   sharedscripts
   postrotate
-<% if File.directory?("#{node[:web][:base_directory]}/rails") -%>
-    PASSENGER_INSTANCE_REGISTRY_DIR=<%= node[:passenger][:instance_registry_dir] %> /usr/bin/passenger-config restart-app --ignore-app-not-running <%= node[:web][:base_directory] %>/rails > /dev/null
+<% if node[:recipes].include?("web::rails") -%>
+    /bin/sleep 30
+    PASSENGER_INSTANCE_REGISTRY_DIR=<%= node[:passenger][:instance_registry_dir] %> /usr/bin/passenger-config restart-app --ignore-app-not-running --name rails > /dev/null
 <% end -%>
-<% if File.directory?("#{node[:web][:base_directory]}/gpx-import") -%>
-    /bin/systemctl try-reload-or-restart gpx-import
+<% if node[:recipes].include?("web::frontend") -%>
+    /bin/systemctl try-reload-or-restart rails-jobs@mailers
+    /bin/systemctl try-reload-or-restart rails-jobs@storage
+    /bin/systemctl try-reload-or-restart rails-jobs@traces
 <% end -%>
-<% if File.directory?("#{node[:web][:base_directory]}/cgimap") -%>
+<% if node[:recipes].include?("web::cgimap") -%>
     /bin/systemctl reload cgimap
     /usr/bin/rsync --preallocate <%= node[:web][:log_directory] %>/cgimap.log.2.gz ironbelly::logs/www.openstreetmap.org/cgimap-<%= node[:hostname] %>-`date -d "-2 days" +%Y-%m-%d`.gz
 <% end -%>
diff --git a/cookbooks/web/templates/default/passenger.cron.erb b/cookbooks/web/templates/default/passenger.cron.erb
deleted file mode 100644 (file)
index d3cef76..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-# Get a list of rack processes that are running
-pgrep -u rails -f Rack | sort > /tmp/rails.actual.$$
-
-# Get a list of rack processes we expect to be running
-PASSENGER_INSTANCE_REGISTRY_DIR=<%= node[:passenger][:instance_registry_dir] %> passenger-status | awk '/PID:/ { print $3 }' | sort > /tmp/rails.expected.$$
-
-# Get a list of unexpected rack processes
-pids=$(comm -23 /tmp/rails.actual.$$ /tmp/rails.expected.$$)
-
-# Kill any expected rack processes
-[ -n "$pids" ] && kill -9 $pids > /dev/null 2>&1
-
-# Remove our temporary files
-rm -f /tmp/rails.actual.$$ /tmp/rails.expected.$$
diff --git a/cookbooks/web/templates/default/statistics.cron.erb b/cookbooks/web/templates/default/statistics.cron.erb
deleted file mode 100644 (file)
index 900856c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-0 0 * * * rails /usr/local/bin/statistics
index a42357ba8e2f3ac4203ad14faaac4b15819c9f9c..30a23a7ac992698361991becacea9d482343183b 100644 (file)
@@ -10,7 +10,7 @@ export PATH=$PATH:/usr/local/bin
 <%= @ruby %> -W0 <%= @directory %>/script/statistics > <%= @directory %>/tmp/data_stats.html
 
 # Move new statistics into place
-mv -f <%= @directory %>/tmp/data_stats.html /store/rails/stats
+rsync --quiet <%= @directory %>/tmp/data_stats.html planet.openstreetmap.org::statistics
 
 # Mail statistics to Blackadder
-mail -s "OpenStreetMap Statistics" blackadderajr@gmail.com < /store/rails/stats/data_stats.html
+mail -s "OpenStreetMap Statistics" blackadderajr@gmail.com < <%= @directory %>/tmp/data_stats.html
index 0b77f3aa725ca3615c9b9805eae91beeb8d285cf..1c39edb1b6602c208c4382884362100ac096752e 100644 (file)
@@ -7,3 +7,4 @@ description       "Installs and configures servers for wiki.openstreetmap.org"
 version           "1.0.0"
 supports          "ubuntu"
 depends           "mediawiki"
+depends           "systemd"
index e7d7daf3fc19f6ffc216103b4548516394a792b5..e7a2b3e57b5ea6067bd41b3347baae9d695e89c1 100644 (file)
@@ -30,8 +30,14 @@ end
 mediawiki_site "wiki.openstreetmap.org" do
   aliases ["wiki.osm.org", "wiki.openstreetmap.com", "wiki.openstreetmap.net",
            "wiki.openstreetmap.ca", "wiki.openstreetmap.eu",
-           "wiki.openstreetmap.pro", "wiki.openstreetmaps.org"]
-  directory "/srv/wiki.openstreetmap.org"
+           "wiki.openstreetmap.pro", "wiki.openstreetmaps.org",
+           "osm.wiki", "www.osm.wiki", "wiki.osm.wiki"]
+
+  fpm_max_children 200
+  fpm_start_servers 25
+  fpm_min_spare_servers 25
+  fpm_max_spare_servers 50
+  fpm_prometheus_port 9253
 
   database_name "wiki"
   database_user "wiki-user"
@@ -47,8 +53,8 @@ mediawiki_site "wiki.openstreetmap.org" do
 
   metanamespace "Wiki"
 
-  recaptcha_public_key "6LdFIQATAAAAAMwtHeI8KDgPqvRbXeNYSq1gujKz"
-  recaptcha_private_key passwords["recaptcha"]
+  hcaptcha_public_key "b67a410b-955e-4049-b432-f9c00e0202c0"
+  hcaptcha_private_key passwords["hcaptcha"]
 
   # site_notice "MAINTENANCE: WIKI READ-ONLY UNTIL Monday 16 May 2016 - 11:00am UTC/GMT."
   # site_readonly "MAINTENANCE: WIKI READ-ONLY UNTIL Monday 16 May 2016 - 11:00am UTC/GMT."
@@ -76,7 +82,7 @@ end
 
 mediawiki_extension "OsmWikibase" do
   site "wiki.openstreetmap.org"
-  repository "git://github.com/nyurik/OsmWikibase.git"
+  repository "https://github.com/nyurik/OsmWikibase.git"
   reference "master"
 end
 
@@ -101,25 +107,38 @@ mediawiki_extension "MultiMaps" do
   template "mw-ext-MultiMaps.inc.php.erb"
   template_cookbook "wiki"
   variables :thunderforest_key => passwords["thunderforest"]
+  action :delete
+end
+
+mediawiki_extension "JsonConfig" do
+  site "wiki.openstreetmap.org"
+  template "mw-ext-JsonConfig.inc.php.erb"
+  template_cookbook "wiki"
+end
+
+mediawiki_extension "Kartographer" do
+  site "wiki.openstreetmap.org"
+  template "mw-ext-Kartographer.inc.php.erb"
+  template_cookbook "wiki"
 end
 
 cookbook_file "/srv/wiki.openstreetmap.org/osm_logo_wiki.png" do
   owner node[:mediawiki][:user]
   group node[:mediawiki][:group]
-  mode 0o644
+  mode "644"
 end
 
 template "/srv/wiki.openstreetmap.org/robots.txt" do
   owner node[:mediawiki][:user]
   group node[:mediawiki][:group]
-  mode 0o644
+  mode "644"
   source "robots.txt.erb"
 end
 
 cookbook_file "/srv/wiki.openstreetmap.org/favicon.ico" do
   owner node[:mediawiki][:user]
   group node[:mediawiki][:group]
-  mode 0o644
+  mode "644"
 end
 
 directory "/srv/wiki.openstreetmap.org/dump" do
@@ -128,10 +147,48 @@ directory "/srv/wiki.openstreetmap.org/dump" do
   mode "0775"
 end
 
-template "/etc/cron.d/wiki-dump" do
-  owner "root"
-  group "root"
-  mode 0o644
-  source "wiki-dump.erb"
-  variables :directory => "/srv/wiki.openstreetmap.org"
+systemd_service "wiki-dump" do
+  description "Wiki dump"
+  type "oneshot"
+  exec_start "/usr/bin/php w/maintenance/dumpBackup.php --full --quiet --output=gzip:dump/dump.xml.gz"
+  working_directory "/srv/wiki.openstreetmap.org"
+  user "wiki"
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/srv/wiki.openstreetmap.org/dump"
+end
+
+systemd_timer "wiki-dump" do
+  description "Wiki dump"
+  on_calendar "02:00"
+end
+
+service "wiki-dump.timer" do
+  action [:enable, :start]
+end
+
+systemd_service "wiki-rdf-dump" do
+  description "Wiki RDF dump"
+  type "oneshot"
+  exec_start [
+    "/usr/bin/php w/extensions/Wikibase/repo/maintenance/dumpRdf.php --wiki wiki --format ttl --flavor full-dump --entity-type item --entity-type property --no-cache --output /tmp/wikibase-rdf.ttl",
+    "/bin/gzip -9 /tmp/wikibase-rdf.ttl",
+    "/bin/mv /tmp/wikibase-rdf.ttl.gz /srv/wiki.openstreetmap.org/dump/wikibase-rdf.ttl.gz"
+  ]
+  working_directory "/srv/wiki.openstreetmap.org"
+  user "wiki"
+  sandbox :enable_network => true
+  memory_deny_write_execute false
+  restrict_address_families "AF_UNIX"
+  read_write_paths "/srv/wiki.openstreetmap.org/dump"
+end
+
+systemd_timer "wiki-rdf-dump" do
+  description "Wiki RDF dump"
+  on_calendar "04:00"
+end
+
+service "wiki-rdf-dump.timer" do
+  action [:enable, :start]
 end
diff --git a/cookbooks/wiki/templates/default/mw-ext-JsonConfig.inc.php.erb b/cookbooks/wiki/templates/default/mw-ext-JsonConfig.inc.php.erb
new file mode 100644 (file)
index 0000000..b3c666b
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+# DO NOT EDIT - This file is being maintained by Chef
+
+# JsonConfig is a requirement for Kartographer extension
+wfLoadExtension( 'JsonConfig' );
+
diff --git a/cookbooks/wiki/templates/default/mw-ext-Kartographer.inc.php.erb b/cookbooks/wiki/templates/default/mw-ext-Kartographer.inc.php.erb
new file mode 100644 (file)
index 0000000..1fef9a1
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+# DO NOT EDIT - This file is being maintained by Chef
+
+wfLoadExtension( 'Kartographer' );
+$wgKartographerMapServer = 'https://tile.openstreetmap.org';
+$wgKartographerSrcsetScales = [];
+$wgKartographerDfltStyle = '';
+$wgKartographerStyles = [];
+$wgKartographerSimpleStyleMarkers = false;
diff --git a/cookbooks/wiki/templates/default/mw-ext-MultiMaps.inc.php.erb b/cookbooks/wiki/templates/default/mw-ext-MultiMaps.inc.php.erb
deleted file mode 100644 (file)
index 7d21412..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-# DO NOT EDIT - This file is being maintained by Chef
-
-require_once "$IP/extensions/MultiMaps/MultiMaps.php";
-
-# Array of String. Array containing all the mapping services that will be made available to the user.
-# First value - default service, which will be used if the service is not in the parameters
-# Values may be a valid name of class based on class BaseMapService or some string and an array if they
-# denote different tiles within a BaseMapService
-$egMultiMaps_MapServices = [
-  'Leaflet',
-  'transport' => [
-    'service' => 'Leaflet',
-    'attribution' => '&copy; <a href="https://osm.org/copyright">OpenStreetMap contributors</a>. Tiles courtesy of <a href="https://www.thunderforest.com/" target="_blank">Andy Allan</a>',
-    'source' => 'https://tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=<%= @thunderforest_key %>',
-  ],
-];
index 6bbede43fbf55e1d49d91d027f4e9dae0488ab82..6f7e8d6ebb7a22e75531ebd1d694dd32e45e922c 100644 (file)
@@ -1,11 +1,14 @@
 <?php
 # DO NOT EDIT - This file is being maintained by Chef
 
+use MediaWiki\MediaWikiServices;
+use Wikibase\Lib\SettingsArray;
+
 $wgEnableWikibaseRepo = true;
 $wgEnableWikibaseClient = true;
 
-require_once "$IP/extensions/Wikibase/repo/Wikibase.php";
-require_once "$IP/extensions/Wikibase/client/WikibaseClient.php";
+wfLoadExtension( 'WikibaseRepository', "$IP/extensions/Wikibase/extension-repo.json" );
+wfLoadExtension( 'WikibaseClient', "$IP/extensions/Wikibase/extension-client.json" );
 // Include Wikibase.searchindex.php to include string and text values in the full text index:
 require_once "$IP/extensions/Wikibase/repo/config/Wikibase.searchindex.php";
 
@@ -17,8 +20,6 @@ call_user_func( function() {
         $wgNamespacesToBeSearchedDefault,
         $wgWBRepoSettings;
 
-    $wgContentHandlerUseDB = true;
-
     $baseNs = 120;
 
     // Define custom namespaces. Use these exact constant names.
@@ -33,12 +34,32 @@ call_user_func( function() {
     $wgExtraNamespaces[WB_NS_PROPERTY] = 'Property';
     $wgExtraNamespaces[WB_NS_PROPERTY_TALK] = 'Property_talk';
 
-    // Tell Wikibase which namespace to use for which kind of entity
-    $wgWBRepoSettings['entityNamespaces']['item'] = WB_NS_ITEM;
-    $wgWBRepoSettings['entityNamespaces']['property'] = WB_NS_PROPERTY;
+    $wgWBRepoSettings['entitySources'] = function ( SettingsArray $settings ) {
+        global $wgServer;
+
+        $entityNamespaces = [
+            'item' => WB_NS_ITEM,
+            'property' => WB_NS_PROPERTY,
+        ];
+
+        $hookContainer = MediaWikiServices::getInstance()->getHookContainer();
+        $hookContainer->run( 'WikibaseRepoEntityNamespaces', [ &$entityNamespaces ] );
+
+        return [
+             $settings->getSetting( 'localEntitySourceName' ) => [
+                                    'entityNamespaces' => $entityNamespaces,
+                                    'repoDatabase' => false,
+                                    'baseUri' => $wgServer . '/entity/',
+                                    'rdfNodeNamespacePrefix' => 'wd',
+                                    'rdfPredicateNamespacePrefix' => '',
+                                    'interwikiPrefix' => '',
+             ],
+        ];
+    };
 
     // Make sure we use the same keys on repo and clients, so we can share cached objects.
-    $wgWBRepoSettings['sharedCacheKeyPrefix'] = $wgDBname . ':WBL/' . rawurlencode( WBL_VERSION );
+    $wgWBRepoSettings['sharedCacheKeyPrefix'] = $wgDBname . ':WBL';
+    $wgWBRepoSettings['sharedCacheKeyGroup'] = $wgDBname;
 
     // Include Wikibase items in the regular search result by default
     $wgNamespacesToBeSearchedDefault[WB_NS_ITEM] = true;
@@ -56,15 +77,55 @@ call_user_func( function() {
 
 } );
 
-// Adapted from "$IP/extensions/Wikibase/client/ExampleSettings.php";
+// Adapted from "$IP/extensions/Wikibase/client/config/WikibaseClient.example.php";
 
 // The global site ID by which this wiki is known on the repo.
 // Defaults to $wgDBname.
 // $wgWBClientSettings['siteGlobalID'] = "osm";
-// $wgWBClientSettings['injectRecentChanges'] = true;
-// $wgWBClientSettings['showExternalRecentChanges'] = true;
+
+$wgWBClientSettings['injectRecentChanges'] = true;
+$wgWBClientSettings['showExternalRecentChanges'] = true;
+
+// Base URL for building links to the repository.
+// Assumes your wiki is setup as "http://repo.example.org/wiki/"
+// This can be protocol relative, such as "//www.wikidata.org"
+$wgWBClientSettings['repoUrl'] = "https://wiki.openstreetmap.org";
+
+// This setting is optional if you have the same type of setup for your
+// repo and client.  It will default to using the client's $wgArticlePath setting,
+// and if you do not have $wgArticlePath set anywhere, MediaWiki has a default for it.
+$wgWBClientSettings['repoArticlePath'] = "/wiki/$1";
+
+// Assuming your wiki is setup with such script path as "http://repo.example.org/w/api.php". This
+// should be the same as the $wgScriptPath setting if you have it set in your repo. If $wgScriptPath
+// is not set, then MediaWiki assumes a default.
+//
+// If your client and repo are setup in the same way, then the below setting is optional and will
+// default to what you have $wgScriptPath set in the client.
+$wgWBClientSettings['repoScriptPath'] = "/w";
+
+// Tell the client which namespace ID on the repo holds which type of entity.
+$baseRepoNs = 120;
+
+define( 'WB_REPO_NS_ITEM', $baseRepoNs );
+define( 'WB_REPO_NS_PROPERTY', $baseRepoNs + 2 );
+
+$wgWBClientSettings['entitySources'] = [
+        'local' => [
+                'repoDatabase' => $wgDBname,
+                'baseUri' => $wgWBClientSettings['repoUrl'] . '/entity',
+                'entityNamespaces' => [
+                        'item' => WB_REPO_NS_ITEM,
+                        'property' => WB_REPO_NS_PROPERTY
+                ],
+                'rdfNodeNamespacePrefix' => 'wd',
+                'rdfPredicateNamespacePrefix' => '',
+                'interwikiPrefix' => '',
+        ],
+];
 
 $wgWBClientSettings['namespaces'] = [ NS_MAIN ];
+$wgWBClientSettings['repoSiteName'] = 'Data Items';
 
 // Avoid complaints that nobody seems to know the cause off...
 $wgWBClientSettings['entityUsagePerPageLimit'] = 500;
@@ -91,8 +152,3 @@ $wgGroupPermissions['data-admin']['property-create'] = true;
 
 // See https://www.mediawiki.org/wiki/Wikibase/Installation/Advanced_configuration#Define_links_for_external_identifiers
 $wgWBRepoSettings['formatterUrlProperty'] = 'P8';
-
-// Disable Wikibase searchbox with this hack (hopefully Wikibase will implement support for it soon)
-// See https://phabricator.wikimedia.org/T205560
-// After upgrading to Wikibase 1.33, this line can be deleted. The 'enableEntitySearchUI' above will do the same thing.
-$wgResourceModules['wikibase.ui.entitysearch']['scripts'] = [];
index de552f04968ad9b22cffee3658752b18e325d965..932d07ebacda4aedd0da02162a9a5a9404ddea59 100644 (file)
@@ -19,6 +19,15 @@ Disallow: /wiki/Special:Search
 User-agent: Exabot
 Crawl-delay: 60
 
+User-Agent: ImagesiftBot
+Crawl-delay: 60
+
+User-agent: SemrushBot
+Crawl-delay: 60
+
+User-agent: SeznamBot
+Crawl-delay: 60
+
 Sitemap: https://wiki.openstreetmap.org/sitemap-index-wiki.xml
 
 Host: wiki.openstreetmap.org
diff --git a/cookbooks/wiki/templates/default/squid.conf.erb b/cookbooks/wiki/templates/default/squid.conf.erb
deleted file mode 100644 (file)
index 55588a0..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-acl osmwiki_sites dstdomain wiki.openstreetmap.org wiki.osm.org
-
-http_access allow osmwiki_sites
-
-cache_peer localhost parent 80 0 no-query originserver name=osmwikiAccel login=PASS connect-timeout=60 no-digest weight=1000
-
-cache_peer_access osmwikiAccel allow osmtile_sites
-cache_peer_access osmwikiAccel deny all
-
-#----------------------------------
-
diff --git a/cookbooks/wiki/templates/default/wiki-dump.erb b/cookbooks/wiki/templates/default/wiki-dump.erb
deleted file mode 100644 (file)
index 8139f28..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# DO NOT EDIT - This file is being maintained by Chef
-
-0 2 * * * wiki cd <%= @directory %> && php w/maintenance/dumpBackup.php --full --quiet --output=gzip:dump/dump.xml.gz
index 9cd3956483de21ddd037becfcfa0594ec25a0014..9233459dcf346fb45148cb1829a9c09c5316ac28 100644 (file)
@@ -1,9 +1,6 @@
 # Enable the "wordpress" role
 default[:accounts][:users][:wordpress][:status] = :role
 
-# Use prefork as PHP is to dumb for anything else
-default[:apache][:mpm] = "prefork"
-
 # Set wordpress defaults
 default[:wordpress][:user] = "wordpress"
 default[:wordpress][:group] = "wordpress"
index 1c2fbcb6a4325618c1a1edee5bee1311d627b2d1..92db4b19924c068079c5f7bc8b76a1e3428cf7bd 100644 (file)
@@ -1,14 +1,14 @@
 require "chef/mixin/shell_out"
 
+require "addressable"
 require "httpclient"
-require "php_serialize"
+require "json"
 
 class Chef
   module Wordpress
     extend Chef::Mixin::ShellOut
 
     @api_responses = {}
-    @svn_responses = {}
 
     class << self
       def current_version
@@ -16,31 +16,21 @@ class Chef
       end
 
       def current_plugin_version(name)
-        if svn_cat("https://plugins.svn.wordpress.org/#{name}/trunk/readme.txt") =~ /Stable tag:\s*([^\s\r]*)[\s\r]*/
-          Regexp.last_match[1]
-        else
-          "trunk"
-        end
+        plugin_information(name)["version"]
       end
 
       private
 
       def core_version_check
-        api_get("https://api.wordpress.org/core/version-check/1.6")
+        api_get("https://api.wordpress.org/core/version-check/1.7")
       end
 
-      def api_get(url)
-        @api_responses[url] ||= ::PHP.unserialize(::HTTPClient.new.get_content(url))
+      def plugin_information(name)
+        api_get("https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request[slug]=#{name}")
       end
 
-      def svn_cat(url)
-        unless @svn_responses[url]
-          result = shell_out!("svn", "cat", url)
-
-          @svn_responses[url] = result.stdout.force_encoding("UTF-8")
-        end
-
-        @svn_responses[url]
+      def api_get(url)
+        @api_responses[url] ||= ::JSON.parse(::HTTPClient.new.get_content(url))
       end
     end
   end
index 6aaf827455585efb37c756a8538a91b1f45f5314..09e29c13381b182fb734515e0556d893ad1f4e30 100644 (file)
@@ -6,9 +6,12 @@ description       "Installs and configures Wordpress"
 
 version           "1.0.0"
 supports          "ubuntu"
+depends           "accounts"
 depends           "apache"
 depends           "chef"
+depends           "fail2ban"
+depends           "git"
 depends           "mysql"
+depends           "php"
 depends           "ssl"
 gem               "httpclient"
-gem               "php_serialize"
index 52c544db53f1d8d3389c695e2a3f1eadc59f385b..2849e592f3e067d58fa4969c1f767b4e85527283 100644 (file)
 # limitations under the License.
 #
 
+include_recipe "accounts"
 include_recipe "apache"
+include_recipe "fail2ban"
+include_recipe "git"
 include_recipe "mysql"
+include_recipe "php::fpm"
 
 package %w[
   subversion
-  php
+  php-mbstring
   php-mysql
+  php-igbinary
+  php-imagick
+  php-intl
+  php-xml
 ]
 
-apache_module "php7.2"
+apache_module "proxy"
+apache_module "proxy_fcgi"
 apache_module "rewrite"
 
 fail2ban_filter "wordpress" do
@@ -39,3 +48,16 @@ fail2ban_jail "wordpress" do
   ports [80, 443]
   maxretry 6
 end
+
+directory "/opt/wp-cli" do
+  owner "root"
+  group "root"
+  mode "755"
+end
+
+remote_file "/opt/wp-cli/wp" do
+  source "https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar"
+  owner "root"
+  group "root"
+  mode "755"
+end
index 778ff6583d98bd5f261dec480a42c29c6e60a471..078b926f5d2675f1e9b95d25664f456158fbfdcf 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :plugin, :kind_of => String, :name_attribute => true
+property :plugin, :kind_of => String, :name_property => true
 property :site, :kind_of => String, :required => true
 property :source, :kind_of => String
 property :version, :kind_of => String
@@ -34,10 +36,10 @@ action :create do
       source new_resource.source
       owner node[:wordpress][:user]
       group node[:wordpress][:group]
-      mode 0o755
+      mode "755"
       files_owner node[:wordpress][:user]
       files_group node[:wordpress][:group]
-      files_mode 0o755
+      files_mode "755"
     end
   else
     plugin_repository = new_resource.repository || default_repository
@@ -60,9 +62,24 @@ action :create do
       end
     end
   end
+
+  execute "wp-cli plugin activate #{new_resource.plugin}" do
+    command "/opt/wp-cli/wp --path='#{site_directory}' plugin activate '#{new_resource.plugin}'"
+    user "www-data"
+    group "www-data"
+    not_if "/opt/wp-cli/wp --path='#{site_directory}' plugin is-active '#{new_resource.plugin}'"
+    ignore_failure plugin_repository.start_with?("https://plugins.svn.wordpress.org/")
+  end
 end
 
 action :delete do
+  execute "wp-cli plugin deactivate #{new_resource.plugin}" do
+    command "/opt/wp-cli/wp --path='#{site_directory}' plugin deactivate '#{new_resource.plugin}'"
+    user "www-data"
+    group "www-data"
+    only_if "/opt/wp-cli/wp --path='#{site_directory}' plugin is-active '#{new_resource.plugin}'"
+  end
+
   directory plugin_directory do
     action :delete
     recursive true
index 72af236b6baa2bb96c7e3abf79628bdafe2769c4..52bba4ce5ae9a724f4bdab868e6b140bee303467 100644 (file)
 
 require "securerandom"
 
+unified_mode true
+
 default_action :create
 
-property :site, :kind_of => String, :name_attribute => true
+property :site, :kind_of => String, :name_property => true
 property :aliases, :kind_of => [String, Array]
+property :title, :kind_of => String
+property :admin_user, :kind_of => String, :default => "osm_admin"
+property :admin_email, :kind_of => String, :default => "admins@openstreetmap.org"
 property :directory, :kind_of => String
 property :version, :kind_of => String
 property :database_name, :kind_of => String, :required => true
-property :database_user, :kind_of => String, :required => true
-property :database_password, :kind_of => String, :required => true
+property :database_user, :kind_of => String, :required => [:create]
+property :database_password, :kind_of => String, :required => [:create]
 property :database_prefix, :kind_of => String, :default => "wp_"
+property :wp2fa_encrypt_key, :kind_of => String, :required => true
 property :urls, :kind_of => Hash, :default => {}
+property :fpm_max_children, :kind_of => Integer, :default => 10
+property :fpm_start_servers, :kind_of => Integer, :default => 4
+property :fpm_min_spare_servers, :kind_of => Integer, :default => 2
+property :fpm_max_spare_servers, :kind_of => Integer, :default => 6
+property :fpm_request_terminate_timeout, :kind_of => Integer, :default => 300
+property :fpm_prometheus_port, :kind_of => Integer
 property :reload_apache, :kind_of => [TrueClass, FalseClass], :default => true
 
 action :create do
   version = new_resource.version || Chef::Wordpress.current_version
 
-  node.normal_unless[:wordpress][:sites][new_resource.site] = {}
-
-  node.normal[:wordpress][:sites][new_resource.site][:directory] = site_directory
+  node.default[:wordpress][:sites][new_resource.site] = {
+    :directory => site_directory
+  }
 
-  node.normal_unless[:wordpress][:sites][new_resource.site][:auth_key] = SecureRandom.base64(48)
-  node.normal_unless[:wordpress][:sites][new_resource.site][:secure_auth_key] = SecureRandom.base64(48)
-  node.normal_unless[:wordpress][:sites][new_resource.site][:logged_in_key] = SecureRandom.base64(48)
-  node.normal_unless[:wordpress][:sites][new_resource.site][:nonce_key] = SecureRandom.base64(48)
-  node.normal_unless[:wordpress][:sites][new_resource.site][:auth_salt] = SecureRandom.base64(48)
-  node.normal_unless[:wordpress][:sites][new_resource.site][:secure_auth_salt] = SecureRandom.base64(48)
-  node.normal_unless[:wordpress][:sites][new_resource.site][:logged_in_salt] = SecureRandom.base64(48)
-  node.normal_unless[:wordpress][:sites][new_resource.site][:nonce_salt] = SecureRandom.base64(48)
+  auth_key = persistent_token("wordpress", new_resource.site, "auth_key")
+  secure_auth_key = persistent_token("wordpress", new_resource.site, "secure_auth_key")
+  logged_in_key = persistent_token("wordpress", new_resource.site, "logged_in_key")
+  nonce_key = persistent_token("wordpress", new_resource.site, "nonce_key")
+  auth_salt = persistent_token("wordpress", new_resource.site, "auth_salt")
+  secure_auth_salt = persistent_token("wordpress", new_resource.site, "secure_auth_salt")
+  logged_in_salt = persistent_token("wordpress", new_resource.site, "logged_in_salt")
+  nonce_salt = persistent_token("wordpress", new_resource.site, "nonce_salt")
 
   mysql_user "#{new_resource.database_user}@localhost" do
     password new_resource.database_password
@@ -58,7 +70,7 @@ action :create do
   declare_resource :directory, site_directory do
     owner node[:wordpress][:user]
     group node[:wordpress][:group]
-    mode 0o755
+    mode "755"
   end
 
   subversion site_directory do
@@ -75,23 +87,31 @@ action :create do
     line.gsub!(/password_here/, new_resource.database_password)
     line.gsub!(/wp_/, new_resource.database_prefix)
 
-    line.gsub!(/('AUTH_KEY', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:auth_key]}'")
-    line.gsub!(/('SECURE_AUTH_KEY', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:secure_auth_key]}'")
-    line.gsub!(/('LOGGED_IN_KEY', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:logged_in_key]}'")
-    line.gsub!(/('NONCE_KEY', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:nonce_key]}'")
-    line.gsub!(/('AUTH_SALT', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:auth_salt]}'")
-    line.gsub!(/('SECURE_AUTH_SALT', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:secure_auth_salt]}'")
-    line.gsub!(/('LOGGED_IN_SALT', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:logged_in_salt]}'")
-    line.gsub!(/('NONCE_SALT', *)'put your unique phrase here'/, "\\1'#{node[:wordpress][:sites][new_resource.site][:nonce_salt]}'")
-
-    if line =~ /define\('WP_DEBUG'/
-      line += "\n"
-      line += "/**\n"
-      line += " * Don't allow file editing.\n"
-      line += " */\n"
-      line += "define('DISALLOW_FILE_EDIT', true);\n"
-      line += "define('FORCE_SSL_LOGIN', true);\n"
-      line += "define('FORCE_SSL_ADMIN', true);\n"
+    line.gsub!(/('AUTH_KEY', *)'put your unique phrase here'/, "\\1'#{auth_key}'")
+    line.gsub!(/('SECURE_AUTH_KEY', *)'put your unique phrase here'/, "\\1'#{secure_auth_key}'")
+    line.gsub!(/('LOGGED_IN_KEY', *)'put your unique phrase here'/, "\\1'#{logged_in_key}'")
+    line.gsub!(/('NONCE_KEY', *)'put your unique phrase here'/, "\\1'#{nonce_key}'")
+    line.gsub!(/('AUTH_SALT', *)'put your unique phrase here'/, "\\1'#{auth_salt}'")
+    line.gsub!(/('SECURE_AUTH_SALT', *)'put your unique phrase here'/, "\\1'#{secure_auth_salt}'")
+    line.gsub!(/('LOGGED_IN_SALT', *)'put your unique phrase here'/, "\\1'#{logged_in_salt}'")
+    line.gsub!(/('NONCE_SALT', *)'put your unique phrase here'/, "\\1'#{nonce_salt}'")
+
+    if line =~ /Add any custom values between this line/
+      line += "\r\n"
+      line += "/**\r\n"
+      line += " * Don't allow file editing.\r\n"
+      line += " */\r\n"
+      line += "define( 'WP_HOME', 'https://#{new_resource.site}');\r\n"
+      line += "define( 'WP_SITEURL', 'https://#{new_resource.site}');\r\n"
+      line += "define( 'DISALLOW_FILE_EDIT', true);\r\n"
+      line += "define( 'DISALLOW_FILE_MODS', true);\r\n"
+      line += "define( 'AUTOMATIC_UPDATER_DISABLED', true);\r\n"
+      line += "define( 'FORCE_SSL_LOGIN', true);\r\n"
+      line += "define( 'FORCE_SSL_ADMIN', true);\r\n"
+      line += "define( 'WP_FAIL2BAN_SITE_HEALTH_SKIP_FILTERS', true);\r\n"
+      line += "define( 'WP_ENVIRONMENT_TYPE', 'production');\r\n"
+      line += "define( 'WP_MEMORY_LIMIT', '128M');\r\n"
+      line += "define( 'WP2FA_ENCRYPT_KEY', '#{new_resource.wp2fa_encrypt_key}');\r\n"
     end
 
     line
@@ -100,14 +120,14 @@ action :create do
   file "#{site_directory}/wp-config.php" do
     owner node[:wordpress][:user]
     group node[:wordpress][:group]
-    mode 0o644
+    mode "644"
     content wp_config
   end
 
   declare_resource :directory, "#{site_directory}/wp-content/uploads" do
     owner "www-data"
     group "www-data"
-    mode 0o755
+    mode "755"
   end
 
   file "#{site_directory}/sitemap.xml" do
@@ -122,14 +142,45 @@ action :create do
     cookbook "wordpress"
     owner node[:wordpress][:user]
     group node[:wordpress][:group]
-    mode 0o644
+    mode "644"
     backup false
   end
 
+  # Setup wordpress database and create admin user with random password
+  execute "wp core install" do
+    command "/opt/wp-cli/wp --path='#{site_directory}' core install --url='#{new_resource.site}' --title='#{new_resource.title}' --admin_user='#{new_resource.admin_user}' --admin_email='#{new_resource.admin_email}' --skip-email"
+    user "www-data"
+    group "www-data"
+    only_if { ::File.exist?("#{site_directory}/wp-config.php") }
+    not_if "/opt/wp-cli/wp  --path='#{site_directory}' core is-installed"
+  end
+
+  execute "wp core update-db" do
+    command "/opt/wp-cli/wp --path='#{site_directory}' core update-db"
+    user "www-data"
+    group "www-data"
+    only_if { ::File.exist?("#{site_directory}/wp-config.php") }
+    subscribes :run, "subversion[#{site_directory}]"
+  end
+
   ssl_certificate new_resource.site do
     domains [new_resource.site] + Array(new_resource.aliases)
   end
 
+  php_fpm new_resource.site do
+    pm_max_children new_resource.fpm_max_children
+    pm_start_servers new_resource.fpm_start_servers
+    pm_min_spare_servers new_resource.fpm_min_spare_servers
+    pm_max_spare_servers new_resource.fpm_max_spare_servers
+    request_terminate_timeout new_resource.fpm_request_terminate_timeout
+    php_admin_values "open_basedir" => "#{site_directory}/:/usr/share/php/:/tmp/",
+                     "disable_functions" => "exec,shell_exec,system,passthru,popen,proc_open"
+    php_values "upload_max_filesize" => "70M",
+               "post_max_size" => "100M",
+               "memory_limit" => "368M"
+    prometheus_port new_resource.fpm_prometheus_port
+  end
+
   apache_site new_resource.site do
     cookbook "wordpress"
     template "apache.erb"
@@ -139,35 +190,35 @@ action :create do
     reload_apache false
   end
 
-  http_request "https://#{new_resource.site}/wp-admin/upgrade.php" do
-    action :nothing
-    url "https://#{new_resource.site}/wp-admin/upgrade.php?step=1"
-    subscribes :get, "subversion[#{site_directory}]"
+  wordpress_plugin "wp-fail2ban" do
+    site new_resource.site
+    reload_apache false
   end
 
-  wordpress_plugin "wp-fail2ban" do
+  wordpress_plugin "wp-2fa" do
     site new_resource.site
     reload_apache false
   end
 
-  script "#{site_directory}/wp-content/plugins/wp-fail2ban" do
-    action :nothing
-    interpreter "php"
-    cwd site_directory
-    user "wordpress"
-    code <<-WP_FAIL2BAN
-    <?php
-    @include "wp-config.php";
-    @include_once "wp-includes/functions.php";
-    @include_once "wp-admin/includes/plugin.php";
-    activate_plugin("wp-fail2ban/wp-fail2ban.php", '', false, false);
-    ?>
-    WP_FAIL2BAN
-    subscribes :run, "wordpress_plugin[wp-fail2ban]"
+  wordpress_plugin "wp-last-login" do
+    site new_resource.site
+    reload_apache false
   end
 end
 
 action :delete do
+  wordpress_plugin "wp-last-login" do
+    action :delete
+    site new_resource.site
+    reload_apache false
+  end
+
+  wordpress_plugin "wp-2fa" do
+    action :delete
+    site new_resource.site
+    reload_apache false
+  end
+
   wordpress_plugin "wp-fail2ban" do
     action :delete
     site new_resource.site
@@ -194,7 +245,8 @@ action :delete do
 end
 
 action_class do
-  include Chef::Mixin::EditFile
+  include OpenStreetMap::Mixin::EditFile
+  include OpenStreetMap::Mixin::PersistentToken
 
   def site_directory
     new_resource.directory || "/srv/#{new_resource.site}"
index d98edb25dd43694a050345ad583dce1fbe9e8ccd..2c4ceda4e5d1947fb048762512818c8b63ae4415 100644 (file)
 # limitations under the License.
 #
 
+unified_mode true
+
 default_action :create
 
-property :theme, :kind_of => String, :name_attribute => true
+property :theme, :kind_of => String, :name_property => true
 property :site, :kind_of => String, :required => true
 property :source, :kind_of => String
 property :version, :kind_of => String
@@ -34,10 +36,10 @@ action :create do
       source new_resource.source
       owner node[:wordpress][:user]
       group node[:wordpress][:group]
-      mode 0o755
+      mode "755"
       files_owner node[:wordpress][:user]
       files_group node[:wordpress][:group]
-      files_mode 0o644
+      files_mode "644"
     end
   else
     theme_repository = new_resource.repository || default_repository
@@ -50,6 +52,22 @@ action :create do
         user node[:wordpress][:user]
         group node[:wordpress][:group]
       end
+    elsif theme_repository.end_with?(".zip")
+      zip_path = "#{Chef::Config[:file_cache_path]}/#{new_resource.theme}.zip"
+
+      remote_file zip_path do
+        source theme_repository
+        action :create
+      end
+
+      archive_file zip_path do
+        destination theme_directory
+        action :nothing
+        overwrite true
+        group node[:wordpress][:group]
+        owner node[:wordpress][:user]
+        subscribes :extract, "remote_file[#{zip_path}]", :immediately
+      end
     else
       subversion theme_directory do
         action :sync
index 34c25059d659cd84db200dd2e853377a7459ba8a..b15ec55d91c3e9edf684d7b968ba80ff4afc435d 100644 (file)
@@ -8,17 +8,19 @@
 
   ServerAdmin webmaster@openstreetmap.org
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
 
   RedirectPermanent /.well-known/acme-challenge/ http://acme.openstreetmap.org/.well-known/acme-challenge/
   RedirectPermanent / https://<%= @name %>/
 </VirtualHost>
+<% unless @aliases.empty? -%>
 
 <VirtualHost *:443>
-  ServerName <%= @name %>
-<% @aliases.each do |alias_name| -%>
+  ServerName <%= @aliases.first %>
+<% @aliases.drop(1).each do |alias_name| -%>
   ServerAlias <%= alias_name %>
+<% end -%>
 
   ServerAdmin webmaster@openstreetmap.org
 
   SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
   SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
 
-  CustomLog /var/log/apache2/<%= @name %>-access.log combined
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
   ErrorLog /var/log/apache2/<%= @name %>-error.log
+
+  RedirectPermanent / https://<%= @name %>/
+</VirtualHost>
 <% end -%>
 
+<VirtualHost *:443>
+  ServerName <%= @name %>
+
+  ServerAdmin webmaster@openstreetmap.org
+
+  SSLEngine on
+  SSLCertificateFile /etc/ssl/certs/<%= @name %>.pem
+  SSLCertificateKeyFile /etc/ssl/private/<%= @name %>.key
+
+  CustomLog /var/log/apache2/<%= @name %>-access.log combined_extended
+  ErrorLog /var/log/apache2/<%= @name %>-error.log
+
   DocumentRoot <%= @directory %>
 <% @urls.each do |url,directory| -%>
   Alias <%= url %> <%= directory %>
   <Directory <%= directory %>>
     AllowOverride None
-    php_admin_flag engine off
     Require all granted
+    <FilesMatch ".+\.ph(ar|p|tml)$">
+      SetHandler None
+    </FilesMatch>
   </Directory>
 <% end -%>
 
-  php_admin_value open_basedir <%= @directory %>/:/usr/share/php/:/tmp/
-  php_admin_value disable_functions "exec,shell_exec,system,passthru,popen,proc_open"
-  php_value upload_max_filesize 70M
-  php_value post_max_size 100M
-
   <Directory <%= @directory %>>
     RewriteEngine on
 
@@ -54,6 +68,7 @@
     RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
     RewriteRule ^wp-includes/theme-compat/ - [F,L]
     RewriteRule ^readme\.html$ [F,L]
+    RewriteRule ^index\.php$ - [L]
     RewriteCond %{REQUEST_FILENAME} !-f
     RewriteCond %{REQUEST_FILENAME} !-d
     RewriteRule . /index.php [L]
     AllowOverride AuthConfig
 
     Require all granted
+
+    # https://www.wp-pay.org/http-authorization-header-missing/
+    CGIPassAuth on
+
+    <FilesMatch ".+\.ph(ar|p|tml)$">
+      SetHandler "proxy:unix:/run/php/php-<%= @name %>-fpm.sock|fcgi://127.0.0.1"
+    </FilesMatch>
   </Directory>
 
   <Files <%= @directory %>/wp-config.php>
@@ -71,7 +93,9 @@
   <Directory <%= @directory %>/uploads>
     AllowOverride None
     AddType text/plain .html .htm .shtml
-    php_admin_flag engine off
+    <FilesMatch ".+\.ph(ar|p|tml)$">
+      SetHandler None
+    </FilesMatch>
   </Directory>
 
   <Directory ~ "\.svn">
     Require all denied
   </Directory>
 
-  <Files ~ "\.(txt|md)$">
+  <Files ~ "(?<!robots|ads|security|humans)\.(txt|md)$">
     Require all denied
   </Files>
 
   <Files ~ "~$">
     Require all denied
   </Files>
+
+  <Files "xmlrpc.php">
+    Require all denied
+  </Files>
 </VirtualHost>
index cb7bc82d55348a9c92229c160e2cdf512b5c1282..449a8c6f2b2166e4bcd9d5bdbe0ae8f675ef4c21 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/ruby
+#!/usr/bin/env ruby
 
 ok = true
 
@@ -12,14 +12,10 @@ if IO.popen(["git", "ls-files", "--unmerged"]).read.empty?
   end.compact
 
   ruby_files = files.select do |file|
-    file =~ /\.rb$/ || (file !~ /\.erb$/ && `file --brief --mime-type #{file}` == "text/x-ruby\n")
+    file =~ /\.rb$/ || (file !~ /\.erb$/ && %x(file --brief --mime-type #{file}) == "text/x-ruby\n")
   end
 
-  ok &&= system("bundle", "exec", "rubocop", *ruby_files) unless ruby_files.empty?
-
-  cookbooks = files.grep(%r{(cookbooks/[^/]+)/}) { Regexp.last_match(1) }.uniq
-
-  ok &&= system("bundle", "exec", "foodcritic", *cookbooks) unless cookbooks.empty?
+  ok &&= system("bundle", "exec", "cookstyle", *ruby_files) unless ruby_files.empty?
 
   system("git", "stash", "pop", "--quiet") if need_stash
 else
index 7e2b97e8bfe30d6223305e5d192831d7091ee9dc..8cab0ea355ed9202539fe48635a22a77c164e0c6 100644 (file)
@@ -10,15 +10,15 @@ default_attributes(
   },
   :hosted_by => "AARNet",
   :location => "Carlton, Victoria, Australia",
-  :timezone => "Australia/Melbourne",
-  :networking => {
-    :nameservers => ["202.158.207.1", "202.158.207.2"]
-  }
+  :timezone => "Australia/Melbourne"
 )
 
 override_attributes(
+  :networking => {
+    :nameservers => ["202.158.207.1", "202.158.207.2"]
+  },
   :ntp => {
-    :servers => ["0.au.pool.ntp.org", "1.au.pool.ntp.org", "europe.pool.ntp.org"]
+    :servers => ["0.au.pool.ntp.org", "1.au.pool.ntp.org", "oceania.pool.ntp.org"]
   }
 )
 
diff --git a/roles/albi.rb b/roles/albi.rb
new file mode 100644 (file)
index 0000000..8608554
--- /dev/null
@@ -0,0 +1,27 @@
+name "albi"
+description "Master role applied to albi"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :external => {
+        :interface => "enp1s0f0",
+        :role => :external,
+        :inet => {
+          :address => "51.159.53.238",
+          :prefix => "24",
+          :gateway => "51.159.53.1"
+        },
+        :inet6 => {
+          :address => "2001:bc8:1200:4:dac4:97ff:fe8a:9cfc",
+          :prefix => "64",
+          :gateway => "fe80::a293:51ff:fea2:ded5"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[scaleway]"
+)
diff --git a/roles/altavoz.rb b/roles/altavoz.rb
deleted file mode 100644 (file)
index 78f6712..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-name "altavoz"
-description "Role applied to all servers at AltaVoz"
-
-default_attributes(
-  :hosted_by => "AltaVoz",
-  :location => "Viña del Mar, Chile",
-  :networking => {
-    :nameservers => [
-      "200.91.44.10",
-      "200.91.41.10"
-    ],
-    :roles => {
-      :external => {
-        :zone => "av"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.cl.pool.ntp.org", "1.cl.pool.ntp.org", "america.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[cl]"
-)
index 12ebea0d5d3ee3fc532aec72df2536df8c8f1618..be08e517cae28fe6ae46de57228a6aa72d0394bc 100644 (file)
@@ -2,46 +2,37 @@ name "angor"
 description "Master role applied to angor"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "18g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "eno1",
-        :role => :external,
-        :family => :inet,
-        :address => "196.10.54.165",
-        :prefix => "29",
-        :gateway => "196.10.54.161"
-      },
-      :external_ipv6 => {
+      :external => {
         :interface => "eno1",
         :role => :external,
-        :family => :inet6,
-        :address => "2001:43f8:1f4:b00:b283:feff:fed8:dd45",
-        :prefix => "64",
-        :gateway => "2001:43f8:1f4:b00::1"
+        :inet => {
+          :address => "196.10.54.165",
+          :prefix => "29",
+          :gateway => "196.10.54.161"
+        },
+        :inet6 => {
+          :address => "2001:43f8:1f4:b00:b283:feff:fed8:dd45",
+          :prefix => "64",
+          :gateway => "2001:43f8:1f4:b00::1"
+        }
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "capetown.render.openstreetmap.org"
+  :accounts => {
+    :users => {
+      :htonl => { :status => :user },
+      :gmoncrieff => { :status => :user },
+      :zander => { :status => :user },
+      :"za-imagery" => {
+          :status => :role,
+          :members => [:grant, :htonl, :gmoncrieff, :zander]
+      }
+    }
   }
 )
 
 run_list(
-  "role[inxza]",
-  "role[tilecache]",
-  "role[ftp]"
+  "role[inxza]"
 )
diff --git a/roles/appliwave.rb b/roles/appliwave.rb
new file mode 100644 (file)
index 0000000..25b4c3e
--- /dev/null
@@ -0,0 +1,25 @@
+name "appliwave"
+description "Role applied to all servers at Appliwave"
+
+default_attributes(
+  :accounts => {
+    :users => {
+      :appliwave => { :status => :administrator }
+    }
+  },
+  :hosted_by => "Appliwave",
+  :location => "Croissy-Beaubourg, France"
+)
+
+override_attributes(
+  :networking => {
+    :nameservers => ["185.73.206.93", "185.73.206.94"]
+  },
+  :ntp => {
+    :servers => ["0.fr.pool.ntp.org", "1.fr.pool.ntp.org", "europe.pool.ntp.org"]
+  }
+)
+
+run_list(
+  "role[fr]"
+)
diff --git a/roles/ar.rb b/roles/ar.rb
new file mode 100644 (file)
index 0000000..ec8b086
--- /dev/null
@@ -0,0 +1,10 @@
+name "ar"
+description "Role applied to all servers located in Argentina"
+
+override_attributes(
+  :country => "ar"
+)
+
+run_list(
+  "role[base]"
+)
index f20cf2ec89b69b1d105f66e185f006c5a8dd5531..b00e22c5f5f3cc84a925cf0480ead1ff66a10521 100644 (file)
@@ -2,38 +2,21 @@ name "ascalon"
 description "Master role applied to ascalon"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "20g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
+      :external => {
         :interface => "eno1",
         :role => :external,
-        :family => :inet,
-        :address => "184.107.48.228",
-        :prefix => "27",
-        :gateway => "184.107.48.225"
+        :inet => {
+          :address => "184.107.48.228",
+          :prefix => "27",
+          :gateway => "184.107.48.225"
+        }
       }
     }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "montreal.render.openstreetmap.org"
   }
 )
 
 run_list(
-  "role[netalerts]",
-  "role[geodns]",
-  "role[tilecache]"
+  "role[netalerts]"
 )
diff --git a/roles/aws-us-east-2.rb b/roles/aws-us-east-2.rb
new file mode 100644 (file)
index 0000000..f9db478
--- /dev/null
@@ -0,0 +1,12 @@
+name "aws-us-east-2"
+description "Role applied to all servers at AWS us-east-2"
+
+default_attributes(
+  :location => "Ohio",
+  :timezone => "US/Eastern"
+)
+
+run_list(
+  "role[us]",
+  "role[aws]"
+)
index 5f4ac7ace2b33f5f5e76a63b1a3488ec20adbd24..4438781614f24736efdabf96e10afd4f38b05636 100644 (file)
@@ -1,34 +1,12 @@
 name "aws"
-description "Role applied to all servers on AWS"
+description "Role applied to all servers at AWS"
 
 default_attributes(
-  :hosted_by => "AWS",
-  :location => "Ireland",
-  :networking => {
-    :nameservers => ["172.31.0.2"],
-    :roles => {
-      :internal => {
-        :inet => {
-          :prefix => "20",
-          :gateway => "172.31.0.1"
-        }
-      },
-      :external => {
-        :zone => "aws",
-        :inet => {
-          :prefix => "32"
-        }
-      }
-    }
-  }
+  :hosted_by => "AWS"
 )
 
 override_attributes(
   :ntp => {
-    :servers => ["0.ie.pool.ntp.org", "1.ie.pool.ntp.org", "europe.pool.ntp.org"]
+    :servers => ["169.254.169.123"]
   }
 )
-
-run_list(
-  "role[ie]"
-)
index b0c519bd8f3c3f1e0ac2c0cc893b55a967b5ee16..339ba54afc2bcf5ead241fd4815267e56e803756 100644 (file)
@@ -2,11 +2,6 @@ name "backup"
 description "Role applied to backup.openstreetmap.org"
 
 default_attributes(
-  :accounts => {
-    :users => {
-      :osmbackup => { :status => :role }
-    }
-  },
   :rsyncd => {
     :modules => {
       :backup => {
@@ -20,18 +15,21 @@ default_attributes(
         :transfer_logging => false,
         :hosts_allow => [
           "193.60.236.0/24",                     # ucl external
-          "10.0.48.0/20",                        # equinix internal
-          "130.117.76.0/27",                     # equinix external
-          "2001:978:2:2C::172:0/112",            # equinix external
+          "10.0.48.0/20",                        # amsterdam internal
+          "184.104.179.128/27",                  # amsterdam external
+          "2001:470:1:fa1::/64",                 # amsterdam external
+          "10.0.64.0/20",                        # dublin internal
+          "184.104.226.96/27",                   # dublin external
+          "2001:470:1:b3b::/64",                 # dublin external
           "10.0.32.0/20",                        # bytemark internal
           "89.16.162.16/28",                     # bytemark external
           "2001:41c9:2:d6::/64",                 # bytemark external
           "212.110.172.32",                      # shenron
           "2001:41c9:1:400::32",                 # shenron
-          "140.211.167.104",                     # osuosl
-          "140.211.167.105",                     # osuosl
-          "2605:bc80:3010:700::8cde:a768",       # osuosl
-          "2605:bc80:3010:700::8cde:a769",       # osuosl
+          "140.211.167.99",                      # osuosl
+          "140.211.167.100",                     # osuosl
+          "2605:bc80:3010:700::8cd3:a763",       # osuosl
+          "2605:bc80:3010:700::8cd3:a764",       # osuosl
           "127.0.0.0/8",                         # localhost
           "::1"                                  # localhost
         ]
index e6695a4c9f094706ffeca7ee1f87027a80276ee5..60e6bbcb06f3e137a7e02de11c86afb85546088a 100644 (file)
@@ -2,40 +2,56 @@ name "balerion"
 description "Master role applied to balerion"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "36g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
+      :external => {
         :interface => "bond0",
         :role => :external,
-        :family => :inet,
-        :address => "138.44.68.134",
-        :prefix => "30",
-        :gateway => "138.44.68.133",
+        :inet => {
+          :address => "138.44.68.134",
+          :prefix => "30",
+          :gateway => "138.44.68.133"
+        },
         :bond => {
-          :slaves => %w[ens14f0 ens14f1]
+          :slaves => %w[ens14f0np0 ens14f1np1]
         }
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "32768 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :effective_cache_size => "16GB"
+      }
+    }
+  },
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
+      }
+    }
   },
-  :tilecache => {
-    :tile_parent => "melbourne.render.openstreetmap.org"
+  :tile => {
+    :database => {
+      :cluster => "16/main",
+      :postgis => "3"
+    },
+    :mapnik => "3.1",
+    :styles => {
+      :default => {
+        :tile_directories => [
+          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
+        ]
+      }
+    }
   }
 )
 
 run_list(
   "role[aarnet]",
-  "role[tilecache]"
+  "role[geodns]",
+  "role[tile]"
 )
index f9cb68efc411a5cc6591f35f6bd91034df1680d0..718b288a5a5b530bab46d60228dcb45506902b00 100644 (file)
@@ -10,23 +10,21 @@ default_attributes(
       :jburgess => { :status => :administrator }
     }
   },
-  :apt => {
-    :sources => ["openstreetmap"]
-  },
-  :munin => {
-    :plugins => {
-      :chrony => {
-        :systime => { :warning => "100", :critical => "250" }
-      }
-    }
-  },
   :networking => {
     :roles => {
-      :internal => { :metric => 200, :zone => "loc" },
+      :internal => { :metric => 200 },
       :external => { :metric => 100 }
     },
     :search => ["openstreetmap.org"]
   },
+  :prometheus => {
+    :metrics => {
+      :exim_queue_limit => {
+        :help => "Mail queue alert level",
+        :metric => 50
+      }
+    }
+  },
   :sysctl => {
     :panic => {
       :comment => "Reboot automatically after a panic",
@@ -44,9 +42,9 @@ default_attributes(
       :parameters => {
         "net.core.rmem_max" => "16777216",
         "net.core.wmem_max" => "16777216",
-        "net.ipv4.tcp_rmem" => "4096\t87380\t16777216",
-        "net.ipv4.tcp_wmem" => "4096\t65536\t16777216",
-        "net.ipv4.udp_mem" => "3145728\t4194304\t16777216"
+        "net.ipv4.tcp_rmem" => "4096 87380 16777216",
+        "net.ipv4.tcp_wmem" => "4096 65536 16777216",
+        "net.ipv4.udp_mem" => "3145728 4194304 16777216"
       }
     },
     :network_backlog => {
@@ -69,15 +67,14 @@ default_attributes(
       }
     },
     :default_qdisc => {
-      :comment => "Use pfifo_fast as the default queuing discipline",
+      :comment => "Use fq as the default queuing discipline",
       :parameters => {
-        "net.core.default_qdisc" => "pfifo_fast"
+        "net.core.default_qdisc" => "fq"
       }
     },
     :tune_cpu_scheduler => {
       :comment => "Tune CPU scheduler for server scheduling",
       :parameters => {
-        "kernel.sched_migration_cost_ns" => 50000000,
         "kernel.sched_autogroup_enabled" => 0
       }
     }
@@ -90,7 +87,7 @@ run_list(
   "recipe[chef]",
   "recipe[devices]",
   "recipe[hardware]",
-  "recipe[munin]",
+  "recipe[prometheus]",
   "recipe[networking]",
   "recipe[exim]",
   "recipe[ntp]",
diff --git a/roles/birthday20.rb b/roles/birthday20.rb
new file mode 100644 (file)
index 0000000..5513242
--- /dev/null
@@ -0,0 +1,19 @@
+name "birthday20"
+description "Role applied to birthday20 servers"
+
+default_attributes(
+  :accounts => {
+    :users => {
+      :mikel => { :status => :administrator },
+      :wordpress => {
+        :status => :role,
+        :members => [:mikel]
+      }
+    },
+  }
+)
+
+# FIXME: Disable while site under development
+# run_list(
+#   "recipe[blog::birthday]"
+# )
diff --git a/roles/blix-nl.rb b/roles/blix-nl.rb
deleted file mode 100644 (file)
index 936694b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-name "blix-nl"
-description "Role applied to all servers at Blix NL"
-
-default_attributes(
-  :location => "Amsterdam, Netherlands"
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.nl.pool.ntp.org", "1.nl.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[nl]",
-  "role[blix]"
-)
diff --git a/roles/blix-no.rb b/roles/blix-no.rb
deleted file mode 100644 (file)
index b4ed5cd..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-name "blix-no"
-description "Role applied to all servers at Blix NO"
-
-default_attributes(
-  :location => "Oslo, Norway"
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.no.pool.ntp.org", "1.no.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[no]",
-  "role[blix]"
-)
diff --git a/roles/blix.rb b/roles/blix.rb
deleted file mode 100644 (file)
index 835da71..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-name "blix"
-description "Role applied to all servers at Blix"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :blixadmin => { :status => :administrator }
-    }
-  },
-  :hosted_by => "Blix Solutions",
-  :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "bx"
-      }
-    }
-  }
-)
diff --git a/roles/blog-staging.rb b/roles/blog-staging.rb
new file mode 100644 (file)
index 0000000..3ad17f2
--- /dev/null
@@ -0,0 +1,19 @@
+name "blog-staging"
+description "Role applied to staging blog servers"
+
+default_attributes(
+  :accounts => {
+    :users => {
+      :mikel => { :status => :administrator },
+      :wordpress => {
+        :status => :role,
+        :members => [:mikel]
+      }
+    },
+  }
+)
+
+# FIXME: Disable while site under development
+# run_list(
+#   "recipe[blog::staging]"
+# )
diff --git a/roles/blogs.rb b/roles/blogs.rb
new file mode 100644 (file)
index 0000000..3881d13
--- /dev/null
@@ -0,0 +1,6 @@
+name "blogs"
+description "Role applied to all blog aggregators"
+
+run_list(
+  "recipe[blogs]"
+)
diff --git a/roles/boitata.rb b/roles/boitata.rb
deleted file mode 100644 (file)
index 7b09561..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-name "boitata"
-description "Master role applied to boitata"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "14g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet,
-        :address => "200.236.31.207",
-        :prefix => "25",
-        :gateway => "200.236.31.254"
-      },
-      :external_ipv6 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet6,
-        :address => "2801:82:80ff:8002:216:ccff:feaa:21",
-        :prefix => "64",
-        :gateway => "fe80::92e2:baff:fe0d:e24"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "10240 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "curitiba.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[c3sl]",
-  "role[tilecache]"
-)
index ebee5e5d44b570f56a2e5c4722203a134862f6f9..8ebde6e8bf4fcaf33c25d9d83280e1d63c747ff7 100644 (file)
@@ -2,30 +2,25 @@ name "bowser"
 description "Master role applied to bowser"
 
 default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
+      :external => {
         :interface => "bond0",
         :role => :external,
-        :family => :inet,
-        :address => "138.44.68.106",
-        :prefix => "30",
-        :gateway => "138.44.68.105",
+        :inet => {
+          :address => "138.44.68.106",
+          :prefix => "30",
+          :gateway => "138.44.68.105"
+        },
         :bond => {
-          :slaves => %w[ens14f0 ens14f1]
+          :slaves => %w[ens14f0np0 ens14f1np1]
         }
       }
     }
   },
   :postgresql => {
-    :versions => ["10"],
     :settings => {
       :defaults => {
-        :shared_buffers => "8GB",
-        :maintenance_work_mem => "7144MB",
         :effective_cache_size => "16GB"
       }
     }
@@ -41,10 +36,10 @@ default_attributes(
   },
   :tile => {
     :database => {
-      :cluster => "10/main",
-      :postgis => "2.4"
+      :cluster => "16/main",
+      :postgis => "3"
     },
-    :node_file => "/store/database/nodes",
+    :mapnik => "3.1",
     :styles => {
       :default => {
         :tile_directories => [
index 2289df6484e929e6b16b80556bbe2c9ae675c78f..8f23bd5d02a806ddcb5d0a385d64a48fdeffb7f6 100644 (file)
@@ -5,16 +5,17 @@ default_attributes(
   :hosted_by => "Bytemark",
   :location => "York, England",
   :networking => {
-    :nameservers => ["10.0.32.20"],
     :roles => {
       :internal => {
         :inet => {
           :prefix => "20",
-          :gateway => "10.0.32.20"
+          :gateway => "10.0.32.20",
+          :routes => {
+            "10.0.0.0/8" => { :via => "10.0.32.20" }
+          }
         }
       },
       :external => {
-        :zone => "bm",
         :inet => {
           :prefix => "28",
           :gateway => "89.16.162.17"
@@ -25,16 +26,12 @@ default_attributes(
         }
       }
     }
-  },
-  :web => {
-    :backends => %w[rails4 rails5],
-    :fileserver => "grisu",
-    :readonly_database_host => "katla.bm.openstreetmap.org"
   }
 )
 
 override_attributes(
   :networking => {
+    :nameservers => ["8.8.8.8", "8.8.4.4"],
     :search => ["bm.openstreetmap.org", "openstreetmap.org"]
   },
   :ntp => {
diff --git a/roles/c3sl.rb b/roles/c3sl.rb
deleted file mode 100644 (file)
index 0870808..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-name "c3sl"
-description "Role applied to all servers at Centro de Computação Científica e Software Livre"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :c3sl => { :status => :administrator }
-    }
-  },
-  :hosted_by => "Centro de Computação Científica e Software Livre, Universidade Federal do Paraná",
-  :location => "Curitiba, Brazil",
-  :timezone => "America/Sao_Paulo",
-  :networking => {
-    :nameservers => ["200.17.202.3", "200.236.31.1"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.br.pool.ntp.org", "1.br.pool.ntp.org", "america.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[br]"
-)
index fab353fa680df20bf02b7c40eb7685e9865867e3..8ed5cb3f64bc602f3e91b02fdbec1b6d33795ba7 100644 (file)
@@ -7,14 +7,7 @@ default_attributes(
       :hbogner => { :status => :administrator }
     }
   },
-  :hosted_by => "CARNet",
-  :networking => {
-    :roles => {
-      :external => {
-        :zone => "cnt"
-      }
-    }
-  }
+  :hosted_by => "CARNet"
 )
 
 override_attributes(
diff --git a/roles/catalyst.rb b/roles/catalyst.rb
deleted file mode 100644 (file)
index edf3fad..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-name "catalyst"
-description "Role applied to all servers at Catalyst"
-
-default_attributes(
-  :hosted_by => "Catalyst",
-  :location => "Hamilton, New Zealand",
-  :networking => {
-    :nameservers => ["202.78.244.85", "202.78.244.86", "202.78.244.87"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.nz.pool.ntp.org", "1.nz.pool.ntp.org", "asia.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[nz]"
-)
index a21cb286b21426c806b158dff44fbbbfa7c90160..9ae1fbc0024efd9e822f53e18f346ae318799176 100644 (file)
@@ -1,20 +1,6 @@
 name "chef-server"
 description "Role applied to all chef servers"
 
-default_attributes(
-  :munin => {
-    :plugins => {
-      :chef_status => {
-        :ascalon => { :warning => ":", :critical => ":" },
-        :idris => { :warning => ":", :critical => ":" },
-        :norbert => { :warning => ":", :critical => ":" },
-        :smaug => { :warning => ":", :critical => ":" },
-        :zark => { :warning => ":", :critical => ":" }
-      }
-    }
-  }
-)
-
 run_list(
   "recipe[chef::server]"
 )
diff --git a/roles/cherufe.rb b/roles/cherufe.rb
deleted file mode 100644 (file)
index e10feab..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-name "cherufe"
-description "Master role applied to cherufe"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "12g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens18",
-        :role => :external,
-        :family => :inet,
-        :address => "200.91.44.37",
-        :prefix => "23",
-        :gateway => "200.91.44.1"
-      }
-    }
-  },
-  :openssh => {
-    :port => 45222
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "8192 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :max_size => "4096M"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "vinadelmar.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[altavoz]",
-  "role[tilecache]"
-)
diff --git a/roles/chrysophylax.rb b/roles/chrysophylax.rb
deleted file mode 100644 (file)
index 93c6b21..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-name "chrysophylax"
-description "Master role applied to chrysophylax"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "12g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens160",
-        :role => :external,
-        :family => :inet,
-        :address => "217.71.244.22",
-        :prefix => "30",
-        :gateway => "217.71.244.21"
-      },
-      :external_ipv6 => {
-        :interface => "ens160",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:8e0:40:2039::10",
-        :prefix => "64",
-        :gateway => "2001:8e0:40:2039::1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "10240 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "zurich.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[iway]",
-  "role[geodns]",
-  "role[tilecache]"
-)
diff --git a/roles/clifford.rb b/roles/clifford.rb
deleted file mode 100644 (file)
index 2471257..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-name "clifford"
-description "Master role applied to clifford"
-
-default_attributes(
-  :exim => {
-    :rewrites => [
-      {
-        :pattern => "www-data@openstreetmap.org",
-        :replacement => "forum@noreply.openstreetmap.org",
-        :flags => "F"
-      }
-    ]
-  },
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp2s0f0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.17"
-      },
-      :external_ipv4 => {
-        :interface => "enp2s0f0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.11"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[hp-dl360-g6]",
-  "role[forum]"
-)
diff --git a/roles/cmok.rb b/roles/cmok.rb
deleted file mode 100644 (file)
index 41de78a..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-name "cmok"
-description "Master role applied to cmok"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "6g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "enp4s0",
-        :role => :external,
-        :family => :inet,
-        :address => "31.130.201.40",
-        :prefix => "27",
-        :gateway => "31.130.201.33"
-      },
-      :external_ipv6 => {
-        :interface => "enp4s0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:67c:2268:1005:21e:8cff:fe8c:8d3b",
-        :prefix => "64",
-        :gateway => "fe80::20c:42ff:feb2:8ff8"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "4096 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "minsk.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[datahata]",
-  "role[tilecache]"
-)
diff --git a/roles/co.rb b/roles/co.rb
new file mode 100644 (file)
index 0000000..123288a
--- /dev/null
@@ -0,0 +1,11 @@
+name "co"
+description "Role applied to all servers located in Colombia"
+
+override_attributes(
+  :country => "co",
+  :timezone => "America/Bogota"
+)
+
+run_list(
+  "role[base]"
+)
diff --git a/roles/community.rb b/roles/community.rb
new file mode 100644 (file)
index 0000000..c24e40f
--- /dev/null
@@ -0,0 +1,17 @@
+name "community"
+description "Role applied to all community servers"
+
+default_attributes(
+  :accounts => {
+    :users => {
+      :community => {
+        :status => :role,
+        :members => [:grant, :tomh]
+      }
+    }
+  }
+)
+
+run_list(
+  "recipe[community]"
+)
index 7e255307baad6f9018191697b75181d0e9d918f4..cbcd8628d986cf5f967b87b940b22f3077b937c8 100644 (file)
@@ -8,7 +8,7 @@ default_attributes(
     }
   },
   :exim => {
-    :local_domains => ["join.osmfoundation.org"],
+    :local_domains => ["join.osmfoundation.org", "supporting.openstreetmap.org"],
     :routes => {
       :join_return => {
         :comment => "return@join.osmfoundation.org",
@@ -25,6 +25,22 @@ default_attributes(
         :maildir => "/var/mail/crm-mail",
         :user => "www-data",
         :group => "mail"
+      },
+      :supporting_return => {
+        :comment => "return@supporting.openstreetmap.org",
+        :domains => ["supporting.osmfoundation.org"],
+        :local_parts => ["return"],
+        :maildir => "/var/mail/crm-return",
+        :user => "www-data",
+        :group => "mail"
+      },
+      :supporting_mail => {
+        :comment => "mail@supporting.openstreetmap.org",
+        :domains => ["supporting.openstreetmap.org"],
+        :local_parts => ["mail"],
+        :maildir => "/var/mail/crm-mail",
+        :user => "www-data",
+        :group => "mail"
       }
     },
     :trusted_users => ["www-data"]
@@ -32,9 +48,7 @@ default_attributes(
   :mysql => {
     :settings => {
       :mysqld => {
-        :innodb_strict_mode => true,
-        :innodb_file_per_table => true,
-        :innodb_file_format => "Barracuda"
+        :log_bin_trust_function_creators => 1
       }
     }
   }
index 442009794bb3711dd9e24a4aaf04886e619d259f..4cdf87cafb3da6c85ef9573ed7ba5a60ea7d192a 100644 (file)
@@ -2,44 +2,66 @@ name "culebre"
 description "Master role applied to culebre"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "18g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet,
-        :address => "155.210.4.103",
-        :prefix => "28",
-        :gateway => "155.210.4.110"
-      },
-      :internal_ipv4 => {
-        :interface => "ens4",
+      :internal => {
+        :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.148.97.151",
-        :prefix => "24"
+        :inet => {
+          :address => "10.0.64.9"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[enp68s0f0 enp68s0f1 enp68s0f2 enp68s0f3]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.105"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::9"
+        }
+      }
+    }
+  },
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :effective_cache_size => "16GB"
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
+      }
+    }
   },
-  :tilecache => {
-    :tile_parent => "zaragoza.render.openstreetmap.org"
+  :tile => {
+    :database => {
+      :cluster => "16/main",
+      :postgis => "3"
+    },
+    :mapnik => "3.1",
+    :styles => {
+      :default => {
+        :tile_directories => [
+          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
+        ]
+      }
+    }
   }
 )
 
 run_list(
-  "role[unizar]",
-  "role[tilecache]"
+  "role[equinix-dub]",
+  "role[tile]"
 )
diff --git a/roles/datahata.rb b/roles/datahata.rb
deleted file mode 100644 (file)
index 650c8a7..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-name "datahata"
-description "Role applied to all servers at DataHata"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :kom => { :status => :administrator }
-    }
-  },
-  :hosted_by => "DataHata",
-  :location => "Minsk, Belarus",
-  :networking => {
-    :nameservers => [
-      "31.130.200.2",
-      "8.8.8.8",
-      "8.8.4.4"
-    ],
-    :roles => {
-      :external => {
-        :zone => "dh"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.by.pool.ntp.org", "1.by.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[by]"
-)
index 3bfdbd7ca2fbccb9025176e1d3d82ea982f371de..36d70e9023531d7fe6461a9b335f84a2c5b2c79d 100644 (file)
@@ -3,19 +3,12 @@ description "Role applied to all the master database server"
 
 default_attributes(
   :postgresql => {
-    :versions => ["9.5"],
+    :monitor_queries => true,
     :settings => {
       :defaults => {
-        :wal_level => "hot_standby",
         :archive_mode => "on",
-        :archive_command => "/usr/local/bin/openstreetmap-wal-e --terse wal-push %p",
-        :max_wal_senders => "3",
-        :late_authentication_rules => [
-          { :database => "replication", :user => "replication", :address => "10.0.48.50/32" },
-          { :database => "replication", :user => "replication", :address => "10.0.48.5/32" },
-          { :database => "replication", :user => "replication", :address => "10.0.0.10/32" },
-          { :database => "replication", :user => "replication", :address => "10.0.32.40/32" }
-        ]
+        :archive_command => "/usr/local/bin/openstreetmap-wal-g wal-push %p --walg-prevent-wal-overwrite=true",
+        :wal_keep_size => "16384"
       }
     }
   }
index 5b5c09b33fe85424d079bcb8200d1d09b07d1619..8def8c8b0d0b532be144afe32c4f09346e2cd879 100644 (file)
@@ -3,19 +3,18 @@ description "Role applied to all slave database servers"
 
 default_attributes(
   :postgresql => {
-    :versions => ["9.5"],
     :settings => {
       :defaults => {
         :hot_standby => "on",
         :hot_standby_feedback => "on",
         :standby_mode => "on",
         :primary_conninfo => {
-          :host => "karm.ams.openstreetmap.org",
+          :host => "snap-01.ams.openstreetmap.org",
           :port => "5432",
           :user => "replication",
           :passwords => { :bag => "db", :item => "passwords" }
         },
-        :restore_command => "/usr/local/bin/openstreetmap-wal-e --terse wal-fetch %f %p"
+        :restore_command => "/usr/local/bin/openstreetmap-wal-g wal-fetch %f %p"
       }
     }
   }
index bb13e00c5d543b5332c0c5d64257e992fff52aed..24ae106838bc76ee796153504a4579f3a064c633 100644 (file)
@@ -15,45 +15,26 @@ default_attributes(
       :enable => false
     }
   },
-  :munin => {
-    :plugins => {
-      :postgres_connections_openstreetmap => {
-        :waiting => {
-          :warning => 10,
-          :critical => 20
-        }
-      },
-      :postgres_locks_openstreetmap => {
-        :accesssharelock => {
-          :warning => 900,
-          :critical => 1000
-        },
-        :rowexclusivelock => {
-          :warning => 250,
-          :critical => 300
-        }
-      }
-    }
-  },
-  :nfs => {
-    "/store/rails" => { :host => "ironbelly", :path => "/store/rails" }
-  },
   :postgresql => {
-    :versions => ["9.5"],
     :settings => {
       :defaults => {
         :listen_addresses => "*",
-        :max_connections => "1000",
+        :max_connections => "1500",
         :max_stack_depth => "7MB",
-        :checkpoint_segments => "32",
+        :wal_level => "logical",
         :max_wal_size => "1536MB",
         :checkpoint_completion_target => "0.8",
         :cpu_tuple_cost => "0.1",
+        :jit => "off",
         :log_min_duration_statement => "1000",
         :late_authentication_rules => [
-          { :address => "10.0.16.0/20" },
-          { :address => "10.0.32.0/20" },
-          { :address => "10.0.48.0/20" }
+          { :address => "10.0.48.0/20" }, # amsterdam
+          { :address => "10.0.64.0/20" }, # dublin
+          { :database => "replication", :user => "replication", :address => "10.0.0.4/32" },   # snap-02
+          { :database => "replication", :user => "replication", :address => "10.0.0.10/32" },  # eddie
+          { :database => "replication", :user => "replication", :address => "10.0.48.49/32" }, # snap-01
+          { :database => "replication", :user => "replication", :address => "10.0.48.50/32" }, # karm
+          { :database => "replication", :user => "replication", :address => "10.0.64.50/32" }  # snap-03
         ]
       }
     }
@@ -67,7 +48,3 @@ default_attributes(
     }
   }
 )
-
-run_list(
-  "recipe[nfs]"
-)
diff --git a/roles/delta.rb b/roles/delta.rb
deleted file mode 100644 (file)
index 109c934..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-name "delta"
-description "Role applied to all servers at Delta Telecom"
-
-default_attributes(
-  :hosted_by => "Delta Telecom",
-  :location => "Baku, Azerbaijan",
-  :networking => {
-    :nameservers => ["94.20.20.20", "8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "dt"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.az.pool.ntp.org", "1.az.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[az]"
-)
index 17b5c4726072897a5a0a114ca31cce6452c4d8b3..f85849e888b70116b1a02cd232e55a273664316d 100644 (file)
@@ -4,69 +4,79 @@ description "Role applied to all development servers"
 default_attributes(
   :accounts => {
     :users => {
-      :edgemaster => { :status => :administrator },
-      :emacsen => { :status => :administrator },
-      :twain => { :status => :user },
-      :bretth => { :status => :user },
-      :richard => { :status => :user },
-      :shaunmcdonald => { :status => :user },
-      :random => { :status => :user },
-      :steve8 => { :status => :user },
+      :ant => { :status => :user },
+      :antonkh => { :status => :user },
+      :apmon => { :status => :user },
       :blackadder => { :status => :user },
-      :timsc => { :status => :user },
       :bobkare => { :status => :user },
+      :bretth => { :status => :user },
+      :bsupnik => { :status => :user },
+      :chippy => { :status => :user },
+      :cobra => { :status => :user },
+      :contrapunctus => { :status => :user },
+      :csmale => { :status => :user },
+      :dan => { :status => :user },
       :daveh => { :status => :user },
-      :gravitystorm => { :status => :user },
-      :fred => { :status => :user },
-      :nick => { :status => :user },
+      :davidearl => { :status => :user },
       :deelkar => { :status => :user },
-      :simone => { :status => :user },
-      :mitjak => { :status => :user },
+      :derick => { :status => :user },
+      :dmlu => { :status => :user },
+      :dodobas => { :status => :user },
+      :edgemaster => { :status => :administrator },
+      :emacsen => { :status => :user },
+      :enelson => { :status => :user },
+      :fred => { :status => :user },
+      :gmoncrieff => { :status => :user },
+      :gravitystorm => { :status => :user },
+      :gregory => { :status => :user },
+      :gregrs => { :status => :user },
+      :harrywood => { :status => :user },
       :htonl => { :status => :user },
-      :russ => { :status => :user },
-      :merio => { :status => :user },
-      :chippy => { :status => :user },
+      :jeslop => { :status => :user },
+      :jfire => { :status => :user },
+      :jgc => { :status => :user },
       :joerichards => { :status => :user },
-      :pafciu17 => { :status => :user },
-      :ojw => { :status => :user },
-      :harrywood => { :status => :user },
-      :yellowbkpk => { :status => :user },
-      :apmon => { :status => :user },
-      :mackerski => { :status => :user },
+      :joshd => { :status => :user },
       :ldp => { :status => :user },
+      :lfrancke => { :status => :user },
+      :ligfietser => { :status => :user },
+      :lonvia => { :status => :user },
+      :maba => { :status => :user },
+      :mackerski => { :status => :user },
+      :malenki => { :status => :user },
       :mdaines => { :status => :user },
-      :dan => { :status => :user },
-      :ris => { :status => :user },
+      :merio => { :status => :user },
+      :mhohmann => { :status => :user },
+      :milliams => { :status => :user },
+      :mitjak => { :status => :user },
+      :msbarry => { :status => :user },
+      :mvexel => { :status => :user },
+      :nick => { :status => :user },
+      :nicolas17 => { :status => :user },
       :nroets => { :status => :user },
+      :ojw => { :status => :user },
       :ollie => { :status => :user },
-      :mvexel => { :status => :user },
-      :tomchance => { :status => :user },
-      :lfrancke => { :status => :user },
-      :davidearl => { :status => :user },
-      :rweait => { :status => :user },
-      :ant => { :status => :user },
-      :milliams => { :status => :user },
+      :pafciu17 => { :status => :user },
       :pierzen => { :status => :user },
-      :gregory => { :status => :user },
-      :bsupnik => { :status => :user },
-      :derick => { :status => :user },
-      :joshd => { :status => :user },
-      :maba => { :status => :user },
       :pnorman => { :status => :user },
-      :csmale => { :status => :user },
-      :jgc => { :status => :user },
-      :cobra => { :status => :user },
       :ppawel => { :status => :user },
+      :random => { :status => :user },
+      :richard => { :status => :user },
+      :rtnf => { :status => :user },
+      :ris => { :status => :user },
+      :russ => { :status => :user },
+      :rweait => { :status => :user },
+      :shaunmcdonald => { :status => :user },
       :simon04 => { :status => :user },
-      :jfire => { :status => :user },
-      :malenki => { :status => :user },
-      :lonvia => { :status => :user },
-      :nicolas17 => { :status => :user },
+      :simone => { :status => :user },
+      :stereo => { :status => :user },
+      :steve8 => { :status => :user },
+      :timsc => { :status => :user },
+      :tomchance => { :status => :user },
+      :twain => { :status => :user },
+      :yellowbkpk => { :status => :user },
+      :zander => { :status => :user },
       :zverik => { :status => :user },
-      :dodobas => { :status => :user },
-      :mhohmann => { :status => :user },
-      :enelson => { :status => :user },
-      :gregrs => { :status => :user },
       :ooc => {
         :status => :role,
         :members => [:tomh, :blackadder, :timsc, :ollie]
@@ -82,6 +92,10 @@ default_attributes(
       :gpsmid => {
         :status => :role,
         :members => [:apmon, :maba]
+      },
+      :"za-imagery" => {
+          :status => :role,
+          :members => [:grant, :htonl, :gmoncrieff, :zander]
       }
     }
   },
@@ -95,53 +109,53 @@ default_attributes(
       :max_connections_per_child => 10000
     }
   },
-  :apt => {
-    :sources => ["postgresql"]
-  },
   :dev => {
     :rails => {
       :master => {
         :repository => "https://git.openstreetmap.org/public/rails.git",
         :revision => "master",
-        :cgimap_repository => "git://github.com/zerebubuth/openstreetmap-cgimap.git",
+        :cgimap_repository => "https://github.com/zerebubuth/openstreetmap-cgimap.git",
         :cgimap_revision => "master",
         :aliases => ["api06.dev.openstreetmap.org"]
       },
       :tomh => {
-        :repository => "git://github.com/tomhughes/openstreetmap-website.git",
-        :revision => "next"
+        :repository => "https://github.com/tomhughes/openstreetmap-website.git",
+        :revision => "next",
+        :cgimap_repository => "https://github.com/zerebubuth/openstreetmap-cgimap.git",
+        :cgimap_revision => "master"
       },
       :comments => {
-        :repository => "git://github.com/ukasiu/openstreetmap-website.git",
+        :repository => "https://github.com/ukasiu/openstreetmap-website.git",
         :revision => "comments_list"
       },
       :locale => {
-        :repository => "git://github.com/tomhughes/openstreetmap-website.git",
+        :repository => "https://github.com/tomhughes/openstreetmap-website.git",
         :revision => "locale"
       },
-      :upload => {
-        :repository => "https://git.openstreetmap.org/public/rails.git",
-        :revision => "master",
-        :cgimap_repository => "git://github.com/zerebubuth/openstreetmap-cgimap.git",
-        :cgimap_revision => "feature/bulk_upload"
+      :microcosms => {
+        :repository => "https://github.com/openbrian/osm-microcosms.git",
+        :revision => "microcosms"
+      },
+      :signup => {
+        :repository => "https://github.com/milan-cvetkovic/openstreetmap-website.git",
+        :revision => "issue_4128_login_signup"
       }
     }
   },
   :postgresql => {
-    :versions => ["9.1", "9.5"],
+    :versions => ["15"],
     :settings => {
       :defaults => {
+        :max_connections => "500",
         :shared_buffers => "1GB",
         :work_mem => "32MB",
         :maintenance_work_mem => "64MB",
         :max_stack_depth => "4MB",
         :effective_cache_size => "4GB"
       },
-      "9.1" => {
-        :port => "5433"
-      },
-      "9.5" => {
-        :port => "5432"
+      "15" => {
+        :port => "5432",
+        :wal_level => "logical"
       }
     }
   },
@@ -153,6 +167,9 @@ default_attributes(
         "kernel.shmmax" => "17179869184"
       }
     }
+  },
+  :openssh => {
+    :password_authentication => true
   }
 )
 
index 25ac17f00d2eb30ebfbedced23177de58766a525..c2af27b5895a809a3c2306f6f05aec7b2558aee2 100644 (file)
@@ -1,12 +1,6 @@
 name "dns"
 description "Role applied to DNS management servers"
 
-default_attributes(
-  :dns => {
-    :repository => "/var/lib/git/public/dns.git"
-  }
-)
-
 run_list(
   "recipe[dns]"
 )
diff --git a/roles/donate.rb b/roles/donate.rb
deleted file mode 100644 (file)
index 6e5f2c6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-name "donate"
-description "Role applied to all donate servers"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :donate => {
-        :status => :role,
-        :members => [:grant, :tomh, :matt]
-      }
-    }
-  }
-)
-
-run_list(
-  "recipe[donate]"
-)
diff --git a/roles/dotsrc.rb b/roles/dotsrc.rb
deleted file mode 100644 (file)
index e236f27..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-name "dotsrc"
-description "Role applied to all servers at dotsrc.org"
-
-default_attributes(
-  :hosted_by => "dotsrc.org",
-  :location => "Aalborg, Denmark",
-  :networking => {
-    :nameservers => [
-      "130.226.1.2",
-      "130.226.255.53",
-      "2001:878:0:100::2"
-    ],
-    :roles => {
-      :external => {
-        :zone => "ds"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.dk.pool.ntp.org", "1.dk.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[dk]"
-)
diff --git a/roles/draco.rb b/roles/draco.rb
deleted file mode 100644 (file)
index 536e33a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-name "draco"
-description "Master role applied to draco"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp3s0f0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.11"
-      },
-      :external_ipv4 => {
-        :interface => "enp3s0f0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.12"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]"
-)
diff --git a/roles/dribble.rb b/roles/dribble.rb
new file mode 100644 (file)
index 0000000..ce6da2f
--- /dev/null
@@ -0,0 +1,42 @@
+name "dribble"
+description "Master role applied to dribble"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.48.4"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
+        }
+      },
+      :external => {
+        :interface => "bond0.3",
+        :role => :external,
+        :inet => {
+          :address => "184.104.179.132"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::4"
+        }
+      }
+    }
+  },
+  :accounts => {
+    :users => {
+      :stereo => { :status => :administrator }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-ams]",
+  "role[taginfo]"
+)
diff --git a/roles/drogon.rb b/roles/drogon.rb
deleted file mode 100644 (file)
index 1938270..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-name "drogon"
-description "Master role applied to drogon"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :zelja => { :status => :administrator }
-    }
-  },
-  :hardware => {
-    :shm_size => "18g"
-  },
-  :location => "Osijek, Croatia",
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "161.53.30.107",
-        :prefix => "27",
-        :gateway => "161.53.30.97"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:b68:c0ff:0:221:5eff:fe40:c7c4",
-        :prefix => "64",
-        :gateway => "fe80::161:53:30:97"
-      }
-    },
-    :nameservers => [
-      "161.53.30.100",
-      "8.8.8.8"
-    ]
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "osijek.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[carnet]",
-  "role[tilecache]"
-)
index 35c811f3533109f4a61f5fced107590cdfaf3ef2..e69ea39ddbfaf839621ab181be369dc0ab0d2770 100644 (file)
@@ -4,67 +4,56 @@ description "Master role applied to dulcy"
 default_attributes(
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.9",
+        :inet => {
+          :address => "10.0.48.9"
+        },
         :bond => {
-          :slaves => %w[p18p1 p18p2]
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[ens18f0 ens18f1]
         }
       },
-      :external_ipv4 => {
-        :interface => "bond0.2",
+      :external => {
+        :interface => "bond0.3",
         :role => :external,
-        :family => :inet,
-        :address => "130.117.76.9"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:9"
+        :inet => {
+          :address => "184.104.179.137"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::9"
+        }
       }
     }
   },
   :postgresql => {
-    :versions => ["10"],
+    :versions => ["15"],
     :settings => {
       :defaults => {
-        :work_mem => "300MB",
-        :maintenance_work_mem => "10GB",
-        :random_page_cost => "1.5",
-        :effective_cache_size => "60GB",
-        :fsync => "on",
-        :effective_io_concurrency => "3"
+        :work_mem => "240MB",
+        :effective_io_concurrency => "500"
       }
     }
   },
   :nominatim => {
     :state => "standalone",
-    :enable_backup => false,
-    :enable_git_updates => true,
-    :dbadmins => %w[lonvia tomh],
-    :dbcluster => "10/main",
-    :postgis => "2.4",
+    :dbcluster => "15/main",
+    :postgis => "3",
     :flatnode_file => "/ssd/nominatim/nodes.store",
     :logdir => "/ssd/nominatim/log",
-    :tablespaces => {
-      "dosm" => "/ssd/tablespaces/dosm",
-      "iosm" => "/ssd/tablespaces/iosm",
-      "dplace" => "/ssd/tablespaces/dplace",
-      "iplace" => "/ssd/tablespaces/iplace",
-      "daddress" => "/ssd/tablespaces/daddress",
-      "iaddress" => "/ssd/tablespaces/iaddress",
-      "dsearch" => "/ssd/tablespaces/dsearch",
-      "isearch" => "/ssd/tablespaces/isearch",
-      "daux" => "/ssd/tablespaces/daux",
-      "iaux" => "/ssd/tablespaces/iaux"
+    :api_flavour => "python",
+    :api_workers => 14,
+    :api_pool_size => 10,
+    :config => {
+      :forward_dependencies => "yes"
     }
   }
 )
 
 run_list(
-  "role[equinix]",
+  "role[equinix-ams]",
   "role[nominatim]"
 )
index d900fbb4f41dfe7d1d0809cf6680d2f5596ffdf3..61e4524557657c1214b2eeae51cba28679c20139 100644 (file)
@@ -2,19 +2,14 @@ name "eddie"
 description "Master role applied to eddie"
 
 default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
-  :db => {
-    :cluster => "9.5/main"
-  },
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "enp1s0f0.2801",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.10"
+        :inet => {
+          :address => "10.0.0.10"
+        }
       }
     }
   },
@@ -24,9 +19,7 @@ default_attributes(
         :shared_buffers => "64GB",
         :work_mem => "64MB",
         :maintenance_work_mem => "1GB",
-        :effective_cache_size => "180GB",
-        :effective_io_concurrency => "256",
-        :random_page_cost => "1.1"
+        :effective_cache_size => "180GB"
       }
     }
   },
diff --git a/roles/epix.rb b/roles/epix.rb
new file mode 100644 (file)
index 0000000..76b6de5
--- /dev/null
@@ -0,0 +1,17 @@
+name "epix"
+description "Role applied to all servers at EPIX"
+
+default_attributes(
+  :hosted_by => "EPIX",
+  :location => "Katowice, Poland"
+)
+
+override_attributes(
+  :ntp => {
+    :servers => ["0.pl.pool.ntp.org", "1.pl.pool.ntp.org", "europe.pool.ntp.org"]
+  }
+)
+
+run_list(
+  "role[pl]"
+)
similarity index 52%
rename from roles/equinix.rb
rename to roles/equinix-ams.rb
index a35b4775c50b97526ad92825f812b937402d4396..7923e09d46e744837baf0221ae07bf37f14c4df6 100644 (file)
@@ -1,39 +1,49 @@
-name "equinix"
-description "Role applied to all servers at Equinix"
+name "equinix-ams"
+description "Role applied to all servers at Equinix Amsterdam"
 
 default_attributes(
   :networking => {
-    :nameservers => ["66.28.0.45", "66.28.0.61", "2001:978:1:1::d", "2001:978:1:2::d"],
     :roles => {
       :internal => {
         :inet => {
           :prefix => "20",
-          :gateway => "10.0.48.10"
+          :gateway => "10.0.48.10",
+          :routes => {
+            "10.0.0.0/8" => { :via => "10.0.48.10" }
+          }
         }
       },
       :external => {
         :zone => "ams",
         :inet => {
           :prefix => "27",
-          :gateway => "130.117.76.1"
+          :gateway => "184.104.179.129"
         },
         :inet6 => {
           :prefix => "64",
-          :gateway => "2001:978:2:2C::172:1"
+          :gateway => "2001:470:1:fa1::1"
         }
       }
     }
   },
+  :prometheus => {
+    :metrics => {
+      :host_location => {
+        :help => "Host location",
+        :labels => { :site => "amsterdam" }
+      }
+    }
+  },
   :web => {
-    :backends => %w[rails1 rails2 rails3],
     :fileserver => "ironbelly",
-    :readonly_database_host => "karm.ams.openstreetmap.org",
+    :readonly_database_host => "snap-01.ams.openstreetmap.org",
     :primary_cluster => true
   }
 )
 
 override_attributes(
   :networking => {
+    :nameservers => ["10.0.48.10", "8.8.8.8", "8.8.4.4"],
     :search => ["ams.openstreetmap.org", "openstreetmap.org"]
   },
   :ntp => {
diff --git a/roles/equinix-dub.rb b/roles/equinix-dub.rb
new file mode 100644 (file)
index 0000000..e24d71a
--- /dev/null
@@ -0,0 +1,64 @@
+name "equinix-dub"
+description "Role applied to all servers at Equinix Dublin"
+
+default_attributes(
+  :sysctl => {
+    :enable_bbr_10g => {
+      :comment => "Enable BBR. Equinix Dub has 10G uplink unlikely to buffer overrun",
+      :parameters => {
+        "net.ipv4.tcp_congestion_control" => "bbr",
+        "net.ipv4.tcp_notsent_lowat" => "16384"
+      }
+    }
+  },
+  :networking => {
+    :roles => {
+      :internal => {
+        :inet => {
+          :prefix => "20",
+          :gateway => "10.0.64.2",
+          :routes => {
+            "10.0.0.0/8" => { :via => "10.0.64.2" }
+          }
+        }
+      },
+      :external => {
+        :zone => "dub",
+        :inet => {
+          :prefix => "27",
+          :gateway => "184.104.226.97"
+        },
+        :inet6 => {
+          :prefix => "64",
+          :gateway => "2001:470:1:b3b::1"
+        }
+      }
+    }
+  },
+  :prometheus => {
+    :metrics => {
+      :host_location => {
+        :help => "Host location",
+        :labels => { :site => "dublin" }
+      }
+    }
+  },
+  :web => {
+    :fileserver => "fafnir",
+    :readonly_database_host => "snap-03.dub.openstreetmap.org"
+  }
+)
+
+override_attributes(
+  :networking => {
+    :nameservers => ["10.0.64.2", "8.8.8.8", "8.8.4.4"],
+    :search => ["dub.openstreetmap.org", "openstreetmap.org"]
+  },
+  :ntp => {
+    :servers => ["0.ie.pool.ntp.org", "1.ie.pool.ntp.org", "europe.pool.ntp.org"]
+  }
+)
+
+run_list(
+  "role[ie]"
+)
diff --git a/roles/errol.rb b/roles/errol.rb
deleted file mode 100644 (file)
index e4db08b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-name "errol"
-description "Master role applied to errol"
-
-default_attributes(
-  :devices => {
-    :osdsk => {
-      :comment => "First os disk",
-      :type => "block",
-      :bus => "scsi",
-      :serial => "20004d927fffff800",
-      :attrs => {
-        "queue/scheduler" => "deadline",
-        "queue/nr_requests" => "512"
-      }
-    },
-    :homedsk => {
-      :comment => "First home disk",
-      :type => "block",
-      :bus => "scsi",
-      :serial => "20004d927fffff801",
-      :attrs => {
-        "queue/scheduler" => "deadline",
-        "queue/nr_requests" => "512"
-      }
-    }
-  },
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "eth0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.14"
-      },
-      :external_ipv4 => {
-        :interface => "eth0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.13"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[tyan-s7010]",
-  "role[dev]"
-)
diff --git a/roles/euserv.rb b/roles/euserv.rb
deleted file mode 100644 (file)
index 8a2de04..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-name "euserv"
-description "Role applied to all servers at EUserv"
-
-default_attributes(
-  :hosted_by => "EUserv",
-  :location => "Jena, Germany",
-  :networking => {
-    :nameservers => [
-      "85.31.184.60", "85.31.184.61", "85.31.185.60", "85.31.185.61"
-    ],
-    :roles => {
-      :external => {
-        :zone => "es"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.de.pool.ntp.org", "1.de.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[de]"
-)
diff --git a/roles/eustace.rb b/roles/eustace.rb
deleted file mode 100644 (file)
index 4aa2fdd..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-name "eustace"
-description "Master role applied to eustace"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "eth0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.9"
-      },
-      :external_ipv4 => {
-        :interface => "eth0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.14"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[hp-dl360-g6]",
-  "role[piwik]"
-)
index ea1c0048161a117b6c24acebef058947cd16ddf3..93068a76c86a5653034c2d0c865628e1c6c0b454 100644 (file)
@@ -10,10 +10,8 @@ default_attributes(
   :hosted_by => "Exonetric",
   :location => "London, England",
   :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
     :roles => {
       :external => {
-        :zone => "ex",
         :inet => {
           :prefix => "28",
           :gateway => "178.250.74.33"
diff --git a/roles/faffy.rb b/roles/faffy.rb
new file mode 100644 (file)
index 0000000..c4963d1
--- /dev/null
@@ -0,0 +1,37 @@
+name "faffy"
+description "Master role applied to faffy"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.48.3"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
+        }
+      },
+      :external => {
+        :interface => "bond0.3",
+        :role => :external,
+        :inet => {
+          :address => "184.104.179.131"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::3"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-ams]",
+  "role[dev]"
+)
index c526226a845f107e80744d698e5a81bfa35ac94b..c443332c2e493096f626108862d76ff755892d49 100644 (file)
@@ -2,45 +2,67 @@ name "fafnir"
 description "Master role applied to fafnir"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "36g"
+  :dhcpd => {
+    :first_address => "10.0.79.1",
+    :last_address => "10.0.79.254"
+  },
+  :exim => {
+    :routes => {
+      :openstreetmap => {
+        :comment => "openstreetmap.org",
+        :domains => ["openstreetmap.org"],
+        :host => ["shenron.openstreetmap.org"]
+      }
+    }
   },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "enp3s0f0",
-        :role => :external,
-        :family => :inet,
-        :address => "130.239.18.114",
-        :prefix => "27",
-        :gateway => "130.239.18.97"
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.2"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
       },
-      :external_ipv6 => {
-        :interface => "enp3s0f0",
+      :external => {
+        :interface => "bond0.101",
         :role => :external,
-        :family => :inet6,
-        :address => "2001:6b0:e:2a18::114",
-        :prefix => "64",
-        :gateway => "fe80::5a97:bdff:fe79:dbc0"
+        :inet => {
+          :address => "184.104.226.98"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::2"
+        }
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "32768 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "sweden.render.openstreetmap.org"
+  :prometheus => {
+    :junos => {
+      "switch1" => { :address => "184.104.226.97", :labels => { "site" => "dublin" } }
+    },
+    :snmp => {
+      "pdu1" => { :address => "10.0.64.100", :modules => %w[apcups], :labels => { "site" => "dublin" } },
+      "pdu2" => { :address => "10.0.64.101", :modules => %w[apcups], :labels => { "site" => "dublin" } }
+    },
+    :metrics => {
+      :uplink_interface => {
+        :help => "Site uplink interface name",
+        :labels => { :site => "dublin", :name => "xe-[01]/2/[01]|ge-[01]/2/2" }
+      }
+    }
   }
 )
 
 run_list(
-  "role[umu]",
-  "role[tilecache]"
+  "role[equinix-dub]",
+  "role[hp-g9]",
+  "role[gateway]",
+  "role[mail]",
+  "recipe[dhcpd]"
 )
diff --git a/roles/ffrl.rb b/roles/ffrl.rb
deleted file mode 100644 (file)
index 7858e1b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-name "ffrl"
-description "Role applied to all servers at Freifunk Rheinland"
-
-default_attributes(
-  :hosted_by => "Freifunk Rheinland",
-  :location => "Berlin, Germany",
-  :networking => {
-    :nameservers => [
-      "8.8.8.8",
-      "8.8.4.4"
-    ],
-    :roles => {
-      :external => {
-        :zone => "ffr"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.de.pool.ntp.org", "1.de.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[de]"
-)
index 58f78d3326727d0b7a5cbfa4c5271e36c9387e54..150f62d6fe089ac38531387faa55facabee017ad 100644 (file)
@@ -3,16 +3,12 @@ description "Role applied to all servers at Firefishy"
 
 default_attributes(
   :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
     :roles => {
       :internal => {
         :inet => {
           :prefix => "24",
           :gateway => "10.89.121.1"
         }
-      },
-      :external => {
-        :zone => "ff"
       }
     }
   }
diff --git a/roles/forum.rb b/roles/forum.rb
deleted file mode 100644 (file)
index e9a3814..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-name "forum"
-description "Role applied to all forum servers"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :lambertus => {
-        :status => :administrator
-      },
-      :forum => {
-        :status => :role,
-        :members => [:lambertus, :grant]
-      }
-    }
-  },
-  :apache => {
-    :mpm => "prefork",
-    :timeout => 60,
-    :keepalive => false,
-    :prefork => {
-      :start_servers => 20,
-      :min_spare_servers => 20,
-      :max_spare_servers => 50,
-      :max_request_workers => 256
-    }
-  }
-)
-
-run_list(
-  "recipe[forum]"
-)
index 9a2c2e553837c30fda36b4e030a889d73c2051aa..fb8024291d163f49403d30d253cf9041aca3957f 100644 (file)
@@ -2,16 +2,8 @@ name "foundation"
 description "Role applied to all OSMF servers"
 
 default_attributes(
-  :apache => {
-    :mpm => "prefork",
-    :timeout => 60,
-    :keepalive => false
-  },
-  :apt => {
-    :sources => ["passenger"]
-  },
   :elasticsearch => {
-    :version => "5.x",
+    :version => "7.x",
     :cluster => {
       :name => "foundation"
     }
@@ -27,8 +19,6 @@ default_attributes(
         :innodb_buffer_pool_size => "512M",
         :key_buffer_size => "64M",
         :max_connections => "200",
-        :query_cache_size => "48M",
-        :query_cache_type => "1",
         :sort_buffer_size => "8M",
         :tmp_table_size => "48M"
       }
@@ -42,6 +32,5 @@ run_list(
   "recipe[foundation::wiki]",
   "recipe[foundation::board]",
   "recipe[foundation::dwg]",
-  "recipe[foundation::mwg]",
-  "recipe[foundation::owg]"
+  "recipe[foundation::mwg]"
 )
diff --git a/roles/fullsave.rb b/roles/fullsave.rb
deleted file mode 100644 (file)
index 657f927..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-name "fullsave"
-description "Role applied to all servers at FullSave"
-
-default_attributes(
-  :hosted_by => "FullSave",
-  :location => "Toulouse, France",
-  :networking => {
-    :firewall => {
-      :inet => [
-        {
-          :action => "ACCEPT",
-          :source => "net:185.116.130.12",
-          :dest => "fw",
-          :proto => "udp",
-          :dest_ports => "snmp",
-          :source_ports => "1024:",
-          :rate_limit => "-",
-          :connection_limit => "-"
-        },
-        {
-          :action => "ACCEPT",
-          :source => "net:100.80.8.0/24",
-          :dest => "fw",
-          :proto => "udp",
-          :dest_ports => "snmp",
-          :source_ports => "1024:",
-          :rate_limit => "-",
-          :connection_limit => "-"
-        }
-      ]
-    },
-    :nameservers => ["141.0.202.202", "141.0.202.203"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.fr.pool.ntp.org", "1.fr.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[fr]"
-)
index 176a22d617b8299289a5cf33b1143163802e11b5..6af2333b4d6de6ef766451a3a56843c001eacd31 100644 (file)
@@ -2,37 +2,37 @@ name "fume"
 description "Master role applied to fume"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "6g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens3",
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.16"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
         :role => :external,
-        :family => :inet,
-        :address => "147.228.60.16",
-        :prefix => "24",
-        :gateway => "147.228.60.1"
+        :inet => {
+          :address => "184.104.226.112"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::10"
+        }
       }
     }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "4096 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "pilsen.render.openstreetmap.org"
   }
 )
 
 run_list(
-  "role[zcu]",
-  "role[tilecache]"
+  "role[equinix-dub]",
+  "role[blog-staging]",
+  "role[birthday20]"
 )
diff --git a/roles/g5solutions.rb b/roles/g5solutions.rb
deleted file mode 100644 (file)
index 5cb41ec..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-name "g5solutions"
-description "Role applied to all servers at G5 Solutions"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :g5team => { :status => :administrator }
-    }
-  },
-  :hosted_by => "G5 Solutions",
-  :location => "Indonesia",
-  :networking => {
-    :nameservers => [
-      "8.8.8.8",
-      "8.8.4.4"
-    ],
-    :roles => {
-      :external => {
-        :zone => "g5s"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.id.pool.ntp.org", "1.id.pool.ntp.org", "asia.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[id]"
-)
diff --git a/roles/gandi.rb b/roles/gandi.rb
new file mode 100644 (file)
index 0000000..2fcd108
--- /dev/null
@@ -0,0 +1,20 @@
+name "gandi"
+description "Role applied to all servers at Gandi"
+
+default_attributes(
+  :hosted_by => "Gandi",
+  :location => "Bissen, Luxembourg"
+)
+
+override_attributes(
+  :networking => {
+    :nameservers => ["217.70.186.194", "217.70.186.193", "2001:4b98:dc2:49::193"]
+  },
+  :ntp => {
+    :servers => ["0.lu.pool.ntp.org", "1.lu.pool.ntp.org", "europe.pool.ntp.org"]
+  }
+)
+
+run_list(
+  "role[lu]"
+)
index b9007b86ece3163425243dcf5c324e6b4d810659..d842bf41268e418e7f2c4f56da167a3388c5c26c 100644 (file)
@@ -7,12 +7,10 @@ default_attributes(
       :comment => "Enable forwarding",
       :parameters => { "net.ipv4.ip_forward" => "1" }
     }
-  },
-  :exim => {
-    :relay_from_hosts => ["10.0.0.0/8"]
   }
 )
 
 run_list(
-  "recipe[bind]"
+  "recipe[bind]",
+  "recipe[prometheus::smokeping]"
 )
index a31437a697444fec0dcf63c21bf3ff2ea2a3eed1..a2ad092f323812b6e142dc427bb0ea7bdadaaf0f 100644 (file)
@@ -12,7 +12,8 @@ default_attributes(
         :list => false,
         :transfer_logging => false,
         :hosts_allow => [
-          "193.60.236.20" # sarel
+          "184.104.226.102",  # idris
+          "2001:470:1:b3b::6" # idris
         ]
       }
     }
index 31ad54036829706b2021062d37b0d9b213cf2927..c401c865f6311eece5ec360cb16bccedb864d613 100644 (file)
@@ -16,9 +16,13 @@ default_attributes(
         :status => :user,
         :shell => "/usr/bin/git-shell"
       },
+      :stereo => {
+        :status => :user,
+        :shell => "/usr/bin/git-shell"
+      },
       :git => {
         :status => :role,
-        :members => [:tomh, :grant, :matt, :lonvia, :yellowbkpk]
+        :members => [:tomh, :grant, :matt, :lonvia, :yellowbkpk, :stereo]
       }
     }
   },
diff --git a/roles/gorynych.rb b/roles/gorynych.rb
deleted file mode 100644 (file)
index 8509291..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-name "gorynych"
-description "Master role applied to gorynych"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "20g"
-  },
-  :munin => {
-    :plugins => {
-      :smart_sdc => {
-        :smartctl_exit_status => { :warning => ":8" }
-      },
-      :smart_sdd => {
-        :smartctl_exit_status => { :warning => ":8" }
-      }
-    }
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth1",
-        :role => :external,
-        :family => :inet,
-        :address => "5.45.248.21",
-        :prefix => "30",
-        :gateway => "5.45.248.22"
-      },
-      :external_ipv6 => {
-        :interface => "eth1",
-        :role => :external,
-        :family => :inet6,
-        :address => "2a02:6b8:b010:5065::a001",
-        :prefix => "64",
-        :gateway => "2a02:6b8:b010:5065::1"
-      }
-    }
-  },
-  :sysfs => {
-    :md_tune => {
-      :comment => "Tune the md sync performance so as not to kill system performance",
-      :parameters => {
-        "block/md0/md/sync_speed_min" => "1",
-        "block/md0/md/sync_speed_max" => "100000"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :directory => "/store/nginx-cache/proxy-cache"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "moscow.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[yandex]",
-  "role[tilecache]"
-)
diff --git a/roles/gp-dl360e-g8.rb b/roles/gp-dl360e-g8.rb
new file mode 100644 (file)
index 0000000..695bc95
--- /dev/null
@@ -0,0 +1,2 @@
+name "hp-dl360e-g8"
+description "Role applied to all HP DL360e G8 machines"
index 285d461de69cea0ed216758151eda7cec42a8ebb..e6a0e5ec2f340fd1001c85bac26b5117bf1a531c 100644 (file)
@@ -6,7 +6,6 @@ default_attributes(
     :users => {
       :enf => { :status => :administrator },
       :gpstile => {
-        :status => :role,
         :members => [:enf, :tomh]
       }
     }
@@ -25,6 +24,5 @@ default_attributes(
 )
 
 run_list(
-  "recipe[memcached]",
   "recipe[gps-tile]"
 )
diff --git a/roles/grifon.rb b/roles/grifon.rb
deleted file mode 100644 (file)
index 054af06..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-name "grifon"
-description "Role applied to all servers at Grifon"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :alarig => { :status => :administrator },
-      :gizmo => { :status => :administrator },
-      :nemo => { :status => :administrator }
-    }
-  },
-  :hosted_by => "Grifon",
-  :location => "Rennes, France",
-  :munin => {
-    :allow => ["2a00:5884::8"]
-  },
-  :networking => {
-    :firewall => {
-      :inet6 => [
-        {
-          :action => "ACCEPT",
-          :source => "net:[2a00:5884::8]",
-          :dest => "fw",
-          :proto => "tcp",
-          :dest_ports => "munin",
-          :source_ports => "1024:",
-          :rate_limit => "-",
-          :connection_limit => "-"
-        }
-      ]
-    },
-    :nameservers => ["2a00:5884::7", "8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "grf"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.fr.pool.ntp.org", "1.fr.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[fr]"
-)
diff --git a/roles/grindtooth.rb b/roles/grindtooth.rb
deleted file mode 100644 (file)
index 2d78c10..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "grindtooth"
-description "Master role applied to grindtooth"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "em1.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.19"
-      },
-      :external_ipv4 => {
-        :interface => "em1.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.15"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[taginfo]"
-)
index 8e177a8ff49ea2781610271c2015f8c0236587d8..17b0aaa556fe9c64b8558e12f34dac231626e369 100644 (file)
@@ -2,72 +2,36 @@ name "grisu"
 description "Master role applied to grisu"
 
 default_attributes(
-  :bind => {
-    :clients => "bytemark"
-  },
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.32.20",
+        :inet => {
+          :address => "10.0.64.17"
+        },
         :bond => {
-          :slaves => %w[em1 em2]
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
         }
       },
-      :external_ipv4 => {
-        :interface => "bond0.214",
+      :external => {
+        :interface => "bond0.101",
         :role => :external,
-        :family => :inet,
-        :address => "89.16.162.20"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.214",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:41c9:2:d6::20"
-      }
-    }
-  },
-  :openvpn => {
-    :address => "10.0.16.5",
-    :tunnels => {
-      :ic2bm => {
-        :port => "1194",
-        :mode => "server",
-        :peer => {
-          :host => "ironbelly.openstreetmap.org"
-        }
-      },
-      :aws2bm => {
-        :port => "1195",
-        :mode => "server",
-        :peer => {
-          :host => "fafnir.openstreetmap.org"
-        }
-      },
-      :ucl2bm => {
-        :port => "1196",
-        :mode => "server",
-        :peer => {
-          :host => "ridley.openstreetmap.org"
+        :inet => {
+          :address => "184.104.226.113"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::11"
         }
       }
     }
-  },
-  :planet => {
-    :replication => "disabled"
   }
 )
 
 run_list(
-  "role[bytemark]",
-  "role[hp-dl180-g6]",
-  "role[gateway]",
-  "role[web-storage]",
-  "role[backup]",
-  "role[planet]",
-  # "role[planetdump]",
-  "recipe[openvpn]"
+  "role[equinix-dub]",
+  "role[overpass-query]"
 )
diff --git a/roles/grnet.rb b/roles/grnet.rb
deleted file mode 100644 (file)
index 6893b65..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-name "grnet"
-description "Role applied to all servers at GRNET"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :grnet => { :status => :administrator }
-    }
-  },
-  :hosted_by => "GRNET",
-  :location => "Athens, Greece",
-  :networking => {
-    :nameservers => [
-      "8.8.8.8",
-      "8.8.4.4"
-    ],
-    :roles => {
-      :external => {
-        :zone => "grn"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.gr.pool.ntp.org", "1.gr.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[gr]"
-)
diff --git a/roles/hetzner.rb b/roles/hetzner.rb
deleted file mode 100644 (file)
index 4ed0865..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-name "hetzner"
-description "Role applied to all servers at Hetzner"
-
-default_attributes(
-  :hosted_by => "Hetzner",
-  :networking => {
-    :nameservers => [
-      "213.133.98.98",
-      "213.133.99.99",
-      "213.133.100.100",
-      "2a01:4f8:0:a111::add:9898",
-      "2a01:4f8:0:a102::add:9999",
-      "2a01:4f8:0:a0a1::add:1010"
-    ],
-    :roles => {
-      :external => {
-        :zone => "hz"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.de.pool.ntp.org", "1.de.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[de]"
-)
diff --git a/roles/horntail.rb b/roles/horntail.rb
new file mode 100644 (file)
index 0000000..afaf946
--- /dev/null
@@ -0,0 +1,38 @@
+name "horntail"
+description "Master role applied to horntail"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.10"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[enp25s0f0 enp25s0f1]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.106"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::a"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[geodns]",
+  "role[planet]"
+)
diff --git a/roles/hostedinnz.rb b/roles/hostedinnz.rb
deleted file mode 100644 (file)
index ef24387..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-name "hostedinnz"
-description "Role applied to all servers at HostedIn.NZ"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :asmith => { :status => :administrator }
-    }
-  },
-  :hosted_by => "HostedIn.NZ",
-  :location => "Wellington, New Zealand",
-  :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  },
-  :snmpd => {
-    :clients => ["103.106.66.28"],
-    :community => "hostedinnz",
-    :location => "Wellington"
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.nz.pool.ntp.org", "1.nz.pool.ntp.org", "asia.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[nz]",
-  "recipe[snmpd]"
-)
index edb65fe63fc8682784c71ff033d45d6a69070ab6..f7aa64a3a21bc73d1a7ffcea33712ad0d93d5d53 100644 (file)
@@ -2,43 +2,7 @@ name "hp-dl180-g6"
 description "Role applied to all HP DL180 G6 machines"
 
 default_attributes(
-  :munin => {
-    :plugins => {
-      :hpasmcli2_fans => {
-        :fan1 => { :warning => "90", :critical => "100" },
-        :fan2 => { :warning => "90", :critical => "100" },
-        :fan3 => { :warning => "90", :critical => "100" },
-        :fan4 => { :warning => "90", :critical => "100" }
-      },
-      :hpasmcli2_temp => {
-        :temp3 => { :warning => "80.0", :critical => "85" }
-      },
-      :ipmi_temp => {
-        :Temp1 => { :label => "Air Inlet" },
-        :Temp2CPU1 => { :warning => ":", :label => "CPU 1" },
-        :Temp3CPU2 => { :warning => ":", :label => "CPU 2" },
-        :Temp4 => { :warning => ":", :label => "Memory 1" },
-        :Temp5 => { :warning => ":", :label => "Memory 2" },
-        :Temp8MemB0 => { :warning => ":", :label => "Memory 3" },
-        :Temp9MemB0 => { :warning => ":", :label => "Memory 4" },
-        :Temp10MemB0 => { :warning => ":", :label => "Memory 5" },
-        :Temp12MemB1 => { :warning => ":", :label => "Memory 6" },
-        :Temp13MemB1 => { :warning => ":", :label => "Memory 7" },
-        :Temp14MemB1 => { :warning => ":", :label => "Memory 8" },
-        :Temp15 => { :warning => ":", :label => "Main System Board 3" },
-        :Temp16 => { :warning => ":", :label => "Main System Board 4" },
-        :Temp17 => { :warning => ":", :label => "Main System Board 5" },
-        :Temp18 => { :warning => ":", :label => "Main System Board 6" },
-        :Temp19 => { :warning => ":", :label => "Main System Board 7" },
-        :Temp20 => { :warning => ":", :label => "Main System Board 8" },
-        :Temp21 => { :warning => ":", :label => "Main System Board 9" },
-        :Temp26 => { :warning => ":", :label => "Drive Backplane 1" },
-        :Temp27 => { :warning => ":", :label => "Drive Backplane 2" },
-        :Temp28 => { :warning => ":", :label => "Drive Backplane 3" },
-        :Temp29 => { :warning => ":", :label => "Drive Backplane 4" },
-        :Temp30 => { :warning => ":", :label => "Drive Backplane 5" },
-        :Temp31 => { :warning => ":", :label => "Drive Backplane 6" }
-      }
-    }
+  :hardware => {
+    :blacklisted_modules => %w[acpi_power_meter]
   }
 )
index 3f0cfd6004f04b72e7574bf9fd236c9eec0c92f6..fe953d50a8e19db4601cad66f3bdc78f696f9c34 100644 (file)
@@ -2,38 +2,7 @@ name "hp-dl360-g6"
 description "Role applied to all HP DL360 G6 machines"
 
 default_attributes(
-  :munin => {
-    :plugins => {
-      :ipmi_temp => {
-        :Temp1 => { :label => "External Environment" },
-        :Temp2 => { :warning => ":", :label => "CPU 1" },
-        :Temp3 => { :warning => ":", :label => "CPU 2" },
-        :Temp4 => { :warning => ":", :label => "Memory 1" },
-        :Temp5 => { :warning => ":", :label => "Memory 2" },
-        :Temp6 => { :warning => ":", :label => "Memory 3" },
-        :Temp7 => { :warning => ":", :label => "Memory 4" },
-        :Temp8 => { :warning => ":", :label => "Memory 5" },
-        :Temp9 => { :warning => ":", :label => "Memory 6" },
-        :Temp10 => { :warning => ":", :label => "Memory 7" },
-        :Temp11 => { :warning => ":", :label => "Memory 8" },
-        :Temp12 => { :warning => ":", :label => "PSU 1" },
-        :Temp13 => { :warning => ":", :label => "PSU 2" },
-        :Temp14 => { :warning => ":", :label => "Memory 9" },
-        :Temp15 => { :warning => ":", :label => "CPU Zone 1" },
-        :Temp16 => { :warning => ":", :label => "CPU Zone 2" },
-        :Temp17 => { :warning => ":", :label => "Memory 10" },
-        :Temp18 => { :warning => ":", :label => "CPU Zone 3" },
-        :Temp19 => { :warning => ":", :label => "Peripheral Bay 1" },
-        :Temp20 => { :warning => ":", :label => "Peripheral Bay 2" },
-        :Temp21 => { :warning => ":", :label => "Peripheral Bay 3" },
-        :Temp22 => { :warning => ":", :label => "Peripheral Bay 4" },
-        :Temp23 => { :warning => ":", :label => "Peripheral Bay 5" },
-        :Temp24 => { :warning => ":", :label => "Peripheral Bay 6" },
-        :Temp25 => { :warning => ":", :label => "Peripheral Bay 7" },
-        :Temp26 => { :warning => ":", :label => "Peripheral Bay 8" },
-        :Temp27 => { :warning => ":", :label => "Drive Backplane" },
-        :Temp28 => { :warning => ":", :label => "System Board" }
-      }
-    }
+  :hardware => {
+    :blacklisted_modules => %w[acpi_power_meter]
   }
 )
index 01f2afc001de04d30612b48229f9dffddb8ba488..4d086da763ab4a052f3d88a9140680c28e49f23a 100644 (file)
@@ -1,15 +1,2 @@
 name "hp-g9"
 description "Role applied to all HP G9 machines"
-
-default_attributes(
-  :munin => {
-    :plugins => {
-      :hpasmcli2_temp => {
-        :temp11 => { :warning => 85, :critical => 100 },
-        :temp12 => { :warning => 85, :critical => 100 },
-        :temp19 => { :warning => 85, :critical => 100 },
-        :temp20 => { :warning => 85, :critical => 100 }
-      }
-    }
-  }
-)
diff --git a/roles/idris.rb b/roles/idris.rb
new file mode 100644 (file)
index 0000000..0a7f593
--- /dev/null
@@ -0,0 +1,45 @@
+name "idris"
+description "Master role applied to idris"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.6"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.102"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::6"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[hp-g9]",
+  "role[chef-server]",
+  "role[chef-repository]",
+  "role[dns]",
+  "role[git]",
+  "role[letsencrypt]",
+  "role[oxidized]",
+  "role[supybot]",
+  "recipe[serverinfo]"
+)
index fedd79afc43b7fbd21aa79780b229113f1cc0a40..78437a60887c44aee95b45b52aa99d9b4cf8d519 100644 (file)
@@ -4,35 +4,21 @@ description "Role applied to all imagery servers"
 default_attributes(
   :accounts => {
     :users => {
+      :dmlu => { :status => :user },
       :htonl => { :status => :user },
+      :stereo => { :status => :administrator },
       :imagery => {
         :status => :role,
-        :members => [:grant, :tomh, :htonl]
+        :members => [:grant, :tomh, :dmlu, :htonl, :stereo ]
       }
     }
   },
-  :apt => {
-    :sources => %w[nginx ubuntugis-unstable]
-  },
   :sysctl => {
     :sockets => {
       :comment => "Increase size of connection queue",
       :parameters => {
         "net.core.somaxconn" => 10000
       }
-    },
-    :kernel_scheduler_tune => {
-      :comment => "Tune kernel scheduler preempt",
-      :parameters => {
-        "kernel.sched_min_granularity_ns" => 10000000,
-        "kernel.sched_wakeup_granularity_ns" => 15000000
-      }
-    },
-    :kernel_tfo_listen_enable => {
-      :comment => "Enable TCP Fast Open for listening sockets",
-      :parameters => {
-        "net.ipv4.tcp_fastopen" => 3
-      }
     }
   },
   :nginx => {
@@ -55,5 +41,7 @@ run_list(
   "recipe[imagery::gb_surrey_aerial]",
   "recipe[imagery::za_ngi_topo]",
   "recipe[imagery::za_coct_aerial]",
-  "recipe[imagery::na_sgswa_topo]"
+  "recipe[imagery::na_sgswa_topo]",
+  "recipe[imagery::lu_ngl_dtm]",
+  "recipe[imagery::lu_lidar_hillshade]"
 )
index 03d5ff70e4cb998a02c4e661637a4120b7bcc6d1..96dd61a960a9584fd929d78ba91fb03d9cb77922 100644 (file)
@@ -3,22 +3,13 @@ description "Role applied to all servers at INX-ZA"
 
 default_attributes(
   :hosted_by => "INX-ZA",
-  :location => "Cape Town, South Africa",
-  :networking => {
-    :nameservers => [
-      "196.10.52.52",
-      "196.10.54.54",
-      "196.10.55.55"
-    ],
-    :roles => {
-      :external => {
-        :zone => "ixz"
-      }
-    }
-  }
+  :location => "Cape Town, South Africa"
 )
 
 override_attributes(
+  :networking => {
+    :nameservers => ["196.10.52.52", "196.10.54.54", "196.10.55.55"]
+  },
   :ntp => {
     :servers => ["0.za.pool.ntp.org", "1.za.pool.ntp.org", "africa.pool.ntp.org"]
   }
index f12e2691e9d0be208d120df607764f5bcbcb5934..732542e69a0350cc3460e6d1033336a97eecd0f8 100644 (file)
@@ -2,5 +2,5 @@ name "irc"
 description "Role applied to all IRC gateways"
 
 run_list(
-  "recipe[cgiirc]"
+  "recipe[irc]"
 )
index 2f05572fb1009330586ea4db84ffbe34f1ef5494..4d3c83a747260f6be2195cc5648d77a6b59bb6a7 100644 (file)
@@ -2,12 +2,6 @@ name "ironbelly"
 description "Master role applied to ironbelly"
 
 default_attributes(
-  :apt => {
-    :sources => ["ubuntugis-unstable"]
-  },
-  :bind => {
-    :clients => "equinix"
-  },
   :dhcpd => {
     :first_address => "10.0.63.1",
     :last_address => "10.0.63.254"
@@ -32,76 +26,58 @@ default_attributes(
   },
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.10",
+        :inet => {
+          :address => "10.0.48.10"
+        },
         :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
           :slaves => %w[eth0 eth1]
         }
       },
-      :external_ipv4 => {
-        :interface => "bond0.2",
+      :external => {
+        :interface => "bond0.3",
         :role => :external,
-        :family => :inet,
-        :address => "130.117.76.10"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:A"
+        :inet => {
+          :address => "184.104.179.138"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::a"
+        }
       }
     }
   },
-  :openvpn => {
-    :address => "10.0.16.2",
-    :tunnels => {
-      :ic2ucl => {
-        :port => "1194",
-        :mode => "server",
-        :peer => {
-          :host => "ridley.openstreetmap.org"
-        }
-      },
-      :aws2ic => {
-        :port => "1195",
-        :mode => "server",
-        :peer => {
-          :host => "fafnir.openstreetmap.org"
-        }
-      },
-      :ic2bm => {
-        :port => "1196",
-        :mode => "client",
-        :peer => {
-          :host => "grisu.openstreetmap.org",
-          :port => "1194"
-        }
+  :prometheus => {
+    :junos => {
+      "switch1" => { :address => "184.104.179.129", :labels => { "site" => "amsterdam" } }
+    },
+    :snmp => {
+      "pdu1" => { :address => "10.0.48.100", :modules => %w[apcups], :labels => { "site" => "amsterdam" } },
+      "pdu2" => { :address => "10.0.48.101", :modules => %w[apcups], :labels => { "site" => "amsterdam" } }
+    },
+    :metrics => {
+      :uplink_interface => {
+        :help => "Site uplink interface name",
+        :labels => { :site => "amsterdam", :name => "ge-[01]/2/[02]" }
       }
     }
   },
-  :planet => {
-    :replication => "enabled"
+  :nginx => {
+    :cache => {
+      :proxy => {
+          :enable => true,
+          :keys_zone => "proxy_cache_zone:256M",
+          :inactive => "180d",
+          :max_size => "51200M"
+      }
+    }
   },
   :rsyncd => {
     :modules => {
-      :hosts => {
-        :comment => "Host data",
-        :path => "/home/hosts",
-        :read_only => true,
-        :write_only => false,
-        :list => false,
-        :uid => "tomh",
-        :gid => "tomh",
-        :transfer_logging => false,
-        :hosts_allow => [
-          "212.110.172.32",                      # shenron
-          "2001:41c9:1:400::32",                 # shenron
-          "212.159.112.221"                      # grant
-        ]
-      },
       :logs => {
         :comment => "Log files",
         :path => "/store/logs",
@@ -113,32 +89,27 @@ default_attributes(
         :transfer_logging => false,
         :hosts_allow => [
           "193.60.236.0/24",          # ucl external
-          "10.0.48.0/20",             # equinix internal
-          "130.117.76.0/27",          # equinix external
-          "2001:978:2:2C::172:0/112", # equinix external
+          "10.0.48.0/20",             # amsterdam internal
+          "184.104.179.128/27",       # amsterdam external
+          "2001:470:1:fa1::/64",      # amsterdam external
+          "10.0.64.0/20",             # dublin internal
+          "184.104.226.96/27",        # dublin external
+          "2001:470:1:b3b::/64",      # dublin external
           "10.0.32.0/20",             # bytemark internal
           "89.16.162.16/28",          # bytemark external
           "2001:41c9:2:d6::/64",      # bytemark external
           "127.0.0.0/8",              # localhost
           "::1"                       # localhost
-        ],
-        :nodes_allow => "roles:tilecache"
+        ]
       }
     }
   }
 )
 
 run_list(
-  "role[equinix]",
+  "role[equinix-ams]",
   "role[gateway]",
-  "role[web-storage]",
-  "role[supybot]",
-  "role[backup]",
-  "role[planet]",
-  "role[planetdump]",
-  "role[logstash]",
   "recipe[rsyncd]",
   "recipe[dhcpd]",
-  "recipe[openvpn]",
-  "recipe[tilelog]"
+  "recipe[imagery::za_ngi_aerial]"
 )
diff --git a/roles/iway.rb b/roles/iway.rb
deleted file mode 100644 (file)
index b734f2e..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-name "iway"
-description "Role applied to all servers at iWay"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :cramer => { :status => :administrator }
-    }
-  },
-  :hosted_by => "iWay",
-  :location => "Zurich, Switzerland",
-  :networking => {
-    :firewall => {
-      :inet => [
-        {
-          :action => "ACCEPT",
-          :source => "net:212.25.24.64/28",
-          :dest => "fw",
-          :proto => "udp",
-          :dest_ports => "snmp",
-          :source_ports => "1024:",
-          :rate_limit => "-",
-          :connection_limit => "-"
-        }
-      ]
-    },
-    :nameservers => ["2001:8e0:ffff:ac1::1", "8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.ch.pool.ntp.org", "1.ch.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[ch]"
-)
index 5fc22b2b066d7007d571a95a8a75be3f1f4608e1..1f92c87df3c0c3682c04efb39362117dab7242a4 100644 (file)
@@ -2,68 +2,42 @@ name "jakelong"
 description "Master role applied to jakelong"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "3g"
+  :dhcpd => {
+    :first_address => "10.0.78.1",
+    :last_address => "10.0.78.254"
   },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "71.19.155.177",
-        :prefix => "24",
-        :gateway => "71.19.155.1"
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.12"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 ens1f0 ens1f1]
+        }
       },
-      :external_ipv6 => {
-        :interface => "eth0",
+      :external => {
+        :interface => "bond0.101",
         :role => :external,
-        :family => :inet6,
-        :address => "2605:2700:0:17:a800:ff:fe3e:cdca",
-        :prefix => "64",
-        :gateway => "2605:2700:0:17::1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "1024 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 3840 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 4800 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 6720 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 8640 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :max_size => "2048M"
+        :inet => {
+          :address => "184.104.226.108"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::c"
+        }
       }
     }
-  },
-  :sysctl => {
-    :kvm => {
-      :comment => "Tuning for KVM guest",
-      :parameters => {
-        "kernel.sched_min_granularity_ns" => 10000000,
-        "kernel.sched_wakeup_granularity_ns" => 15000000
-      }
-    },
-    :network_conntrack_max => {
-      :comment => "Increase max number of connections tracked",
-      :parameters => {
-        "net.netfilter.nf_conntrack_max" => "65536"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "sanfrancisco.render.openstreetmap.org"
   }
 )
 
 run_list(
-  "role[prgmr]",
-  "role[geodns]",
-  "role[tilecache]"
+  "role[equinix-dub]",
+  "role[hp-dl360e-g8]",
+  "role[community]",
+  "recipe[dhcpd]"
 )
diff --git a/roles/jump.rb b/roles/jump.rb
deleted file mode 100644 (file)
index 9a026f3..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-name "jump"
-description "Role applied to all servers at Jump Networks"
-
-default_attributes(
-  :hosted_by => "Jump Networks",
-  :location => "London, England",
-  :networking => {
-    :nameservers => [
-      "185.73.44.3",
-      "2001:ba8:0:2c02::",
-      "2001:ba8:0:2c03::",
-      "2001:ba8:0:2c04::"
-    ],
-    :roles => {
-      :external => {
-        :zone => "jn"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.uk.pool.ntp.org", "1.uk.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[gb]"
-)
diff --git a/roles/kalessin.rb b/roles/kalessin.rb
deleted file mode 100644 (file)
index 9176d2a..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-name "kalessin"
-description "Master role applied to kalessin"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "20g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet,
-        :address => "185.66.195.245",
-        :prefix => "28",
-        :gateway => "185.66.195.241"
-      },
-      :external_ipv6 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet6,
-        :address => "2a03:2260:2000:1::5",
-        :prefix => "64",
-        :gateway => "2a03:2260:2000:1::1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :max_size => "2048M"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "germany.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[ffrl]",
-  "role[geodns]",
-  "role[tilecache]"
-)
index 8f0ce7a234de14536cf422a0bbc8028ad677c389..ac28c48d4f3866a35e7880cb328dd2e9712feed4 100644 (file)
@@ -2,21 +2,19 @@ name "karm"
 description "Master role applied to karm"
 
 default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
-  :db => {
-    :cluster => "9.5/main"
-  },
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.50",
+        :inet => {
+          :address => "10.0.48.50"
+        },
         :bond => {
-          :slaves => %w[enp1s0f0 enp1s0f1]
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[enp1s0f0 enp1s0f1 enp2s0f0 enp2s0f1]
         }
       }
     }
@@ -27,9 +25,8 @@ default_attributes(
         :shared_buffers => "64GB",
         :work_mem => "64MB",
         :maintenance_work_mem => "1GB",
-        :effective_cache_size => "180GB",
-        :effective_io_concurrency => "256",
-        :random_page_cost => "1.1"
+        :effective_cache_size => "180GB"
+
       }
     }
   },
@@ -45,7 +42,6 @@ default_attributes(
 )
 
 run_list(
-  "role[equinix]",
-  "role[db-master]",
-  "role[db-backup]"
+  "role[equinix-ams]",
+  "role[db-slave]"
 )
diff --git a/roles/katie.rb b/roles/katie.rb
deleted file mode 100644 (file)
index b54ebb1..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-name "katie"
-description "Master role applied to katie"
-
-default_attributes(
-  :devices => {
-    :disktune => {
-      :comment => "Tune scheduler for Toshiba disks",
-      :type => "block",
-      :bus => "ata",
-      :serial => "TOSHIBA_DT01ACA300_*",
-      :attrs => {
-        "queue/scheduler" => "deadline"
-      }
-    }
-  },
-  :hardware => {
-    :shm_size => "20g"
-  },
-  :location => "Falkenstein, Germany",
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "144.76.70.77",
-        :prefix => "27",
-        :gateway => "144.76.70.65"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2a01:4f8:191:834c::2",
-        :prefix => "64",
-        :gateway => "fe80::1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "germany.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[hetzner]",
-  "role[geodns]",
-  "role[tilecache]"
-)
diff --git a/roles/katla.rb b/roles/katla.rb
deleted file mode 100644 (file)
index 1e471b0..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-name "katla"
-description "Master role applied to katla"
-
-default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
-  :db => {
-    :cluster => "9.5/main"
-  },
-  :devices => {
-    :store_slow => {
-      :comment => "RAID array mounted on /store/arrays/slow",
-      :type => "block",
-      :bus => "scsi",
-      :serial => "3600605b005a0609019290f178be8de77",
-      :attrs => {
-        "queue/scheduler" => "deadline",
-        "queue/nr_requests" => "975",
-        "queue/rq_affinity" => "2"
-      }
-    },
-    :store_fast => {
-      :comment => "RAID array mounted on /store/arrays/fast",
-      :type => "block",
-      :bus => "scsi",
-      :serial => "3600605b005a0726019d062ae23b426fd",
-      :attrs => {
-        "queue/scheduler" => "deadline",
-        "queue/nr_requests" => "975",
-        "queue/rq_affinity" => "2"
-      }
-    },
-    :store_ssd_1 => {
-      :comment => "First disk of RAID array mounted on /store/arrays/ssd",
-      :type => "block",
-      :bus => "ata",
-      :serial => "INTEL_SSDSC2BA400G3_BTTV3141041E400HGN",
-      :attrs => {
-        "queue/scheduler" => "noop"
-      }
-    },
-    :store_ssd_2 => {
-      :comment => "Second disk of RAID array mounted on /store/arrays/ssd",
-      :type => "block",
-      :bus => "ata",
-      :serial => "INTEL_SSDSC2BA400G3_BTTV3141044Q400HGN",
-      :attrs => {
-        "queue/scheduler" => "noop"
-      }
-    }
-  },
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.32.40",
-        :bond => {
-          :slaves => %w[eth0 eth1]
-        }
-      }
-    }
-  },
-  :postgresql => {
-    :settings => {
-      :defaults => {
-        :shared_buffers => "64GB",
-        :work_mem => "64MB",
-        :maintenance_work_mem => "1GB",
-        :effective_cache_size => "180GB"
-      }
-    }
-  },
-  :sysctl => {
-    :postgres => {
-      :comment => "Increase shared memory for postgres",
-      :parameters => {
-        "kernel.shmmax" => 66 * 1024 * 1024 * 1024,
-        "kernel.shmall" => 66 * 1024 * 1024 * 1024 / 4096
-      }
-    }
-  }
-)
-
-run_list(
-  "role[bytemark]",
-  "role[db-slave]"
-)
diff --git a/roles/keizer.rb b/roles/keizer.rb
deleted file mode 100644 (file)
index 7011197..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-name "keizer"
-description "Master role applied to keizer"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "12g"
-  },
-  :location => "Nuremberg, Germany",
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "195.201.226.63",
-        :prefix => "32",
-        :gateway => "172.31.1.1"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2a01:4f8:1c1c:bc54::1",
-        :prefix => "64",
-        :gateway => "fe80::1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "10240 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "germany.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[hetzner]",
-  "role[tilecache]"
-)
index 941e9b2b232309fae03c5d1e59d87dffddcd0441..3505bc18a2edf7c999fae979dafdc3f7c23cd524 100644 (file)
@@ -10,31 +10,17 @@ default_attributes(
       }
     }
   },
-  :munin => {
-    :plugins => {
-      :sensors_temp => {
-        :temp6 => { :warning => "71.0", :critical => "76.0" },
-        :temp7 => { :warning => "71.0", :critical => "76.0" },
-        :temp8 => { :warning => "71.0", :critical => "76.0" },
-        :temp9 => { :warning => "71.0", :critical => "76.0" }
-      }
-    }
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "em1",
-        :role => :external,
-        :family => :inet,
-        :address => "178.250.74.36",
-        :hwaddress => "d8:d3:85:5d:87:5e"
-      },
-      :external_ipv6 => {
-        :interface => "em1",
+      :external => {
+        :interface => "enp2s0f0",
         :role => :external,
-        :family => :inet6,
-        :address => "2a02:1658:4:0:dad3:85ff:fe5d:875e",
-        :hwaddress => "d8:d3:85:5d:87:5e"
+        :inet => {
+          :address => "178.250.74.36"
+        },
+        :inet6 => {
+          :address => "2a02:1658:4:0:dad3:85ff:fe5d:875e"
+        }
       }
     }
   }
index 6198120cfd7c65f680a4923fc97a0c95ce403b11..d45d4e53f9e2a3421710f6bb5bd4709022e60f26 100644 (file)
@@ -1,14 +1,6 @@
 name "kibana"
 description "Role applied to all kibana servers"
 
-default_attributes(
-  :accounts => {
-    :users => {
-      :kibana => { :status => :role }
-    }
-  }
-)
-
 run_list(
   "recipe[kibana]"
 )
index 8b529781dae7c659f3de7c4e7a418398cb679585..b23841de21f8a159eacd06ddee4e1d678149d4b3 100644 (file)
@@ -2,45 +2,37 @@ name "konqi"
 description "Master role applied to konqi"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "20g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "81.7.11.83",
-        :prefix => "24",
-        :gateway => "81.7.11.1"
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.7"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
       },
-      :external_ipv6 => {
-        :interface => "eth0",
+      :external => {
+        :interface => "bond0.101",
         :role => :external,
-        :family => :inet6,
-        :address => "2a02:180:1:1::517:b53",
-        :prefix => "64",
-        :gateway => "2a02:180:1:1::1"
+        :inet => {
+          :address => "184.104.226.103"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::7"
+        }
       }
     }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "germany.render.openstreetmap.org"
   }
 )
 
 run_list(
-  "role[euserv]",
-  "role[tilecache]"
+  "role[equinix-dub]",
+  "role[hp-g9]",
+  "role[wiki]"
 )
diff --git a/roles/ladon.rb b/roles/ladon.rb
deleted file mode 100644 (file)
index 9db2555..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-name "ladon"
-description "Master role applied to ladon"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "36g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "bond0",
-        :role => :external,
-        :family => :inet,
-        :address => "83.212.2.116",
-        :prefix => "29",
-        :gateway => "83.212.2.113",
-        :bond => {
-          :mode => "802.3ad",
-          :miimon => "100",
-          :xmithashpolicy => "layer3+4",
-          :slaves => %w[eth0 eth1]
-        }
-      },
-      :external_ipv6 => {
-        :interface => "bond0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:648:2ffe:4::116",
-        :prefix => "64",
-        :gateway => "2001:648:2ffe:4::1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "32768 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "athens.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[grnet]",
-  "role[tilecache]"
-)
index c0b389da90aa2a3eba8b2a4e7b5815f967d6ceb8..3c96b90ae18a589b72119b0476c2b1e3565e2e71 100644 (file)
@@ -1,16 +1,6 @@
 name "letsencrypt"
 description "Role applied to all letsencrypt servers"
 
-default_attributes(
-  :accounts => {
-    :users => {
-      :letsencrypt => {
-        :status => :role
-      }
-    }
-  }
-)
-
 run_list(
   "recipe[letsencrypt]"
 )
index 991dfa04e124d0b642476ab413079ade117bb35f..0f99a7c3d20b9138f3a1d227068797b8689e82fa 100644 (file)
@@ -4,8 +4,12 @@ description "Role applied to all mailing list servers"
 default_attributes(
   :exim => {
     :aliases => {
-      "mailman-loop" => "/dev/null"
-    }
+      "mailman-loop" => "/dev/null",
+      "prometheus" => "/dev/null"
+    },
+    :local_domains => [
+      "openstreetmap.org"
+    ]
   }
 )
 
index 60b34a31189107fe906b3326d28ee3dad47d08b0..bb0b777f3d1602e2ceaebb2a58e7666080fd8626 100644 (file)
@@ -1,12 +1,6 @@
 name "logstash-forwarder"
 description "Role applied to all logstash forwarders"
 
-default_attributes(
-  :apt => {
-    :sources => ["elasticsearch5.x"]
-  }
-)
-
 run_list(
   "recipe[logstash::forwarder]"
 )
index 9e421fc8d2ad5ec7eb7ef53334684df6eec242e6..b5cbac83630910bb098a2a944afa92d9d7c38ae1 100644 (file)
@@ -2,12 +2,6 @@ name "logstash"
 description "Role applied to all logstash servers"
 
 default_attributes(
-  :elasticsearch => {
-    :cluster => {
-      :name => "logstash"
-    },
-    :version => "6.x"
-  },
   :kibana => {
     :sites => {
       :logstash => {
index 9b8855bff386a1b9491116e616b58adfa6097604..ced4e927db2076c1ce2dc255db1c03c027d183d6 100644 (file)
@@ -2,57 +2,65 @@ name "longma"
 description "Master role applied to longma"
 
 default_attributes(
-  :exim => {
-    :aliases => {
-      :root => "ceasar"
-    }
-  },
-  :hardware => {
-    :shm_size => "20g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens160",
-        :role => :external,
-        :family => :inet,
-        :address => "140.110.240.7",
-        :prefix => "24",
-        :gateway => "140.110.240.254"
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.13"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[enp68s0f0 enp68s0f1 enp68s0f2 enp68s0f3]
+        }
       },
-      :external_ipv6 => {
-        :interface => "ens160",
+      :external => {
+        :interface => "bond0.101",
         :role => :external,
-        :family => :inet6,
-        :address => "2001:e10:2000:240::7",
-        :prefix => "64",
-        :gateway => "2001:e10:2000:240::254"
+        :inet => {
+          :address => "184.104.226.109"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::d"
+        }
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store.new-san/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store.new-san/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store.new-san/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store.new-san/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :directory => "/store.new-san/nginx-cache/proxy-cache"
+  :postgresql => {
+    :versions => ["16"],
+    :settings => {
+      :defaults => {
+        :max_connections => "550",
+        :work_mem => "240MB",
+        :effective_io_concurrency => "500"
       }
     }
   },
-  :tilecache => {
-    :tile_parent => "hsinchu.render.openstreetmap.org"
+  :nominatim => {
+    :state => "standalone",
+    :dbcluster => "16/main",
+    :postgis => "3",
+    :enable_qa_tiles => true,
+    :flatnode_file => "/ssd/nominatim/nodes.store",
+    :logdir => "/ssd/nominatim/log",
+    :api_flavour => "python",
+    :api_workers => 24,
+    :api_pool_size => 10,
+    :fpm_pools => {
+      "nominatim.openstreetmap.org" => {
+        :max_children => 200
+      }
+    },
+    :config => {
+      :forward_dependencies => "yes"
+    }
   }
 )
 
 run_list(
-  "role[nchc]",
-  "role[tilecache]"
+  "role[equinix-dub]",
+  "role[nominatim]"
 )
diff --git a/roles/lu.rb b/roles/lu.rb
new file mode 100644 (file)
index 0000000..dd381e5
--- /dev/null
@@ -0,0 +1,11 @@
+name "lu"
+description "Role applied to all servers located in Luxembourg"
+
+override_attributes(
+  :country => "lu",
+  :timezone => "Europe/Luxembourg"
+)
+
+run_list(
+  "role[base]"
+)
index a5aff59e0b33853778abbada6fe3fce94d3ef8d7..b37ccb05c1e6b8d4f583a1a4c48b8c432e7302e9 100644 (file)
@@ -4,19 +4,11 @@ description "Role applied to all servers at LyonIX"
 default_attributes(
   :hosted_by => "LyonIX",
   :location => "Lyon, France",
-  :networking => {
-    :nameservers => ["77.95.64.205", "77.95.64.206", "8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "ly"
-      }
-    }
-  },
   :snmpd => {
-    :clients => ["77.95.64.0/24", "77.95.70.0/24"],
+    :clients => ["77.95.64.0/21", "2a03:9180::/32", "2001:7f8:47::/48"],
     :community => "lyonix",
     :location => "LYON",
-    :contact => "noc@lyonix.net"
+    :contact => "sysadm@rezopole.net"
   }
 )
 
diff --git a/roles/lysator.rb b/roles/lysator.rb
deleted file mode 100644 (file)
index 22f34ea..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-name "lysator"
-description "Role applied to all servers at Lysator"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :aoh => { :status => :administrator },
-      :lysroot => { :status => :administrator }
-    }
-  },
-  :hosted_by => "Lysator",
-  :location => "Linköping, Sweden",
-  :networking => {
-    :nameservers => ["130.236.254.225", "2001:6b0:17:f0a0::e1", "130.236.254.4"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.se.pool.ntp.org", "1.se.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[se]"
-)
index 483260bb0df9981095e2e5efddb555c6a72c1094..de74af25ae1bd47765e3a8bdaa6eacded76b5fd3 100644 (file)
@@ -18,33 +18,57 @@ default_attributes(
     :daemon_smtp_ports => [25, 26],
     :certificate_names => [
       "mail.openstreetmap.org",
-      "a.mx.openstreetmap.org"
+      "a.mx.openstreetmap.org",
+      "a.mx.osm.org",
+      "a.mx.openstreetmap.com",
+      "a.mx.openstreetmap.io",
+      "a.mx.openstreetmap.pro",
+      "a.mx.openstreetmaps.org",
+      "a.mx.osm.io"
     ],
+    :queue_run_max => 25,
+    :smtp_accept_max => 200,
     :smarthost_name => "mail.openstreetmap.org",
-    :smarthost_via => false,
-    :dns_blacklists => ["zen.spamhaus.org"],
+    :smarthost_via => nil,
+    :dns_blacklists => ["zen.spamhaus.org!&0.255.255.0"],
     :routes => {
       :messages => {
         :comment => "messages.openstreetmap.org",
         :domains => ["messages.openstreetmap.org"],
-        :host => ["spike-06.openstreetmap.org", "spike-07.openstreetmap.org", "spike-08.openstreetmap.org"]
+        :host => [
+          "spike-01.openstreetmap.org",
+          "spike-02.openstreetmap.org",
+          "spike-03.openstreetmap.org",
+          "spike-06.openstreetmap.org",
+          "spike-07.openstreetmap.org",
+          "spike-08.openstreetmap.org"
+        ]
       },
       :otrs => {
         :comment => "otrs.openstreetmap.org",
         :domains => ["otrs.openstreetmap.org"],
         :host => "ridley.ucl.openstreetmap.org"
       },
-      :tickets => {
-        :comment => "tickets.openstreetmap.org",
-        :domains => ["tickets.openstreetmap.org"],
-        :host => "ridley.ucl.openstreetmap.org"
-      },
       :join => {
         :comment => "join.osmfoundation.org",
         :domains => ["join.osmfoundation.org"],
         :host => "ridley.ucl.openstreetmap.org"
+      },
+      :supporting => {
+        :comment => "supporting.openstreetmap.org",
+        :domains => ["supporting.openstreetmap.org"],
+        :host => "ridley.ucl.openstreetmap.org"
+      },
+      :community => {
+        :comment => "community.openstreetmap.org",
+        :domains => ["community.openstreetmap.org"],
+        :host => "jakelong.dub.openstreetmap.org::2500"
       }
     },
+    :dkim_selectors => {
+      "openstreetmap.org" => "20200301",
+      "osmfoundation.org" => "20201112"
+    },
     :aliases => {
       "abuse" => "root",
       "postmaster" => "root",
@@ -52,7 +76,7 @@ default_attributes(
       "clamav" => "root",
       "rails" => "root",
       "trac" => "root",
-      "munin" => "root",
+      "prometheus" => "root",
       "www-data" => "root",
       "osmbackup" => "root",
       "noreply" => "/dev/null",
@@ -68,23 +92,20 @@ default_attributes(
       "support" => "support@otrs.openstreetmap.org",
       "memorial" => "communication@osmfoundation.org",
       "legal" => "legal@osmfoundation.org",
-      "dmca" => "dmca@osmfoundation.org"
+      "dmca" => "dmca@osmfoundation.org",
+      "program-sotm" => "sotm-program@otrs.openstreetmap.org"
     },
     :private_aliases => "mail"
   },
-  :munin => {
-    :plugins => {
-      :exim_mailqueue => {
-        :mails => {
-          :warning => 500,
-          :critical => 1000
-        }
-      }
+  :prometheus => {
+    :metrics => {
+      :exim_queue_limit => { :metric => 2500 }
     }
   }
 )
 
 run_list(
   "recipe[clamav]",
+  "recipe[exim]",
   "recipe[spamassassin]"
 )
diff --git a/roles/matomo.rb b/roles/matomo.rb
new file mode 100644 (file)
index 0000000..f171e43
--- /dev/null
@@ -0,0 +1,33 @@
+name "matomo"
+description "Role applied to all Matomo servers"
+
+default_attributes(
+  :apache => {
+    :mpm => "event",
+    :event => {
+      :server_limit => 30,
+      :max_request_workers => 1000,
+      :threads_per_child => 50,
+      :min_spare_threads => 75,
+      :max_spare_threads => 175,
+      :listen_cores_buckets_ratio => 4
+    }
+  },
+  :mysql => {
+    :settings => {
+      :mysqld => {
+        :innodb_buffer_pool_instances => "128",
+        :innodb_buffer_pool_size => "128GB",
+        :innodb_flush_log_at_trx_commit => "2",
+        :innodb_log_file_size => "16GB",
+        :join_buffer_size => "1GB",
+        :key_buffer_size => "0",
+        :max_connections => "64"
+      }
+    }
+  }
+)
+
+run_list(
+  "recipe[matomo]"
+)
diff --git a/roles/meraxes.rb b/roles/meraxes.rb
new file mode 100644 (file)
index 0000000..3c75dba
--- /dev/null
@@ -0,0 +1,31 @@
+name "meraxes"
+description "Master role applied to meraxes"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :external => {
+        :interface => "enp1s0f0",
+        :role => :external,
+        :inet => {
+          :address => "51.15.185.90",
+          :prefix => "24",
+          :gateway => "51.15.185.1"
+        },
+        :inet6 => {
+          :address => "2001:bc8:2d57:100:aa1e:84ff:fe72:e660",
+          :prefix => "48",
+          :gateway => "2001:bc8:2::2:258:1",
+          :dhcp => {
+            :duidtype => "link-layer",
+            :duidrawdata => "00:01:14:e9:19:1c:49:e0"
+          }
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[scaleway]"
+)
diff --git a/roles/milkywan.rb b/roles/milkywan.rb
deleted file mode 100644 (file)
index d84cf53..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-name "milkywan"
-description "Role applied to all servers at MilkyWan"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :milkywan => { :status => :administrator }
-    }
-  },
-  :hosted_by => "MilkyWan",
-  :location => "Paris, France",
-  :networking => {
-    :firewall => {
-      :inet => [
-        {
-          :action => "ACCEPT",
-          :source => "net:212.25.24.64/28",
-          :dest => "fw",
-          :proto => "udp",
-          :dest_ports => "snmp",
-          :source_ports => "1024:",
-          :rate_limit => "-",
-          :connection_limit => "-"
-        }
-      ]
-    },
-    :nameservers => ["130.117.11.11", "2a0b:cbc0:42::42"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.fr.pool.ntp.org", "1.fr.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[fr]"
-)
diff --git a/roles/muirdris.rb b/roles/muirdris.rb
new file mode 100644 (file)
index 0000000..81cb639
--- /dev/null
@@ -0,0 +1,40 @@
+name "muirdris"
+description "Master role applied to muirdris"
+
+default_attributes(
+  :memcached => {
+    :memory_limit => 128 * 1024
+  },
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.15"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.111"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::f"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[gps-tile]"
+)
diff --git a/roles/munin.rb b/roles/munin.rb
deleted file mode 100644 (file)
index 1522c96..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-name "munin"
-description "Role applied to all munin servers"
-
-default_attributes(
-  :munin => {
-    :plugins => {
-      :munin_update => {
-        :contacts => "null"
-      }
-    }
-  }
-)
-
-run_list(
-  "recipe[munin::server]"
-)
index 8c09f2dbd02b188935622d44d78d901f4caa9a3c..2586aaf4a194fe35551afefa0a3b75d51f47041d 100644 (file)
@@ -2,37 +2,62 @@ name "naga"
 description "Master role applied to naga"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "38g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.8"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
         :role => :external,
-        :family => :inet,
-        :address => "185.116.130.151",
-        :prefix => "24",
-        :gateway => "185.116.130.151"
+        :inet => {
+          :address => "184.104.226.104"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::8"
+        }
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "32768 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
+  :otrs => {
+    :site => "test.otrs.openstreetmap.org",
+    :site_aliases => ["test.otrs.osm.org"],
+    :database_cluster => "16/main"
   },
-  :tilecache => {
-    :tile_parent => "france.render.openstreetmap.org"
+  :postgresql => {
+    :versions => ["16"],
+    :settings => {
+      "16" => {
+        :port => 5433
+      }
+    }
   }
 )
 
 run_list(
-  "role[fullsave]",
-  "role[tilecache]"
+  "role[equinix-dub]",
+  "role[hp-g9]",
+  "role[subversion]",
+  "role[trac]",
+  "role[irc]",
+  "role[blogs]",
+  "role[switch2osm]",
+  "recipe[foundation::mastodon]",
+  "recipe[foundation::owg]",
+  "recipe[foundation::welcome]",
+  "recipe[stateofthemap::container]",
+  "recipe[hot]",
+  "recipe[ideditor]",
+  "recipe[dmca]",
+  "recipe[otrs::debian]"
 )
diff --git a/roles/nchc.rb b/roles/nchc.rb
deleted file mode 100644 (file)
index bb9181f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-name "nchc"
-description "Role applied to all servers at NCHC"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :steven => { :status => :administrator },
-      :ceasar => { :status => :administrator }
-    }
-  },
-  :hosted_by => "NCHC",
-  :location => "Hsinchu, Taiwan",
-  :networking => {
-    :nameservers => ["140.110.16.1", "140.110.4.1"],
-    :roles => {
-      :external => {
-        :zone => "nc"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.tw.pool.ntp.org", "1.tw.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[tw]"
-)
index 9d86e7d2d168482e0c2889902bf4bbf911732c09..c113f451a78092a36696ef8be2016d3b5f06993c 100644 (file)
@@ -2,45 +2,41 @@ name "necrosan"
 description "Master role applied to necrosan"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "12g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens18",
-        :role => :external,
-        :family => :inet,
-        :address => "80.67.167.77",
-        :prefix => "32",
-        :gateway => "10.0.6.1"
-      },
-      :external_ipv6 => {
-        :interface => "ens18",
+      :external => {
+        :interface => "bond0",
+        :mtu => 9000,
         :role => :external,
-        :family => :inet6,
-        :address => "2a0b:cbc0:110d:1::1c",
-        :prefix => "64",
-        :gateway => "2a0b:cbc0:110d:1::1"
+        :inet => {
+          :address => "45.85.134.91",
+          :prefix => "31",
+          :gateway => "45.85.134.90"
+        },
+        :inet6 => {
+          :address => "2a05:46c0:100:1004:ffff:ffff:ffff:ffff",
+          :prefix => "64",
+          :gateway => "2a05:46c0:100:1004::"
+        },
+        :bond => {
+          :slaves => %w[eno1 eno2],
+          :mode => "802.3ad",
+          :lacprate => "fast"
+        }
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "10240 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "france.render.openstreetmap.org"
+  :sysfs => {
+    :hdd_tune => {
+      :comment => "Tune the queue for improved performance",
+      :parameters => {
+        "block/sda/queue/nr_requests" => "975",
+        "block/sdb/queue/rotational" => "0"
+      }
+    }
   }
 )
 
 run_list(
-  "role[milkywan]",
-  "role[tilecache]"
+  "role[appliwave]"
 )
diff --git a/roles/nepomuk.rb b/roles/nepomuk.rb
deleted file mode 100644 (file)
index 53cd0ef..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-name "nepomuk"
-description "Master role applied to nepomuk"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "12g"
-  },
-  :networking => {
-    :firewall => {
-      :inet => [
-        {
-          :action => "ACCEPT",
-          :source => "net:77.95.64.120,77.95.64.131,77.95.64.139",
-          :dest => "fw",
-          :proto => "tcp",
-          :dest_ports => "5666",
-          :source_ports => "1024:",
-          :rate_limit => "-",
-          :connection_limit => "-"
-        }
-      ]
-    },
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "77.95.65.39",
-        :prefix => "27",
-        :gateway => "77.95.65.33"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2a03:9180:0:100::7",
-        :prefix => "64",
-        :gateway => "2a03:9180:0:100::1"
-      }
-    }
-  },
-  :sysctl => {
-    :kvm => {
-      :comment => "Tuning for KVM guest",
-      :parameters => {
-        "kernel.sched_min_granularity_ns" => 10000000,
-        "kernel.sched_wakeup_granularity_ns" => 15000000
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "10240 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :sysfs => {
-    :hdd_tune => {
-      :comment => "Tune the queue for improved performance",
-      :parameters => {
-        "block/vda/queue/nr_requests" => "128"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "france.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[lyonix]",
-  "role[tilecache]"
-)
index 41f1908325e9815c4735b57f9a21ac342b4f0f69..bbccac112d7d9ea9a1147699b490bd932e426620 100644 (file)
@@ -4,23 +4,15 @@ description "Role applied to all servers at NetAlerts"
 default_attributes(
   :hosted_by => "NetAlerts",
   :location => "Montréal, Canada",
-  :timezone => "America/Montreal",
-  :networking => {
-    :nameservers => [
-      "209.172.41.202",
-      "209.172.41.200"
-    ],
-    :roles => {
-      :external => {
-        :zone => "na"
-      }
-    }
-  }
+  :timezone => "America/Montreal"
 )
 
 override_attributes(
+  :networking => {
+    :nameservers => ["209.172.41.202", "209.172.41.200"]
+  },
   :ntp => {
-    :servers => ["0.ca.pool.ntp.org", "1.ca.pool.ntp.org", "america.pool.ntp.org"]
+    :servers => ["0.ca.pool.ntp.org", "1.ca.pool.ntp.org", "north-america.pool.ntp.org"]
   }
 )
 
index 004381680068657aa7a1fd560f7419ba56d4cf6a..29f43dca41982358c830df4ec1cf4dfa0c906431 100644 (file)
@@ -2,45 +2,63 @@ name "nidhogg"
 description "Master role applied to nidhogg"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "14g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens18",
-        :role => :external,
-        :family => :inet,
-        :address => "130.236.254.221",
-        :prefix => "24",
-        :gateway => "130.236.254.1"
-      },
-      :external_ipv6 => {
-        :interface => "ens18",
+      :external => {
+        :interface => "bond0",
         :role => :external,
-        :family => :inet6,
-        :address => "2001:6b0:17:f0a0::dd",
-        :prefix => "64",
-        :gateway => "2001:6b0:17:f0a0::1"
+        :inet => {
+          :address => "194.71.11.111",
+          :prefix => "25",
+          :gateway => "194.71.11.1"
+        },
+        :inet6 => {
+          :address => "2001:6b0:19:2::111",
+          :prefix => "64",
+          :gateway => "2001:6b0:19:2::1"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[enp68s0f0 enp68s0f1 enp68s0f2 enp68s0f3]
+        }
       }
     }
   },
-  :squid => {
-    :version => 4,
-    :cache_mem => "12288 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :effective_cache_size => "16GB"
+      }
+    }
   },
-  :tilecache => {
-    :tile_parent => "sweden.render.openstreetmap.org"
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
+      }
+    }
+  },
+  :tile => {
+    :database => {
+      :cluster => "16/main",
+      :postgis => "3"
+    },
+    :mapnik => "3.1",
+    :styles => {
+      :default => {
+        :tile_directories => [
+          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
+        ]
+      }
+    }
   }
 )
 
 run_list(
-  "role[lysator]",
-  "role[tilecache]"
+  "role[umu]",
+  "role[tile]"
 )
index 9bfcc288d2dad4112584498adc1870ee03812d8e..e79a7fce2bb141ce63c3d4a690f255cfa931134d 100644 (file)
@@ -5,31 +5,12 @@ default_attributes(
   :accounts => {
     :users => {
       :lonvia => { :status => :administrator },
-      :twain => { :status => :administrator },
       :nominatim => {
         :status => :role,
-        :members => [:lonvia, :tomh, :twain]
+        :members => [:lonvia, :tomh]
       }
     }
   },
-  :apache => {
-    :mpm => "event",
-    :timeout => 30,
-    :keepalive => false,
-    :reqtimeout => true,
-    :event => {
-      :server_limit => 60,
-      :max_request_workers => 2400,
-      :threads_per_child => 50,
-      :min_spare_threads => 125,
-      :max_spare_threads => 925,
-      :async_request_worker_factor => 4,
-      :listen_cores_buckets_ratio => 6
-    }
-  },
-  :apt => {
-    :sources => ["postgresql"]
-  },
   :networking => {
     :firewall => {
       :http_rate_limit => "s:2/sec:15"
@@ -40,11 +21,18 @@ default_attributes(
       :defaults => {
         :max_connections => "450",
         :synchronous_commit => "off",
-        :checkpoint_segments => "32",
         :checkpoint_timeout => "10min",
         :checkpoint_completion_target => "0.9",
+        :jit => "off",
         :shared_buffers => "2GB",
-        :autovacuum_max_workers => "1"
+        :autovacuum_max_workers => "1",
+        :max_parallel_workers_per_gather => "0",
+        :maintenance_work_mem => "10GB",
+        :seq_page_cost => "3.0",
+        :random_page_cost => "3.0",
+        :effective_cache_size => "60GB",
+        :wal_level => "minimal",
+        :max_wal_senders => "0"
       }
     }
   },
@@ -56,13 +44,6 @@ default_attributes(
         "kernel.shmall" => 26 * 1024 * 1024 * 1024 / 4096
       }
     },
-    :kernel_scheduler_tune => {
-      :comment => "Tune kernel scheduler preempt",
-      :parameters => {
-        "kernel.sched_min_granularity_ns" => 10000000,
-        "kernel.sched_wakeup_granularity_ns" => 15000000
-      }
-    },
     :swappiness => {
       :comment => "Reduce swap usage",
       :parameters => {
@@ -78,9 +59,24 @@ default_attributes(
     :network_conntrack_max => {
       :comment => "Increase max number of connections tracked",
       :parameters => {
-        "net.netfilter.nf_conntrack_max" => "131072"
+        "net.netfilter.nf_conntrack_max" => "196608"
       }
     }
+  },
+  :nominatim => {
+    :dbadmins => %w[lonvia tomh],
+    :tablespaces => {
+      "dosm" => "/ssd/tablespaces/dosm",
+      "iosm" => "/ssd/tablespaces/iosm",
+      "dplace" => "/ssd/tablespaces/dplace",
+      "iplace" => "/ssd/tablespaces/iplace",
+      "daddress" => "/ssd/tablespaces/daddress",
+      "iaddress" => "/ssd/tablespaces/iaddress",
+      "dsearch" => "/ssd/tablespaces/dsearch",
+      "isearch" => "/ssd/tablespaces/isearch",
+      "daux" => "/ssd/tablespaces/daux",
+      "iaux" => "/ssd/tablespaces/iaux"
+    }
   }
 )
 
diff --git a/roles/noomoahk.rb b/roles/noomoahk.rb
deleted file mode 100644 (file)
index a22e805..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-name "noomoahk"
-description "Master role applied to noomoahk"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "6g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet,
-        :address => "91.224.148.166",
-        :prefix => "32",
-        :gateway => "89.234.156.230"
-      },
-      :external_ipv6 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet6,
-        :address => "2a03:7220:8080:a600::1",
-        :prefix => "56",
-        :gateway => "fe80::1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "4096 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "france.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[tetaneutral]",
-  "role[tilecache]"
-)
diff --git a/roles/noquiklos.rb b/roles/noquiklos.rb
deleted file mode 100644 (file)
index f42afa8..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-name "noquiklos"
-description "Master role applied to noquiklos"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "eth0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.13"
-      },
-      :external_ipv4 => {
-        :interface => "eth0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.16"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[hp-dl360-g6]",
-  "role[gps-tile]"
-)
index 1ab77bb8f4ec3b04f772b05c6e6638b28cc978f8..50b8566ea36aa8fbfeefb1efb7443cba9898c2a1 100644 (file)
@@ -2,52 +2,43 @@ name "norbert"
 description "Master role applied to norbert"
 
 default_attributes(
-  :hardware => {
-    :shm_size => "14g"
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens18",
-        :role => :external,
-        :family => :inet,
-        :address => "89.234.186.100",
-        :prefix => "27",
-        :gateway => "89.234.186.97"
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.48.17"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[enp25s0f0 enp25s0f1]
+        }
       },
-      :external_ipv6 => {
-        :interface => "ens18",
+      :external => {
+        :interface => "bond0.3",
         :role => :external,
-        :family => :inet6,
-        :address => "2a00:5884:821c::1",
-        :prefix => "48",
-        :gateway => "fe80::204:92:100:1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "12288 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :max_size => "2048M"
+        :inet => {
+          :address => "184.104.179.145"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::11"
+        }
       }
     }
   },
-  :tilecache => {
-    :tile_parent => "france.render.openstreetmap.org"
+  :planet => {
+    :replication => "enabled"
   }
 )
 
 run_list(
-  "role[grifon]",
-  "role[tilecache]"
+  "role[equinix-ams]",
+  "role[geodns]",
+  "role[backup]",
+  "role[planet]",
+  "role[planetdump]",
+  "recipe[tilelog]"
 )
index b6c64a1b1a8d8a946392913a3a6aaf297a8d74ac..9a19c5b2ddd642a24c6e311f8ef797a94928c45f 100644 (file)
@@ -2,40 +2,36 @@ name "odin"
 description "Master role applied to odin"
 
 default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.15",
+        :inet => {
+          :address => "10.0.48.15"
+        },
         :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
           :slaves => %w[eno1 eno2]
         }
       },
-      :external_ipv4 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet,
-        :address => "130.117.76.15"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
+      :external => {
+        :interface => "bond0.3",
         :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:F"
+        :inet => {
+          :address => "184.104.179.143"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::f"
+        }
       }
     }
   },
   :postgresql => {
-    :versions => ["10"],
     :settings => {
       :defaults => {
-        :shared_buffers => "8GB",
-        :maintenance_work_mem => "7144MB",
         :effective_cache_size => "16GB"
       }
     }
@@ -51,10 +47,10 @@ default_attributes(
   },
   :tile => {
     :database => {
-      :cluster => "10/main",
-      :postgis => "2.4"
+      :cluster => "16/main",
+      :postgis => "3"
     },
-    :node_file => "/store/database/nodes",
+    :mapnik => "3.1",
     :styles => {
       :default => {
         :tile_directories => [
@@ -66,6 +62,6 @@ default_attributes(
 )
 
 run_list(
-  "role[equinix]",
+  "role[equinix-ams]",
   "role[tile]"
 )
diff --git a/roles/orm.rb b/roles/orm.rb
deleted file mode 100644 (file)
index e8caaf8..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-name "orm"
-description "Master role applied to orm"
-
-default_attributes(
-  :devices => {
-    :ssd_samsung => {
-      :comment => "Tune scheduler for SSD",
-      :type => "block",
-      :bus => "ata",
-      :serial => "Samsung_SSD_840_PRO_Series_*",
-      :attrs => {
-        "queue/scheduler" => "noop",
-        "queue/nr_requests" => "256",
-        "queue/read_ahead_kb" => "2048"
-      }
-    },
-    :arecavoltune => {
-      :comment => "Tune scheduler for Areca",
-      :type => "block",
-      :bus => "scsi",
-      :serial => "2001b4d20*",
-      :attrs => {
-        "queue/scheduler" => "deadline",
-        "queue/nr_requests" => "512",
-        "queue/read_ahead_kb" => "2048"
-      }
-    }
-  },
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.3",
-        :bond => {
-          :slaves => %w[eth0 eth1]
-        }
-      },
-      :external_ipv4 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet,
-        :address => "130.117.76.3"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:3"
-      }
-    }
-  },
-  :sysctl => {
-    :postgres => {
-      :comment => "Increase shared memory for postgres",
-      :parameters => {
-        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
-        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
-      }
-    }
-  }
-)
-
-override_attributes(
-  :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"]
-  }
-)
-
-run_list(
-  "role[equinix]",
-  "role[tyan-s7010]"
-)
index da7036fe05214fc3b7f592ffe7953a446b38664b..45a4cf04c1bca0aa8f0eb7e99908252faf8012c9 100644 (file)
@@ -2,11 +2,6 @@ name "osqa"
 description "Role applied to all OSQA servers"
 
 default_attributes(
-  :accounts => {
-    :users => {
-      :osqa => { :status => :role }
-    }
-  },
   :osqa => {
     :sites => [
       { :name => "help.openstreetmap.org",
index f80b1177a2fae2f824922a527ee91f17f08e3ac0..99a3a992fd2a0ee1e30ceb8d96c32f5340f6d35b 100644 (file)
@@ -9,12 +9,10 @@ default_attributes(
   },
   :hosted_by => "OSUOSL",
   :location => "Corvallis, Oregon",
-  :timezone => "PST8PDT",
+  :timezone => "US/Pacific",
   :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
     :roles => {
       :external => {
-        :zone => "ool",
         :inet => {
           :prefix => "28",
           :gateway => "140.211.167.97"
index c895b122a6fa98b3780bb3a778684cb3022aba35..94d4c4cd291120f93af8a57d10d26c5ee2a9112f 100644 (file)
@@ -2,16 +2,6 @@ name "otrs"
 description "Role applied to all OTRS servers"
 
 default_attributes(
-  :accounts => {
-    :users => {
-      :otrs => { :status => :role }
-    },
-    :groups => {
-      :"www-data" => {
-        :members => [:otrs]
-      }
-    }
-  },
   :exim => {
     :local_domains => ["otrs.openstreetmap.org"],
     :routes => {
@@ -42,6 +32,15 @@ default_attributes(
         :group => "www-data",
         :home_directory => "/opt/otrs"
       },
+      :otrs_membership_osmf_talk_owner => {
+        :comment => "osmf-talk-owner@otrs.openstreetmap.org",
+        :domains => ["otrs.openstreetmap.org"],
+        :local_parts => ["osmf-talk-owner"],
+        :command => "/opt/otrs/bin/otrs.Console.pl Maint::PostMaster::Read --target-queue 'Membership Working Group::osmf-talk'",
+        :user => "otrs",
+        :group => "www-data",
+        :home_directory => "/opt/otrs"
+      },
       :otrs_legal => {
         :comment => "legal@otrs.openstreetmap.org",
         :domains => ["otrs.openstreetmap.org"],
@@ -78,6 +77,33 @@ default_attributes(
         :group => "www-data",
         :home_directory => "/opt/otrs"
       },
+      :otrs_sotm_program => {
+        :comment => "sotm-program@otrs.openstreetmap.org",
+        :domains => ["otrs.openstreetmap.org"],
+        :local_parts => ["sotm-program"],
+        :command => "/opt/otrs/bin/otrs.Console.pl Maint::PostMaster::Read --target-queue 'State of the Map:Program'",
+        :user => "otrs",
+        :group => "www-data",
+        :home_directory => "/opt/otrs"
+      },
+      :otrs_communications => {
+        :comment => "communications@otrs.openstreetmap.org",
+        :domains => ["otrs.openstreetmap.org"],
+        :local_parts => ["communications"],
+        :command => "/opt/otrs/bin/otrs.Console.pl Maint::PostMaster::Read --target-queue 'Communications Working Group'",
+        :user => "otrs",
+        :group => "www-data",
+        :home_directory => "/opt/otrs"
+      },
+      :otrs_communications_freebies => {
+        :comment => "freebies@otrs.openstreetmap.org",
+        :domains => ["otrs.openstreetmap.org"],
+        :local_parts => ["freebies"],
+        :command => "/opt/otrs/bin/otrs.Console.pl Maint::PostMaster::Read --target-queue 'Communications Working Group::Freebies'",
+        :user => "otrs",
+        :group => "www-data",
+        :home_directory => "/opt/otrs"
+      },
       :otrs_support => {
         :comment => "support@otrs.openstreetmap.org",
         :domains => ["otrs.openstreetmap.org"],
@@ -91,14 +117,7 @@ default_attributes(
   },
   :otrs => {
     :site => "otrs.openstreetmap.org",
-    :site_aliases => ["otrs.osm.org"],
-    :database_cluster => "10/main",
-    :database_name => "otrs",
-    :database_user => "otrs",
-    :database_password => "otrs"
-  },
-  :postgresql => {
-    :versions => ["10"]
+    :site_aliases => ["otrs.osm.org"]
   }
 )
 
diff --git a/roles/overpass-query.rb b/roles/overpass-query.rb
new file mode 100644 (file)
index 0000000..819bad1
--- /dev/null
@@ -0,0 +1,29 @@
+name "overpass-query"
+description "Role applied to overpass servers for the query feature."
+
+default_attributes(
+  :accounts => {
+    :users => {
+      :lonvia => { :status => :administrator },
+      :overpass => {
+        :status => :role,
+        :members => [:lonvia, :tomh]
+      }
+    }
+  },
+  :overpass => {
+    :fqdn => "query.openstreetmap.org",
+    :meta_mode => "no",
+    :compression_mode => "lz4",
+    :restricted_api => true
+  },
+  :prometheus => {
+    :files => %w[
+      /srv/query.openstreetmap.org/diffs/latest.osc
+    ]
+  }
+)
+
+run_list(
+  "recipe[overpass::default]"
+)
index 506be9c9a14ef5a8c2c211e6de9eb7317738cf9d..f8391a2aa941ae1d535850de69e3743c2d13f2e0 100644 (file)
@@ -3,20 +3,13 @@ description "Role applied to all servers at OVH"
 
 default_attributes(
   :hosted_by => "OVH",
-  :location => "Roubaix, France",
-  :networking => {
-    :nameservers => [
-      "213.186.33.99"
-    ],
-    :roles => {
-      :external => {
-        :zone => "ovh"
-      }
-    }
-  }
+  :location => "Roubaix, France"
 )
 
 override_attributes(
+  :networking => {
+    :nameservers => ["213.186.33.99"]
+  },
   :ntp => {
     :servers => ["0.fr.pool.ntp.org", "1.fr.pool.ntp.org", "europe.pool.ntp.org"]
   }
diff --git a/roles/oxidized.rb b/roles/oxidized.rb
new file mode 100644 (file)
index 0000000..7835c2e
--- /dev/null
@@ -0,0 +1,17 @@
+name "oxidized"
+description "Role applied to all oxidized servers"
+
+default_attributes(
+  :accounts => {
+    :users => {
+      :oxidized => {
+        :status => :role,
+        :members => [:grant, :tomh]
+      }
+    }
+  }
+)
+
+run_list(
+  "recipe[oxidized]"
+)
diff --git a/roles/palulukon.rb b/roles/palulukon.rb
new file mode 100644 (file)
index 0000000..661febe
--- /dev/null
@@ -0,0 +1,63 @@
+name "palulukon"
+description "Master role applied to palulukon"
+
+default_attributes(
+  :networking => {
+    :firewall => {
+      :allowlist => ["172.31.0.2"]
+    },
+    :interfaces => {
+      :external => {
+        :interface => "ens5",
+        :role => :external,
+        :inet => {
+          :address => "172.31.37.101",
+          :prefix => "20",
+          :gateway => "172.31.32.1",
+          :public_address => "3.144.0.72"
+        }
+      }
+    }
+  },
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :effective_cache_size => "16GB"
+      }
+    }
+  },
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
+      }
+    }
+  },
+  :tile => {
+    :database => {
+      :cluster => "16/main",
+      :postgis => "3"
+    },
+    :mapnik => "3.1",
+    :styles => {
+      :default => {
+        :tile_directories => [
+          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
+        ]
+      }
+    }
+  }
+)
+
+override_attributes(
+  :networking => {
+    :nameservers => ["172.31.0.2"]
+  }
+)
+
+run_list(
+  "role[aws-us-east-2]",
+  "role[tile]"
+)
index b84b86c96ca6d91f046a5e84b423b2f604b8d16a..1fad914b4d09e2cccc6811511e33efe5b62c4480 100644 (file)
@@ -9,21 +9,13 @@ default_attributes(
     }
   },
   :hosted_by => "Université de Pau et des Pays de l'Adour",
-  :location => "Pau, France",
-  :munin => {
-    :allow => ["10.64.1.11"]
-  },
-  :networking => {
-    :nameservers => ["10.64.1.42", "194.167.156.13", "10.64.1.3"],
-    :roles => {
-      :external => {
-        :zone => "pa"
-      }
-    }
-  }
+  :location => "Pau, France"
 )
 
 override_attributes(
+  :networking => {
+    :nameservers => ["10.64.1.42", "194.167.156.13", "10.64.1.3"]
+  },
   :ntp => {
     :servers => ["cannelle.paulla.asso.fr"]
   }
diff --git a/roles/piasa.rb b/roles/piasa.rb
new file mode 100644 (file)
index 0000000..b1e775a
--- /dev/null
@@ -0,0 +1,57 @@
+name "piasa"
+description "Master role applied to piasa"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :external => {
+        :interface => "bond0",
+        :role => :external,
+        :inet => {
+          :address => "140.211.167.101"
+        },
+        :inet6 => {
+          :address => "2605:bc80:3010:700::8cd3:a765"
+        },
+        :bond => {
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
+        }
+      }
+    }
+  },
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :effective_cache_size => "16GB"
+      }
+    }
+  },
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
+      }
+    }
+  },
+  :tile => {
+    :database => {
+      :cluster => "16/main",
+      :postgis => "3"
+    },
+    :mapnik => "3.1",
+    :styles => {
+      :default => {
+        :tile_directories => [
+          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
+        ]
+      }
+    },
+  }
+)
+
+run_list(
+  "role[osuosl]",
+  "role[tile]"
+)
diff --git a/roles/piwik.rb b/roles/piwik.rb
deleted file mode 100644 (file)
index 886784b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-name "piwik"
-description "Role applied to all Piwik servers"
-
-default_attributes(
-  :apache => {
-    :mpm => "prefork",
-    :prefork => {
-      :server_limit => 450,
-      :max_request_workers => 450
-    }
-  },
-  :mysql => {
-    :settings => {
-      :mysqld => {
-        :innodb_buffer_pool_instances => "8",
-        :innodb_buffer_pool_size => "16GB",
-        :innodb_flush_log_at_trx_commit => "2"
-      }
-    }
-  }
-)
-
-run_list(
-  "recipe[piwik]"
-)
diff --git a/roles/pl.rb b/roles/pl.rb
new file mode 100644 (file)
index 0000000..ad8a61d
--- /dev/null
@@ -0,0 +1,11 @@
+name "pl"
+description "Role applied to all servers located in Poland"
+
+override_attributes(
+  :country => "pl",
+  :timezone => "Europe/Warsaw"
+)
+
+run_list(
+  "role[base]"
+)
diff --git a/roles/planet-current.rb b/roles/planet-current.rb
deleted file mode 100644 (file)
index 97f23d2..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-name "planet-current"
-description "Role applied to all servers needing an up to date planet file"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :planet => {
-        :status => :role
-      }
-    }
-  }
-)
-
-run_list(
-  "recipe[planet::current]"
-)
index 6c765845bb7f4893bfba6f900383638c76e2cfbf..4dd1f1d7476ec2cd3533c37280f0738f1427e129 100644 (file)
@@ -2,15 +2,36 @@ name "planet"
 description "Role applied to all planet servers"
 
 default_attributes(
-  :accounts => {
-    :users => {
-      :bretth => { :status => :user },
-      :planet => {
-        :status => :administrator,
-        :members => [:bretth]
-      }
+  :apache => {
+    :mpm => "event",
+    :keepalive => true,
+    :event => {
+      :server_limit => 30,
+      :max_request_workers => 1000,
+      :threads_per_child => 50,
+      :min_spare_threads => 75,
+      :max_spare_threads => 525,
+      :listen_cores_buckets_ratio => 4
     }
   },
+  :networking => {
+    :firewall => {
+      :http_connection_limit => 10
+    }
+  },
+  :prometheus => {
+    :files => %w[
+      /store/planet/notes/planet-notes-latest.osn.bz2
+      /store/planet/pbf/planet-latest.osm.pbf
+      /store/planet/planet/changesets-latest.osm.bz2
+      /store/planet/planet/discussions-latest.osm.bz2
+      /store/planet/planet/planet-latest.osm.bz2
+      /store/planet/replication/changesets/state.yaml
+      /store/planet/replication/day/state.txt
+      /store/planet/replication/hour/state.txt
+      /store/planet/replication/minute/state.txt
+    ]
+  },
   :rsyncd => {
     :modules => {
       :planet => {
@@ -28,24 +49,19 @@ default_attributes(
         :ignore_nonreadable => true,
         :timeout => 3600,
         :refuse_options => ["checksum"]
+      },
+      :statistics => {
+        :comment => "Statistics",
+        :path => "/store/planet/statistics",
+        :read_only => false,
+        :write_only => true,
+        :list => false,
+        :uid => "planet",
+        :gid => "planet",
+        :transfer_logging => false,
+        :nodes_allow => "roles:web-statistics"
       }
     }
-  },
-  :networking => {
-    :firewall => {
-      :http_connection_limit => 10
-    }
-  },
-  :apache => {
-    :mpm => "worker",
-    :keepalive => true,
-    :worker => {
-      :server_limit => 20,
-      :max_request_workers => 1000,
-      :threads_per_child => 50,
-      :min_spare_threads => 75,
-      :max_spare_threads => 525
-    }
   }
 )
 
@@ -53,6 +69,5 @@ run_list(
   "role[web-db]",
   "recipe[planet]",
   "recipe[planet::replication]",
-  "recipe[nfs::server]",
   "recipe[rsyncd]"
 )
diff --git a/roles/prgmr.rb b/roles/prgmr.rb
deleted file mode 100644 (file)
index 1477757..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "prgmr"
-description "Role applied to all servers at prgmr.com"
-
-default_attributes(
-  :hosted_by => "prgmr.com",
-  :location => "San Francisco, California",
-  :timezone => "PST8PDT",
-  :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "pr"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.us.pool.ntp.org", "1.us.pool.ntp.org", "2.us.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[us]"
-)
diff --git a/roles/prometheus.rb b/roles/prometheus.rb
new file mode 100644 (file)
index 0000000..0f83e82
--- /dev/null
@@ -0,0 +1,16 @@
+name "prometheus"
+description "Role applied to all prometheus servers"
+
+default_attributes(
+  :apache => {
+    :evasive => {
+      :enable => false
+    }
+  }
+)
+
+run_list(
+  "recipe[awscli]",
+  "recipe[prometheus::server]",
+  "recipe[prometheus::smokeping]"
+)
diff --git a/roles/pummelzacken.rb b/roles/pummelzacken.rb
deleted file mode 100644 (file)
index e431a66..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-name "pummelzacken"
-description "Master role applied to pummelzacken"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "em1.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.20"
-      },
-      :external_ipv4 => {
-        :interface => "em1.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.18"
-      }
-    }
-  },
-  :postgresql => {
-    :versions => ["10"],
-    :settings => {
-      :defaults => {
-        :listen_addresses => "10.0.0.20",
-        :work_mem => "160MB",
-        :maintenance_work_mem => "10GB",
-        :random_page_cost => "1.5",
-        :effective_cache_size => "60GB",
-        :fsync => "on"
-      }
-    }
-  },
-  :nominatim => {
-    :state => "standalone",
-    :dbadmins => %w[lonvia tomh],
-    :dbcluster => "10/main",
-    :postgis => "2.4",
-    :enable_backup => true,
-    :flatnode_file => "/ssd/nominatim/nodes.store",
-    :tablespaces => {
-      "dosm" => "/ssd/tablespaces/dosm",
-      "iosm" => "/ssd/tablespaces/iosm",
-      "dplace" => "/ssd/tablespaces/dplace",
-      "iplace" => "/ssd/tablespaces/iplace",
-      "daddress" => "/ssd/tablespaces/daddress",
-      "iaddress" => "/ssd/tablespaces/iaddress",
-      "dsearch" => "/ssd/tablespaces/dsearch",
-      "isearch" => "/ssd/tablespaces/isearch",
-      "daux" => "/data/tablespaces/daux",
-      "iaux" => "/data/tablespaces/iaux"
-    },
-    :fpm_pools => {
-      :www => {
-        :max_children => "40"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[nominatim]"
-)
diff --git a/roles/pyrene.rb b/roles/pyrene.rb
deleted file mode 100644 (file)
index b3bee0f..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-name "pyrene"
-description "Master role applied to pyrene"
-
-default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
-  :munin => {
-    :plugins => {
-      :hpasmcli2_temp => {
-        :temp15 => { :warning => "59.5", :critical => "70" },
-        :temp17 => { :warning => "59.5", :critical => "70" }
-      }
-    }
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eno1",
-        :role => :external,
-        :family => :inet,
-        :address => "140.211.167.98"
-      },
-      :external_ipv6 => {
-        :interface => "eno1",
-        :role => :external,
-        :family => :inet6,
-        :address => "2605:bc80:3010:700::8cd3:a762"
-      }
-    }
-  },
-  :postgresql => {
-    :versions => ["10"],
-    :settings => {
-      :defaults => {
-        :shared_buffers => "8GB",
-        :maintenance_work_mem => "7144MB",
-        :effective_cache_size => "16GB"
-      }
-    }
-  },
-  :sysctl => {
-    :postgres => {
-      :comment => "Increase shared memory for postgres",
-      :parameters => {
-        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
-        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
-      }
-    }
-  },
-  :tile => {
-    :database => {
-      :cluster => "10/main",
-      :postgis => "2.4"
-    },
-    :node_file => "/store/database/nodes",
-    :styles => {
-      :default => {
-        :tile_directories => [
-          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
-        ]
-      }
-    }
-  }
-)
-
-run_list(
-  "role[osuosl]",
-  "role[tile]"
-)
diff --git a/roles/ramoth.rb b/roles/ramoth.rb
deleted file mode 100644 (file)
index 71d4d13..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-name "ramoth"
-description "Master role applied to ramoth"
-
-default_attributes(
-  :devices => {
-    :store_openstreetmap => {
-      :comment => "RAID array mounted on /store/postgresql/openstreetmap",
-      :type => "block",
-      :bus => "scsi",
-      :serial => "3600605b00599aa401c02b4f53bf5c805",
-      :attrs => {
-        "queue/scheduler" => "deadline",
-        "queue/nr_requests" => "975"
-      }
-    },
-    :store_system => {
-      :comment => "RAID array mounted on /store/postgresql/system",
-      :type => "block",
-      :bus => "scsi",
-      :serial => "3600605b0039483a017092ff8fa5a6332",
-      :attrs => {
-        "queue/scheduler" => "deadline",
-        "queue/nr_requests" => "975"
-      }
-    }
-  },
-  :hardware => {
-    :watchdog => "w83627hf_wdt"
-  },
-  :munin => {
-    :plugins => {
-      :smart_sg0_33 => {
-        :smartctl_exit_status => { :warning => ":8" }
-      },
-      :smart_sg0_34 => {
-        :smartctl_exit_status => { :warning => ":8" }
-      }
-    }
-  },
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.5",
-        :bond => {
-          :slaves => %w[enp7s0f0 enp7s0f1]
-        }
-      }
-    }
-  }
-)
-
-run_list(
-  "role[equinix]"
-)
index 0ca0618fb21a9720b0b32c10157676ff949a5f97..61352aaa7b4c8f73dbf91a1cbf59bfe585ef4f26 100644 (file)
@@ -7,94 +7,23 @@ default_attributes(
       :mmiler => { :status => :administrator }
     }
   },
-  :apt => {
-    :sources => ["postgresql"]
-  },
-  :devices => {
-    :ssd_samsung => {
-      :comment => "Tune scheduler for SSD",
-      :type => "block",
-      :bus => "ata",
-      :serial => "Samsung_SSD_860_PRO_*",
-      :attrs => {
-        "queue/scheduler" => "noop",
-        "queue/nr_requests" => "256",
-        "queue/read_ahead_kb" => "2048"
-      }
-    }
-  },
   :location => "Zagreb, Croatia",
-  :munin => {
-    :plugins => {
-      :sensors_temp => {
-        :temp1 => { :warning => "85.0" },
-        :temp2 => { :warning => "85.0" },
-        :temp3 => { :warning => "85.0" },
-        :temp4 => { :warning => "85.0" },
-        :temp5 => { :warning => "85.0" },
-        :temp6 => { :warning => "85.0" },
-        :temp8 => { :warning => "85.0" },
-        :temp9 => { :warning => "85.0" },
-        :temp10 => { :warning => "85.0" },
-        :temp11 => { :warning => "85.0" },
-        :temp12 => { :warning => "85.0" },
-        :temp13 => { :warning => "85.0" }
-      }
-    }
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "enp1s0f0",
+      :external => {
+        :interface => "eno1",
         :role => :external,
-        :family => :inet,
-        :address => "10.5.0.77",
-        :prefix => "16",
-        :gateway => "10.5.0.1",
-        :public_address => "161.53.248.77"
-      }
-    },
-    :nameservers => [
-      "10.5.0.7",
-      "8.8.8.8"
-    ]
-  },
-  :postgresql => {
-    :versions => ["10"],
-    :settings => {
-      :defaults => {
-        :shared_buffers => "8GB",
-        :maintenance_work_mem => "7144MB",
-        :effective_cache_size => "16GB"
-      }
-    }
-  },
-  :sysctl => {
-    :postgres => {
-      :comment => "Increase shared memory for postgres",
-      :parameters => {
-        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
-        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
-      }
-    }
-  },
-  :tile => {
-    :database => {
-      :cluster => "10/main",
-      :postgis => "2.4"
-    },
-    :node_file => "/store/database/nodes",
-    :styles => {
-      :default => {
-        :tile_directories => [
-          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
-        ]
+        :inet => {
+          :address => "10.5.0.77",
+          :prefix => "16",
+          :gateway => "10.5.0.1",
+          :public_address => "161.53.248.77"
+        }
       }
     }
   }
 )
 
 run_list(
-  "role[carnet]",
-  "role[tile]"
+  "role[carnet]"
 )
diff --git a/roles/ridgeback.rb b/roles/ridgeback.rb
deleted file mode 100644 (file)
index 42926b9..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-name "ridgeback"
-description "Master role applied to ridgeback"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "10g"
-  },
-  :munin => {
-    :plugins => {
-      :ipmi_fans => {
-        :Fan4 => { :graph => "no", :warning => "0:" },
-        :Fan5 => { :graph => "no", :warning => "0:" },
-        :Fan6 => { :graph => "no", :warning => "0:" },
-        :Fan7CPU1 => { :graph => "no", :warning => "0:" }
-      },
-      :smart_sda => {
-        :smartctl_exit_status => {
-          :warning => 8
-        }
-      },
-      :smart_sdb => {
-        :smartctl_exit_status => {
-          :warning => 8
-        }
-      }
-    }
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "31.169.50.10",
-        :prefix => "30",
-        :gateway => "31.169.50.9"
-      }
-    }
-  },
-  :sysfs => {
-    :md_tune => {
-      :comment => "Tune the md sync performance so as not to kill system performance",
-      :parameters => {
-        "block/md0/md/sync_speed_min" => "1",
-        "block/md0/md/sync_speed_max" => "100000",
-        "block/md1/md/sync_speed_min" => "1",
-        "block/md1/md/sync_speed_max" => "100000"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "8192 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "oslo.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[blix-no]",
-  "role[geodns]",
-  "role[tilecache]"
-)
index 591f31ae2fd00fb7936f73a35e5b84313c03cb93..08a97417dc6e79fdf6b7844b178988aed6472a76 100644 (file)
@@ -2,8 +2,15 @@ name "ridley"
 description "Master role applied to ridley"
 
 default_attributes(
-  :bind => {
-    :clients => "ucl"
+  :apache => {
+    :mpm => "event",
+    :event => {
+      :start_servers => 12,
+      :server_limit => 48,
+      :min_spare_threads => 25,
+      :max_spare_threads => 75,
+      :max_connections_per_child => 10000
+    }
   },
   :dhcpd => {
     :first_address => "10.0.15.1",
@@ -11,54 +18,18 @@ default_attributes(
   },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
+      :external => {
         :interface => "eth0.2800",
         :role => :external,
-        :family => :inet,
-        :address => "193.60.236.19"
+        :inet => {
+          :address => "193.60.236.19"
+        }
       },
-      :internal_ipv4 => {
+      :internal => {
         :interface => "eth0.2801",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.3"
-      }
-    }
-  },
-  :openvpn => {
-    :address => "10.0.16.1",
-    :tunnels => {
-      :ic2ucl => {
-        :port => "1194",
-        :mode => "client",
-        :peer => {
-          :host => "ironbelly.openstreetmap.org",
-          :port => "1194"
-        }
-      },
-      :shenron2ucl => {
-        :port => "1195",
-        :mode => "client",
-        :peer => {
-          :host => "shenron.openstreetmap.org",
-          :port => "1194"
-        }
-      },
-      :ucl2bm => {
-        :port => "1196",
-        :mode => "client",
-        :peer => {
-          :host => "grisu.openstreetmap.org",
-          :port => "1196"
-        }
-      },
-      :firefishy => {
-        :port => "1197",
-        :mode => "client",
-        :peer => {
-          :host => "home.firefishy.com",
-          :port => "1194",
-          :address => "10.0.16.201"
+        :inet => {
+          :address => "10.0.0.3"
         }
       }
     }
@@ -71,12 +42,7 @@ run_list(
   "role[gateway]",
   "role[foundation]",
   "role[stateofthemap]",
-  "role[switch2osm]",
   "role[blog]",
   "role[otrs]",
-  "role[donate]",
-  "recipe[hot]",
-  "recipe[dmca]",
-  "recipe[dhcpd]",
-  "recipe[openvpn]"
+  "recipe[dhcpd]"
 )
diff --git a/roles/rimfaxe.rb b/roles/rimfaxe.rb
deleted file mode 100644 (file)
index 383f754..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-name "rimfaxe"
-description "Master role applied to rimfaxe"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "10g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "130.225.254.109",
-        :prefix => "27",
-        :gateway => "130.225.254.97"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:878:346::109",
-        :prefix => "64",
-        :gateway => "2001:878:346::97"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "8192 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "aalborg.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[dotsrc]",
-  "role[tilecache]"
-)
diff --git a/roles/roundup.rb b/roles/roundup.rb
deleted file mode 100644 (file)
index ec099e6..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-name "roundup"
-description "Role applied to all roundup servers"
-
-run_list(
-  "recipe[roundup]"
-)
diff --git a/roles/saphira.rb b/roles/saphira.rb
deleted file mode 100644 (file)
index 1c4b9a1..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-name "saphira"
-description "Master role applied to saphira"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "10g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "185.73.44.30",
-        :prefix => "22",
-        :gateway => "185.73.44.1"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:ba8:0:2c1e::",
-        :prefix => "64",
-        :gateway => "fe80::fcff:ffff:feff:ffff"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "8192 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :max_size => "4096M"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "london.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[jump]",
-  "role[geodns]",
-  "role[tilecache]"
-)
diff --git a/roles/sarel.rb b/roles/sarel.rb
deleted file mode 100644 (file)
index 647aa57..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-name "sarel"
-description "Master role applied to sarel"
-
-default_attributes(
-  :git => {
-    :private_user => "chefrepo",
-    :private_group => "chefrepo",
-    :private_nodes => "fqdn:*"
-  },
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp3s0f0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.12"
-      },
-      :external_ipv4 => {
-        :interface => "enp3s0f0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.20"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[chef-server]",
-  "role[chef-repository]",
-  "role[letsencrypt]",
-  "role[git]",
-  "role[dns]",
-  "recipe[serverinfo]"
-)
diff --git a/roles/sarkany.rb b/roles/sarkany.rb
deleted file mode 100644 (file)
index 6cd1424..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-name "sarkany"
-description "Master role applied to sarkany"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "8g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "37.17.173.8",
-        :prefix => "24",
-        :gateway => "37.17.173.254"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:4c48:2:bf04:250:56ff:fe8f:5c81",
-        :prefix => "64",
-        :gateway => "fe80::224:14ff:fe84:5000"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "6144 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :max_size => "4096M"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "budapest.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[szerverem]",
-  "role[tilecache]"
-)
diff --git a/roles/scaleway.rb b/roles/scaleway.rb
new file mode 100644 (file)
index 0000000..26833e1
--- /dev/null
@@ -0,0 +1,20 @@
+name "scaleway"
+description "Role applied to all servers at Scaleway"
+
+default_attributes(
+  :hosted_by => "Scaleway",
+  :location => "Paris, France"
+)
+
+override_attributes(
+  :networking => {
+    :nameservers => ["62.210.16.6", "62.210.16.7"]
+  },
+  :ntp => {
+    :servers => ["0.fr.pool.ntp.org", "1.fr.pool.ntp.org", "europe.pool.ntp.org"]
+  }
+)
+
+run_list(
+  "role[fr]"
+)
index 07c2932e46230752ed72f621c3247b24b8eaf011..0649374f4980841f4ce9f4525c5350d850f406b9 100644 (file)
@@ -2,9 +2,6 @@ name "scorch"
 description "Master role applied to scorch"
 
 default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
   :devices => {
     :ssd_system => {
       :comment => "Tune scheduler for system disk",
@@ -18,67 +15,26 @@ default_attributes(
       }
     }
   },
-  :hardware => {
-    :mcelog => {
-      :enabled => false
-    }
-  },
   :networking => {
     :interfaces => {
-      :external_ipv4 => {
+      :external => {
         :interface => "eth0",
         :role => :external,
-        :family => :inet,
-        :address => "176.31.235.79",
-        :prefix => "24",
-        :gateway => "176.31.235.254"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:41d0:2:fc4f::1",
-        :prefix => "64",
-        :gateway => "2001:41d0:2:fcff:ff:ff:ff:ff"
-      }
-    }
-  },
-  :postgresql => {
-    :versions => ["10"],
-    :settings => {
-      :defaults => {
-        :shared_buffers => "8GB",
-        :maintenance_work_mem => "7144MB",
-        :effective_cache_size => "16GB"
-      }
-    }
-  },
-  :sysctl => {
-    :postgres => {
-      :comment => "Increase shared memory for postgres",
-      :parameters => {
-        "kernel.shmmax" => 9 * 1024 * 1024 * 1024,
-        "kernel.shmall" => 9 * 1024 * 1024 * 1024 / 4096
-      }
-    }
-  },
-  :tile => {
-    :database => {
-      :cluster => "10/main",
-      :postgis => "2.4"
-    },
-    :node_file => "/store/database/nodes",
-    :styles => {
-      :default => {
-        :tile_directories => [
-          { :name => "/store/tiles/default", :min_zoom => 0, :max_zoom => 19 }
-        ]
+        :inet => {
+          :address => "176.31.235.79",
+          :prefix => "24",
+          :gateway => "176.31.235.254"
+        },
+        :inet6 => {
+          :address => "2001:41d0:2:fc4f::1",
+          :prefix => "64",
+          :gateway => "2001:41d0:2:fcff:ff:ff:ff:ff"
+        }
       }
     }
   }
 )
 
 run_list(
-  "role[ovh]",
-  "role[tile]"
+  "role[ovh]"
 )
index c3db86355878f4cb3b0f1e17c460b59b6daa7007..f916772268737add51adcddb0c0d2d414bd437d1 100644 (file)
@@ -10,59 +10,46 @@ default_attributes(
     }
   },
   :hardware => {
-    :mcelog => {
-      :enabled => false
+    :hwmon => {
+      "platform_it87_552" => {
+        :ignore => %w[in6]
+      }
     },
     :modules => [
       "it87"
     ]
   },
-  :openvpn => {
-    :address => "10.0.16.3",
-    :tunnels => {
-      :shenron2ucl => {
-        :port => "1194",
-        :mode => "server",
-        :peer => {
-          :host => "ridley.openstreetmap.org"
-        }
-      }
+  :prometheus => {
+    :metrics => {
+      :exim_queue_limit => { :metric => 250 }
     }
   }
 )
 
 override_attributes(
   :networking => {
+    :dnssec => "false",
     :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "212.110.172.32",
-        :prefix => "26",
-        :gateway => "212.110.172.1"
-      },
-      :external_ipv6 => {
+      :external => {
         :interface => "eth0",
         :role => :external,
-        :family => :inet6,
-        :address => "2001:41c9:1:400::32",
-        :prefix => "64",
-        :gateway => "fe80::1"
+        :inet => {
+          :address => "212.110.172.32",
+          :prefix => "26",
+          :gateway => "212.110.172.1"
+        },
+        :inet6 => {
+          :address => "2001:41c9:1:400::32",
+          :prefix => "64",
+          :gateway => "fe80::1"
+        }
       }
-    },
-    :nameservers => ["89.16.162.20", "2001:41c9:2:d6::20"]
+    }
   }
 )
 
 run_list(
   "role[bytemark]",
-  "role[mail]",
   "role[lists]",
-  "role[subversion]",
-  "role[trac]",
-  "role[osqa]",
-  "role[irc]",
-  "recipe[blogs]",
-  "recipe[openvpn]"
+  "role[osqa]"
 )
diff --git a/roles/simurgh.rb b/roles/simurgh.rb
deleted file mode 100644 (file)
index 3923f4f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-name "simurgh"
-description "Master role applied to simurgh"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "18g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens32",
-        :role => :external,
-        :family => :inet,
-        :address => "94.20.20.55",
-        :prefix => "24",
-        :gateway => "94.20.20.1"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :nginx => {
-    :cache => {
-      :proxy => {
-        :max_size => "2048M"
-      }
-    }
-  },
-  :tilecache => {
-    :tile_parent => "baku.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[delta]",
-  "role[tilecache]"
-)
diff --git a/roles/smaug.rb b/roles/smaug.rb
new file mode 100644 (file)
index 0000000..fd74747
--- /dev/null
@@ -0,0 +1,37 @@
+name "smaug"
+description "Master role applied to smaug"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.14"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.110"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::e"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[matomo]"
+)
diff --git a/roles/snap-01.rb b/roles/snap-01.rb
new file mode 100644 (file)
index 0000000..d7fb452
--- /dev/null
@@ -0,0 +1,47 @@
+name "snap-01"
+description "Master role applied to snap-01"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.48.49"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4]
+        }
+      }
+    }
+  },
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :shared_buffers => "128GB",
+        :work_mem => "128MB",
+        :maintenance_work_mem => "2GB",
+        :effective_cache_size => "360GB"
+      }
+    }
+  },
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 132 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 132 * 1024 * 1024 * 1024 / 4096
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-ams]",
+  "role[db-master]",
+  "role[db-backup]"
+)
diff --git a/roles/snap-02.rb b/roles/snap-02.rb
new file mode 100644 (file)
index 0000000..80a2b35
--- /dev/null
@@ -0,0 +1,40 @@
+name "snap-02"
+description "Master role applied to snap-02"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "eno1.2801",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.0.4"
+        }
+      }
+    }
+  },
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :shared_buffers => "128GB",
+        :work_mem => "128MB",
+        :maintenance_work_mem => "2GB",
+        :effective_cache_size => "360GB"
+      }
+    }
+  },
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 132 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 132 * 1024 * 1024 * 1024 / 4096
+      }
+    }
+  }
+)
+
+run_list(
+  "role[ucl]",
+  "role[db-slave]"
+)
diff --git a/roles/snap-03.rb b/roles/snap-03.rb
new file mode 100644 (file)
index 0000000..749859e
--- /dev/null
@@ -0,0 +1,46 @@
+name "snap-03"
+description "Master role applied to snap-03"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.50"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[enp25s0f0 enp25s0f1]
+        }
+      }
+    }
+  },
+  :postgresql => {
+    :settings => {
+      :defaults => {
+        :shared_buffers => "128GB",
+        :work_mem => "128MB",
+        :maintenance_work_mem => "2GB",
+        :effective_cache_size => "360GB"
+      }
+    }
+  },
+  :sysctl => {
+    :postgres => {
+      :comment => "Increase shared memory for postgres",
+      :parameters => {
+        "kernel.shmmax" => 132 * 1024 * 1024 * 1024,
+        "kernel.shmall" => 132 * 1024 * 1024 * 1024 / 4096
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[db-slave]"
+)
diff --git a/roles/spike-01.rb b/roles/spike-01.rb
new file mode 100644 (file)
index 0000000..5f048e3
--- /dev/null
@@ -0,0 +1,38 @@
+name "spike-01"
+description "Master role applied to spike-01"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.3"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.99"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::3"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[hp-g9]",
+  "role[web-frontend]"
+)
diff --git a/roles/spike-02.rb b/roles/spike-02.rb
new file mode 100644 (file)
index 0000000..dfded54
--- /dev/null
@@ -0,0 +1,38 @@
+name "spike-02"
+description "Master role applied to spike-02"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.4"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.100"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::4"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[hp-g9]",
+  "role[web-frontend]"
+)
diff --git a/roles/spike-03.rb b/roles/spike-03.rb
new file mode 100644 (file)
index 0000000..f2803fc
--- /dev/null
@@ -0,0 +1,38 @@
+name "spike-03"
+description "Master role applied to spike-03"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.64.5"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
+      },
+      :external => {
+        :interface => "bond0.101",
+        :role => :external,
+        :inet => {
+          :address => "184.104.226.101"
+        },
+        :inet6 => {
+          :address => "2001:470:1:b3b::5"
+        }
+      }
+    }
+  }
+)
+
+run_list(
+  "role[equinix-dub]",
+  "role[hp-g9]",
+  "role[web-frontend]"
+)
diff --git a/roles/spike-04.rb b/roles/spike-04.rb
deleted file mode 100644 (file)
index bc2e53f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-name "spike-04"
-description "Master role applied to spike-04"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.32.21",
-        :bond => {
-          :slaves => %w[em1 em2]
-        }
-      },
-      :external_ipv4 => {
-        :interface => "bond0.214",
-        :role => :external,
-        :family => :inet,
-        :address => "89.16.162.21"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.214",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:41c9:2:d6::21"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[bytemark]",
-  "role[web-frontend]"
-  # "role[web-gpximport]",
-  # "role[web-statistics]",
-  # "role[web-cleanup]"
-)
diff --git a/roles/spike-05.rb b/roles/spike-05.rb
deleted file mode 100644 (file)
index ce41465..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-name "spike-05"
-description "Master role applied to spike-05"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.32.22",
-        :bond => {
-          :slaves => %w[em1 em2]
-        }
-      },
-      :external_ipv4 => {
-        :interface => "bond0.214",
-        :role => :external,
-        :family => :inet,
-        :address => "89.16.162.22"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.214",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:41c9:2:d6::22"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[bytemark]",
-  "role[web-frontend]"
-)
index 4ba626cd3d7d03295472dc47e5c73c9c601cb5be..6be7da43dec7dfb0d44d81c971f256eb8684505d 100644 (file)
@@ -4,33 +4,35 @@ description "Master role applied to spike-06"
 default_attributes(
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.11",
+        :inet => {
+          :address => "10.0.48.11"
+        },
         :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
           :slaves => %w[eno1 eno2]
         }
       },
-      :external_ipv4 => {
-        :interface => "bond0.2",
+      :external => {
+        :interface => "bond0.3",
         :role => :external,
-        :family => :inet,
-        :address => "130.117.76.11"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:B"
+        :inet => {
+          :address => "184.104.179.139"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::b"
+        }
       }
     }
   }
 )
 
 run_list(
-  "role[equinix]",
+  "role[equinix-ams]",
   "role[hp-g9]",
   "role[web-frontend]",
   "role[web-statistics]",
index 6868385cd456bfbf970b11dab878268c9fd02eb5..7db3819346f612a30ebdfa8686b45aaea63e4477 100644 (file)
@@ -4,33 +4,35 @@ description "Master role applied to spike-07"
 default_attributes(
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.12",
+        :inet => {
+          :address => "10.0.48.12"
+        },
         :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
           :slaves => %w[eno1 eno2]
         }
       },
-      :external_ipv4 => {
-        :interface => "bond0.2",
+      :external => {
+        :interface => "bond0.3",
         :role => :external,
-        :family => :inet,
-        :address => "130.117.76.12"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:C"
+        :inet => {
+          :address => "184.104.179.140"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::c"
+        }
       }
     }
   }
 )
 
 run_list(
-  "role[equinix]",
+  "role[equinix-ams]",
   "role[hp-g9]",
   "role[web-frontend]"
 )
index 2504064794e70a3b827e78966d5fa59f7a4d0eb9..391206f36a8a5d910437f1345a49861cc320f6d8 100644 (file)
@@ -4,33 +4,35 @@ description "Master role applied to spike-08"
 default_attributes(
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "bond0",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.13",
+        :inet => {
+          :address => "10.0.48.13"
+        },
         :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
           :slaves => %w[eno1 eno2]
         }
       },
-      :external_ipv4 => {
-        :interface => "bond0.2",
+      :external => {
+        :interface => "bond0.3",
         :role => :external,
-        :family => :inet,
-        :address => "130.117.76.13"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:D"
+        :inet => {
+          :address => "184.104.179.141"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::d"
+        }
       }
     }
   }
 )
 
 run_list(
-  "role[equinix]",
+  "role[equinix-ams]",
   "role[hp-g9]",
   "role[web-frontend]"
 )
index 5afe706c2d6628b4c29f14516d9dd56591f307f4..512a038b41dccaafadaa6211654286b20c56ee38 100644 (file)
@@ -2,5 +2,6 @@ name "stateofthemap"
 description "Role applied to State of the Map servers"
 
 run_list(
-  "recipe[stateofthemap]"
+  "recipe[stateofthemap]",
+  "recipe[stateofthemap::wordpress]"
 )
diff --git a/roles/stormfly-01.rb b/roles/stormfly-01.rb
deleted file mode 100644 (file)
index fc50adc..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-name "stormfly-01"
-description "Master role applied to stormfly-01"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "em1",
-        :role => :external,
-        :family => :inet,
-        :address => "140.211.167.104"
-      },
-      :external_ipv6 => {
-        :interface => "em1",
-        :role => :external,
-        :family => :inet6,
-        :address => "2605:bc80:3010:700::8cde:a768"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[osuosl]",
-  "role[hp-dl360-g6]",
-  "role[taginfo]"
-)
diff --git a/roles/stormfly-02.rb b/roles/stormfly-02.rb
deleted file mode 100644 (file)
index 25f4357..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-name "stormfly-02"
-description "Master role applied to stormfly-02"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "38g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "em1",
-        :role => :external,
-        :family => :inet,
-        :address => "140.211.167.105"
-      },
-      :external_ipv6 => {
-        :interface => "em1",
-        :role => :external,
-        :family => :inet6,
-        :address => "2605:bc80:3010:700::8cde:a769"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "32768 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "corvallis.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[osuosl]",
-  "role[hp-dl360-g6]",
-  "role[geodns]",
-  "role[tilecache]"
-)
diff --git a/roles/stormfly-03.rb b/roles/stormfly-03.rb
new file mode 100644 (file)
index 0000000..d81b06c
--- /dev/null
@@ -0,0 +1,29 @@
+name "stormfly-03"
+description "Master role applied to stormfly-03"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :external => {
+        :interface => "bond0",
+        :role => :external,
+        :inet => {
+          :address => "140.211.167.99"
+        },
+        :inet6 => {
+          :address => "2605:bc80:3010:700::8cd3:a763"
+        },
+        :bond => {
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
+      }
+    },
+    :private_address => "10.0.16.200"
+  }
+)
+
+run_list(
+  "role[osuosl]",
+  "role[hp-g9]",
+  "role[prometheus]"
+)
diff --git a/roles/stormfly-04.rb b/roles/stormfly-04.rb
new file mode 100644 (file)
index 0000000..4b94cb2
--- /dev/null
@@ -0,0 +1,51 @@
+name "stormfly-04"
+description "Master role applied to stormfly-04"
+
+default_attributes(
+  :hardware => {
+    :shm_size => "38g"
+  },
+  :networking => {
+    :interfaces => {
+      :external => {
+        :interface => "bond0",
+        :role => :external,
+        :inet => {
+          :address => "140.211.167.100"
+        },
+        :inet6 => {
+          :address => "2605:bc80:3010:700::8cd3:a764"
+        },
+        :bond => {
+          :slaves => %w[eno1 eno2 eno3 eno4 eno49 eno50]
+        }
+      }
+    }
+  },
+  :postgresql => {
+    :versions => ["15"],
+    :settings => {
+      :defaults => {
+        :work_mem => "300MB",
+        :fsync => "on",
+        :effective_io_concurrency => "100"
+      }
+    }
+  },
+  :nominatim => {
+    :state => "standalone",
+    :dbcluster => "15/main",
+    :postgis => "3",
+    :flatnode_file => "/srv/nominatim.openstreetmap.org/planet-project/nodes.store",
+    :api_flavour => "python",
+    :api_workers => 19,
+    :api_pool_size => 7
+  }
+)
+
+run_list(
+  "role[osuosl]",
+  "role[hp-g9]",
+  "role[geodns]",
+  "role[nominatim]"
+)
diff --git a/roles/supermicro-x8dtt-h.rb b/roles/supermicro-x8dtt-h.rb
deleted file mode 100644 (file)
index 84e172e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-name "supermicro-x8dtt-h"
-description "Role applied to all Supermicro X8DTT-H machines"
-
-default_attributes(
-  :hardware => {
-    :watchdog => "w83627hf_wdt"
-  }
-)
index 877fc766a7c930c847f921a4dbe4c9a87fde6355..23a64d835784892d3a6d3bf68a779b83af3e98c7 100644 (file)
@@ -1,14 +1,6 @@
 name "supybot"
 description "Role applied to all supybot servers"
 
-default_attributes(
-  :accounts => {
-    :users => {
-      :supybot => { :status => :role }
-    }
-  }
-)
-
 run_list(
   "recipe[supybot]"
 )
diff --git a/roles/szerverem.rb b/roles/szerverem.rb
deleted file mode 100644 (file)
index 137600f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-name "szerverem"
-description "Role applied to all servers at szerverem.hu"
-
-default_attributes(
-  :hosted_by => "szerverem.hu",
-  :location => "Budapest, Hungary",
-  :networking => {
-    :nameservers => [
-      "8.8.8.8",
-      "8.8.4.4"
-    ],
-    :roles => {
-      :external => {
-        :zone => "sz"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.hu.pool.ntp.org", "1.hu.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[hu]"
-)
diff --git a/roles/tabaluga.rb b/roles/tabaluga.rb
deleted file mode 100644 (file)
index 8645291..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-name "tabaluga"
-description "Master role applied to tabaluga"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.14",
-        :bond => {
-          :slaves => %w[eno1 eno2]
-        }
-      },
-      :external_ipv4 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet,
-        :address => "130.117.76.14"
-      },
-      :external_ipv6 => {
-        :interface => "bond0.2",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:978:2:2C::172:E"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[equinix]",
-  "role[hp-g9]",
-  "role[wiki]"
-)
index 9da56f28c2903015501474ff6079101bc25f0a49..40bffdce2f48f91b0e45504523325a9e9712a081 100644 (file)
@@ -8,7 +8,6 @@ default_attributes(
         :status => :administrator
       },
       :taginfo => {
-        :status => :role,
         :members => [:jochen, :tomh]
       }
     }
@@ -27,16 +26,6 @@ default_attributes(
   :passenger => {
     :max_pool_size => 50
   },
-  :planet => {
-    :current => {
-      :jobs => {
-        :taginfo => {
-          :command => "/usr/local/bin/taginfo-update",
-          :user => "taginfo"
-        }
-      }
-    }
-  },
   :taginfo => {
     :sites => [
       {
@@ -52,6 +41,5 @@ default_attributes(
 )
 
 run_list(
-  "role[planet-current]",
   "recipe[taginfo]"
 )
index ea2dece10828260223a330d063bfedc0f3723829..8704fb679200a9065b8a967e8d95d821bdbe120b 100644 (file)
@@ -3,15 +3,7 @@ description "Role applied to all servers at Teleservice"
 
 default_attributes(
   :hosted_by => "Teleservice Skåne AB",
-  :location => "Sjöbo, Sweden",
-  :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "ts"
-      }
-    }
-  }
+  :location => "Sjöbo, Sweden"
 )
 
 override_attributes(
diff --git a/roles/teraswitch.rb b/roles/teraswitch.rb
deleted file mode 100644 (file)
index 292232e..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-name "teraswitch"
-description "Role applied to all servers at TeraSwitch Networks"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :sysadmin => { :status => :administrator }
-    }
-  },
-  :hosted_by => "TeraSwitch Networks",
-  :location => "Pittsburgh, Pennsylvania",
-  :timezone => "EST5EDT",
-  :networking => {
-    :nameservers => [
-      "1.1.1.1",
-      "8.8.8.8"
-    ],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.us.pool.ntp.org", "1.us.pool.ntp.org", "america.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[us]"
-)
diff --git a/roles/tetaneutral.rb b/roles/tetaneutral.rb
deleted file mode 100644 (file)
index 07a2676..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-name "tetaneutral"
-description "Role applied to all servers at Tetaneutral.net"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :tetaneutral => { :status => :administrator }
-    }
-  },
-  :hosted_by => "Tetaneutral.net",
-  :location => "Toulouse, France",
-  :networking => {
-    :nameservers => [
-      "8.8.8.8",
-      "8.8.4.4"
-    ],
-    :roles => {
-      :external => {
-        :zone => "tnn"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.fr.pool.ntp.org", "1.fr.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[fr]"
-)
diff --git a/roles/thorn-01.rb b/roles/thorn-01.rb
deleted file mode 100644 (file)
index 27bd25c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-name "thorn-01"
-description "Master role applied to thorn-01"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.51",
-        :bond => {
-          :slaves => %w[eth0 eth1]
-        }
-      }
-    }
-  }
-)
-
-run_list(
-  "role[equinix]",
-  "role[web-backend]"
-)
diff --git a/roles/thorn-02.rb b/roles/thorn-02.rb
deleted file mode 100644 (file)
index 0975436..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-name "thorn-02"
-description "Master role applied to thorn-02"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.52",
-        :bond => {
-          :slaves => %w[eth0 eth1]
-        }
-      }
-    }
-  }
-)
-
-run_list(
-  "role[equinix]",
-  "role[web-backend]"
-)
diff --git a/roles/thorn-03.rb b/roles/thorn-03.rb
deleted file mode 100644 (file)
index 9a23936..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-name "thorn-03"
-description "Master role applied to thorn-03"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.48.53",
-        :bond => {
-          :slaves => %w[eth0 eth1]
-        }
-      }
-    }
-  }
-)
-
-run_list(
-  "role[equinix]",
-  "role[web-backend]"
-)
diff --git a/roles/thorn-04.rb b/roles/thorn-04.rb
deleted file mode 100644 (file)
index 7afcfb3..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-name "thorn-04"
-description "Master role applied to thorn-04"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.32.41",
-        :bond => {
-          :slaves => %w[em1 em2]
-        }
-      }
-    }
-  }
-)
-
-run_list(
-  "role[bytemark]",
-  "role[web-backend]"
-)
diff --git a/roles/thorn-05.rb b/roles/thorn-05.rb
deleted file mode 100644 (file)
index 7d0db0e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-name "thorn-05"
-description "Master role applied to thorn-05"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "bond0",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.32.42",
-        :bond => {
-          :slaves => %w[em1 em2]
-        }
-      }
-    }
-  }
-)
-
-run_list(
-  "role[bytemark]",
-  "role[web-backend]"
-)
diff --git a/roles/tiamat-00.rb b/roles/tiamat-00.rb
deleted file mode 100644 (file)
index 0004b91..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-00"
-description "Master role applied to tiamat-00"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.40"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.40"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-01.rb b/roles/tiamat-01.rb
deleted file mode 100644 (file)
index 463381c..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-01"
-description "Master role applied to tiamat-01"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.41"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.41"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-02.rb b/roles/tiamat-02.rb
deleted file mode 100644 (file)
index d81ada6..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-02"
-description "Master role applied to tiamat-02"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.42"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.42"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-03.rb b/roles/tiamat-03.rb
deleted file mode 100644 (file)
index 7c31e7e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-03"
-description "Master role applied to tiamat-03"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.43"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.43"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-10.rb b/roles/tiamat-10.rb
deleted file mode 100644 (file)
index 1aa3781..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-10"
-description "Master role applied to tiamat-10"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.44"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.44"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-11.rb b/roles/tiamat-11.rb
deleted file mode 100644 (file)
index 2fd7e44..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-11"
-description "Master role applied to tiamat-11"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.45"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.45"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-12.rb b/roles/tiamat-12.rb
deleted file mode 100644 (file)
index 661e25a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-12"
-description "Master role applied to tiamat-12"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.46"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.46"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-13.rb b/roles/tiamat-13.rb
deleted file mode 100644 (file)
index c75c4ff..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-13"
-description "Master role applied to tiamat-13"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.47"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.47"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-20.rb b/roles/tiamat-20.rb
deleted file mode 100644 (file)
index d1369cf..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-20"
-description "Master role applied to tiamat-20"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.48"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.48"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-21.rb b/roles/tiamat-21.rb
deleted file mode 100644 (file)
index 73b7710..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-21"
-description "Master role applied to tiamat-21"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.49"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.49"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-22.rb b/roles/tiamat-22.rb
deleted file mode 100644 (file)
index 094c8c8..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-22"
-description "Master role applied to tiamat-22"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.50"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.50"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
diff --git a/roles/tiamat-23.rb b/roles/tiamat-23.rb
deleted file mode 100644 (file)
index e1b0ada..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "tiamat-23"
-description "Master role applied to tiamat-23"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "enp1s0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.51"
-      },
-      :external_ipv4 => {
-        :interface => "enp1s0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.51"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[supermicro-x8dtt-h]"
-)
index cb703ae71511b39cb172cab9e95b5a531c887b26..97bd895f8d55f49ed75dcbb024a55a88ff3d8f8b 100644 (file)
@@ -4,53 +4,51 @@ description "Role applied to all tile servers"
 default_attributes(
   :accounts => {
     :users => {
+      :pnorman => { :status => :administrator },
       :tile => {
-        :status => :role,
-        :members => [:jburgess, :tomh]
+        :members => [:jburgess, :tomh, :pnorman]
       }
     }
   },
   :apache => {
     :mpm => "event",
     :timeout => 60,
+    :evasive => {
+      :enable => false
+    },
     :event => {
-      :server_limit => 60,
-      :max_request_workers => 1200,
       :threads_per_child => 20,
       :min_spare_threads => 300,
-      :max_spare_threads => 1200,
       :max_connections_per_child => 0,
       :async_request_worker_factor => 4,
-      :listen_cores_buckets_ratio => 6
-    }
-  },
-  :munin => {
-    :plugins => {
-      :renderd_processed => {
-        :graph_order => "reqPrio req reqLow dirty reqBulk dropped",
-        :reqPrio => { :draw => "AREA" },
-        :req => { :draw => "STACK" }
-      }
+      :listen_cores_buckets_ratio => 8
     }
   },
   :postgresql => {
     :settings => {
       :defaults => {
         :max_connections => "250",
-        :temp_buffers => "32MB",
+        :shared_buffers => "16GB",
         :work_mem => "128MB",
+        :maintenance_work_mem => "8GB",
+        :max_parallel_workers_per_gather => "0",
+        :wal_level => "minimal",
         :wal_buffers => "1024kB",
         :wal_writer_delay => "500ms",
+        :checkpoint_timeout => "60min",
         :commit_delay => "10000",
-        :checkpoint_segments => "60",
-        :max_wal_size => "2880MB",
-        :random_page_cost => "1.1",
+        :max_wal_size => "10GB",
+        :max_wal_senders => "0",
+        :jit => "off",
         :track_activity_query_size => "16384",
         :autovacuum_vacuum_scale_factor => "0.05",
         :autovacuum_analyze_scale_factor => "0.02"
       }
     }
   },
+  :ssl => {
+    :ct_report_uri => false
+  },
   :sysctl => {
     :sockets => {
       :comment => "Increase size of connection queue",
@@ -58,49 +56,50 @@ default_attributes(
         "net.core.somaxconn" => 10000
       }
     },
-    :kernel_scheduler_tune => {
-      :comment => "Tune kernel scheduler preempt",
+    :network_conntrack_time_wait => {
+      :comment => "Only track completed connections for 30 seconds",
+      :parameters => {
+        "net.netfilter.nf_conntrack_tcp_timeout_time_wait" => "30"
+      }
+    },
+    :network_conntrack_max => {
+      :comment => "Increase max number of connections tracked",
       :parameters => {
-        "kernel.sched_min_granularity_ns" => 10000000,
-        "kernel.sched_wakeup_granularity_ns" => 15000000
+        "net.netfilter.nf_conntrack_max" => "524288"
+      }
+    },
+    :no_tcp_slow_start => {
+      :comment => "Disable TCP slow start",
+      :parameters => {
+        "net.ipv4.tcp_slow_start_after_idle" => "0"
+      }
+    },
+    :tcp_use_bbr => {
+      :comment => "Use TCP BBR Congestion Control",
+      :parameters => {
+        "net.core.default_qdisc" => "fq",
+        "net.ipv4.tcp_congestion_control" => "bbr"
       }
     }
   },
   :tile => {
-    :data => {
-      :simplified_land_polygons => {
-        :url => "https://osmdata.openstreetmap.de/download/simplified-land-polygons-complete-3857.zip",
-        :refresh => true
-      },
-      :simplified_water_polygons => {
-        :url => "https://osmdata.openstreetmap.de/download/simplified-water-polygons-split-3857.zip",
-        :refresh => true
-      },
-      :admin_boundaries => {
-        :url => "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_boundary_lines_land.zip",
-        :directory => "ne_110m_admin_0_boundary_lines_land"
-      },
-      :land_polygons => {
-        :url => "https://osmdata.openstreetmap.de/download/land-polygons-split-3857.zip",
-        :refresh => true
-      },
-      :water_polygons => {
-        :url => "https://osmdata.openstreetmap.de/download/water-polygons-split-3857.zip",
-        :refresh => true
-      },
-      :antarctica_icesheet_polygons => {
-        :url => "https://osmdata.openstreetmap.de/download/antarctica-icesheet-polygons-3857.zip",
-        :refresh => true
-      },
-      :antarctica_icesheet_outlines => {
-        :url => "https://osmdata.openstreetmap.de/download/antarctica-icesheet-outlines-3857.zip",
-        :refresh => true
-      }
+    :database => {
+      :style_file => "/srv/tile.openstreetmap.org/styles/default/openstreetmap-carto.style",
+      :tag_transform_script => "/srv/tile.openstreetmap.org/styles/default/openstreetmap-carto.lua",
+      :external_data_script => "/srv/tile.openstreetmap.org/styles/default/scripts/get-external-data.py -c /srv/tile.openstreetmap.org/styles/default/external-data.yml",
+      :external_data_tables => %w[
+        icesheet_outlines
+        icesheet_polygons
+        ne_110m_admin_0_boundary_lines_land
+        simplified_water_polygons
+        water_polygons
+      ]
     },
     :styles => {
       :default => {
-        :repository => "git://github.com/gravitystorm/openstreetmap-carto.git",
-        :revision => "v4.24.1",
+        :repository => "https://github.com/gravitystorm/openstreetmap-carto.git",
+        :revision => "v5.8.0",
+        :fonts_script => "/srv/tile.openstreetmap.org/styles/default/scripts/get-fonts.sh",
         :max_zoom => 19
       }
     }
diff --git a/roles/tilecache.rb b/roles/tilecache.rb
deleted file mode 100644 (file)
index 6869073..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-name "tilecache"
-description "Role applied to all tile cache servers"
-
-default_attributes(
-  :accounts => {
-    :groups => {
-      :proxy => {
-        :members => [:tomh, :grant, :matt, :jburgess]
-      }
-    }
-  },
-  :apt => {
-    :sources => ["nginx"]
-  },
-  :networking => {
-    :tcp_fastopen_key => "tile"
-  },
-  :nginx => {
-    :access_log => false,
-    :cache => {
-      :proxy => {
-        :enable => true,
-        :keys_zone => "proxy_cache_zone:64M",
-      }
-    }
-  },
-  :sysctl => {
-    :sockets => {
-      :comment => "Increase size of connection queue",
-      :parameters => {
-        "net.core.somaxconn" => 10000
-      }
-    },
-    :network_conntrack_time_wait => {
-      :comment => "Only track completed connections for 30 seconds",
-      :parameters => {
-        "net.netfilter.nf_conntrack_tcp_timeout_time_wait" => "30"
-      }
-    },
-    :network_conntrack_max => {
-      :comment => "Increase max number of connections tracked",
-      :parameters => {
-        "net.netfilter.nf_conntrack_max" => "524288"
-      }
-    },
-    :network_local_port_range => {
-      :comment => "Increase available local port range",
-      :parameters => {
-        "net.ipv4.ip_local_port_range" => "1024\t65000"
-      }
-    },
-    :network_tcp_timewait_reuse => {
-      :comment => "Allow tcp timewait reuse",
-      :parameters => {
-        "net.ipv4.tcp_tw_reuse" => 1
-      }
-    },
-    :kernel_tfo_listen_enable => {
-      :comment => "Enable TCP Fast Open for listening sockets",
-      :parameters => {
-        "net.ipv4.tcp_fastopen" => 3
-      }
-    },
-    :squid_swappiness => {
-      :comment => "Prefer not to swapout to free memory",
-      :parameters => {
-        "vm.swappiness" => "1"
-      }
-    },
-    :sched_wakeup => {
-      :comment => "Tune scheduler",
-      :parameters => {
-        "kernel.sched_min_granularity_ns" => "10000000",
-        "kernel.sched_wakeup_granularity_ns" => "15000000"
-      }
-    }
-  }
-)
-
-run_list(
-  "recipe[tilecache]"
-)
diff --git a/roles/toothless.rb b/roles/toothless.rb
deleted file mode 100644 (file)
index fefc1e4..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-name "toothless"
-description "Master role applied to toothless"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "6g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "185.73.44.167",
-        :prefix => "22",
-        :gateway => "185.73.44.1"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:ba8:0:2ca7::",
-        :prefix => "64",
-        :gateway => "fe80::fcff:ffff:feff:ffff"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "4096 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 12800 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 16000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 22400 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 22800 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "london.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[jump]",
-  "role[geodns]",
-  "role[tilecache]"
-)
index 8f916ed13ebbfe65e320f86fc9658537ab3e90a7..9276c88951aa4ac980b9508d803ea2f1af5dd39a 100644 (file)
@@ -1,13 +1,6 @@
 name "trac"
 description "Role applied to all trac servers"
 
-default_attributes(
-  :accounts => {
-    :users => {
-      :trac => { :status => :role }
-    }
-  }
-)
 run_list(
   "recipe[trac]"
 )
diff --git a/roles/trogdor.rb b/roles/trogdor.rb
deleted file mode 100644 (file)
index 09dd945..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-name "trogdor"
-description "Master role applied to trogdor"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "12g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "134.90.146.26",
-        :prefix => "30",
-        :gateway => "134.90.146.25"
-      }
-    }
-  },
-  :sysfs => {
-    :md_tune => {
-      :comment => "Tune the md sync performance so as not to kill system performance",
-      :parameters => {
-        "block/md0/md/sync_speed_min" => "1",
-        "block/md0/md/sync_speed_max" => "100000",
-        "block/md1/md/sync_speed_min" => "1",
-        "block/md1/md/sync_speed_max" => "100000"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "10240 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "amsterdam.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[blix-nl]",
-  "role[tilecache]"
-)
diff --git a/roles/tuatara.rb b/roles/tuatara.rb
deleted file mode 100644 (file)
index 4b56ff3..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-name "tuatara"
-description "Master role applied to tuatara"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "14g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eno1",
-        :role => :external,
-        :family => :inet,
-        :address => "114.23.141.203",
-        :prefix => "29",
-        :gateway => "114.23.141.201"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "12288 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "wellington.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[hostedinnz]",
-  "role[tilecache]"
-)
diff --git a/roles/tyan-s7010.rb b/roles/tyan-s7010.rb
deleted file mode 100644 (file)
index c6e21bd..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-name "tyan-s7010"
-description "Role applied to machines using the Tyan S7010 motherboard"
-
-default_attributes(
-  :hardware => {
-    :modules => %w[i2c_i801 jc42 w83793],
-    :sensors => {
-      "jc42-*" => {
-        :temps => {
-          "temp1" => { :max => 75 }
-        }
-      },
-      "w83793-i2c-*-2f" => {
-        :volts => {
-          "in0" => { :min => 0.696, :max => 1.424 },
-          "in1" => { :min => 0.696, :max => 1.424 },
-          "in5" => { :min => 2.992, :max => 3.536 },
-          "in9" => { :min => 2.608, :max => 3.536 }
-        },
-        :fans => {
-          "fan1" => { :min => 1500 },
-          "fan2" => { :min => 1500 },
-          "fan3" => { :ignore => true },
-          "fan4" => { :ignore => true },
-          "fan5" => { :ignore => true },
-          "fan6" => { :ignore => true },
-          "fan7" => { :ignore => true },
-          "fan8" => { :ignore => true },
-          "fan9" => { :ignore => true },
-          "fan10" => { :ignore => true },
-          "fan11" => { :ignore => true },
-          "fan12" => { :ignore => true }
-        },
-        :temps => {
-          "temp5" => { :max => 78, :max_hyst => 73 },
-          "temp6" => { :max => 78, :max_hyst => 73 }
-        }
-      }
-    }
-  },
-  :munin => {
-    :plugins => {
-      :ipmi_fans => {
-        :Sys3Front1 => { :graph => "no", :warning => "0:" },
-        :Sys4Front2 => { :graph => "no", :warning => "0:" },
-        :Sys5Rear1 => { :graph => "no", :warning => "0:" },
-        :Sys6 => { :graph => "no", :warning => "0:" },
-        :Sys7 => { :graph => "no", :warning => "0:" },
-        :Sys8 => { :graph => "no", :warning => "0:" },
-        :Sys9 => { :graph => "no", :warning => "0:" },
-        :Sys10 => { :graph => "no", :warning => "0:" }
-      },
-      :ipmi_temp => {
-        :CPU0belowTmax => { :critical => "10:" },
-        :CPU1belowTmax => { :critical => "10:" }
-      },
-      :sensors_volt => {
-        "VCoreA" => { :warning => "0.70:1.42", :critical => "0.70:1.42" },
-        "VCoreB" => { :warning => "0.70:1.42", :critical => "0.70:1.42" },
-        "in2" => { :warning => "0.00:2.05", :critical => "0.00:2.05" },
-        "in3" => { :warning => "0.00:4.08", :critical => "0.00:4.08" },
-        "in4" => { :warning => "0.00:4.08", :critical => "0.00:4.08" },
-        "in5" => { :warning => "2.99:3.54", :critical => "2.99:3.54" },
-        "in6" => { :warning => "0.00:2.04", :critical => "0.00:2.04" },
-        "+5V" => { :warning => "4.52:5.50", :critical => "4.52:5.50" },
-        "5VSB" => { :warning => "4.52:5.50", :critical => "4.52:5.50" },
-        "Vbat" => { :warning => "2.70:3.30", :critical => "2.70:3.30" }
-      }
-    }
-  }
-)
index 27064ea2359a8a42a83c83705ae899c20a1b3777..516c925d39f5e81073d242ca1d7a88425287596a 100644 (file)
@@ -8,7 +8,10 @@ default_attributes(
       :internal => {
         :inet => {
           :prefix => "20",
-          :gateway => "10.0.0.3"
+          :gateway => "10.0.0.3",
+          :routes => {
+            "10.0.0.0/8" => { :via => "10.0.0.3" }
+          }
         }
       },
       :external => {
@@ -18,6 +21,9 @@ default_attributes(
           :gateway => "193.60.236.254"
         }
       }
+    },
+    :wireguard => {
+      :keepalive => 180
     }
   }
 )
index 70c88a25313364e3f3c82054361b81920f7bfd72..9e783264dfb98f059d29a63a0a71ee3c59f78c3b 100644 (file)
@@ -8,18 +8,13 @@ default_attributes(
     }
   },
   :hosted_by => "Academic Computer Club, Umeå University",
-  :location => "Umeå, Sweden",
-  :networking => {
-    :nameservers => ["130.239.18.251", "130.239.18.252", "130.239.1.90"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
+  :location => "Umeå, Sweden"
 )
 
 override_attributes(
+  :networking => {
+    :nameservers => ["130.239.18.251", "130.239.18.252", "130.239.1.90"]
+  },
   :ntp => {
     :servers => ["0.se.pool.ntp.org", "1.se.pool.ntp.org", "europe.pool.ntp.org"]
   }
diff --git a/roles/unizar.rb b/roles/unizar.rb
deleted file mode 100644 (file)
index f9d5d12..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-name "unizar"
-description "Role applied to all servers at University of Zaragoza"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :osluz => { :status => :administrator }
-    }
-  },
-  :hosted_by => "University of Zaragoza",
-  :location => "Zaragoza, Spain",
-  :networking => {
-    :nameservers => ["155.210.12.9", "155.210.3.12"],
-    :roles => {
-      :external => {
-        :zone => "uz"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.es.pool.ntp.org", "1.es.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[es]"
-)
diff --git a/roles/urmel.rb b/roles/urmel.rb
deleted file mode 100644 (file)
index dba68ec..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-name "urmel"
-description "Master role applied to urmel"
-
-default_attributes(
-  :networking => {
-    :interfaces => {
-      :internal_ipv4 => {
-        :interface => "eth0.2801",
-        :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.6"
-      },
-      :external_ipv4 => {
-        :interface => "eth0.2800",
-        :role => :external,
-        :family => :inet,
-        :address => "193.60.236.21"
-      }
-    }
-  }
-)
-
-run_list(
-  "role[ucl]",
-  "role[hp-dl360-g6]",
-  "role[munin]"
-)
diff --git a/roles/utelecom.rb b/roles/utelecom.rb
deleted file mode 100644 (file)
index d4aca4c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-name "utelecom"
-description "Role applied to all servers at Ukrainian Telecommunication Group"
-
-default_attributes(
-  :hosted_by => "Ukrainian Telecommunication Group",
-  :location => "Kiev, Ukraine",
-  :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.ua.pool.ntp.org", "1.ua.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[ua]"
-)
diff --git a/roles/vhagar.rb b/roles/vhagar.rb
new file mode 100644 (file)
index 0000000..fc482f3
--- /dev/null
@@ -0,0 +1,45 @@
+name "vhagar"
+description "Master role applied to vhagar"
+
+default_attributes(
+  :networking => {
+    :interfaces => {
+      :internal => {
+        :interface => "bond0",
+        :role => :internal,
+        :inet => {
+          :address => "10.0.48.5"
+        },
+        :bond => {
+          :mode => "802.3ad",
+          :lacprate => "fast",
+          :xmithashpolicy => "layer3+4",
+          :slaves => %w[eno1 eno2 eno3 eno4 eno5 eno6]
+        }
+      },
+      :external => {
+        :interface => "bond0.3",
+        :role => :external,
+        :inet => {
+          :address => "184.104.179.133"
+        },
+        :inet6 => {
+          :address => "2001:470:1:fa1::5"
+        }
+      }
+    }
+  },
+  :nominatim => {
+    :state => "standalone",
+    :dbcluster => "15/main",
+    :flatnode_file => "/srv/nominatim.openstreetmap.org/planet-project/nodes.store",
+    :api_flavour => "python",
+    :api_workers => 24,
+    :api_pool_size => 8
+  }
+)
+
+run_list(
+  "role[equinix-ams]",
+  "role[nominatim]"
+)
diff --git a/roles/vipertooth.rb b/roles/vipertooth.rb
deleted file mode 100644 (file)
index e91318a..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-name "vipertooth"
-description "Master role applied to vipertooth"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "18g"
-  },
-  :location => "Kiev, Ukraine",
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens160",
-        :role => :external,
-        :family => :inet,
-        :address => "176.122.99.101",
-        :prefix => "26",
-        :gateway => "176.122.99.126"
-      },
-      :external_ipv6 => {
-        :interface => "ens160",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:67c:2d40::65",
-        :prefix => "64",
-        :gateway => "2001:67c:2d40::fffe"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "16384 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "kiev.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[utelecom]",
-  "role[tilecache]"
-)
diff --git a/roles/viserion.rb b/roles/viserion.rb
deleted file mode 100644 (file)
index 33675f1..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-name "viserion"
-description "Master role applied to viserion"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :anovak => { :status => :administrator }
-    }
-  },
-  :hardware => {
-    :shm_size => "36g"
-  },
-  :location => "Pula, Croatia",
-  :munin => {
-    :allow => ["193.198.233.210"]
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet,
-        :address => "193.198.233.211",
-        :prefix => "29",
-        :gateway => "193.198.233.209"
-      },
-      :external_ipv6 => {
-        :interface => "eth0",
-        :role => :external,
-        :family => :inet6,
-        :address => "2001:b68:4cff:3::3",
-        :prefix => "64",
-        :gateway => "2001:b68:4cff:3::1"
-      }
-    },
-    :nameservers => [
-      "8.8.8.8",
-      "8.8.4.4",
-      "2001:4860:4860::8888",
-      "2001:4860:4860::8844"
-    ]
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "32768 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "pula.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[carnet]",
-  "role[tilecache]"
-)
diff --git a/roles/waima.rb b/roles/waima.rb
deleted file mode 100644 (file)
index e614caa..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-name "waima"
-description "Master role applied to waima"
-
-default_attributes(
-  :hardware => {
-    :shm_size => "12g"
-  },
-  :networking => {
-    :interfaces => {
-      :external_ipv4 => {
-        :interface => "ens3",
-        :role => :external,
-        :family => :inet,
-        :address => "192.168.1.4",
-        :prefix => "24",
-        :gateway => "192.168.1.1",
-        :public_address => "103.197.61.160"
-      }
-    }
-  },
-  :squid => {
-    :version => 4,
-    :cache_mem => "10240 MB",
-    :cache_dir => [
-      "rock /store/squid/rock-4096 20000 swap-timeout=200 slot-size=4096 max-size=3996",
-      "rock /store/squid/rock-8192 25000 swap-timeout=200 slot-size=8192 min-size=3997 max-size=8092",
-      "rock /store/squid/rock-16384 35000 swap-timeout=200 slot-size=16384 min-size=8093 max-size=16284",
-      "rock /store/squid/rock-32768 45000 swap-timeout=200 slot-size=32768 min-size=16285 max-size=262144"
-    ]
-  },
-  :tilecache => {
-    :tile_parent => "hamilton.render.openstreetmap.org"
-  }
-)
-
-run_list(
-  "role[catalyst]",
-  "role[tilecache]"
-)
diff --git a/roles/web-backend.rb b/roles/web-backend.rb
deleted file mode 100644 (file)
index d59ce81..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-name "web-backend"
-description "Role applied to all web/api backend servers"
-
-default_attributes(
-  :apache => {
-    :mpm => "worker",
-    :worker => {
-      :max_connections_per_child => 10000
-    }
-  },
-  :logstash => {
-    :forwarder => {
-      "filebeat.prospectors" => [
-        { "input_type" => "log", "paths" => ["/var/log/apache2/access.log"], "fields" => { "type" => "apache" } },
-        { "input_type" => "log", "paths" => ["/var/log/web/rails-logstash.log"], "fields" => { "type" => "rails" } }
-      ]
-    }
-  },
-  :memcached => {
-    :memory_limit => 4096
-  },
-  :passenger => {
-    :max_pool_size => 12
-  }
-)
-
-run_list(
-  "role[web]",
-  "role[logstash-forwarder]",
-  "recipe[web::backend]"
-)
index 3db0cc4a787d0d816d4c9086de923d7cab52dfac..c03da5277b620a825a52d96a7b4213957a92401e 100644 (file)
@@ -3,6 +3,6 @@ description "Role applied to all servers needing to find the main database"
 
 default_attributes(
   :web => {
-    :database_host => "karm.ams.openstreetmap.org"
+    :database_host => "snap-01.ams.openstreetmap.org"
   }
 )
index 0435872dd1c751b166465f04f34d76e702c9aa29..b5597adb67278a6628e506ad382d778308e2330f 100644 (file)
@@ -15,14 +15,19 @@ default_attributes(
   },
   :logstash => {
     :forwarder => {
-      "filebeat.prospectors" => [
-        { "input_type" => "log", "paths" => ["/var/log/apache2/access.log"], "fields" => { "type" => "apache" } },
-        { "input_type" => "log", "paths" => ["/var/log/web/rails-logstash.log"], "fields" => { "type" => "rails" } }
+      "filebeat.inputs" => [
+        { "type" => "filestream", "id" => "apache", "paths" => ["/var/log/apache2/access.log"], "fields" => { "type" => "apache" }, "fields_under_root" => true },
+        { "type" => "filestream", "id" => "rails", "paths" => ["/var/log/web/rails-logstash.log"], "fields" => { "type" => "rails" }, "fields_under_root" => true }
       ]
     }
   },
+  :memcached => {
+    :memory_limit => 8192
+  },
   :networking => {
-    :tcp_fastopen_key => "www"
+    :firewall => {
+      :http_rate_limit => "s:5/sec:30"
+    }
   },
   :passenger => {
     :max_pool_size => 50
@@ -33,14 +38,13 @@ default_attributes(
       :messages => {
         :comment => "messages.openstreetmap.org",
         :domains => ["messages.openstreetmap.org"],
-        :command => "/usr/local/bin/passenger-ruby /srv/www.openstreetmap.org/rails/script/deliver-message $local_part",
+        :local_parts => ["${lookup{$local_part}lsearch*,ret=key{/etc/exim4/detaint}}"],
+        :command => "/usr/local/bin/deliver-message $local_part_data",
         :user => "rails",
         :group => "rails",
         :home_directory => "/srv/www.openstreetmap.org/rails",
         :path => "/bin:/usr/bin:/usr/local/bin",
-        :environment => {
-          "RAILS_ENV" => "production"
-        }
+        :case_sensitive => true
       }
     }
   }
diff --git a/roles/web-storage.rb b/roles/web-storage.rb
deleted file mode 100644 (file)
index 4dc1b3d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-name "web-storage"
-description "Base role applied to all web/api storage servers"
-
-default_attributes(
-  :accounts => {
-    :users => {
-      :rails => { :status => :role }
-    }
-  }
-)
-
-run_list(
-  "recipe[nfs::server]"
-)
index 3276e43e4dc8bd7fdfbec542a1057c0dc61eadd3..594c18f842334523036f53e869319eca640d7c51 100644 (file)
@@ -5,7 +5,6 @@ default_attributes(
   :accounts => {
     :users => {
       :rails => {
-        :status => :role,
         :members => [:tomh, :grant]
       }
     }
@@ -18,7 +17,7 @@ default_attributes(
   },
   :web => {
     :status => "online",
-    :memcached_servers => %w[rails1.ams rails2.ams rails3.ams]
+    :memcached_servers => %w[spike-06.ams spike-07.ams spike-08.ams]
   }
 )
 
index 845f99fe269b6d13cdf0cfc9567486725ac40557..0c83be4c5ed6e4f16c7093e339e46fa66e91c3a7 100644 (file)
@@ -8,23 +8,27 @@ default_attributes(
     }
   },
   :apache => {
-    :mpm => "prefork",
+    :mpm => "event",
     :timeout => 30,
     :event => {
       :server_limit => 32,
       :max_request_workers => 800,
       :threads_per_child => 50,
       :max_connections_per_child => 10000
+    },
+    :evasive => {
+      :page_count => 250,
+      :site_count => 500
     }
   },
   :elasticsearch => {
-    :version => "5.x",
+    :version => "7.x",
     :cluster => {
       :name => "wiki"
     }
   },
   :exim => {
-    :trusted_users => ["www-data"],
+    :trusted_users => %w[www-data wiki],
     :aliases => {
       :root => "grant"
     },
@@ -37,19 +41,25 @@ default_attributes(
     ]
   },
   :memcached => {
-    :memory_limit => 1024,
+    :memory_limit => 4096,
     :connection_limit => 8192,
-    :chunk_growth_factor => 1.05,
-    :min_item_size => 5
+    :chunk_growth_factor => 1.25,
+    :min_item_size => 48
+  },
+  :sysctl => {
+    :swappiness => {
+      :comment => "Reduce swap usage",
+      :parameters => {
+        "vm.swappiness" => 10
+      }
+    }
   },
   :mysql => {
     :settings => {
       :mysqld => {
         :innodb_buffer_pool_size => "4G",
         :key_buffer_size => "64M",
-        :max_connections => "200",
-        :query_cache_size => "256M",
-        :query_cache_type => "1",
+        :max_connections => "500",
         :sort_buffer_size => "8M",
         :tmp_table_size => "128M"
       }
diff --git a/roles/yandex.rb b/roles/yandex.rb
deleted file mode 100644 (file)
index 0199950..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-name "yandex"
-description "Role applied to all servers at Yandex"
-
-default_attributes(
-  :hosted_by => "Yandex",
-  :location => "Moscow, Russia",
-  :timezone => "Europe/Moscow",
-  :networking => {
-    :nameservers => ["8.8.8.8", "8.8.4.4"],
-    :roles => {
-      :external => {
-        :zone => "yx"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.ru.pool.ntp.org", "1.ru.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[ru]"
-)
index b23b6da265744ad3d858591d789fb31560a63ae8..889bf27e9a4443b58e248d21691936eed298ca7a 100644 (file)
@@ -2,31 +2,27 @@ name "ysera"
 description "Master role applied to ysera"
 
 default_attributes(
-  :apt => {
-    :sources => ["postgresql"]
-  },
   :networking => {
     :interfaces => {
-      :internal_ipv4 => {
+      :internal => {
         :interface => "eno1.2801",
         :role => :internal,
-        :family => :inet,
-        :address => "10.0.0.15"
+        :inet => {
+          :address => "10.0.0.15"
+        }
       },
-      :external_ipv4 => {
+      :external => {
         :interface => "eno1.2800",
         :role => :external,
-        :family => :inet,
-        :address => "193.60.236.22"
+        :inet => {
+          :address => "193.60.236.22"
+        }
       }
     }
   },
   :postgresql => {
-    :versions => ["10"],
     :settings => {
       :defaults => {
-        :shared_buffers => "8GB",
-        :maintenance_work_mem => "7144MB",
         :effective_cache_size => "16GB"
       }
     }
@@ -42,10 +38,10 @@ default_attributes(
   },
   :tile => {
     :database => {
-      :cluster => "10/main",
-      :postgis => "2.4"
+      :cluster => "16/main",
+      :postgis => "3"
     },
-    :node_file => "/store/database/nodes",
+    :mapnik => "3.1",
     :styles => {
       :default => {
         :tile_directories => [
diff --git a/roles/zcu.rb b/roles/zcu.rb
deleted file mode 100644 (file)
index b059c5b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-name "zcu"
-description "Role applied to all servers at University of West Bohemia"
-
-default_attributes(
-  :hosted_by => "University of West Bohemia",
-  :location => "Pilsen, Czech Republic",
-  :networking => {
-    :nameservers => ["147.228.3.3", "147.228.52.11"],
-    :roles => {
-      :external => {
-        :zone => "osm"
-      }
-    }
-  }
-)
-
-override_attributes(
-  :ntp => {
-    :servers => ["0.cz.pool.ntp.org", "1.cz.pool.ntp.org", "europe.pool.ntp.org"]
-  }
-)
-
-run_list(
-  "role[cz]"
-)
diff --git a/test/data_bags/accounts/community.json b/test/data_bags/accounts/community.json
new file mode 100644 (file)
index 0000000..b4b5fd3
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "id": "community",
+  "uid": "527",
+  "comment": "Community"
+}
diff --git a/test/data_bags/accounts/forum.json b/test/data_bags/accounts/forum.json
deleted file mode 100644 (file)
index 12c9e38..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "id": "forum",
-  "uid": "522",
-  "comment": "Forum",
-  "manage_home": false
-}
diff --git a/test/data_bags/accounts/git.json b/test/data_bags/accounts/git.json
new file mode 100644 (file)
index 0000000..1938a3f
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "git",
+  "uid": "508",
+  "comment": "git.openstreetmap.org",
+  "home": "/var/lib/git"
+}
diff --git a/test/data_bags/accounts/gpstile.json b/test/data_bags/accounts/gpstile.json
new file mode 100644 (file)
index 0000000..3a242c4
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "gpstile",
+  "uid": "519",
+  "comment": "gps-tile.openstreetmap.org",
+  "home": "/srv/gps-tile.openstreetmap.org"
+}
diff --git a/test/data_bags/accounts/kibana.json b/test/data_bags/accounts/kibana.json
new file mode 100644 (file)
index 0000000..1d2fc53
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "kibana",
+  "uid": "521",
+  "comment": "Kibana",
+  "manage_home": false
+}
diff --git a/test/data_bags/accounts/lonvia.json b/test/data_bags/accounts/lonvia.json
new file mode 100644 (file)
index 0000000..1684539
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "lonvia",
+  "uid": "1056",
+  "comment": "Sarah Hoffmann",
+  "email": "lonvia@example.com"
+}
diff --git a/test/data_bags/accounts/nominatim.json b/test/data_bags/accounts/nominatim.json
new file mode 100644 (file)
index 0000000..675eb77
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "nominatim",
+  "uid": "518",
+  "comment": "nominatim.openstreetmap.org",
+  "home": "/srv/nominatim.openstreetmap.org"
+}
diff --git a/test/data_bags/accounts/osmbackup.json b/test/data_bags/accounts/osmbackup.json
new file mode 100644 (file)
index 0000000..2fcfd71
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "id": "osmbackup",
+  "uid": 501,
+  "comment": "Backups",
+  "home": "/store/backup",
+  "manage_home": false
+}
diff --git a/test/data_bags/accounts/osqa.json b/test/data_bags/accounts/osqa.json
new file mode 100644 (file)
index 0000000..22361d0
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "osqa",
+  "uid": "510",
+  "comment": "osqa.openstreetmap.org",
+  "home": "/srv/help.openstreetmap.org"
+}
diff --git a/test/data_bags/accounts/overpass.json b/test/data_bags/accounts/overpass.json
new file mode 100644 (file)
index 0000000..7aa7c2b
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "overpass",
+  "uid": "528",
+  "comment": "query.openstreetmap.org",
+  "home": "/srv/query.openstreetmap.org"
+}
diff --git a/test/data_bags/accounts/planet.json b/test/data_bags/accounts/planet.json
new file mode 100644 (file)
index 0000000..b69305f
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "id": "planet",
+  "uid": "502",
+  "comment": "planet.openstreetmap.org"
+}
diff --git a/test/data_bags/accounts/rails.json b/test/data_bags/accounts/rails.json
new file mode 100644 (file)
index 0000000..564acef
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "rails",
+  "uid": "500",
+  "comment": "Rails",
+  "manage_home": false
+}
diff --git a/test/data_bags/accounts/supybot.json b/test/data_bags/accounts/supybot.json
new file mode 100644 (file)
index 0000000..b623c99
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "id": "supybot",
+  "uid": "517",
+  "comment": "Supybot"
+}
diff --git a/test/data_bags/accounts/taginfo.json b/test/data_bags/accounts/taginfo.json
new file mode 100644 (file)
index 0000000..b74e3b0
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "taginfo",
+  "uid": "520",
+  "comment": "Taginfo",
+  "manage_home": false
+}
diff --git a/test/data_bags/accounts/tile.json b/test/data_bags/accounts/tile.json
new file mode 100644 (file)
index 0000000..435cb15
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "tile",
+  "uid": "515",
+  "comment": "tile.openstreetmap.org",
+  "home": "/srv/tile.openstreetmap.org"
+}
diff --git a/test/data_bags/accounts/trac.json b/test/data_bags/accounts/trac.json
new file mode 100644 (file)
index 0000000..9c89cb1
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "id": "trac",
+  "uid": "509",
+  "comment": "trac.openstreetmap.org",
+  "home": "/var/lib/trac",
+  "manage_home": false
+}
diff --git a/test/data_bags/accounts/wiki.json b/test/data_bags/accounts/wiki.json
new file mode 100644 (file)
index 0000000..0ee9618
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "id": "wiki",
+  "uid": "555",
+  "comment": "wiki.openstreetmap.org",
+  "home": "/opt/wiki",
+  "manage_home": false
+}
diff --git a/test/data_bags/accounts/wordpress.json b/test/data_bags/accounts/wordpress.json
new file mode 100644 (file)
index 0000000..a081519
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "id": "wordpress",
+  "uid": "516",
+  "comment": "Wordpress"
+}
diff --git a/test/data_bags/blog/passwords.json b/test/data_bags/blog/passwords.json
new file mode 100644 (file)
index 0000000..7db4860
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "passwords",
+  "osm-blog-user": "osm-blog-password"
+}
diff --git a/test/data_bags/blog/wp2fa_encrypt_keys.json b/test/data_bags/blog/wp2fa_encrypt_keys.json
new file mode 100644 (file)
index 0000000..9eb1e21
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "wp2fa_encrypt_keys",
+  "key": "vQk0IGrkn/nvKjyY8XNOrw=="
+}
diff --git a/test/data_bags/civicrm/passwords.json b/test/data_bags/civicrm/passwords.json
new file mode 100644 (file)
index 0000000..bcd1ad4
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "id": "passwords",
+  "database": "database-password",
+  "admin": "admin-password",
+  "site_key": "site_key",
+  "cred_keys": "cred_keys",
+  "sign_keys": "sign_keys",
+  "batch": "batch"
+}
diff --git a/test/data_bags/civicrm/wp2fa_encrypt_keys.json b/test/data_bags/civicrm/wp2fa_encrypt_keys.json
new file mode 100644 (file)
index 0000000..bfca5cd
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "wp2fa_encrypt_keys",
+  "key": "iPWRI6ZJ6Q0CuLA8+FsVQw=="
+}
diff --git a/test/data_bags/community/passwords.json b/test/data_bags/community/passwords.json
new file mode 100644 (file)
index 0000000..486dded
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "id": "passwords",
+  "database": "database",
+  "oauth2_client_id": "oauth2_client_id",
+  "oauth2_secret": "oauth2_secret",
+  "mail_receiver_api_key": "mail_receiver_api_key"
+}
diff --git a/test/data_bags/db/passwords.json b/test/data_bags/db/passwords.json
new file mode 100644 (file)
index 0000000..532c1d0
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "id": "passwords",
+  "openstreetmap": "openstreetmap-password",
+  "rails": "rails-password",
+  "cgimap": "cgimap-password",
+  "planetdump": "planetdump-password",
+  "planetdiff": "planetdiff-password",
+  "backup": "backup-password",
+  "replication": "replication-password"
+}
diff --git a/test/data_bags/db/wal-secrets.json b/test/data_bags/db/wal-secrets.json
new file mode 100644 (file)
index 0000000..6f558f2
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "wal-secrets",
+  "s3_key": "s3-key"
+}
diff --git a/test/data_bags/dns/passwords.json b/test/data_bags/dns/passwords.json
new file mode 100644 (file)
index 0000000..cd7b6c9
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "id": "passwords",
+  "rsync": "rsync",
+  "statuscake": "statuscake",
+  "gandi": "gandi",
+  "cloudflare": "cloudflare"
+}
diff --git a/test/data_bags/donate/passwords.json b/test/data_bags/donate/passwords.json
new file mode 100644 (file)
index 0000000..5cfde8e
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "passwords",
+  "database": "database-password"
+}
diff --git a/test/data_bags/exim/aliases.json b/test/data_bags/exim/aliases.json
new file mode 100644 (file)
index 0000000..7003ab2
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "id": "aliases",
+  "mail": {
+    "test": "test@example.com"
+  }
+}
diff --git a/test/data_bags/exim/dkim.json b/test/data_bags/exim/dkim.json
new file mode 100644 (file)
index 0000000..08b8673
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "id": "dkim",
+  "openstreetmap.org": [
+    "-----BEGIN RSA PRIVATE KEY-----",
+    "-----END RSA PRIVATE KEY-----"
+  ],
+  "osmfoundation.org": [
+    "-----BEGIN RSA PRIVATE KEY-----",
+    "-----END RSA PRIVATE KEY-----"
+  ]
+}
diff --git a/test/data_bags/foundation/passwords.json b/test/data_bags/foundation/passwords.json
new file mode 100644 (file)
index 0000000..b8b93ca
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "id": "passwords",
+  "wiki": {
+    "database": "database_password",
+    "admin": "admin_password"
+  },
+  "board": {
+    "database": "database_password",
+    "admin": "admin_password"
+  },
+  "dwg": {
+    "database": "database_password",
+    "admin": "admin_password"
+  },
+  "mwg": {
+    "database": "database_password",
+    "admin": "admin_password"
+  }
+}
diff --git a/test/data_bags/geoipupdate/license-keys.json b/test/data_bags/geoipupdate/license-keys.json
new file mode 100644 (file)
index 0000000..a53c128
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "license-keys",
+  "149244": "key"
+}
diff --git a/test/data_bags/letsencrypt/.gitkeep b/test/data_bags/letsencrypt/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/data_bags/logstash/keys.json b/test/data_bags/logstash/keys.json
new file mode 100644 (file)
index 0000000..69f7fe5
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "id": "keys",
+  "lumberjack": [
+    "-----BEGIN PRIVATE KEY-----",
+    "-----END PRIVATE KEY-----"
+  ],
+  "beats": [
+    "-----BEGIN PRIVATE KEY-----",
+    "-----END PRIVATE KEY-----"
+  ]
+}
diff --git a/test/data_bags/matomo/passwords.json b/test/data_bags/matomo/passwords.json
new file mode 100644 (file)
index 0000000..396b281
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "id": "passwords",
+  "database": "database-password",
+  "salt": "salt"
+}
diff --git a/test/data_bags/networking/keys.json b/test/data_bags/networking/keys.json
new file mode 100644 (file)
index 0000000..de1f901
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "keys",
+  "wireguard": "cQzuTMFj9LwSTdv7YqZhwsnbP2ZYzlSiK/Bgj4A9D/o="
+}
diff --git a/test/data_bags/otrs-debian/passwords.json b/test/data_bags/otrs-debian/passwords.json
new file mode 100644 (file)
index 0000000..ccb5fec
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "passwords",
+  "otrs": "database-password"
+}
diff --git a/test/data_bags/planet/aws.json b/test/data_bags/planet/aws.json
new file mode 100644 (file)
index 0000000..787bf1c
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "aws",
+  "osm-pds": "osm-pds"
+}
diff --git a/test/data_bags/postgresql/passwords.json b/test/data_bags/postgresql/passwords.json
new file mode 100644 (file)
index 0000000..120914c
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "passwords",
+  "prometheus": "prometheus-password"
+}
diff --git a/test/data_bags/prometheus/passwords.json b/test/data_bags/prometheus/passwords.json
new file mode 100644 (file)
index 0000000..81a2ce6
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "passwords",
+  "grafana_admin": "grafana_admin"
+}
diff --git a/test/data_bags/prometheus/tokens.json b/test/data_bags/prometheus/tokens.json
new file mode 100644 (file)
index 0000000..61646f7
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "tokens",
+  "fastly": "fastly_token"
+}
diff --git a/test/data_bags/snmpd/communities.json b/test/data_bags/snmpd/communities.json
new file mode 100644 (file)
index 0000000..3532754
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  "id": "communities"
+}
diff --git a/test/data_bags/stateofthemap/passwords.json b/test/data_bags/stateofthemap/passwords.json
new file mode 100644 (file)
index 0000000..88d27ac
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "id": "passwords",
+  "sotm2007": "sotm2007",
+  "sotm2008": "sotm2008",
+  "sotm2009": "sotm2009",
+  "sotm2010": "sotm2010",
+  "sotm2011": "sotm2011",
+  "sotm2012": "sotm2012"
+}
diff --git a/test/data_bags/stateofthemap/wp2fa_encrypt_keys.json b/test/data_bags/stateofthemap/wp2fa_encrypt_keys.json
new file mode 100644 (file)
index 0000000..e537098
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "id": "wp2fa_encrypt_keys",
+  "sotm2007": "q1bhaOUla4GIHvTp/QR5bw==",
+  "sotm2008": "VUkZ0vbiXgTu8IwZyz71Lg==",
+  "sotm2009": "8nQDE9ng6QW8AKDpsm3NOA==",
+  "sotm2010": "Bu968voFkvMpSgogWBrf6g==",
+  "sotm2011": "vsrEyBqcI30SFv9gyYkyWQ==",
+  "sotm2012": "Qe3olwbbSFuraQAoUXieHA=="
+}
diff --git a/test/data_bags/supybot/passwords.json b/test/data_bags/supybot/passwords.json
new file mode 100644 (file)
index 0000000..4ae280f
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "passwords",
+  "nickserv": "nickserv"
+}
diff --git a/test/data_bags/supybot/users.json b/test/data_bags/supybot/users.json
new file mode 100644 (file)
index 0000000..7a318dc
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "users",
+  "Firefishy": "Firefishy"
+}
diff --git a/test/data_bags/tile/blocks.json b/test/data_bags/tile/blocks.json
new file mode 100644 (file)
index 0000000..7088976
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "id": "blocks",
+  "user_agents": [
+    "dummy"
+  ],
+  "referers": [
+    "https://www.example.com/"
+  ]
+}
diff --git a/test/data_bags/tilelog/passwords.json b/test/data_bags/tilelog/passwords.json
new file mode 100644 (file)
index 0000000..0606029
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "id": "passwords",
+  "aws_key": "AWS_KEY_VALUE"
+}
diff --git a/test/data_bags/web/matomo.json b/test/data_bags/web/matomo.json
new file mode 100644 (file)
index 0000000..0bae1e2
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "id": "matomo",
+  "location": "matomo",
+  "site": 100,
+  "goals": {
+    "signup": 1001,
+    "mapnik": 1002,
+    "cyclemap": 1003,
+    "transportmap": 1004,
+    "mapquest": 1005
+  }
+}
diff --git a/test/data_bags/web/passwords.json b/test/data_bags/web/passwords.json
new file mode 100644 (file)
index 0000000..4c0eea4
--- /dev/null
@@ -0,0 +1,48 @@
+{
+  "id": "passwords",
+  "secret_key_base": "base",
+  "potlatch2_key": "potlatch2",
+  "id_key": "id",
+  "oauth_key": "oauth",
+  "google_auth_secret": "google",
+  "facebook_auth_secret": "facebook",
+  "microsoft_auth_secret": "microsoft",
+  "github_auth_secret": "github",
+  "wikipedia_auth_secret": "wikipedia",
+  "mapquest_key": "mapquest",
+  "mapzen_valhalla_key": "mapzen-valhalla",
+  "thunderforest_key": "thunderforest",
+  "tracestrack_key": "tracestrack",
+  "totp_key": "totp",
+  "aws_key": "aws",
+  "openid_connect_key": [
+    "-----BEGIN PRIVATE KEY-----",
+    "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC1yJqM4c0bJNVN",
+    "BLUrKA1Hmu4XoesiIjiuN9CwvVKTbtSy4CxymxaVYDarFoypwY7fOLzTU2F1En9n",
+    "B0ShiFclbRVqpAXwGH4KeKI5qcHUrZeYSKgy7MQmyvsHOF2hSuL5SOgHyhU888sN",
+    "CyFnFnBrf4jxi1crdBYPO3gQvLtxG4q0xSpDPsyKAKX8K86JGDMIJlEJTJo5esLO",
+    "QOYsZp6g3olaTlWzxafPPz26pWMIcYIW3TFa9Lj5zFtF6YAitk7KRhX+0O5T9Zfn",
+    "WDE8ZC8oQPZxIBIuBG2tvih6NpUFAeVEMCqHs6S7hYSW/Oguow36FFMeQ/snQzPy",
+    "sO+AQKaPAgMBAAECggEADT+0J+1zHfXWx/i+XYlbQmtDzBwkf4Xf/K6buq3pvU4Y",
+    "GXtmMeokwLlU8q4/jUXKrHE9redHVJmHCJLKiT1fIJ6tL2sJ9cBLO2ckZ7B8LIyE",
+    "Xnh5LdD80Nj9Z77PcCh9l26dXqf3WUxpcadshU9o3STb7cLalROuYejTLOEchjc8",
+    "sKdMW0OjzHt8qLEa5wjZ9mG6hfyMzBzYbQCYTPU67FnJun7Ssej3WWJDkgnVdx4x",
+    "hTvtVjOh3fGIE01I1qbSz4oJ+b3mvqQpCGPM3nvkKxTSlcnxr25c8V/6F7I896eW",
+    "tAyxf5R7t4p6uGWfXUtOF+nuAo9ePHkPlQ6qOQAR7QKBgQDhTHkKepttw98cIay4",
+    "N93kpDYU+hA/oKcZr/OkXye4Ym1cbV4TTFfLs/8+t67PB0kx8ONnxoTsDaxhb1Uh",
+    "qK9yonYUeiwF07Wbtc59WVtHob9h/f4J9+x1rFNgkZoaFn5AJPxmRF57HUFw8mql",
+    "1XiY3jnZxV3A9fsggyZvQU6FXQKBgQDOjhwaEov/xNsvv987nMi8rYq6uLOW1HHE",
+    "Fc5Fw9aHMAN19hnCUxS3WQowP/XT3c11/aXTbz4xpscIZfuBqmpBWgNSs1wEzBfO",
+    "STx1FY/FF3TQr3QPzUH+nKJ39hmCoOC4uwKyezvnL12nmboDYLa5N51hA+4JUlxp",
+    "nH6dUA3Q2wKBgQDaXycLEx/H2oxMVg91VyEJ1mhdGKvbIDoW2caL0XdMboqVhaQj",
+    "jGGknciO37beD6/Qai3gjjiUHASzRBf90eSMdg+BdZFp7HQggq2sLYod+hboQimT",
+    "O+zDec4u0bHOC3M/dRn3fdkd95NQiIb6SdjkQrFL9NMUjtdkAfqk52XWOQKBgQCy",
+    "7708gPCzJBBVrzxt4gasHRLfav55HZVorxNAsMT53AhDem0aQOrjYslGv0Hwxmcl",
+    "XhT3s5kHXllx1xcoXz8pWhci36pJpZzB4gPz0jf4H7fcyQIcZk5TidHdZl73IPNM",
+    "VQWjJMriHdBeTvgr0O66SYmW79aYULcp7p5pHV66nQKBgQDSGUHJ0/QMe57kb5SE",
+    "ftJBefU7R7b5VKmQjouGjUFFr4pkBg+6+Y7WiqiM5ttDQNsd3x2Eqwh2Zk+cSJSh",
+    "WePy2Q+V52Bu23rf43BO6NKzEtpcKCPbelMsdHGL35huzJEIXlisouIGhlV8NKjT",
+    "wlbD0G8f/zHjhf8cNhmQKJt0sQ==",
+    "-----END PRIVATE KEY-----"
+  ]
+}
diff --git a/test/data_bags/wiki/passwords.json b/test/data_bags/wiki/passwords.json
new file mode 100644 (file)
index 0000000..961e60f
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "database": "database_password",
+  "admin": "admin_password",
+  "hcaptcha": "precaptcha_token",
+  "thunderforest": "thunderforest_token"
+}
similarity index 76%
rename from test/integration/forum/serverspec/apache_spec.rb
rename to test/integration/apache/inspec/apache_spec.rb
index 9d5268271b4f3898a2b4b9587b36dae630534146..8006330b441e96365a635a878578c9623dfe1469 100644 (file)
@@ -1,8 +1,3 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
 describe package("apache2") do
   it { should be_installed }
 end
@@ -14,8 +9,10 @@ end
 
 describe port(80) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
 
 describe port(443) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
diff --git a/test/integration/apache/serverspec/apache_spec.rb b/test/integration/apache/serverspec/apache_spec.rb
deleted file mode 100644 (file)
index 57b0b7d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("apache2") do
-  it { should be_installed }
-end
-
-describe service("apache2") do
-  it { should be_enabled }
-  it { should be_running }
-end
-
-describe port(80) do
-  it { should be_listening }
-end
-
-describe port(443) do
-  it { should_not be_listening }
-end
diff --git a/test/integration/awscli/inspec/awscli_spec.rb b/test/integration/awscli/inspec/awscli_spec.rb
new file mode 100644 (file)
index 0000000..de0a9e6
--- /dev/null
@@ -0,0 +1,3 @@
+describe command("/opt/awscli/v2/current/bin/aws --version") do
+  its("exit_status") { should eq 0 }
+end
similarity index 75%
rename from test/integration/bind/serverspec/bind_spec.rb
rename to test/integration/bind/inspec/bind_spec.rb
index bdf529cf326eb2e361734ea24b45e678732dd32c..399ec9b51401213726eff1687dc1ecdae8d5c9fc 100644 (file)
@@ -1,8 +1,3 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
 describe package("bind9") do
   it { should be_installed }
 end
@@ -14,4 +9,5 @@ end
 
 describe port(53) do
   it { should be_listening }
+  its("protocols") { should cmp %w[udp udp6 tcp tcp6] }
 end
similarity index 76%
rename from test/integration/apache-ssl/serverspec/apache_spec.rb
rename to test/integration/blog/inspec/apache_spec.rb
index 9d5268271b4f3898a2b4b9587b36dae630534146..8006330b441e96365a635a878578c9623dfe1469 100644 (file)
@@ -1,8 +1,3 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
 describe package("apache2") do
   it { should be_installed }
 end
@@ -14,8 +9,10 @@ end
 
 describe port(80) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
 
 describe port(443) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
diff --git a/test/integration/blog/inspec/wordpress_spec.rb b/test/integration/blog/inspec/wordpress_spec.rb
new file mode 100644 (file)
index 0000000..6533511
--- /dev/null
@@ -0,0 +1,7 @@
+describe command("/opt/wp-cli/wp --allow-root --path=/srv/blog.openstreetmap.org/wp/ core is-installed") do
+  its("exit_status") { should eq 0 }
+end
+
+describe command("/opt/wp-cli/wp --allow-root --path=/srv/blog.openstreetmap.org/wp/ plugin is-active wp-fail2ban") do
+  its("exit_status") { should eq 0 }
+end
similarity index 76%
rename from test/integration/otrs/serverspec/apache_spec.rb
rename to test/integration/blogs/inspec/apache_spec.rb
index 9d5268271b4f3898a2b4b9587b36dae630534146..8006330b441e96365a635a878578c9623dfe1469 100644 (file)
@@ -1,8 +1,3 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
 describe package("apache2") do
   it { should be_installed }
 end
@@ -14,8 +9,10 @@ end
 
 describe port(80) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
 
 describe port(443) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
diff --git a/test/integration/chef/inspec/chef_spec.rb b/test/integration/chef/inspec/chef_spec.rb
new file mode 100644 (file)
index 0000000..b1abdc0
--- /dev/null
@@ -0,0 +1,17 @@
+describe package("chef") do
+  it { should be_installed }
+end
+
+describe systemd_service("chef-client") do
+  it { should be_installed }
+end
+
+describe systemd_service("chef-client.timer") do
+  it { should be_installed }
+  it { should be_enabled }
+end
+
+describe command("chef-client --version") do
+  its("exit_status") { should eq 0 }
+  its("stdout") { should match /Chef Infra Client/ }
+end
similarity index 76%
rename from test/integration/blogs/serverspec/apache_spec.rb
rename to test/integration/civicrm/inspec/apache_spec.rb
index 9d5268271b4f3898a2b4b9587b36dae630534146..8006330b441e96365a635a878578c9623dfe1469 100644 (file)
@@ -1,8 +1,3 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
 describe package("apache2") do
   it { should be_installed }
 end
@@ -14,8 +9,10 @@ end
 
 describe port(80) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
 
 describe port(443) do
   it { should be_listening }
+  its("protocols") { should cmp "tcp" }
 end
diff --git a/test/integration/clamav/inspec/clamav_spec.rb b/test/integration/clamav/inspec/clamav_spec.rb
new file mode 100644 (file)
index 0000000..f70323c
--- /dev/null
@@ -0,0 +1,17 @@
+describe package("clamav-daemon") do
+  it { should be_installed }
+end
+
+describe service("clamav-daemon") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe package("clamav-freshclam") do
+  it { should be_installed }
+end
+
+describe service("clamav-freshclam") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/community/inspec/docker_spec.rb b/test/integration/community/inspec/docker_spec.rb
new file mode 100644 (file)
index 0000000..08853df
--- /dev/null
@@ -0,0 +1,20 @@
+describe package("docker-ce") do
+  it { should be_installed }
+end
+
+describe service("docker") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe docker_image("local_discourse/data:latest") do
+  it { should exist }
+end
+
+describe docker_image("local_discourse/mail-receiver:latest") do
+  it { should exist }
+end
+
+describe docker_image("local_discourse/web_only:latest") do
+  it { should exist }
+end
diff --git a/test/integration/community/inspec/http_spec.rb b/test/integration/community/inspec/http_spec.rb
new file mode 100644 (file)
index 0000000..e5e0677
--- /dev/null
@@ -0,0 +1,9 @@
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/db-backup/inspec/backup_spec.rb b/test/integration/db-backup/inspec/backup_spec.rb
new file mode 100644 (file)
index 0000000..411949a
--- /dev/null
@@ -0,0 +1,4 @@
+describe service("backup-db.timer") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/db-base/inspec/postgresql_spec.rb b/test/integration/db-base/inspec/postgresql_spec.rb
new file mode 100644 (file)
index 0000000..4c5872e
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("postgresql-15") do
+  it { should be_installed }
+end
+
+describe service("postgresql@15-main") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(5432) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/db-master/inspec/postgresql_spec.rb b/test/integration/db-master/inspec/postgresql_spec.rb
new file mode 100644 (file)
index 0000000..4c5872e
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("postgresql-15") do
+  it { should be_installed }
+end
+
+describe service("postgresql@15-main") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(5432) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/db-slave/inspec/postgresql_spec.rb b/test/integration/db-slave/inspec/postgresql_spec.rb
new file mode 100644 (file)
index 0000000..4c5872e
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("postgresql-15") do
+  it { should be_installed }
+end
+
+describe service("postgresql@15-main") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(5432) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/dhcpd/inspec/dhcpd_spec.rb b/test/integration/dhcpd/inspec/dhcpd_spec.rb
new file mode 100644 (file)
index 0000000..dd6ec86
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("isc-dhcp-server") do
+  it { should be_installed }
+end
+
+describe service("isc-dhcp-server") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(67) do
+  it { should be_listening }
+  its("protocols") { should cmp "udp" }
+end
diff --git a/test/integration/dmca/inspec/apache_spec.rb b/test/integration/dmca/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/dns/inspec/apache_spec.rb b/test/integration/dns/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/dns/inspec/dnscontrol_spec.rb b/test/integration/dns/inspec/dnscontrol_spec.rb
new file mode 100644 (file)
index 0000000..e623363
--- /dev/null
@@ -0,0 +1,7 @@
+describe package("dnscontrol") do
+  it { should be_installed }
+end
+
+describe command("dnscontrol version") do
+  its(:exit_status) { should eq 0 }
+end
diff --git a/test/integration/docker/inspec/docker_spec.rb b/test/integration/docker/inspec/docker_spec.rb
new file mode 100644 (file)
index 0000000..515bd6d
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("docker-ce") do
+  it { should be_installed }
+end
+
+describe service("docker") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/elasticsearch/inspec/elasticsearch_spec.rb b/test/integration/elasticsearch/inspec/elasticsearch_spec.rb
new file mode 100644 (file)
index 0000000..5977b23
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("elasticsearch") do
+  it { should be_installed }
+end
+
+describe service("elasticsearch") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+# describe port(9200) do
+#   it { should be_listening }
+#   its("protocols") { should cmp "tcp" }
+# end
diff --git a/test/integration/exim/inspec/exim_spec.rb b/test/integration/exim/inspec/exim_spec.rb
new file mode 100644 (file)
index 0000000..170ef0a
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("exim4") do
+  it { should be_installed }
+end
+
+describe service("exim4") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(25) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/fail2ban/inspec/fail2ban_spec.rb b/test/integration/fail2ban/inspec/fail2ban_spec.rb
new file mode 100644 (file)
index 0000000..54c6be7
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("fail2ban") do
+  it { should be_installed }
+end
+
+describe service("fail2ban") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/forum/serverspec/mysql_spec.rb b/test/integration/forum/serverspec/mysql_spec.rb
deleted file mode 100644 (file)
index 68e6358..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("mysql-server") do
-  it { should be_installed }
-end
-
-describe service("mysql") do
-  it { should be_enabled }
-  it { should be_running }
-end
-
-describe port(3306) do
-  it { should be_listening }
-end
diff --git a/test/integration/foundation-board/inspec/apache_spec.rb b/test/integration/foundation-board/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/foundation-dwg/inspec/apache_spec.rb b/test/integration/foundation-dwg/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/foundation-mastodon/inspec/apache_spec.rb b/test/integration/foundation-mastodon/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/foundation-mwg/inspec/apache_spec.rb b/test/integration/foundation-mwg/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/foundation-owg/inspec/apache_spec.rb b/test/integration/foundation-owg/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/foundation-welcome/inspec/apache_spec.rb b/test/integration/foundation-welcome/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/foundation-wiki/inspec/apache_spec.rb b/test/integration/foundation-wiki/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/ftp/inspec/vsftpd_spec.rb b/test/integration/ftp/inspec/vsftpd_spec.rb
new file mode 100644 (file)
index 0000000..388370d
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("vsftpd") do
+  it { should be_installed }
+end
+
+describe service("vsftpd") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(21) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/geodns/inspec/gdsnd_spec.rb b/test/integration/geodns/inspec/gdsnd_spec.rb
new file mode 100644 (file)
index 0000000..52befb1
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("gdnsd") do
+  it { should be_installed }
+end
+
+describe service("gdnsd") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(53) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[udp tcp] }
+end
diff --git a/test/integration/git-web/inspec/apache_spec.rb b/test/integration/git-web/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/git-web/inspec/gitweb_spec.rb b/test/integration/git-web/inspec/gitweb_spec.rb
new file mode 100644 (file)
index 0000000..6db5339
--- /dev/null
@@ -0,0 +1,3 @@
+describe package("gitweb") do
+  it { should be_installed }
+end
diff --git a/test/integration/git/inspec/git_spec.rb b/test/integration/git/inspec/git_spec.rb
new file mode 100644 (file)
index 0000000..92c6c1f
--- /dev/null
@@ -0,0 +1,3 @@
+describe package("git") do
+  it { should be_installed }
+end
diff --git a/test/integration/gps-tile/inspec/apache_spec.rb b/test/integration/gps-tile/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/gps-tile/inspec/gpsupdate_spec.rb b/test/integration/gps-tile/inspec/gpsupdate_spec.rb
new file mode 100644 (file)
index 0000000..36add24
--- /dev/null
@@ -0,0 +1,4 @@
+describe service("gps-update") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/hot/inspec/apache_spec.rb b/test/integration/hot/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/ideditor/inspec/apache_spec.rb b/test/integration/ideditor/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/imagery-tiler/inspec/nginx_spec.rb b/test/integration/imagery-tiler/inspec/nginx_spec.rb
new file mode 100644 (file)
index 0000000..366cecb
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("nginx") do
+  it { should be_installed }
+end
+
+describe service("nginx") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/imagery-tiler/inspec/tiler_spec.rb b/test/integration/imagery-tiler/inspec/tiler_spec.rb
new file mode 100644 (file)
index 0000000..366cecb
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("nginx") do
+  it { should be_installed }
+end
+
+describe service("nginx") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/irc/inspec/apache_spec.rb b/test/integration/irc/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/kibana/inspec/apache_spec.rb b/test/integration/kibana/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/logstash-forwarder/inspec/filebeat_spec.rb b/test/integration/logstash-forwarder/inspec/filebeat_spec.rb
new file mode 100644 (file)
index 0000000..10d7dcf
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("filebeat") do
+  it { should be_installed }
+end
+
+describe service("filebeat") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/logstash/inspec/elasticsearch_spec.rb b/test/integration/logstash/inspec/elasticsearch_spec.rb
new file mode 100644 (file)
index 0000000..5977b23
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("elasticsearch") do
+  it { should be_installed }
+end
+
+describe service("elasticsearch") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+# describe port(9200) do
+#   it { should be_listening }
+#   its("protocols") { should cmp "tcp" }
+# end
diff --git a/test/integration/logstash/inspec/logstash_spec.rb b/test/integration/logstash/inspec/logstash_spec.rb
new file mode 100644 (file)
index 0000000..0ebfe55
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("logstash") do
+  it { should be_installed }
+end
+
+describe service("logstash") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+# describe port(5044) do
+#   it { should be_listening }
+#   its("protocols") { should cmp "tcp" }
+# end
diff --git a/test/integration/mail/inspec/clamav_spec.rb b/test/integration/mail/inspec/clamav_spec.rb
new file mode 100644 (file)
index 0000000..f70323c
--- /dev/null
@@ -0,0 +1,17 @@
+describe package("clamav-daemon") do
+  it { should be_installed }
+end
+
+describe service("clamav-daemon") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe package("clamav-freshclam") do
+  it { should be_installed }
+end
+
+describe service("clamav-freshclam") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/mail/inspec/exim_spec.rb b/test/integration/mail/inspec/exim_spec.rb
new file mode 100644 (file)
index 0000000..170ef0a
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("exim4") do
+  it { should be_installed }
+end
+
+describe service("exim4") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(25) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/mail/inspec/spamassassin_spec.rb b/test/integration/mail/inspec/spamassassin_spec.rb
new file mode 100644 (file)
index 0000000..18506ea
--- /dev/null
@@ -0,0 +1,19 @@
+service_name = if os.name == "debian"
+                 "spamd"
+               else
+                 "spamassassin"
+               end
+
+describe package("spamassassin") do
+  it { should be_installed }
+end
+
+describe service(service_name) do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(783) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/mailman/inspec/apache_spec.rb b/test/integration/mailman/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/mailman/inspec/mailman_spec.rb b/test/integration/mailman/inspec/mailman_spec.rb
new file mode 100644 (file)
index 0000000..8f858b1
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("mailman") do
+  it { should be_installed }
+end
+
+describe service("mailman") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/matomo/inspec/apache_spec.rb b/test/integration/matomo/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/memcached/inspec/memcached_spec.rb b/test/integration/memcached/inspec/memcached_spec.rb
new file mode 100644 (file)
index 0000000..72efd17
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("memcached") do
+  it { should be_installed }
+end
+
+describe service("memcached") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(11211) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/munin-server/serverspec/apache_spec.rb b/test/integration/munin-server/serverspec/apache_spec.rb
deleted file mode 100644 (file)
index 57b0b7d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("apache2") do
-  it { should be_installed }
-end
-
-describe service("apache2") do
-  it { should be_enabled }
-  it { should be_running }
-end
-
-describe port(80) do
-  it { should be_listening }
-end
-
-describe port(443) do
-  it { should_not be_listening }
-end
diff --git a/test/integration/munin-server/serverspec/munin_spec.rb b/test/integration/munin-server/serverspec/munin_spec.rb
deleted file mode 100644 (file)
index eeae1e4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("munin") do
-  it { should be_installed }
-end
diff --git a/test/integration/munin-server/serverspec/rrdcached_spec.rb b/test/integration/munin-server/serverspec/rrdcached_spec.rb
deleted file mode 100644 (file)
index dad61e8..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("rrdcached") do
-  it { should be_installed }
-end
-
-describe service("rrdcached") do
-  it { should be_enabled }
-  it { should be_running }
-end
diff --git a/test/integration/munin/serverspec/munin_node_spec.rb b/test/integration/munin/serverspec/munin_node_spec.rb
deleted file mode 100644 (file)
index 5fbe383..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("munin-node") do
-  it { should be_installed }
-end
-
-describe service("munin-node") do
-  it { should be_enabled }
-  it { should be_running }
-end
-
-describe port(4949) do
-  it { should be_listening }
-end
diff --git a/test/integration/mysql/inspec/mysql_spec.rb b/test/integration/mysql/inspec/mysql_spec.rb
new file mode 100644 (file)
index 0000000..549f33d
--- /dev/null
@@ -0,0 +1,19 @@
+mysql_variant = if os.name == "ubuntu"
+                  "mysql"
+                else
+                  "mariadb"
+                end
+
+describe package("#{mysql_variant}-server") do
+  it { should be_installed }
+end
+
+describe service("#{mysql_variant}") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(3306) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/mysql/serverspec/mysql_spec.rb b/test/integration/mysql/serverspec/mysql_spec.rb
deleted file mode 100644 (file)
index 68e6358..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("mysql-server") do
-  it { should be_installed }
-end
-
-describe service("mysql") do
-  it { should be_enabled }
-  it { should be_running }
-end
-
-describe port(3306) do
-  it { should be_listening }
-end
diff --git a/test/integration/networking/inspec/nftables_spec.rb b/test/integration/networking/inspec/nftables_spec.rb
new file mode 100644 (file)
index 0000000..c928d2b
--- /dev/null
@@ -0,0 +1,15 @@
+describe package("nftables") do
+  it { should be_installed }
+end
+
+describe service("nftables") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe file("/etc/nftables.conf") do
+  it { should be_file }
+  its(:content) { should match(/echo-request.*accept/) }
+  its(:content) { should match(/http.*accept/) }
+  its(:content) { should match(/https.*accept/) }
+end
diff --git a/test/integration/networking/serverspec/shorewall_spec.rb b/test/integration/networking/serverspec/shorewall_spec.rb
deleted file mode 100644 (file)
index 2518b72..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-require "serverspec"
-
-# Required by serverspec
-set :backend, :exec
-
-describe package("shorewall") do
-  it { should be_installed }
-end
-
-describe service("shorewall") do
-  it { should be_enabled }
-  it { should be_running }
-end
-
-describe file("/etc/shorewall/rules") do
-  it { should be_file }
-  its(:content) { should match(/ACCEPT.*echo-request/) }
-  its(:content) { should match(/ACCEPT.*http/) }
-  its(:content) { should match(/ACCEPT.*https/) }
-end
diff --git a/test/integration/nginx/inspec/nginx_spec.rb b/test/integration/nginx/inspec/nginx_spec.rb
new file mode 100644 (file)
index 0000000..b8f124f
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("nginx") do
+  it { should be_installed }
+end
+
+describe service("nginx") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(8050) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/nodejs/inspec/nodejs_spec.rb b/test/integration/nodejs/inspec/nodejs_spec.rb
new file mode 100644 (file)
index 0000000..eef75a2
--- /dev/null
@@ -0,0 +1,7 @@
+describe package("nodejs") do
+  it { should be_installed }
+end
+
+describe package("yarn") do
+  it { should be_installed }
+end
diff --git a/test/integration/nominatim/inspec/nginx_spec.rb b/test/integration/nominatim/inspec/nginx_spec.rb
new file mode 100644 (file)
index 0000000..b8f124f
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("nginx") do
+  it { should be_installed }
+end
+
+describe service("nginx") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(8050) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/ntp/inspec/chronyd_spec.rb b/test/integration/ntp/inspec/chronyd_spec.rb
new file mode 100644 (file)
index 0000000..90e6563
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("chrony") do
+  it { should be_installed }
+end
+
+describe service("chronyd") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/openssh/inspec/openssh_spec.rb b/test/integration/openssh/inspec/openssh_spec.rb
new file mode 100644 (file)
index 0000000..6560895
--- /dev/null
@@ -0,0 +1,17 @@
+describe package("openssh-client") do
+  it { should be_installed }
+end
+
+describe package("openssh-server") do
+  it { should be_installed }
+end
+
+describe service("ssh") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(22) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/osmosis/inspec/osmosis_spec.rb b/test/integration/osmosis/inspec/osmosis_spec.rb
new file mode 100644 (file)
index 0000000..6757d1e
--- /dev/null
@@ -0,0 +1,3 @@
+describe file("/usr/local/bin/osmosis") do
+  it { should be_symlink }
+end
diff --git a/test/integration/osqa/inspec/apache_spec.rb b/test/integration/osqa/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/otrs-debian/inspec/apache_spec.rb b/test/integration/otrs-debian/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/otrs/inspec/apache_spec.rb b/test/integration/otrs/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/overpass/inspec/apache_spec.rb b/test/integration/overpass/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/php-apache/inspec/apache_spec.rb b/test/integration/php-apache/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/planet-dump/inspec/planetdump_spec.rb b/test/integration/planet-dump/inspec/planetdump_spec.rb
new file mode 100644 (file)
index 0000000..71891e3
--- /dev/null
@@ -0,0 +1,9 @@
+describe file("/opt/planet-dump-ng/planet-dump-ng") do
+  it { should be_file }
+  it { should be_executable }
+end
+
+describe file("/usr/local/bin/planetdump") do
+  it { should be_file }
+  it { should be_executable }
+end
diff --git a/test/integration/planet-notes/inspec/planetdump_spec.rb b/test/integration/planet-notes/inspec/planetdump_spec.rb
new file mode 100644 (file)
index 0000000..be7a946
--- /dev/null
@@ -0,0 +1,9 @@
+describe file("/usr/local/bin/planet-notes-dump") do
+  it { should be_file }
+  it { should be_executable }
+end
+
+describe service("planet-notes-dump.timer") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/planet/inspec/apache_spec.rb b/test/integration/planet/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..fa98727
--- /dev/null
@@ -0,0 +1,193 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe http("http://localhost") do
+  its("status") { should cmp 200 }
+end
+
+# Minutely Replication Diffs
+
+describe http("https://127.0.0.1/replication/minute/state.txt",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/minute/state.txt" }
+end
+
+describe http("https://127.0.0.1/replication/changesets/001/002/003.state.txt",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/changesets/replication/minute/001/002/003.state.txt" }
+end
+
+describe http("https://127.0.0.1/replication/minute/001/002/003.osc.gz",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/minute/001/002/003.osc.gz" }
+end
+
+# Hourly Replication Diffs
+
+describe http("https://127.0.0.1/replication/hour/state.txt",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/hour/state.txt" }
+end
+
+describe http("https://127.0.0.1/replication/hour/001/002/003.state.txt",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/hour/001/002/003.state.txt" }
+end
+
+describe http("https://127.0.0.1/replication/minute/001/002/003.osc.gz",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/minute/001/002/003.osc.gz" }
+end
+
+# Daily Replication Diffs
+
+describe http("https://127.0.0.1/replication/day/state.txt",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/day/state.txt" }
+end
+
+describe http("https://127.0.0.1/replication/day/001/002/003.state.txt",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/day/001/002/003.state.txt" }
+end
+
+describe http("https://127.0.0.1/replication/day/001/002/003.osc.gz",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/replication/day/001/002/003.osc.gz" }
+end
+
+# Changeset Replication Diffs
+
+describe http("https://127.0.0.1/replication/changesets/state.yaml",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/changesets/replication/minute/state.yaml" }
+end
+
+describe http("https://127.0.0.1/replication/changesets/001/002/003.state.txt",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/changesets/replication/minute/001/002/003.state.txt" }
+end
+
+describe http("https://127.0.0.1/replication/changesets/001/002/003.osm.gz",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/changesets/replication/minute/001/002/003.osm.gz" }
+end
+
+# Planet File
+
+describe http("https://127.0.0.1/planet/2023/planet-231016.osm.bz2",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/osm/2023/planet-231016.osm.bz2" }
+end
+
+# Planet File MD5
+
+describe http("https://127.0.0.1/planet/2023/planet-231016.osm.bz2.md5",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/osm/2023/planet-231016.osm.bz2.md5" }
+end
+
+# Full History Planet File
+
+describe http("https://127.0.0.1/planet/full-history/2023/history-231016.osm.bz2",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet-full-history/osm/2023/history-231016.osm.bz2" }
+end
+
+# Full History Planet File MD5
+
+describe http("https://127.0.0.1/planet/full-history/2023/history-231016.osm.bz2.md5",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet-full-history/osm/2023/history-231016.osm.bz2.md5" }
+end
+
+# PBF planet file
+
+describe http("https://127.0.0.1/pbf/planet-231016.osm.pbf",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet/pbf/2023/planet-231016.osm.pbf" }
+end
+
+# PBF full history planet file
+
+describe http("https://127.0.0.1/pbf/full-history/history-231016.osm.pbf",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/planet-full-history/pbf/2023/history-231016.osm.pbf" }
+end
+
+# Notes file
+
+describe http("https://127.0.0.1/notes/2023/planet-notes-231222.osn.bz2",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/notes/osn/2023/planet-notes-231222.osn.bz2" }
+end
+
+describe http("https://127.0.0.1/notes/2023/planet-notes-231222.osn.bz2.md5",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/notes/osn/2023/planet-notes-231222.osn.bz2.md5" }
+end
+
+# Tiles log
+
+describe http("https://127.0.0.1/tile_logs/tiles-2023-10-21.txt.xz",
+              :headers => { "Host" => "planet.openstreetmap.org" },
+              :ssl_verify => false) do
+  its("status") { should eq 302 }
+  its("headers.Location") { should eq "https://osm-planet-eu-central-1.s3.dualstack.eu-central-1.amazonaws.com/tile_logs/standard_layer/tiles/2023/tiles-2023-10-21.txt.xz" }
+end
diff --git a/test/integration/postgresql/inspec/postgresql_spec.rb b/test/integration/postgresql/inspec/postgresql_spec.rb
new file mode 100644 (file)
index 0000000..4c5872e
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("postgresql-15") do
+  it { should be_installed }
+end
+
+describe service("postgresql@15-main") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(5432) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/prometheus-server/inspec/alertmanager_spec.rb b/test/integration/prometheus-server/inspec/alertmanager_spec.rb
new file mode 100644 (file)
index 0000000..bbdc651
--- /dev/null
@@ -0,0 +1,9 @@
+describe service("prometheus-alertmanager") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(9093) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/prometheus-server/inspec/apache_spec.rb b/test/integration/prometheus-server/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/prometheus-server/inspec/grafana_spec.rb b/test/integration/prometheus-server/inspec/grafana_spec.rb
new file mode 100644 (file)
index 0000000..f568f8f
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("grafana-enterprise") do
+  it { should be_installed }
+end
+
+describe service("grafana-server") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(3000) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/prometheus-server/inspec/karma_spec.rb b/test/integration/prometheus-server/inspec/karma_spec.rb
new file mode 100644 (file)
index 0000000..c907b46
--- /dev/null
@@ -0,0 +1,9 @@
+describe service("prometheus-karma") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(8081) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/prometheus-server/inspec/prometheus_spec.rb b/test/integration/prometheus-server/inspec/prometheus_spec.rb
new file mode 100644 (file)
index 0000000..5426941
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("prometheus") do
+  it { should be_installed }
+end
+
+describe service("prometheus") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(9090) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/prometheus/inspec/prometheus_node_exporter_spec.rb b/test/integration/prometheus/inspec/prometheus_node_exporter_spec.rb
new file mode 100644 (file)
index 0000000..42d26a0
--- /dev/null
@@ -0,0 +1,9 @@
+describe service("prometheus-node-exporter") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(9100) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/rsyncd/inspec/rsync_spec.rb b/test/integration/rsyncd/inspec/rsync_spec.rb
new file mode 100644 (file)
index 0000000..d284182
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("rsync") do
+  it { should be_installed }
+end
+
+describe service("rsync") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(873) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/serverinfo/inspec/apache_spec.rb b/test/integration/serverinfo/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/snmpd/inspec/snmpd_spec.rb b/test/integration/snmpd/inspec/snmpd_spec.rb
new file mode 100644 (file)
index 0000000..1e44d40
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("snmpd") do
+  it { should be_installed }
+end
+
+describe service("snmpd") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(161) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[udp] }
+end
diff --git a/test/integration/spamassassin/inspec/spamassassin_spec.rb b/test/integration/spamassassin/inspec/spamassassin_spec.rb
new file mode 100644 (file)
index 0000000..18506ea
--- /dev/null
@@ -0,0 +1,19 @@
+service_name = if os.name == "debian"
+                 "spamd"
+               else
+                 "spamassassin"
+               end
+
+describe package("spamassassin") do
+  it { should be_installed }
+end
+
+describe service(service_name) do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(783) do
+  it { should be_listening }
+  its("protocols") { should cmp %w[tcp tcp6] }
+end
diff --git a/test/integration/stateofthemap-container/inspec/apache_spec.rb b/test/integration/stateofthemap-container/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/stateofthemap-wordpress/inspec/apache_spec.rb b/test/integration/stateofthemap-wordpress/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/subversion/inspec/apache_spec.rb b/test/integration/subversion/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/supybot/inspec/supybot_spec.rb b/test/integration/supybot/inspec/supybot_spec.rb
new file mode 100644 (file)
index 0000000..53cd93f
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("limnoria") do
+  it { should be_installed }
+end
+
+describe service("supybot") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/switch2osm/inspec/apache_spec.rb b/test/integration/switch2osm/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/sysfs/inspec/sysfsutils_spec.rb b/test/integration/sysfs/inspec/sysfsutils_spec.rb
new file mode 100644 (file)
index 0000000..da429ae
--- /dev/null
@@ -0,0 +1,8 @@
+describe package("sysfsutils") do
+  it { should be_installed }
+end
+
+describe service("sysfsutils") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/taginfo/inspec/apache_spec.rb b/test/integration/taginfo/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/tile/inspec/apache_spec.rb b/test/integration/tile/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/trac/inspec/apache_spec.rb b/test/integration/trac/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/web-cgimap/inspec/cgimap_spec.rb b/test/integration/web-cgimap/inspec/cgimap_spec.rb
new file mode 100644 (file)
index 0000000..2d39534
--- /dev/null
@@ -0,0 +1,8 @@
+describe service("cgimap") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe file("/run/cgimap/socket") do
+  it { should be_socket }
+end
diff --git a/test/integration/web-frontend/inspec/apache_spec.rb b/test/integration/web-frontend/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/web-frontend/inspec/cgimap_spec.rb b/test/integration/web-frontend/inspec/cgimap_spec.rb
new file mode 100644 (file)
index 0000000..2d39534
--- /dev/null
@@ -0,0 +1,8 @@
+describe service("cgimap") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe file("/run/cgimap/socket") do
+  it { should be_socket }
+end
diff --git a/test/integration/web-frontend/inspec/memcached_spec.rb b/test/integration/web-frontend/inspec/memcached_spec.rb
new file mode 100644 (file)
index 0000000..72efd17
--- /dev/null
@@ -0,0 +1,13 @@
+describe package("memcached") do
+  it { should be_installed }
+end
+
+describe service("memcached") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(11211) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/web-frontend/inspec/rails_spec.rb b/test/integration/web-frontend/inspec/rails_spec.rb
new file mode 100644 (file)
index 0000000..69e9da3
--- /dev/null
@@ -0,0 +1,14 @@
+describe service("api-statistics") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe service("rails-jobs@mailers") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe service("rails-jobs@storage") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/web-rails/inspec/apache_spec.rb b/test/integration/web-rails/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/web-rails/inspec/rails_spec.rb b/test/integration/web-rails/inspec/rails_spec.rb
new file mode 100644 (file)
index 0000000..65d82b6
--- /dev/null
@@ -0,0 +1,4 @@
+describe service("api-statistics") do
+  it { should be_enabled }
+  it { should be_running }
+end
diff --git a/test/integration/wiki/inspec/apache_spec.rb b/test/integration/wiki/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
diff --git a/test/integration/wordpress/inspec/apache_spec.rb b/test/integration/wordpress/inspec/apache_spec.rb
new file mode 100644 (file)
index 0000000..8006330
--- /dev/null
@@ -0,0 +1,18 @@
+describe package("apache2") do
+  it { should be_installed }
+end
+
+describe service("apache2") do
+  it { should be_enabled }
+  it { should be_running }
+end
+
+describe port(80) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end
+
+describe port(443) do
+  it { should be_listening }
+  its("protocols") { should cmp "tcp" }
+end