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"
}

pageantに秘密鍵を登録するバッチの作成

概要

毎回pageant秘密鍵を入れる操作が面倒なのでバッチにしておく

やり方

pageant.exeがあるディレクトリ内にテキストファイルを拡張子batで用意する
ex) pageant_regist.bat

start pageant
timeout 3
pageant C:\key\any_key1.ppk
pageant C:\key\any_key2.ppk
pageant C:\key\any_key3.ppk
pause

スタートアップに入れておけば起動時に走らせる事もできる

サーバーに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+でテレビ電話システムを構築する

システム概要

raspberry pi 3B+ によるテレビ電話システム
※記載内容に責任は持てません、全て自己責任でお願いします

概念図

f:id:miya15:20190222233504p:plain

背景

  • 妻が夕食の準備中に子供の相手が大変である
  • おばあちゃんが一人なので心配である

改善案

  • 子供とおばあちゃんが気軽にテレビ電話が出来るようにする

要件

  • テレビ電話が出来ること
  • 手軽に使えること(煩雑だと結局使われない)
  • 費用は抑えること(常套句)

想定シナリオ

  • 妻が子供たちを連れて帰宅
  • 我が家からリモコンでスイッチオン
    • 我が家とおばあちゃん家のテレビが自動で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すれば大丈夫だと思う(試してない)

状態遷移図

f:id:miya15:20190228163315p:plain

開始処理のシーケンス図

f:id:miya15:20190228163332p:plain

終了処理のシーケンス図

f:id:miya15:20190228163340p:plain

APIサーバーの機能(超単純)

  • 現在の状態を取得できる
  • 状態を変更できる
  • 接続すべきURLを取得できる
  • セキュリティ関連
    • 必要に応じてapiキーによる制御

やり方

raspberry pi 3(caller, receiverともに)

raspberry pi 3(receiverのみ)

  • 「vtc-exec-receiver.sh」をcronで定期実行させる(間隔はお任せ)
  • 注意:シェルスクリプトAPIサーバーのURLとAPIキーを記載する場所があるので適宜入れておくこと

raspberry pi 3(callerのみ)

  • AB Shutter3 で任意のシェルが叩ける準備(下記の記事を参考に準備する)

miya15.hatenablog.com

  • ON用のボタンが押されたら「vtc-exec-caller-on.sh」を叩くようにする
  • OFF用のボタンが押されたら「vtc-exec-caller-off.sh」を叩くようにする
  • 注意:どちらのシェルスクリプトにもAPIサーバーのURLとAPIキーを記載する場所があるので適宜入れておくこと

APIサーバー

  • docker, docker-compose が入っていなければインストール
    • 直接配置したい人は無くても問題無い
    • ssl付ける人でlet's encrypt使う場合はapache等でリバースプロキシすると良い
      • ssl付けないとapiキー付けてもキャプチャされたら無防備な点に注意
      • sslの詳細は省きます
  • プログラム配置
  • 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"

各種プログラム

注意事項

  • 電化製品なので漏電や火災に気を付けましょう
  • 各種OSやミドルウェアのバージョンを新しく保つよう心がけましょう
    • raspberry pi もパソコンですからBOT化しないよう気を付ける
  • テレビによってはHDMIの制御が効かないものがあります、ご注意ください
    • まずはraspberry piを1台だけ買って双方のテレビに繋いでコマンド投げて試す方が良い
  • 接続先URLをAPIサーバーから取得するようになっているので気になる方は直接プログラムに埋め込んだ方がより安全です
    • URLが変更できるようになっているのはルームIDを変更したり別のサービスに切り替えるのが手軽に出来るようにする為です

今後の発展

  • 状態遷移はjson形式で渡しているので遷移を増やすと面白いかもしれない
  • 定期的にAIで在席・不在を判断できるとその後のアクションにも繋げられるか

運用中に発生した問題点について

  • receiver側でHDMIの制御がうまくいかない事があった
    • 具体的にはch2に繋いでいるのに"as"で入力1になってしまう。ログを取ったが物理アドレスを誤認識している様子。仕方ないので直接chを指定する形で回避。コメントアウトしているが「cmd = "echo 'tx 1f:82:20:00' | cec-client -s"」の部分。1f:82:20でch2、1f:82:10でch1となるがテレビによって違う可能性あり。
  • 実際に繋がると子供(5歳男児)は映っている自分に興奮して踊りだし、おばあちゃんとの会話にならない(苦笑いしてるというありさま)
    • 完全に想定外

メモ

  • APIサーバーはAWSapi gatewayとlambdaとDynamoDBの組み合わせでも問題無いと思うが今回はパス(悪意のあるユーザーに大量に叩かれたら嫌なだけ)
  • Herokuの無料プランでも使えるかもしれない
    • ちょっと試したけどredis使うならクレジットカード登録が必要ですね
  • 今回はraspberry piを使う事が前提にあったが、intel系のスティックPCとかでskypeを使う方式としても使えるかもしれない(skypeには自動応答機能があるので、コマンドラインからコール出来れば完成したようなもの)
  • プログラムが最適化されていない点はご容赦ください
  • バグなどありましたらコメント頂けるとありがたいです
  • 取り敢えず1ヵ月ほど運用してみましたがうまく動いています(思ったほど活用されてないのが残念ですが・・・)

redmineでPlantUMLを表示する際にサーバー側で画像を生成させる方法

概要

PlantUMLは便利ですが画像生成をするアプローチに苦慮します。
記述している内容を秘匿する必要がある場合は尚更です。
今回はredmineプラグインplantuml-redmine-macroに手を加えて社内サーバーで画像を生成させ、それをHTTPレスポンスに含めるやり方を説明したいと思います。

やり方

まずはプラグインのご紹介。

bitbucket.org

このままだと公式サーバーの方に情報が流れてしまうので社内サーバーを立てます。
今回も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