:install end service 'nginx' do action [:enable, :start] end CentOS chkconfig nginx on service nginx start Ubuntu systemctl enable nginx systemctl start nginx
package(name, &block) result << ['package', name] end def result; @result ||= []; end end Implementation script = <<-EOS package 'nginx' do action :install end EOS dsl = DSL.new dsl.instance_eval(script) dsl.result #=> [["package", "nginx", {:action=>[:install]}]]
package(name, &block) pkg = Package.new pkg.instance_exec(&block) result << ['package', name, pkg.attrs] end def result; @result ||= []; end end class Package def action(actions) attrs[:action] = Array(actions) end def attrs; @attrs ||= {}; end end Implementation script = <<-EOS package 'nginx' do action :install end EOS dsl = DSL.new dsl.instance_eval(script) dsl.result #=> [["package", "nginx", {:action=>[:install]}]]
for macOS and Linux • We wanted to use Ruby DSL to simply describe operations for multiple OS distributions • For maintenance cost, we used the same Ruby DSL as a server provisioning tool we develop and use, which is Itamae • https://github.com/itamae-kitchen/itamae
difficulties to use MRI on an initial environment • In macOS, we don’t want to use end-of-life Ruby, which is shipped with latest macOS • In Linux, most Linux distro doesn't ship MRI out of the box • We don’t want to manually install MRI prior to bootstrap
use MRI for user’s environment, you have to care about how a gem is set up everytime you run Ruby DSL • Are rbenv and MRIs already installed? • Is the gem installed to MRI currently selected by rbenv? • Packaging ruby, gem, … to run just one gem is a little overkill
enough? • No, our use case is development environment bootstrap and we should also care about dependencies other than MRI • We want to build it as a “single binary” • There are some good ways to do that
DSL • go-mruby • Use mruby only for evaluating Ruby DSL and implement others in Go language • mruby-cli • Implement both Ruby DSL and others using mruby
of “Itamae”, a configuration management tool inspired by Chef • Single binary, built with Go language and go-mruby • https://github.com/k0kubun/itamae-go
Call mrb_load_string str := mrb.LoadString("%w[hello world].join") // Prints "helloworld\n" fmt.Println(mrb.StringValue(str)) How to run Ruby scripts from Go
to connect Ruby and Go world is really boring • Checking errors for all Ruby method calls • Required to use 3 languages: Ruby, Go, C (for mrbgem) • You need to prepare environment for cross compiling by yourself
make it as a single binary • To implement IO operations for development environment bootstrap • Can't we achieve them without Go language? • Try mruby-cli!
apps using mruby • https://github.com/hone/mruby-cli • Eric gave a talk "Building maintainable command-line tools with MRuby" this morning • If you've missed it, watch the video later
same way as MRI • Required to add some “mrbgems” to call methods which is not provided by default • mruby-eval for instance_eval • mruby-object-ext for instance_exec
Unlike rubygem, it’s compiled together when building mruby • So we can use it without adding dependency to a binary • Some of built-in features in MRI are separated to mrbgem in mruby
when they are written in Ruby • Most features required for Ruby programming except keyword arguments are available at existing mrbgems • mrbgems I created to implement MItamae: • mruby-shellwords • mruby-hashie
and Kernel.` (`command`) • But I wanted to capture stdout, stderr and status separately • There were no Open3 and Kernel.#spawn • It was necessary to write C to implement Kernel.#spawn
on command execution $ time itamae version Itamae v1.9.9 itamae version 0.54s user 0.22s system 98% cpu 0.776 total $ time mitamae version MItamae v0.6.0 mitamae version 0.02s user 0.00s system 85% cpu 0.023 total on 1.3 GHz Intel Core m7
configuration management tool configured by Ruby DSL as a single binary using mruby • https://github.com/k0kubun/mitamae • There are 2 ways to build a tool configured by Ruby DSL as a single binary • If there’s a reason to use Go language, use go-mruby • Otherwise mruby-cli is recommended