流れに乗って @xtetsuji さんからの出題をやってみる

ということで流れに乗ってみました。

アルゴリズムそんな自信ないのでどうなんだろう.....。競プロerからなんか突っ込まれそう

gist.github.com

シグナルでプロセスが終了されるとぴえんするコマンド作った

最近YouTubeでPIENのプレイ動画をよく見るので作りました

pienの後に渡したプログラムがシグナルで死んだ場合はぴえんの歌が再生されます github.com

なんとなくRustの勉強も兼ねてRustで書いてます。

地味にbrewでもダウンロードできるようになってます。

$ brew tap anatofuz/pien
$ brew install anatofuz/pien

別途音源が必要なので音源配布サイトからダウンロードして、ホームディレクトリに.pien.mp3で置いておくと再生されます。

soundevotee.net

実装方法

音声を流すのはafplayを雑に叩くみたいな世界観です。そぼく.....

RustでのCLIの作り方は全然解ってなかったので、いいかんじのチュートリアルを読みながら勉強しました。

rust-cli.github.io

肝なのは外部コマンドの終了コードの取得ですね。 Rustの場合は外部コマンドの終了コードはいい感じにパターンマッチで取得できます。

doc.rust-lang.org

use std::process::Command;

let status = Command::new("mkdir")
                     .arg("projects")
                     .status()
                     .expect("failed to execute mkdir");

match status.code() {
    Some(code) => println!("Exited with status code: {}", code),
    None       => println!("Process terminated by signal")
}

この例だとNoneに分類されるやつらが全員シグナルで死んでるので、Noneの場合は音楽を再生すれば良いということになります。その為今回は入力で受け取ったコマンドの結果をパターンマッチし、シグナルで死んでたらafplayを実行するみたいな極めて単純な実装になってます。

こういう一発ネタみたいなコマンド作るのやはり楽しいですね。

apache -> nginx -> gitlab-ceのプロキシを止める

追記 2020/07/15

8080ポートはgitlabのrailsアプリケーションのポートなのだけど、ここに直接プロキシするのではなく、gitlabのHTTPのルーティングを行っているgitlab-workhorseの8181ポートに繋げないと駄目だった


自分が在籍している学科ではオンプレ上にgitlabを構築して運用している。

gitlab.ie.u-ryukyu.ac.jp

gitlabが動いているサーバーはオンプレ上に構築したKVMで動かしているVMなのだけど、歴史的理由でこのサーバーでは他にjenkinsやredmineなども動作している。

もともとredmine-> jenkins -> gitlabの順でサーバー上に構築されたこともあり、サーバー全体のwebサーバーはapacheで動いている。

問題がgitlabのinstallでgitlab-ceを使っていたのだけれど、gitlab-ceはデフォルトでgitlabにまつわるすべてのミドルウェアなどもインストールして構築してくれる。 具体的に言うとデータベースとしてPostgreSQL、webサーバーとしてnginxを同梱している。

現状の学科のgitlabは、このgitlab-ceに同梱されているnginxをポート8000番で起動させ、apacheからそのnginxにプロキシをしていた。つまりapache -> nginx -> gitlabの順でHTTPリクエストが伝搬 される。

具体的に見るとこういう感じだった。大変ですね。

$ lsof -i :8000
COMMAND   PID       USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
nginx    5769       root    9u  IPv4 131461357      0t0  TCP *:irdmi (LISTEN)
nginx    5770 gitlab-www    9u  IPv4 131461357      0t0  TCP *:irdmi (LISTEN)
nginx    5770 gitlab-www   19u  IPv4 131528575      0t0  TCP localhost:irdmi->localhost:52234 (ESTABLISHED)
nginx    5770 gitlab-www   20u  IPv4 131524330      0t0  TCP localhost:irdmi->localhost:52192 (ESTABLISHED)
nginx    5771 gitlab-www    9u  IPv4 131461357      0t0  TCP *:irdmi (LISTEN)
nginx    5771 gitlab-www   18u  IPv4 131526937      0t0  TCP localhost:irdmi->localhost:52196 (ESTABLISHED)
nginx    5771 gitlab-www   19u  IPv4 131530893      0t0  TCP localhost:irdmi->localhost:52244 (ESTABLISHED)
nginx    5772 gitlab-www    9u  IPv4 131461357      0t0  TCP *:irdmi (LISTEN)
nginx    5772 gitlab-www   15u  IPv4 131530209      0t0  TCP localhost:irdmi->localhost:52230 (ESTABLISHED)
nginx    5773 gitlab-www    9u  IPv4 131461357      0t0  TCP *:irdmi (LISTEN)
httpd    7873     apache   16u  IPv4 131524319      0t0  TCP localhost:52186->localhost:irdmi (CLOSE_WAIT)
httpd    7874     apache   16u  IPv4 131527717      0t0  TCP localhost:52192->localhost:irdmi (ESTABLISHED)
httpd    8583     apache   16u  IPv4 131528766      0t0  TCP localhost:52198->localhost:irdmi (CLOSE_WAIT)
httpd    8831     apache   16u  IPv4 131525112      0t0  TCP localhost:52164->localhost:irdmi (CLOSE_WAIT)
httpd    9433     apache   16u  IPv4 131524337      0t0  TCP localhost:52196->localhost:irdmi (ESTABLISHED)
httpd   10272     apache   16u  IPv4 131524317      0t0  TCP localhost:52184->localhost:irdmi (CLOSE_WAIT)
httpd   11736     apache   16u  IPv4 131529561      0t0  TCP localhost:52244->localhost:irdmi (ESTABLISHED)
httpd   24102     apache   16u  IPv4 131528566      0t0  TCP localhost:52230->localhost:irdmi (ESTABLISHED)
httpd   24103     apache   16u  IPv4 131525592      0t0  TCP localhost:52188->localhost:irdmi (CLOSE_WAIT)
httpd   24111     apache   16u  IPv4 131530228      0t0  TCP localhost:52234->localhost:irdmi (ESTABLISHED)
httpd   24166     apache   16u  IPv4 131526971      0t0  TCP localhost:52200->localhost:irdmi (CLOSE_WAIT)

この構成であまり問題は無かったのだけれど、諸事情でgitlabのHTTPヘッダにAccess-Control-Allow-Originの設定をする必要が出た。現状の構成だとApache側でAccess-Control-Allow-Originを付与しておけば良いと思ったのだけれど、実際はapache -> nginxに伝搬される際に、nginx側でヘッダ情報が落とされることが判明した。さらにgitlab-ceが生成するnginxの設定ファイルでAccess-Control-Allow-Originを付与するのが結構めんどくさそうだった。

というわけでapache -> nginx -> gitlab-ceのプロキシを止めて、apache -> gitlab-ceに一本化したい。本来ならapacheやめてnginxにしたいのだけれど、redmineやjenkinsのプロキシ設定も変更する必要があり、やや工数的にめんどいので段階的にやることにした。

gitlab側の設定

まずはnginxを止めなければならない。

これらはgitlab側の設定ファイルgitlab.rbを編集することで停止できる。

若干違うけれど、gitlab公式の同梱されてないnginxを使う方法が参考になった。 docs.gitlab.com

とりあえずnginxの使用を止める

nginx['enable'] = false

この後に続く nginx['hoge']的な記述はすべてコメントアウトしておく。

末尾にこの2行を追加する(これは効果があるかどうかは不明)

gitlab_workhorse['listen_network'] = "tcp" 
gitlab_workhorse['listen_addr'] = "127.0.0.1:8181" 

apache

今まではこんな感じの設定だった

<VirtualHost *:443>
        ServerName gitlab.ie.u-ryukyu.ac.jp
        ProxyRequests off
        ProxyPass / https://127.0.0.1:8000/
        ProxyPassReverse / https://127.0.0.1:8000/
        SSLEngine on
        SSLProxyEngine on
        SSLProxyCheckPeerCN off
        SSLProxyCheckPeerName off
        SSLCertificateFile hoge.cer
        SSLCertificateKeyFile hoge.key
        SSLCertificateChainFile hoge.cer
</VirtualHost>

何も考えずにnginxにプロキシしていたが、apacheからgitlabに直接プロキシする場合はある程度設定を書き加える必要がある。

様々な人がブログエントリで設定例を書いていたが、最終的にはgitlab公式が出しているapacheの設定例が一番正しかった。

gitlab.com

httpsでやってることもあるので、この例の通りにやらないとリポジトリの中身が表示されないとか、LDAPログインした後にコールバックされないなどの悲しさが存在する。

ここまで設定したらgitrlabとapacheを再起動すればよい

gitlab-ctl reconfigure
gitlab-ctl restart
gitlab-ctl reconfigure
systemctl restart httpd

Akka実践バイブル読み始めた

追記

akkaとakkaHTTPを最新にしてみたら動いた

diff --git a/chapter-up-and-running/build.sbt b/chapter-up-and-running/build.sbt
index 1d6c95a..4e10c25 100644
--- a/chapter-up-and-running/build.sbt
+++ b/chapter-up-and-running/build.sbt
@@ -7,8 +7,8 @@ version := "1.0"
 organization := "com.goticks"

 libraryDependencies ++= {
-  val akkaVersion = "2.5.4"
-  val akkaHttpVersion = "10.0.10"
+  val akkaVersion = "2.6.6"
+  val akkaHttpVersion = "10.1.12"
   Seq(
     "com.typesafe.akka" %% "akka-actor"      % akkaVersion,
     "com.typesafe.akka" %% "akka-stream"     % akkaVersion,

最近Scalaやりたい感が強く、特にAkkaを使ってみたい気持ちがあったので「Akka実践バイブル」を図書館で借りて読み始めた。

Akkaが採用しているアクターモデルは今やっている研究にも応用できそうとかそういう意味合いもある。

Scalaあんま書いたことがないので、Scalaの勉強がてらみたいなところ。とりあえずsbtを使えば色々できるらしいということは解っている。

とりあえず第2章でサンプルコードがあったのでGitHubからcloneして動かした所見事に動かなかった。

日本語版のは本家のリポジトリをforkしており、それを実行すると次の様なエラーが出る。

github.com

[ERROR] Failed to construct terminal; falling back to unsupported
java.lang.NumberFormatException: For input string: "0x100"
        at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
        at java.base/java.lang.Integer.parseInt(Integer.java:658)
        at java.base/java.lang.Integer.valueOf(Integer.java:989)
        at jline.internal.InfoCmp.parseInfoCmp(InfoCmp.java:59)
        at jline.UnixTerminal.parseInfoCmp(UnixTerminal.java:242)
        at jline.UnixTerminal.<init>(UnixTerminal.java:65)
        at jline.UnixTerminal.<init>(UnixTerminal.java:50)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
        at java.base/java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:166)
        at java.base/jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:404)
        at java.base/java.lang.Class.newInstance(Class.java:591)
        at jline.TerminalFactory.getFlavor(TerminalFactory.java:211)
        at jline.TerminalFactory.create(TerminalFactory.java:102)
        at jline.TerminalFactory.get(TerminalFactory.java:186)
        at jline.TerminalFactory.get(TerminalFactory.java:192)
        at sbt.ConsoleLogger$.ansiSupported(ConsoleLogger.scala:123)
        at sbt.ConsoleLogger$.<init>(ConsoleLogger.scala:117)
        at sbt.ConsoleLogger$.<clinit>(ConsoleLogger.scala)
        at sbt.GlobalLogging$.initial(GlobalLogging.scala:43)
        at sbt.StandardMain$.initialGlobalLogging(Main.scala:116)
        at sbt.StandardMain$.initialState(Main.scala:125)
        at sbt.xMain.run(Main.scala:34)
        at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:111)
        at xsbt.boot.Launch$.withContextLoader(Launch.scala:130)
        at xsbt.boot.Launch$.run(Launch.scala:111)
        at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:37)
        at xsbt.boot.Launch$.launch(Launch.scala:119)
        at xsbt.boot.Launch$.apply(Launch.scala:20)

本家の方で動かすとぬるぽする

github.com

[info] Loading project definition from /Users/anatofuz/src/github.com/RayRoestenburg/akka-in-action/chapter-up-and-running/project
java.lang.NullPointerException
        at java.base/java.util.regex.Matcher.getTextLength(Matcher.java:1770)
        at java.base/java.util.regex.Matcher.reset(Matcher.java:416)
        at java.base/java.util.regex.Matcher.<init>(Matcher.java:253)
        at java.base/java.util.regex.Pattern.matcher(Pattern.java:1134)
        at java.base/java.util.regex.Pattern.split(Pattern.java:1262)
        at java.base/java.util.regex.Pattern.split(Pattern.java:1335)
        at sbt.IO$.pathSplit(IO.scala:744)
        at sbt.IO$.parseClasspath(IO.scala:859)
        at sbt.compiler.CompilerArguments.extClasspath(CompilerArguments.scala:62)
        at sbt.compiler.AggressiveCompile.withBootclasspath(AggressiveCompile.scala:50)
        at sbt.compiler.AggressiveCompile.compile2(AggressiveCompile.scala:83)
        at sbt.compiler.AggressiveCompile.compile1(AggressiveCompile.scala:70)
        at sbt.compiler.AggressiveCompile.apply(AggressiveCompile.scala:45)
        at sbt.Compiler$.apply(Compiler.scala:74)
        at sbt.Compiler$.apply(Compiler.scala:65)
        at sbt.Defaults$.sbt$Defaults$$compileTaskImpl(Defaults.scala:789)
        at sbt.Defaults$$anonfun$compileTask$1.apply(Defaults.scala:781)
        at sbt.Defaults$$anonfun$compileTask$1.apply(Defaults.scala:781)
        at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
        at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
        at sbt.std.Transform$$anon$4.work(System.scala:63)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
        at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
        at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
        at sbt.Execute.work(Execute.scala:235)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
        at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
        at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
        at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:830)
[error] (compile:compile) java.lang.NullPointerException

なんか初手で出鼻くじかれた感じあって辛ぽよですね。3,4年前くらいの本なのでしゃーない気もする。いい感じにパッチ当ててるリポジトリを探してみよう。

学科newsサイトのhugo移行への道のり 1

自分が在籍している学科(琉大工学部知能情報コース)は学科関連のお知らせをインターネット経由で流している。歴史的にはネットニュース(fj)時代から運用されており、その後wordpressに移行している。

現在はここから見れる

WordPressでの運用は元気に動いている間は良いのだけれど、数年前にplugin経由でGoogle検索結果を爆撃されるという事件があったりした。最近はDBのコネクションエラーが多発しており、ログを取って解析していても原因が追求できない。

更に追い打ちをかけるように学科ウェブはだいたいマルチサイト化されたWordPressで動かしているので、どこかでDBエラーなどが発生すると全滅するということになっていた。

まぁこれが辛いので静的サイト化するぞ!!!!! というのをid:unimarimoと話していたのだけど、最近のシステム更新のどさくさに紛れてシス管MTGで話したら河野先生も乗り気にできたので進めている。

静的サイト化!!!

静的サイト化としては色々方法があって、nuxt.jsを使う方法などを発見していた。 とはいえ学科のメンバーとwebサイトを管理しているシス管メンバーが毎年コンスタントにnuxt.jsのことが解るようになるかと言われると微妙なところがあった。

まぁこれはメンバーと主に僕の趣味で、バイナリをおいておけばどうにかなるhugoを使ってmarkdownから変換する形式にしていこうとなった。

静的サイトのつくりかた

ということで今考えている構成はこんな感じ

  • markdown化したnews-ieリポジトリを学科gitlabにたてる
  • 投稿したい人がなにかでリポジトリmarkdown等をpushする
  • jenkinsかgitlab ciが頑張ってhugoを動かしてhtmlを生成する
  • どうにかしてそのファイルをwwwサーバーに送りつける

ci移行のとこと投稿に関しては手探りではあるのだけど、なんとなく行けそうな気がする。

news-ieは他に学科アカウントが無いと閲覧できないという機能があって、今まではwordpressのpluginで管理していたのだけれど、これはnginx側で制御することにしたい。ついでに今はwwwサーバーはapacheなのでapacheからnginxへの移行もやってしまう。

手順?

基本的には現在のnews-ieのエントリをすべて回収してくる必要がある。 賢い人はいるみたいですでにwordpress pluginでhugoで使えるmarkdown形式に変換した上でzipダウンロードしてくれるやつがあった。

github.com

管理コンソールでこのpluginを使ったところ、本当に動いているか怪しいほど時間はかかった。 1分以上立った後で、zipが無事ダウンロードされたのだけれど、ちゃんと添付ファイル込でmarkdownにしていたのでかなり良かった。

とりあえずこれで今までの投稿のmarkdownが手に入ったので、後は頑張ってhugoでhtmlを組み立てていくフェーズとなる。続きはまた...

golangのldflagsに引っかかった

golangにはビルド時のリンク関連の制御のldflagsオプションがある。

ldflagsを利用するとビルド時に変数の埋め込みなどが出来るのだが、これで引っかかった。

やろうとしていたことは次の様なコード。

環境変数の代わりにldflagsで変数埋め込みを行い、実行する場合は環境変数の設定を無くしたかった。

package main

import (
    "fmt"
    "os"
)

var envtest string = os.Getenv("ENVTEST")

func main() {
    fmt.Println(envtest)
}

実際にこれを go build -ldflags "-X main.envtest=goodnight" ./main.goの様にldflagsを使って変数埋め込み行いビルドした。

環境変数を設定していない状態で、生成したバイナリを実行するとこの様な結果になる。

$ ./main

何も表示されなかった。つまりenvtestENVTEST環境変数をロードしにいっていることになる。 とはいえstringsコマンドをかけてやると普通に出てくる。どういうことなの。

$ strings ./main | grep goodnight
goodnight

え〜と思い代入文を外して実験した。

package main

import (
    "fmt"
)

var envtest string

func main() {
    fmt.Println(envtest)
}

これで全く同じ方法でビルドした。

$ ./main 
goodnight

埋め込まれてる!!!!!!!!!!

ネタバラシ

ドキュメントを見たところちゃんと書いてあった

-X importpath.name=value

Set the value of the string variable in importpath named name to value. This is only effective if the variable is declared in the source code either uninitialized or initialized to a constant string expression. -X will not work if the initializer makes a function call or refers to other variables. Note that before Go 1.5 this option took two separate arguments.

「This is only effective if the variable is declared in the source code either uninitialized or initialized to a constant string expression.」とのことだったので、ちゃんとドキュメントは読もうな.....

ちなみに開発環境では環境変数使って実行環境では使いたくないときはどうするべきなんだろう。。。 initで空文字列かどうかを判定して、空文字列だったら環境変数から取るとかにするのがいいのかな。

WEB+DB PRESS vol.117 「Perl Hackers Hub」 第62回「Perl歴史散策」に寄稿しました

というわけで一度投稿してみたかったエントリです!!!

2020年6月24日(水)に発売される WEB+DB Press Vol.117Perl Hackers Hub に「Perl歴史散策」を書かせていただきました!!みんな買ってくれ!!!!!!

沖縄だと多分無いですが大手書店では6月16日からテスト販売があるそうです!!!自分の近所の書店が大手書店だと思われる人は買ってください!!!

ちなみに外出するのはな...という皆様のために電子書籍でも販売しています!!!

f:id:anatofuz:20200608185623j:plain

気になる内容

気になる内容ですが

  • Perl1.0から現在のPerl5.32に至るまでの代表的なバージョン(1,2,3,4,5)の解説
  • Perl6/Rakuの歴史と現在
  • 最新Perl5情報

...と、個人的な趣味MAXみたいな内容でお送りしています。(別に僕が書いたコードの話ではない^q^)

今からPerlを始めてみよう、 Perlってどんな言語なのかちょっと知りたいというPerlビギナーの方はもちろんのこと。 PerlがどのようにC言語で実装されているか気になる方まで、 Perlに興味がある方なら面白いかなと思う内容だと思います!

所感

Perl Hackers Hubは第一線のバリバリPerlエンジニアの方が多く執筆されており、業務で使っていない以前にそもそも業務をしていない学生だったので(!!!!????)となりましたが、せっかくチャンスを頂いたので書かせていただきました!

執筆はmarkdownベースの文法なファイルをガンガン書いていって、そのファイル上で校正をしていただける運用でした。こういう執筆作業でもgitみたいなバージョン管理使っているのか~!と驚きました。

実際に書籍の文章が我々の手元に届くまでにはかなりの労力がかかっている事を身を以て体験できました。徹底的に編集部の皆様に文章の校正をしていただいて、人々に伝わりやすい文章を作る難しさを痛感しました。今までと異なる目線で技術書などの書籍を見ることが出来るようになったと思います。

あとは犯罪以外で自分の名前が書かれた書籍が全国に頒布されるのは嬉しいですね。しかも憧れのWEB+DB PRESSなので感慨もひとしおです。

謝辞

お誘い頂いたid:papixさんや、 的確な指摘で文章のリファクタリングをしていただいた技術評論社の稲尾さん、 英語や技術的内容のレビューをしていただいた監修の牧さんを始めとする校正などに関わってくださった皆さんに御礼申し上げます。

もう一度

2020年6月24日(水)に発売される WEB+DB Press Vol.117Perl Hackers Hub に「Perl歴史散策」を書かせていただきました!!よろしくお願いします!!!!!!