diff --git a/.yamllint b/.yamllint index 5a060ef..73d532d 100644 --- a/.yamllint +++ b/.yamllint @@ -14,7 +14,7 @@ ignore: | .cache/ .git/ node_modules/ - test/**/states/**/*.sls + test/salt/**/*.sls .kitchen/ yaml-files: diff --git a/nginx/config.sls b/nginx/config.sls index 3cd00b5..82b181f 100644 --- a/nginx/config.sls +++ b/nginx/config.sls @@ -31,3 +31,6 @@ nginx_config: - context: config: {{ nginx.server.config|json(sort_keys=False) }} {% endif %} +{% if nginx.check_config_before_apply %} + - check_cmd: /usr/sbin/nginx -t -c +{% endif %} diff --git a/nginx/map.jinja b/nginx/map.jinja index c273349..5b3e1bd 100644 --- a/nginx/map.jinja +++ b/nginx/map.jinja @@ -9,7 +9,7 @@ 'Debian': { 'package': 'nginx', 'passenger_package': 'passenger', - 'passenger_config_file': '/etc/nginx/conf.d/passenger.conf', + 'passenger_config_file': '/etc/nginx/conf.d/mod-http-passenger.conf', 'service': 'nginx', 'webuser': 'www-data', 'conf_file': '/etc/nginx/nginx.conf', @@ -112,6 +112,7 @@ 'install_from_ppa': False, 'install_from_repo': False, 'install_from_phusionpassenger': False, + 'check_config_before_apply': False, 'ppa_version': 'stable', 'source_version': '1.10.0', 'source_hash': '8ed647c3dd65bc4ced03b0e0f6bf9e633eff6b01bac772bcf97077d58bc2be4d', diff --git a/nginx/passenger.sls b/nginx/passenger.sls index 91808c0..e9ef786 100644 --- a/nginx/passenger.sls +++ b/nginx/passenger.sls @@ -25,6 +25,7 @@ passenger_install: - pkg: nginx_install - require_in: - service: nginx_service + - file: nginx_config /etc/nginx/passenger.conf: file.absent: @@ -46,6 +47,7 @@ passenger_config: - service: nginx_service - require_in: - service: nginx_service + - file: nginx_config - require: - file: /etc/nginx/passenger.conf - pkg: passenger_install diff --git a/nginx/pkg.sls b/nginx/pkg.sls index 3fd8434..a136e18 100644 --- a/nginx/pkg.sls +++ b/nginx/pkg.sls @@ -163,7 +163,7 @@ nginx_phusionpassenger_yum_repo: - baseurl: 'https://oss-binaries.phusionpassenger.com/yum/passenger/el/$releasever/$basearch' - repo_gpgcheck: 1 - gpgcheck: 0 - - gpgkey: 'https://packagecloud.io/gpg.key' + - gpgkey: 'https://oss-binaries.phusionpassenger.com/yum/definitions/RPM-GPG-KEY.asc' - enabled: True - sslverify: 1 - sslcacert: /etc/pki/tls/certs/ca-bundle.crt diff --git a/nginx/snippets.sls b/nginx/snippets.sls index 31a0a15..d09ba36 100644 --- a/nginx/snippets.sls +++ b/nginx/snippets.sls @@ -28,4 +28,9 @@ nginx_snippet_{{ snippet }}: - context: config: {{ config|json() }} nginx: {{ _nginx|json() }} + - require: + - file: nginx_snippets_dir + - require_in: + - file: nginx_config + - service: nginx_service {% endfor %} diff --git a/pillar.example b/pillar.example index 3654979..ce6109b 100644 --- a/pillar.example +++ b/pillar.example @@ -28,6 +28,17 @@ nginx: source_version: '1.10.0' source_hash: '' + # Check the configuration before applying: + # To prevent applying a configuration that might break nginx, set this + # parameter to true so the configuration is checked BEFORE applying. If + # the check fails, the state will fail and it won't be deployed. + # CAVEAT: As the configuration file is created in a temp dir, it can't + # have relative references or it will fail to check. You'll need to + # specify full paths where required (ie, `include`, `load_module`, + # `snippets`, etc.0 + # Defaults to false + check_config_before_apply: false + # These are usually set by grains in map.jinja # Typically you can comment these out. lookup: diff --git a/test/integration/default/controls/config.rb b/test/integration/default/controls/config.rb index a01ef3b..1a405ff 100644 --- a/test/integration/default/controls/config.rb +++ b/test/integration/default/controls/config.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + # Set defaults, use debian as base server_available = '/etc/nginx/sites-available' -server_enabled = '/etc/nginx/sites-enabled' +server_enabled = '/etc/nginx/sites-enabled' # Override by platform family case platform[:family] -when 'redhat','fedora' +when 'redhat', 'fedora' server_available = '/etc/nginx/conf.d' server_enabled = '/etc/nginx/conf.d' when 'suse' @@ -22,9 +24,13 @@ control 'Nginx configuration' do it { should be_owned_by 'root' } it { should be_grouped_into 'root' } its('mode') { should cmp '0644' } - its('content') { should include %Q[ log_format main '$remote_addr - $remote_user [$time_local] $status ' + its('content') do + # rubocop:disable Metrics/LineLength + should include %( log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"';] } + '"$http_user_agent" "$http_x_forwarded_for"';) + # rubocop:enable Metrics/LineLength + end end # snippets configuration @@ -40,12 +46,11 @@ control 'Nginx configuration' do # sites configuration [server_available, server_enabled].each do |dir| - - describe file ("#{dir}/default") do - it { should_not exist } + describe file "#{dir}/default" do + it { should_not exist } end - describe file ("#{dir}/mysite") do + describe file "#{dir}/mysite" do it { should be_file } it { should be_owned_by 'root' } it { should be_grouped_into 'root' } @@ -57,6 +62,5 @@ control 'Nginx configuration' do its('content') { should include 'try_files $uri $uri/ =404;' } its('content') { should include 'include snippets/letsencrypt.conf;' } end - end end diff --git a/test/integration/default/controls/install.rb b/test/integration/default/controls/install.rb index 49aea2e..5aa8d0e 100644 --- a/test/integration/default/controls/install.rb +++ b/test/integration/default/controls/install.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + control 'Nginx package' do title 'should be installed' diff --git a/test/integration/default/controls/service.rb b/test/integration/default/controls/service.rb index c979d24..605e936 100644 --- a/test/integration/default/controls/service.rb +++ b/test/integration/default/controls/service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + control 'Nginx service' do title 'should be running and enabled' diff --git a/test/integration/passenger/README.md b/test/integration/passenger/README.md new file mode 100644 index 0000000..66fa3cd --- /dev/null +++ b/test/integration/passenger/README.md @@ -0,0 +1,50 @@ +# InSpec Profile: `passenger` + +This shows the implementation of the `passenger` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). + +## Verify a profile + +InSpec ships with built-in features to verify a profile structure. + +```bash +$ inspec check passenger +Summary +------- +Location: passenger +Profile: profile +Controls: 4 +Timestamp: 2019-06-24T23:09:01+00:00 +Valid: true + +Errors +------ + +Warnings +-------- +``` + +## Execute a profile + +To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. + +```bash +$ inspec exec passenger +.. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +8 examples, 0 failures +``` + +## Execute a specific control from a profile + +To run one control from the profile use `inspec exec /path/to/profile --controls name`. + +```bash +$ inspec exec passenger --controls package +. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +1 examples, 0 failures +``` + +See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb). diff --git a/test/integration/passenger/controls/config.rb b/test/integration/passenger/controls/config.rb new file mode 100644 index 0000000..177a8dc --- /dev/null +++ b/test/integration/passenger/controls/config.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +# Set defaults, use debian as base + +# Override by OS Family +case platform[:family] +when 'redhat', 'centos', 'fedora' + server_available = '/etc/nginx/conf.d' + server_enabled = '/etc/nginx/conf.d' + passenger_mod = '/usr/lib64/nginx/modules/ngx_http_passenger_module.so' + passenger_root = '/usr/share/ruby/vendor_ruby/phusion_passenger/locations.ini' + passenger_config_file = '/etc/nginx/conf.d/passenger.conf' + should_not_exist_file = '/etc/nginx/conf.d/mod-http-passenger.conf' +when 'debian', 'ubuntu' + server_available = '/etc/nginx/sites-available' + server_enabled = '/etc/nginx/sites-enabled' + passenger_mod = '/usr/lib/nginx/modules/ngx_http_passenger_module.so' + passenger_root = '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini' + passenger_config_file = '/etc/nginx/conf.d/mod-http-passenger.conf' + should_not_exist_file = '/etc/nginx/conf.d/passenger.conf' +end + +control 'Passenger configuration' do + title 'should match desired lines' + + # main configuration + describe file('/etc/nginx/nginx.conf') do + its('content') { should include "load_module #{passenger_mod}" } + end + + describe file(passenger_config_file) do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include "passenger_root #{passenger_root};" } + its('content') { should include 'passenger_ruby /usr/bin/ruby;' } + end + + describe file(should_not_exist_file) do + it { should_not exist } + end + + # sites configuration + [server_available, server_enabled].each do |dir| + describe file "#{dir}/default" do + it { should_not exist } + end + + describe file "#{dir}/mysite" do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'passenger_enabled on;' } + end + end +end diff --git a/test/integration/passenger/controls/install.rb b/test/integration/passenger/controls/install.rb new file mode 100644 index 0000000..bbba8cb --- /dev/null +++ b/test/integration/passenger/controls/install.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +control 'Nginx package' do + title 'should be installed' + + describe package('nginx') do + it { should be_installed } + end +end + +control 'Passenger packages' do + title 'should be installed' + + # Override by OS Family + passenger_mod_pkg = case platform[:family] + when 'redhat', 'centos', 'fedora' + 'nginx-mod-http-passenger' + when 'debian', 'ubuntu' + 'libnginx-mod-http-passenger' + end + + describe package('passenger') do + it { should be_installed } + end + describe package(passenger_mod_pkg) do + it { should be_installed } + end +end diff --git a/test/integration/passenger/controls/service.rb b/test/integration/passenger/controls/service.rb new file mode 100644 index 0000000..b4af800 --- /dev/null +++ b/test/integration/passenger/controls/service.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +control 'Nginx service' do + title 'should be running and enabled' + + describe service('nginx') do + it { should be_enabled } + it { should be_running } + end +end + +control 'Passenger module' do + title 'should be running and enabled' + + describe 'Passenger engine' do + it 'passenger-config should say configuration "looks good"' do + expect(command( + '/usr/bin/passenger-config validate-install --auto' + ).stdout).to match(/looks good/) + end + + it 'passenger-memory-stats should return Passenger stats' do + expect(command('/usr/sbin/passenger-memory-stats').stdout).to match( + %r{nginx: master process /usr/sbin/nginx.*Passenger watchdog.*Passenger core.*}m + ) + end + end +end diff --git a/test/integration/passenger/inspec.yml b/test/integration/passenger/inspec.yml new file mode 100644 index 0000000..08c695d --- /dev/null +++ b/test/integration/passenger/inspec.yml @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +name: default +title: nginx formula +maintainer: SaltStack Formulas +license: Apache-2.0 +summary: Verify that the nginx formula is setup and configured correctly +supports: + - platform-name: debian + - platform-name: ubuntu + - platform-name: centos diff --git a/test/salt/passenger/pillar/nginx.sls b/test/salt/passenger/pillar/nginx.sls new file mode 100644 index 0000000..95edc52 --- /dev/null +++ b/test/salt/passenger/pillar/nginx.sls @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +# Simple pillar setup +# - snippet letsencrypt +# - remove 'default' site +# - create 'mysite' site + +{%- if grains.os_family in ('RedHat',) %} + {%- set passenger_pkg = 'nginx-mod-http-passenger' %} + {%- set passenger_mod = '/usr/lib64/nginx/modules/ngx_http_passenger_module.so' %} +{%- else %} + {%- set passenger_pkg = 'libnginx-mod-http-passenger' %} + {%- set passenger_mod = '/usr/lib/nginx/modules/ngx_http_passenger_module.so' %} +{%- endif %} + +nginx: + check_config_before_apply: true + + install_from_phusionpassenger: true + lookup: + passenger_package: {{ passenger_pkg }} + + snippets: + letsencrypt.conf: + - location ^~ /.well-known/acme-challenge/: + - proxy_pass: http://localhost:9999 + server: + + config: + # This is required to get the passenger module loaded + # In Debian it can be done with this + # include: 'modules-enabled/*.conf' + load_module: {{ passenger_mod }} + + worker_processes: 4 + http: + ### module ngx_http_log_module example + log_format: |- + main '$remote_addr - $remote_user [$time_local] $status ' + '"$request" $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"' + include: + - /etc/nginx/mime.types + - /etc/nginx/conf.d/*.conf + - /etc/nginx/sites-enabled/* + + servers: + managed: + default: + deleted: true + enabled: false + config: {} + + mysite: + enabled: true + config: + - server: + - passenger_enabled: 'on' + + - server_name: localhost + - listen: + - '80 default_server' + - index: 'index.html index.htm' + - location ~ .htm: + - try_files: '$uri $uri/ =404' + # - include: '/etc/nginx/snippets/letsencrypt.conf' + - include: 'snippets/letsencrypt.conf'