From e7e6bc793e728e8468cda4656a242ffdd37fe76f Mon Sep 17 00:00:00 2001 From: David Siaw Date: Fri, 29 Mar 2024 20:14:04 +0900 Subject: [PATCH] make the king arm-friendly --- .github/workflows/default.yml | 4 +-- .rubocop.yml | 6 ++++ .rubocop_todo.yml | 2 +- lib/kaiser/cli.rb | 22 +++++++++++-- lib/kaiser/cmds/shutdown.rb | 2 +- lib/kaiser/cmds/up.rb | 20 +++++++++--- lib/kaiser/kaiserfile.rb | 4 +++ lib/kaiser/version.rb | 2 +- spec/cli_spec.rb | 20 ++++++++++++ spec/cmds/up_spec.rb | 59 +++++++++++++++++++++++++++++++++++ spec/kaiserfile_spec.rb | 20 ++++++++++++ spec/plugins/database_spec.rb | 2 +- 12 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 spec/cmds/up_spec.rb diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index dcd0affd..0e43c970 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -3,7 +3,7 @@ name: default jobs: rspec: container: - image: ruby:2.7 + image: ruby:3.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -23,7 +23,7 @@ jobs: run: bundle exec rspec rubocop: container: - image: ruby:2.7 + image: ruby:3.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.rubocop.yml b/.rubocop.yml index cc32da4b..0c7a7df4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1 +1,7 @@ inherit_from: .rubocop_todo.yml + +# don't look at blocklength for specs +# its basically what they do anyway +Metrics/BlockLength: + Exclude: + - 'spec/**/*.rb' \ No newline at end of file diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 774cecaa..797b66bf 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -43,7 +43,7 @@ Lint/ConstantDefinitionInBlock: # Offense count: 11 # Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods, CountRepeatedAttributes. Metrics/AbcSize: - Max: 57 + Max: 58 # Offense count: 7 # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, AllowedMethods, AllowedPatterns, IgnoredMethods. diff --git a/lib/kaiser/cli.rb b/lib/kaiser/cli.rb index 1a695bc7..d7db189a 100644 --- a/lib/kaiser/cli.rb +++ b/lib/kaiser/cli.rb @@ -396,6 +396,10 @@ def services @services ||= Config.kaiserfile.services.map { |name, info| Service.new(envname, name, info) } end + def force_platform + Config.kaiserfile.platform || '' + end + def db_port Config.config[:envs][envname][:db_port] end @@ -520,6 +524,19 @@ def prepare_cert_volume! end end + def selenium_node_image + return ENV['OVERRIDE_SELENIUM_NODE_IMAGE'] unless ENV['OVERRIDE_SELENIUM_NODE_IMAGE'].nil? + + if RUBY_PLATFORM.start_with?('arm64') || RUBY_PLATFORM.start_with?('aarch64') + # use the seleniarm image because its more stable in arm procs + # somehow the x64 image does not do well under qemu under arm + return 'seleniarm/standalone-chromium' + end + + # default to x64 image + 'selenium/standalone-chrome-debug' + end + def ensure_setup ensure_env @@ -540,9 +557,10 @@ def ensure_setup Config.config[:shared_names][:chrome], "docker run -d -p 5900:5900 + --shm-size='2g' --name #{Config.config[:shared_names][:chrome]} --network #{Config.config[:networkname]} - selenium/standalone-chrome-debug" + #{selenium_node_image}" ) run_if_dead( Config.config[:shared_names][:nginx], @@ -580,7 +598,7 @@ def network def container_dead?(container) x = JSON.parse(`docker inspect #{container} 2>/dev/null`) - return true if x.empty? || x[0]['State']['Running'] == false + x.empty? || x[0]['State']['Running'] == false end def if_container_dead(container) diff --git a/lib/kaiser/cmds/shutdown.rb b/lib/kaiser/cmds/shutdown.rb index a1cb9174..49fcd194 100644 --- a/lib/kaiser/cmds/shutdown.rb +++ b/lib/kaiser/cmds/shutdown.rb @@ -14,7 +14,7 @@ def usage end def execute(_opts) - Config.config[:shared_names].each do |_, container_name| + Config.config[:shared_names].each_value do |container_name| killrm container_name end diff --git a/lib/kaiser/cmds/up.rb b/lib/kaiser/cmds/up.rb index f8a556db..16b42661 100644 --- a/lib/kaiser/cmds/up.rb +++ b/lib/kaiser/cmds/up.rb @@ -28,14 +28,24 @@ def execute(opts) end end + def build_cmd + platform_args = '' + platform_args = "--platform=#{force_platform}" unless force_platform.empty? + build_args = docker_build_args.map { |k, v| "--build-arg #{k}=#{v}" } + [ + 'docker build', + "-t kaiser:#{envname}-#{current_branch}", + "-f #{tmp_dockerfile_name} #{Config.work_dir}", + platform_args, + build_args.join(' ').to_s + ] + end + def setup_app Config.info_out.puts 'Setting up application' File.write(tmp_dockerfile_name, docker_file_contents) - build_args = docker_build_args.map { |k, v| "--build-arg #{k}=#{v}" } - CommandRunner.run! Config.out, "docker build - -t kaiser:#{envname}-#{current_branch} - -f #{tmp_dockerfile_name} #{Config.work_dir} - #{build_args.join(' ')}" + + CommandRunner.run! Config.out, build_cmd.join("\n\t") FileUtils.rm(tmp_dockerfile_name) end end diff --git a/lib/kaiser/kaiserfile.rb b/lib/kaiser/kaiserfile.rb index 0fcb74b7..e2f74f3a 100644 --- a/lib/kaiser/kaiserfile.rb +++ b/lib/kaiser/kaiserfile.rb @@ -76,6 +76,10 @@ def db(image, } end + def force_platform(platform_name) + @platform = platform_name + end + def expose(port) @port = port end diff --git a/lib/kaiser/version.rb b/lib/kaiser/version.rb index e0c9e8dd..27b3ecd5 100644 --- a/lib/kaiser/version.rb +++ b/lib/kaiser/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Kaiser - VERSION = '0.6.7' + VERSION = '0.7.0' end diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index 9cc92924..0a4ad3d3 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -46,4 +46,24 @@ expect(cli.send(:db_image)).to eq('postgres:alpine') end end + + describe '#selenium_node_image' do + it 'for x86 machines returns normal selenium' do + cli = Kaiser::Cli.new + stub_const('RUBY_PLATFORM', 'x86_64-linux') + expect(cli.send(:selenium_node_image)).to eq('selenium/standalone-chrome-debug') + end + + it 'for arm machines on mac' do + cli = Kaiser::Cli.new + stub_const('RUBY_PLATFORM', 'arm64-darwin23') + expect(cli.send(:selenium_node_image)).to eq('seleniarm/standalone-chromium') + end + + it 'for arm machines on linux' do + cli = Kaiser::Cli.new + stub_const('RUBY_PLATFORM', 'aarch64-linux') + expect(cli.send(:selenium_node_image)).to eq('seleniarm/standalone-chromium') + end + end end diff --git a/spec/cmds/up_spec.rb b/spec/cmds/up_spec.rb new file mode 100644 index 00000000..e91cfb66 --- /dev/null +++ b/spec/cmds/up_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +RSpec.describe Kaiser::Cmds::Up do + describe 'cmd' do + it 'generates correctly' do + kaiserfile = double(Kaiser::Kaiserfile) + kaiserconfig = double(Kaiser::Config) + + allow(Kaiser::Config).to receive(:kaiserfile).and_return(kaiserfile) + allow(Kaiser::Config).to receive(:config).and_return(kaiserconfig) + + allow(Kaiser::Config).to receive(:work_dir).and_return('somedir') + + envs = double('Hash') + allow(envs).to receive(:[]).with('somedir').and_return('meow') + + allow(Kaiser::Config.kaiserfile).to receive(:docker_build_args).and_return({}) + allow(Kaiser::Config.config).to receive(:[]).with(:envnames).and_return(envs) + + obj = described_class.new + allow(obj).to receive(:current_branch).and_return('master') + + allow(kaiserfile).to receive(:platform).and_return('') + + expect(obj.build_cmd[0]).to eq 'docker build' + expect(obj.build_cmd[1]).to eq '-t kaiser:meow-master' + expect(obj.build_cmd[2]).to eq '-f /meow-dockerfile somedir' + expect(obj.build_cmd[3].to_s).to eq '' + end + + it 'generates the appropriate build platform' do + kaiserfile = double(Kaiser::Kaiserfile) + kaiserconfig = double(Kaiser::Config) + + allow(Kaiser::Config).to receive(:kaiserfile).and_return(kaiserfile) + allow(Kaiser::Config).to receive(:config).and_return(kaiserconfig) + + allow(Kaiser::Config).to receive(:work_dir).and_return('somedir') + + envs = double('Hash') + allow(envs).to receive(:[]).with('somedir').and_return('meow') + + allow(kaiserfile).to receive(:platform).and_return('linux/catcpu') + + allow(Kaiser::Config.kaiserfile).to receive(:docker_build_args).and_return({}) + allow(Kaiser::Config.config).to receive(:[]).with(:envnames).and_return(envs) + + obj = described_class.new + allow(obj).to receive(:current_branch).and_return('master') + + allow(kaiserfile).to receive(:platform).and_return('linux/catcpu') + + expect(obj.build_cmd[0]).to eq 'docker build' + expect(obj.build_cmd[1]).to eq '-t kaiser:meow-master' + expect(obj.build_cmd[2]).to eq '-f /meow-dockerfile somedir' + expect(obj.build_cmd[3]).to eq '--platform=linux/catcpu' + end + end +end diff --git a/spec/kaiserfile_spec.rb b/spec/kaiserfile_spec.rb index c661ab2a..6075789d 100644 --- a/spec/kaiserfile_spec.rb +++ b/spec/kaiserfile_spec.rb @@ -171,6 +171,26 @@ end end + context '#force_platform' do + context 'when force_platform is specified' do + let(:kaiserfile_contents) { "force_platform 'catcpu'" } + + it 'sets platform' do + kaiserfile = Kaiser::Kaiserfile.new('Kaiserfile') + expect(kaiserfile.platform).to eq('catcpu') + end + end + + context 'when force_platform is not specified' do + let(:kaiserfile_contents) { '' } + + it 'platform is nil' do + kaiserfile = Kaiser::Kaiserfile.new('Kaiserfile') + expect(kaiserfile.platform).to be_nil + end + end + end + context '#service' do context 'when service is specified' do let(:kaiserfile_contents) { "service 'santaclaus'" } diff --git a/spec/plugins/database_spec.rb b/spec/plugins/database_spec.rb index 0c37cb12..239e0a68 100644 --- a/spec/plugins/database_spec.rb +++ b/spec/plugins/database_spec.rb @@ -53,7 +53,7 @@ kaiserfile = Kaiser::Kaiserfile.new('Kaiserfile') allow(kaiserfile).to receive(:require).with('kaiser/databases/somebase') { true } - expect(db_class).to receive(:new) { db_driver }.with(hello: :meow) + expect(db_class).to receive(:new) { db_driver }.with({ hello: :meow }) expect(db_driver).to receive(:options_hash) { { port: 1234 } } expect(db_driver).to receive(:image_name) { '' } expect(kaiserfile).to receive(:db).with('', port: 1234)