Edited at

Chefを使ってCentOS6.5でruby-1.8.7をrbenvからインストールしようとすると失敗するが、インストール出来るようにした

More than 5 years have passed since last update.


Chefを使ってCentOS6.5でruby-1.8.7をrbenvからインストールしようとすると失敗するが、インストール出来るようにした


問題の概要

CentOS6.5でruby-1.8.7をコンパイルすると、opensslの部分でコンパイルエラーになる。

ossl_pkey_ec.c: In function 'ossl_ec_group_initialize':

ossl_pkey_ec.c:761: warning: assignment makes pointer from integer without a cast
ossl_pkey_ec.c:815: error: 'EC_GROUP_new_curve_GF2m' undeclared (first use in this function)
ossl_pkey_ec.c:815: error: (Each undeclared identifier is reported only once
ossl_pkey_ec.c:815: error: for each function it appears in.)

CentOSのopensslパッケージがruby-1.8.7が作成された頃より新しくなったのだが、そのためにミスマッチが生じているらしい。

これの対処法をググると、2つ出てくる。


  1. そのうちopensslの新しいパッケージが出るだろうから、その時に yum install すれば直るだろうから、しばし待て

  2. rubyのossl_pkey_ec.c にパッチを当てろ → https://gist.github.com/hyoshida/11241844

当然2で対応する訳だが、rbenv install にてコンパイルするので、どこでパッチを当てるかという問題になる。

chefからrubyソースにパッチを当てるのか、chefがruby-buildにパッチを当て、ruby-buildがrubyソースにパッチを当てるのか?

最初は、パッチを当てたrubyソースをgithubに置いておきそれをダウンロードするようにして、またruby-buildに専用のバージョン定義ファイルを入れたものを作ってこれもgithubに置いておくようにしていた。

これだとcookbook以外に外部ファイルを2つも置くことになり情報が分散していてよろしくないので、cookbookだけで何とかする方法を探していたが、やり方がわかった。


ruby-buildバージョン定義ファイル中でパッチを当てる

ruby-buildのバージョン定義ファイル内で、rubyソースにパッチを当てる方法がわかった。

定義ファイルはシェルスクリプトであり、その中で before_install_package() 関数を定義してやれば、インストール直前に呼び出される。

この関数の中でパッチを当ててやればいい。

出来た定義ファイルがこれ。


ruby_build/share/ruby-build/1.8.7-p374-centos_openssl

before_install_package() {

if [ "$1" != "ruby-1.8.7-p374" ]; then
return
0
fi
patch -d ${BUILD_PATH}/ruby-1.8.7-p374 -p1 <<PATCH_END
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index cbdad3f..d517b58 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -757,8 +757,10 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
method = EC_GFp_mont_method();
} else if (id == s_GFp_nist) {
method = EC_GFp_nist_method();
+#if !defined(OPENSSL_NO_EC2M)
} else if (id == s_GF2m_simple) {
method = EC_GF2m_simple_method();
+#endif
}

if (method) {
@@ -811,8 +813,10 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)

if (id == s_GFp) {
new_curve = EC_GROUP_new_curve_GFp;
+#if !defined(OPENSSL_NO_EC2M)
} else if (id == s_GF2m) {
new_curve = EC_GROUP_new_curve_GF2m;
+#endif
} else {
rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
}
PATCH_END
echo "openssl patch applied" >&2
}
require_gcc
install_package "ruby-1.8.7-p374" "http://cache.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p374.tar.gz#876eeeaaeeab10cbf4767833547d66d86d6717ef48fd3d89e27db8926a65276c" auto_tcltk standard
install_package "rubygems-1.6.2" "http://production.cf.rubygems.org/rubygems/rubygems-1.6.2.tgz#cb5261818b931b5ea2cb54bc1d583c47823543fcf9682f0d6298849091c1cea7" ruby


これをcookbookの file/ の下に置いておき、レシピ中でruby_buildのダウンロード後に転送してやればいい。

クックブック rbenv を呼び出すので、Berksfile に入れ、metadataにもdependsを記述する。


Berksfile

cookbook 'rbenv'



metadata.rb

depends          'rbenv'


これがレシピ。


recipes/default.rb

include_recipe "rbenv::default"

include_recipe "rbenv::rbenv_vars"
include_recipe "rbenv::ruby_build"

cookbook_file "#{node[:ruby_build][:prefix]}/share/ruby-build/1.8.7-p374-centos_openssl" do
source "1.8.7-p374-centos_openssl"
mode '0644'
owner node[:rbenv][:user]
group node[:rbenv][:group]
end

rbenv_ruby "1.8.7-p374-centos_openssl" do
ruby_version "1.8.7-p374-centos_openssl"
end


cookbookだけで完結してすっきり。