gradleのhello worldメモ
memo
gradleのhello world的なサイトを見ながら操作メモです。(centos7)
gradleのインストール
# cd ~ # yum install -y which unzip zip vim # curl -s http://get.sdkman.io | bash # source ~/.sdkman/bin/sdkman-init.sh # sdk install gradle
hello woldのコンパイルと実行
# yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel # mkdir myapp && cd myapp # gradle init --type java-application # gradle compileJava # gradle run
jarの作成と実行
# gradle jar # ls -la build/libs/ # java -cp build/libs/myapp.jar myapp/App
build.gradleに簡単なタスクを追加して実行
# vim build.gradle ※ファイル末尾に下記を追記 task hello { doLast { println "Hello World!!" } }
# gradle hello > Task :hello Hello World!!
カスタムタスクの利用
DefaultTaskから派生したタスクを定義しておき、実行するメソッドにアノテーションを付けておけば、「type:」で型を指定する形でオブジェクトを生成して実行する事ができる。pluginで提供される機能に対し、任意のパラメータを上書きして実行させるなどして利用する。
class AAATask extends DefaultTask { String message @TaskAction def execMyTask() { println("message is ${message}") } } task execMyTask(type: AAATask) { message = "Hello World" }
サーバーにsshログインした時にslackに通知する
概要
サーバーにsshログインした時にslackに通知する
slack側での作業
- 「チャネル設定」→「アプリを追加する」を順にクリックする
- 「incoming-webhook」をインストールする
- 「incoming-webhook」の設定にある「Webhook URL」をメモする
サーバー側での作業(CentOS7)
下記の「channel-name」と「http://hooks...」の部分は環境に合わせて要変更
$ sudo vim /etc/ssh/sshrc
#!/bin/bash CHANNEL="#channel-name" HOSTNAME=`hostname` MESSAGE="username:${USER} from:${SSH_CLIENT} server:${HOSTNAME}" WEBHOOK_URL='https://hooks.slack.com/services/xxxx/xxxx/xxxx' curl -X POST --data-urlencode 'payload={"channel": "'"${CHANNEL}"'", "username": "login notification", "text": "'"${MESSAGE}"'"}' ${WEBHOOK_URL} 1>/dev/null 2>/dev/null
apacheのリバースプロキシ環境下でのbasic認証
概要
apacheでリバースプロキシを設定しており、伝搬させる前にbasic認証をかけたのだがAuthorizationヘッダーが伝搬してしまう問題の対応方法について。
※特に伝搬先にjenkinsが居るとbasic認証を何度も聞かれる羽目になる・・・
解決方法
下記のようにAuthorizationヘッダを伝搬させないようにするのがポイント
basic認証自体は一般的なもので構わない
<Location />
AuthType Basic
AuthName "mytest"
AuthUserFile /etc/httpd/htpasswd/.htpasswd
Require valid-user
</Location>
RequestHeader unset Authorization
おまけ
basic認証の他にIP制限も設定してある場合、どちらか一方をパスすれば良いという場合は「Satisfy Any」が使える。
dockerコンテナでIP制限するやり方
概要
あるサーバー上で動いているdockerコンテナに対して、任意のマシンからのみアクセスさせる方法について
(centos7を想定しています)
具体的に箇条書きにすると・・・
- Aがクライアント側とする
- Bがサーバー側で内部にdockerコンテナ(C)を起動しているとする
- AからB上のCにアクセスを許可する設定について
- 但し、A以外からは受け付けたくない
例
- AのIPを192.168.0.100とする
- Bで受け付けるポート番号を30000とする
- Cでローカルから受け付けるポート番号を5000とする
$ docker run -d -p 192.168.0.100:30000:5000 (起動したいイメージ名)
より複雑なやり方
- CのIPを172.17.1.10とする
- CのIPが変わらないようにdocker network createで任意のネットワークを作り、docker runで指定しておく
$ docker network create --subnet=172.17.1.0/24 mynetwork $ docker run -d --net mynetwork --ip 172.17.1.10 (コンテナイメージ名)
ファイヤーウォールの設定
$ sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.0.100" forward-port port="30000" protocol="tcp" to-port="5000" to-addr="172.17.1.10"' $ sudo firewall-cmd --reload
こちらのやり方なら対象が増えた時にコンテナを起動し直す必要がない(はず)。
raspberry pi 3B+でテレビ電話システムを構築する
はじめに
この投稿ではサーバーの用意が必要なので、sapislabを使ったやり方を用意しました。
サーバー立てるの厳しい方はこちらをご覧ください。
システム概要
raspberry pi 3B+ によるテレビ電話システム
※記載内容に責任は持てません、全て自己責任でお願いします
概念図
背景
- 妻が夕食の準備中に子供の相手が大変である
- おばあちゃんが一人なので心配である
改善案
- 子供とおばあちゃんが気軽にテレビ電話が出来るようにする
要件
- テレビ電話が出来ること
- 手軽に使えること(煩雑だと結局使われない)
- 費用は抑えること(常套句)
想定シナリオ
- 妻が子供たちを連れて帰宅
- 我が家からリモコンでスイッチオン
- 我が家とおばあちゃん家のテレビが自動でONになりテレビ電話を開始する
- 我が家からリモコンでスイッチオフ
- 我が家とおばあちゃん家のテレビが自動でOFFになりテレビ電話を切断する
前提条件
- おばあちゃんに家のテレビが勝手にONになってリビングが映し出されるプライバシー的な問題について予め了承を得ておくこと(※同居人が居る場合はその方にも)
- VPNは張らない(ルーターの機能的に無理だからw)
用語
- 我が家はcallerに置き換える(呼び出し側)
- おばあちゃん家はreceiverに置き換える(受け手側)
- 途中に出て来るvtcはvideo telephone controlerを略したもの
必要なもの
- raspberry pi 3B+ を2セット
- ヒートシンクは付けておいた方が良いと思う
- 電源やSDカード等の別途必要なものは明示しない
- OSはraspbianを想定
- webカメラを2個
- 1000円程度のもので十分
- USBマウス・USBキーボード
- セットアップ用途
- AB Shutter3 を1個
- シェル起動のトリガーになるなら何でも構わない
- caller,receiver両方のネットワーク環境(従量制ではないこと)
- APIサーバーを立てる場所(及びデプロイできる技量)
- グローバルIPが当ててあるか、DNSで特定できるようになっていること
- ここでは一般的なVPSを想定
- raspberry piで何かしようとしている人ならきっとできる(偏見)
- テレビ電話サービスのアカウント登録用メールアドレスおよびアカウント
- アカウント登録手順などは省略
仕組み
- APIサーバーを仲介役として、callerから指示を出し、receiverがポーリングで反応する
- こうする事でIPが変わる環境でも間接的な連携が可能となる
- ネットワーク的にも分断されたままなので安心(?)
- テレビ電話はskypeも検討したが直接はインストールできない為、ブラウザベースのものを利用
- 特定のURLにアクセスしたら繋がるタイプ(apeer.inやskyway)を使う
- たまたま同じルームを作ってしまって丸見えになる覚悟も必要(skywayでローカルに立てる方式なら問題無さそう)
- 絶対にNGであれば有料会員になってLockすれば大丈夫だと思う(試してない)
状態遷移図
開始処理のシーケンス図
終了処理のシーケンス図
APIサーバーの機能(超単純)
- 現在の状態を取得できる
- 状態を変更できる
- 接続すべきURLを取得できる
- セキュリティ関連
- 必要に応じてapiキーによる制御
やり方
raspberry pi 3(caller, receiverともに)
- ネットワーク設定(wifiとか)
- スクリーンセーバーの無効化
- cec-clientのインストール(HDMI制御に使う)
- $ sudo apt-get install cec-utils
- 接続用エージェントプログラムの配置
- 「https://github.com/miya15/vtc-agent」に置きました
- piユーザー用に記述されている点に注意
raspberry pi 3(receiverのみ)
raspberry pi 3(callerのみ)
- AB Shutter3 で任意のシェルが叩ける準備(下記の記事を参考に準備する)
- ON用のボタンが押されたら「vtc-exec-caller-on.sh」を叩くようにする
- OFF用のボタンが押されたら「vtc-exec-caller-off.sh」を叩くようにする
- 注意:どちらのシェルスクリプトにもAPIサーバーのURLとAPIキーを記載する場所があるので適宜入れておくこと
APIサーバー
- docker, docker-compose が入っていなければインストール
- プログラム配置
- 「https://github.com/miya15/vtc-api-server」に置きました
- docker-compose.ymlがあるディレクトリに移動して「$ docker-compose up -d」で起動する
- apiキーなんて要らないという勇者は「@require_apikey()」を削除すればチェックされません
- raspberry pi 側から疎通確認(ドメインとapiキーを適宜置き換えて)
- $ curl https://example.com/api/echo
- "hello"がレスポンスに含まれること
- $ curl https://example.com/api/url -v -X GET -H "Content-Type: application/json" -H "x-api-key:YourAPIKey"
- redisで設定したurlがレスポンスに含まれること
- $ curl https://example.com/api/echo
- redisを直接操作してapiキーやurlを初期設定する
- 詳細は後述
- apiキーはcallerとreceiverを分けて発行した方が後々の拡張で使えるかもしれません(現状では何ら分ける意味はありません)
redisへの設定値反映方法
redis-cliを叩く手順(docker-composeの利用を想定)
$ docker exec -it vtc-api-server_db_1 /bin/sh /data # redis-cli 127.0.0.1:6379> コマンド(後述参照)
コマンド例
▽APIキーを追加する 127.0.0.1:6379> rpush apikeys xxx ▽urlを設定する(※使える記号は「:/.?=&」) 127.0.0.1:6379> set url xxx ▽状態をrequest to openに設定する 127.0.0.1:6379> set state "request to open"
各種プログラム
- APIサーバーのプログラム
- 接続用エージェントプログラム
注意事項
- 電化製品なので漏電や火災に気を付けましょう
- 各種OSやミドルウェアのバージョンを新しく保つよう心がけましょう
- raspberry pi もパソコンですからBOT化しないよう気を付ける
- テレビによってはHDMIの制御が効かないものがあります、ご注意ください
- まずはraspberry piを1台だけ買って双方のテレビに繋いでコマンド投げて試す方が良い
- 接続先URLをAPIサーバーから取得するようになっているので気になる方は直接プログラムに埋め込んだ方がより安全です
- URLが変更できるようになっているのはルームIDを変更したり別のサービスに切り替えるのが手軽に出来るようにする為です
今後の発展
- 状態遷移はjson形式で渡しているので遷移を増やすと面白いかもしれない
- 定期的にAIで在席・不在を判断できるとその後のアクションにも繋げられるか
運用中に発生した問題点について
- receiver側でHDMIの制御がうまくいかない事があった
- 実際に繋がると子供(5歳男児)は映っている自分に興奮して踊りだし、おばあちゃんとの会話にならない(苦笑いしてるというありさま)
- 完全に想定外
メモ
- APIサーバーはAWSのapi gatewayとlambdaとDynamoDBの組み合わせでも問題無いと思うが今回はパス(悪意のあるユーザーに大量に叩かれたら嫌なだけ)
- Herokuの無料プランでも使えるかもしれない
- ちょっと試したけどredis使うならクレジットカード登録が必要ですね
- 今回はraspberry piを使う事が前提にあったが、intel系のスティックPCとかでskypeを使う方式としても使えるかもしれない(skypeには自動応答機能があるので、コマンドラインからコール出来れば完成したようなもの)
- プログラムが最適化されていない点はご容赦ください
- バグなどありましたらコメント頂けるとありがたいです
- 取り敢えず1ヵ月ほど運用してみましたがうまく動いています(思ったほど活用されてないのが残念ですが・・・)
redmineでPlantUMLを表示する際にサーバー側で画像を生成させる方法
概要
PlantUMLは便利ですが画像生成をするアプローチに苦慮します。
記述している内容を秘匿する必要がある場合は尚更です。
今回はredmineのプラグインplantuml-redmine-macroに手を加えて社内サーバーで画像を生成させ、それをHTTPレスポンスに含めるやり方を説明したいと思います。
やり方
まずはプラグインのご紹介。
このままだと公式サーバーの方に情報が流れてしまうので社内サーバーを立てます。
今回もDockerで手軽に立てましょう。docker-hubはこちらになります。
ポート番号などは任意で。
$ docker run -d -p 8000:8080 plantuml/plantuml-server
次にredmineのプラグインの設定(管理→プラグイン→PlantUML Macro plugin→設定)から「PlantUML Server URL」の項目に立てたサーバーのURLを設定します。
「適用」ボタンをクリックするのを忘れずに。
設定例 http://192.168.0.200:8000/
さて、ここまでの内容でredmineに下記のような記述でPlantUMLの画像が埋め込まれる仕組みが出来ました。
{{plantuml Bob -> Alice : hello }}
しかし、このままだとHTTPレスポンスにはimgタグが含まれるだけで、クライアント側では改めてPlantUMLサーバー(設定値のURL)に問い合わせる事で画像を手に入れます。
そこでinit.rbの内容を下記のように書き換える事でWEBサーバー側で画像を生成してHTTPレスポンスに含めて返す事ができます。
※設定したURLでredmineサーバーからPlantUMLサーバーへアクセスできる必要があります
※このPlantUMLサーバーへのアクセス経路がプライベートネットワークであれば侵入されない限り漏えいしません
require 'redmine' require 'uri' require 'plantuml' require 'open-uri' require 'base64' Redmine::Plugin.register :plantuml_macro do name 'PlantUML Macro plugin' author 'Denis Nelubin' description 'This is a plugin for Redmine to convert PlantUML text into link to the image on PlantUML server' version '0.0.1' url 'https://bitbucket.org/gelin/plantuml-redmine-macro' author_url 'http://google.com/+DenisNelubin' settings :default => { 'plantuml_url' => 'http://plantuml.com/plantuml/' }, :partial => 'settings/plantuml_macro_settings' Redmine::WikiFormatting::Macros.register do desc "Converts PlantUML text into link to the image on PlantUML server. Example:\n\n" + " {{plantuml\n" + " Bob -> Alice : hello\n" + "}}" macro :plantuml do |obj, args, text| url = URI.join(Setting.plugin_plantuml_macro['plantuml_url'] + '/', 'png/') encoded = PlantUML.encode(text) base64image = '' open(URI.join(url, encoded).to_s) do |file| base64image = Base64.strict_encode64(file.read) end image_tag("data:image/png;base64," + base64image) end end end