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つ出てくる。
- そのうちopensslの新しいパッケージが出るだろうから、その時に yum install すれば直るだろうから、しばし待て
- 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() 関数を定義してやれば、インストール直前に呼び出される。
この関数の中でパッチを当ててやればいい。
出来た定義ファイルがこれ。
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を記述する。
cookbook 'rbenv'
depends 'rbenv'
これがレシピ。
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だけで完結してすっきり。