Canvas LMSのQuick Startを試す(Ubuntu/xenial)
公式ドキュメントが全然使えない
Canvas LMSのお試し環境を作ろうと思い、公式ドキュメントの手順で構築を試みた。しかしドキュメントが更新されていないのか、何度試しても途中で詰まってしまう。そもそも同じドキュメントでRubyのバージョンが異なっていたり、yarnのバージョン指定が無いなどの不備があるので、ドキュメントとしてあまり正確な内容ではないのだろう。(2017/12/24時点の話) github.com
今回の構築環境
あくまでもお試し環境を作るだけなので、VagrantでUbuntu環境を構築する。 メモリ容量は4GBくらい確保しておけば良い。容量が足りないとビルド中にエラーになる。IPアドレスの設定値はご自由に。
Vagrantfile
# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure("2") do |config| # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. config.vm.box = "ubuntu/xenial64" # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs # `vagrant box outdated`. This is not recommended. # config.vm.box_check_update = false # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. # NOTE: This will enable public access to the opened port # config.vm.network "forwarded_port", guest: 80, host: 8080 # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine and only allow access # via 127.0.0.1 to disable public access # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" # Create a private network, which allows host-only access to the machine # using a specific IP. config.vm.network "private_network", ip: "192.168.33.20" # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network "public_network" # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. # config.vm.synced_folder "../data", "/vagrant_data" # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # config.vm.provider "virtualbox" do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: vb.memory = "4096" end # # View the documentation for the provider you are using for more # information on available options. # Enable provisioning with a shell script. Additional provisioners such as # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the # documentation for more information about their specific syntax and use. # config.vm.provision "shell", inline: <<-SHELL # apt-get update # apt-get install -y apache2 # SHELL end
ミドルウェアのインストール作業
CODES.shという構築スクリプトが用意されているが、これも何故か動かなかったので自分で一から構築する。
仮想マシンが起動したら、まずaptで必要なものを入れる。
curl -sL https://deb.nodesource.com/setup_6.x | sudo bash - sudo add-apt-repository ppa:brightbox/ruby-ng curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list sudo apt-get update sudo apt-get install ruby2.4 ruby2.4-dev postgresql nodejs libxmlsec1-dev \ zlib1g-dev libxml2-dev libsqlite3-dev libpq-dev curl make g++ redis-server sudo apt-get install yarn=0.27.5-1
インストールしたRedisはとりあえず、裏で動かしておけば良い。
sudo redis-server &
postgresのインストール後に、postgres上にユーザを作成する。
sudo -u postgres createuser $USER sudo -u postgres psql -c "alter user $USER with superuser" postgres
Rubyのインストール後に、Bundlerをインストールする。バージョンによっては後々面倒なことになるので、必ずバージョン指定すること。
sudo gem install bundler -v 1.14.6
Canvas LMSのソースコードを、Githubのリポジトリからクローンする。
git clone https://github.com/instructure/canvas-lms.git canvas cd canvas
Bundlerとnpmのインストール後に、Canvas LMSに必要なモジュールをインストールする。
bundle install npm install
npmでCoffeeScriptをインストールする。
sudo npm install -g coffee-script@1.6.2
設定ファイルのコピー
アプリケーションのサンプル設定ファイルを、使用する設定ファイルとしてコピーする。Quick Startでは特に編集しなくて良い。
for config in amazon_s3 delayed_jobs domain file_store outgoing_mail security external_migration; \ do cp -v config/$config.yml.example config/$config.yml; done cp config/dynamic_settings.yml.example config/dynamic_settings.yml cp config/database.yml.example config/database.yml echo -e "development:\n cache_store: redis_store" > config/cache_store.yml echo -e "development:\n servers:\n - redis://localhost" > config/redis.yml
DBテーブルの作成
Canvas LMSで使用するテーブルを作成する。
createdb canvas_development
Canvas LMSのビルド
ようやくCanvas LMS自体のビルドを行っていく。
bundle exec rails canvas:compile_assets bundle exec rails db:initial_setup
initial_setup後にエラーが出るが、めげずにもう一度同じコマンドを叩く。
bundle exec rails db:initial_setup
そうすると管理者のメールアドレスとパスワードを聞かれるので入力する。 この際に8500ポートに接続失敗したとか何とか言われるが、めげずにもう一度ログイン情報を入力するとインストールが完了する。
エラー内容
Problem creating administrative account, please try again: Connection refused - Connection refused - connect(2) for "localhost" port 8500 (localhost:8500)
ビルド時のエラーと管理者情報入力時のエラーが何故出力されるのかは不明で、issueも今のところ上がっていない。
Canvas LMSを起動
IPアドレスを明示的に指定しないと、ホストマシンからアクセスできないので注意すること。
bundle exec rails server -b 0.0.0.0
ControllerAdviceとResponseEntityExceptionHandlerを用いた例外ハンドラ
やること
Springで例外ハンドラを用意する方法は複数あるが、今回はResponseEntityExceptionHandlerを用いてアプリケーション内で共通の例外ハンドラを定義する。
ResponseEntityExceptionHandler (Spring Framework 5.0.0.RELEASE API)
環境
- Spring Boot 1.5.7.RELEASE
方法
投げる例外の基底クラスを作る
Transactionalでロールバックさせるため、RuntimeExceptionを継承した例外クラスを作る。
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.HttpStatus; abstract public class HttpStatusException extends RuntimeException { private String message; private HttpStatus httpStatus; HttpStatusException(HttpStatus httpStatus, String message) { this.httpStatus = httpStatus; this.message = message; } public HttpStatus getHttpStatus() { return this.httpStatus; } public String toResponseJson() throws JsonProcessingException { return new ObjectMapper().addMixIn(HttpStatusException.class, HttpStatusExceptionMixin.class).writeValueAsString(this); } @JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE ) abstract class HttpStatusExceptionMixin { @JsonProperty String message; } }
例外エラーのフィールドには返すメッセージとHTTPステータスを用意し、返却するJSONを生成するメソッドを実装する。 JSONで返す値はmessageだけで良いので、Mixin用の抽象クラスをインナークラスとして定義しておく。
派生例外クラスを作る
とりあえずBadRequest用のクラスを作る。
import org.springframework.http.HttpStatus; public class BadRequestException extends HttpStatusException{ public BadRequestException(String message) { super(HttpStatus.BAD_REQUEST, message); } }
ControllerAdviceを用いた例外ハンドラを作る
import com.fasterxml.jackson.core.JsonProcessingException; import com.example.exceptions.HttpStatusException; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @ControllerAdvice public class ApiAdviceController extends ResponseEntityExceptionHandler { @ExceptionHandler(HttpStatusException.class) public ResponseEntity handleHttpStatusException(HttpStatusException exception, WebRequest request) throws JsonProcessingException { return handleExceptionInternal(exception, exception.toResponseJson(), new HttpHeaders(), exception.getHttpStatus(), request); } }
ResponseEntityExceptionHandlerを継承したクラスを作り、ControllerAdviceアノテーションを付ける。 ExceptionHandlerをメソッドに付け、HttpStatusExceptionを引っ掛けてやるようにする。 handleExceptionInternalの引数は以下のようになっている。
- 引っ掛けた例外オブジェクト
- レスポンスボディ
- レスポンスヘッダ
- レスポンスステータス
- カレントリクエスト
まとめ
今回はBadRequestExceptionだけ作ったが、必要に応じて他のレスポンスステータスを持つ例外クラスを作ってthrowするだけで色々な例外に対応できる。 今回はコントローラ共通の例外ハンドラを作ったが、コントローラ特有のハンドラを作ればそちらが優先されるらしいので、 汎用的な例外ハンドラはControllerAdviceで実装し、特殊なレスポンスを返すなどの条件があればコントローラに個別定義すれば良い。
参考リンク
LaravelのHomesteadをvagrant upしようとしたらThe requested address is not valid in its context.吐いて止まった
最近、環境構築で手こずることが多いです…
環境
現象
homesteadのboxを無事取り込み、vagrant upしたら以下のようなエラーを吐いて止まりました。
C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:21:in `initialize': The requested address is not valid in its context. - connect(2) for "0.0.0.0" port 8000 (Errno::EADDRNOTAVAIL) from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:21:in `new' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:21:in `block in is_port_open?' from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:88:in `block in timeout' from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:32:in `block in catch' from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:32:in `catch' from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:32:in `catch' from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:103:in `timeout' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:19:in `is_port_open?' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:248:in `port_check' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:121:in `[]' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:121:in `block in handle' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:257:in `block in with_forwarded_ports' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:253:in `each' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:253:in `with_forwarded_ports' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:98:in `handle' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:42:in `block in call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/environment.rb:567:in `lock' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:41:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/prepare_forwarded_port_collision_params.rb:30:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/env_set.rb:19:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/provision.rb:80:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/clear_forwarded_ports.rb:15:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/set_name.rb:50:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/clean_machine_folder.rb:17:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_accessible.rb:18:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/box_check_outdated.rb:78:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/config_validate.rb:25:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_virtualbox.rb:17:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/match_mac_address.rb:19:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/discard_state.rb:15:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/import.rb:74:in `import' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/import.rb:13:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/prepare_clone_snapshot.rb:17:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/prepare_clone.rb:15:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/customize.rb:40:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_accessible.rb:18:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/config_validate.rb:25:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_box.rb:56:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_virtualbox.rb:17:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:225:in `action_raw' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:200:in `block in action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/environment.rb:567:in `lock' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:186:in `call' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:186:in `action' from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/batch_action.rb:82:in `block (2 levels) in run'
解決
ググるとStackOverflowにたどり着く。
stackoverflow.com
vagrant 1.9.3で発生する問題らしいですね。
Homestead/scripts/homestead.rbをエディタで開き以下のように変更する。
# 86行目くらい # Use Default Port Forwarding Unless Overridden unless settings.has_key?("default_ports") && settings["default_ports"] == false default_ports.each do |guest, host| unless settings["ports"].any? { |mapping| mapping["guest"] == guest } config.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true, host_ip: "127.0.0.1" end end end # Add Custom Ports From Configuration if settings.has_key?("ports") settings["ports"].each do |port| config.vm.network "forwarded_port", guest: port["guest"], host: port["host"], protocol: port["protocol"], auto_correct: true, host_ip: "127.0.0.1" end end
VagrantでリモートのboxをaddしようとしたらSSL read: error:00000000:lib(0):func(0):reason(0)で止まる
環境
現象
boxのダウンロード中に以下のようなエラーが出て、ダウンロードが中断される。
An error occurred while downloading the remote file. The error message, if any, is reproduced below. Please fix this error and try again. SSL read: error:00000000:lib(0):func(0):reason(0), errno 50
解決
errnoの部分は自分の環境では50か60だった気がする。 ググると以下のような記事が見つかった。 github.com slick.pl
とりあえずオプションを追加したら無事にダウンロードできました。
vagrant box add --insecure -c laravel/homestead
KotlinとThymeleafの組み合わせで、Thymeleaf側でisHogeフィールドが参照できない。
ThymeleafとKotlinの組み合わせで発生した問題です。 コントローラからビューにisHogeという値を渡した場合に、 ビュー側のThymeleaf内でその値を使用するときisHogeという変数名で参照できないというものです。 これはKotlinのフィールドの概念を理解していればそんなに難しい内容でないのですが、 Kotlinで書いたコードがビルド後にどうなるかを意識していない場合に結構引っかかるのではないかと思います。
KotlinでisHogeというフィールドを書きコンパイルするとHogeというメンバ変数に対し、各アクセサが自動的に生成されるので Thymeleaf側からだとisHogeという変数は存在せずHogeという変数が見えるということですね。
それにしてもキャメルケースで書いた変数がパスカルケースになってしまうのは気持ちが悪いですね。 文章だけでは分かりにくいのでサンプルコードを載せておきます。 モデルは割愛します。
package com.example import org.springframework.stereotype.Controller import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.servlet.ModelAndView @Controller @RequestMapping("/books") @Suppress("unused") class BooksController( val service: BookService ){ @GetMapping("/add") fun add() = ModelAndView("books/add") }
package com.example import org.springframework.stereotype.Service @Service class BookService{ fun getBookList() = arrayListOf<Book>().apply { add(Book(1, "初めてのKotlin", 3000, false)) add(Book(2, "初めてのJava", 2800, true)) add(Book(3, "初めてのIntellij", 4500, false)) } }
package com.example class Book( var id: Long, var title: String, var price: Long, var isRemoved: Boolean = false )
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"/> <title>Book List</title> </head> <body> <table> <tr> <th>ID</th> <th>Title</th> <th>Price</th> <th>IsRemoved</th> </tr> <tr data-th-each="book : ${bookList}"> <td data-th-text="${book.id}"></td> <td data-th-text="${book.title}"></td> <td data-th-text="${book.price}"></td> <td data-th-text="${book.Removed}"></td> <!--<td data-th-text="${book.isRemoved}"></td> isRemovedが参照できずエラーになる--> </tr> </table> </body> </html>
Kotlinのリフレクションを使ってプロパティ情報を取得する
やってることは簡単な内容なのですが、日本語の情報があまりなかったのでメモ程度に記録しようかと。
あるクラスのKClassを取得しプロパティ名と中身を取り出してみるというものです。
import kotlin.reflect.full.memberProperties fun main(args: Array<String>) { val myBook = Book( name = "Hello Kotlin", page = 120, isbn = "978-4865940398" ) myBook::class.memberProperties.forEach { println("${it.name}: ${it.call(myBook)}") } } class Book( val name: String, val page: Long, val isbn: String )
実行結果は以下の通り。
isbn: 978-4865940398 name: Hello Kotlin page: 120
htpasswdでパスワードの設定を行う際に8文字までしか認識してくれない
設定したパスワードよりも短い文字列で認証が通る
SquidでプロキシのBasic認証のパスワード設定をする際に、設定したパスワードより短い文字列でも認証が通ってしまう現象に見舞われた。自分で構築した環境ではないので、仮想マシンで再現環境を構築して色々試してみた。すると9文字以降は認証時に入力の有無に関わらず、認証が通ってしまうことに気がついた。
htpasswd -cb ./.htpasswd hoge password12345
上記のようにパスワードを設定した場合には、「password」以降の「12345」は認証時に入力してもしなくても認証が通ってしまう。
ドキュメントを読む
そこでHtpasswdのドキュメント(http://httpd.apache.org/docs/2.2/programs/htpasswd.html)を読んでみると、dオプションのところに以下のような文章が書いてあった。
This is not supported by the httpd server on Windows and Netware and TPF. This algorithm limits the password length to 8 characters.
そもそも最大8文字までしか対応していなかった。どうやらcrypt関数というものを使う際に、8文字までしか対応していないらしい。警告くらい出してくれると嬉しいな…