From 38ddee213cccc5a36bb90b0eba82219d1a7ef2e5 Mon Sep 17 00:00:00 2001 From: MattGrundy <38431311+MattGrundy@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:18:47 +0100 Subject: [PATCH] Add workflow file Add is-ready check on the default files tests Add a check the entrypoint is not still running (slightly different case to the ready file that gets added on first boot) --- .github/workflows/pr_tests.yml | 29 ++ test/serverspec/spec/always/paths_spec.rb | 301 ++++++++++++------ .../spec/default_web/utils/is-ready_spec.rb | 17 +- usr/local/bin/is-ready | 6 + usr/local/sbin/entrypoint.sh | 7 + 5 files changed, 263 insertions(+), 97 deletions(-) create mode 100644 .github/workflows/pr_tests.yml diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml new file mode 100644 index 0000000..4365d16 --- /dev/null +++ b/.github/workflows/pr_tests.yml @@ -0,0 +1,29 @@ +name: Spec tests + +on: + push: + branches: + - main + + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + run_test_suite: + name: Run test suite + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Earthly + uses: earthly/actions-setup@v1 + with: + version: 0.8.14 + + - name: Run tests + run: | + earthly -P ./test+test diff --git a/test/serverspec/spec/always/paths_spec.rb b/test/serverspec/spec/always/paths_spec.rb index 969f097..b60eeb6 100644 --- a/test/serverspec/spec/always/paths_spec.rb +++ b/test/serverspec/spec/always/paths_spec.rb @@ -1,101 +1,210 @@ require 'spec_helper' -describe file('/etc/php/8.3') do - it { should exist } - it { should be_directory } +describe "Default file checks" do + before(:all) do + system('/usr/local/bin/is-ready --check-entrypoint --check-tasks --wait --timeout 60 -v') or raise "is-ready failed" + end + + describe file('/etc/php/8.3') do + it { should exist } + it { should be_directory } + end + + describe file('/usr/local/share/deskpro/container-var-reference.json') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its(:content_as_json) { should_not be_empty } + end + + describe file('/usr/local/share/deskpro/container-public-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/container-private-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/container-setenv-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/container-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/phpinfo.php') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/var/log/nginx') do + it { should be_directory } + it { should be_owned_by 'nginx' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/var/log/php') do + it { should be_directory } + it { should be_owned_by 'dp_app' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/var/log/deskpro') do + it { should be_directory } + it { should be_owned_by 'dp_app' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/var/lib/vector') do + it { should be_directory } + it { should be_owned_by 'vector' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/srv/deskpro/INSTANCE_DATA') do + it { should be_directory } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + it { should_not be_writable.by('others') } + end + + describe file('/srv/deskpro/INSTANCE_DATA/deskpro-config.d') do + it { should be_directory } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + it { should_not be_writable.by('others') } + end + + describe file('/srv/deskpro/services/messenger-api/.env') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/container-var-reference.json') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its(:content_as_json) { should_not be_empty } + end + + describe file('/usr/local/share/deskpro/container-public-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/container-private-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/container-setenv-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/container-var-list') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/usr/local/share/deskpro/phpinfo.php') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + end + + describe file('/var/log/nginx') do + it { should be_directory } + it { should be_owned_by 'nginx' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/var/log/php') do + it { should be_directory } + it { should be_owned_by 'dp_app' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/var/log/deskpro') do + it { should be_directory } + it { should be_owned_by 'dp_app' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/var/lib/vector') do + it { should be_directory } + it { should be_owned_by 'vector' } + it { should be_grouped_into 'adm' } + + it { should be_readable.by('owner') } + it { should be_readable.by('group') } + it { should be_writable.by('owner') } + it { should_not be_writable.by('others') } + end + + describe file('/srv/deskpro/INSTANCE_DATA') do + it { should be_directory } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + it { should_not be_writable.by('others') } + end + + describe file('/srv/deskpro/INSTANCE_DATA/deskpro-config.d') do + it { should be_directory } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + it { should_not be_writable.by('others') } + end end -describe file('/usr/local/share/deskpro/container-var-reference.json') do - it { should exist } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } - its(:content_as_json) { should_not be_empty } -end - -describe file('/usr/local/share/deskpro/container-public-var-list') do - it { should exist } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } -end - -describe file('/usr/local/share/deskpro/container-private-var-list') do - it { should exist } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } -end - -describe file('/usr/local/share/deskpro/container-setenv-var-list') do - it { should exist } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } -end - -describe file('/usr/local/share/deskpro/container-var-list') do - it { should exist } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } -end - -describe file('/usr/local/share/deskpro/phpinfo.php') do - it { should exist } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } -end - -describe file('/var/log/nginx') do - it { should be_directory } - it { should be_owned_by 'nginx' } - it { should be_grouped_into 'adm' } - - it { should be_readable.by('owner') } - it { should be_readable.by('group') } - it { should be_writable.by('owner') } - it { should_not be_writable.by('others') } -end - -describe file('/var/log/php') do - it { should be_directory } - it { should be_owned_by 'dp_app' } - it { should be_grouped_into 'adm' } - - it { should be_readable.by('owner') } - it { should be_readable.by('group') } - it { should be_writable.by('owner') } - it { should_not be_writable.by('others') } -end - -describe file('/var/log/deskpro') do - it { should be_directory } - it { should be_owned_by 'dp_app' } - it { should be_grouped_into 'adm' } - - it { should be_readable.by('owner') } - it { should be_readable.by('group') } - it { should be_writable.by('owner') } - it { should_not be_writable.by('others') } -end -describe file('/var/lib/vector') do - it { should be_directory } - it { should be_owned_by 'vector' } - it { should be_grouped_into 'adm' } - - it { should be_readable.by('owner') } - it { should be_readable.by('group') } - it { should be_writable.by('owner') } - it { should_not be_writable.by('others') } -end - -describe file('/srv/deskpro/INSTANCE_DATA') do - it { should be_directory } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } - it { should_not be_writable.by('others') } -end - -describe file('/srv/deskpro/INSTANCE_DATA/deskpro-config.d') do - it { should be_directory } - it { should be_owned_by 'root' } - it { should be_grouped_into 'root' } - it { should_not be_writable.by('others') } -end diff --git a/test/serverspec/spec/default_web/utils/is-ready_spec.rb b/test/serverspec/spec/default_web/utils/is-ready_spec.rb index 7260aff..f50046d 100644 --- a/test/serverspec/spec/default_web/utils/is-ready_spec.rb +++ b/test/serverspec/spec/default_web/utils/is-ready_spec.rb @@ -10,6 +10,7 @@ FileUtils.touch('/run/container-ready') FileUtils.remove_file('/run/container-running-installer', true) FileUtils.remove_file('/run/container-running-migrations', true) + FileUtils.remove_file('/run/container-running-entrypoint', true) end it "Blocks when using --wait", :slow do @@ -87,10 +88,24 @@ expect(exit_code).to eq 0 end - it "Post-boot tasks matter with --check-tasks" do + it "Post-boot migration tasks matter with --check-tasks" do FileUtils.touch('/run/container-running-migrations') system('is-ready --check-tasks') exit_code = $?.exitstatus expect(exit_code).to eq 1 end + + it "Post-boot installer tasks matter with --check-tasks" do + FileUtils.touch('/run/container-running-installer') + system('is-ready --check-tasks') + exit_code = $?.exitstatus + expect(exit_code).to eq 1 + end + + it "Post-boot entrypoint tasks matter with --check-tasks" do + FileUtils.touch('/run/container-running-entrypoint') + system('is-ready --check-tasks') + exit_code = $?.exitstatus + expect(exit_code).to eq 1 + end end diff --git a/usr/local/bin/is-ready b/usr/local/bin/is-ready index eecddbf..d212929 100755 --- a/usr/local/bin/is-ready +++ b/usr/local/bin/is-ready @@ -65,7 +65,13 @@ check_ready() { return 1 fi + if [ "$check_tasks" = "1" ]; then + if [ -f "/run/container-running-entrypoint" ]; then + output "Entrypoint initialisation is running" + return 1 + fi + if [ -f "/run/container-running-installer" ]; then output "Installer is running" return 1 diff --git a/usr/local/sbin/entrypoint.sh b/usr/local/sbin/entrypoint.sh index d077c3a..ed69c19 100755 --- a/usr/local/sbin/entrypoint.sh +++ b/usr/local/sbin/entrypoint.sh @@ -56,6 +56,10 @@ else fi main() { + # store the fact that we're running the entrypoint + date -u +"%Y-%m-%dT%H:%M:%SZ" >> /run/container-running-entrypoint + chmod 0644 /run/container-running-entrypoint + # remove sentinel files that may be set from previous boots # (normally set in container-ready.sh - we want to remove them here, early, because they are used in healthcheck) rm -f /run/container-ready /run/container-running-installer /run/container-running-migrations @@ -139,6 +143,9 @@ main() { date -u +"%Y-%m-%dT%H:%M:%SZ" >> /run/container-booted chmod 0644 /run/container-booted + # remove the sentinel file that indicates we're running the entrypoint + rm -f /run/container-running-entrypoint + case "$l_docker_exec" in exec) boot_log_message INFO "Starting services"