ラベル 自動化 の投稿を表示しています。 すべての投稿を表示
ラベル 自動化 の投稿を表示しています。 すべての投稿を表示

2020年4月7日火曜日

Airtest を Android 10 で動かす

Airtest の最新バージョン(v1.2.3)で Android 10 のサポートが入りました。
私物の端末に Android 10 が来ていたので、反射的にアップグレードして Airtest が動かなくなってしまったのですが、助かりました。

ただし、普通に connect した場合におそらく minitouch の Permission denined error が発生すると思います。
[07:11:37][DEBUG] C:\Python27amd64\lib\site-packages\airtest\core\android\static\adb\windows\adb.exe -s BH900FPXD1 shell /data/local/tmp/minitouch -n 'minitouch_19717' 2>&1
[07:11:37][DEBUG] [minitouch_server]'open: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event8 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event7 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event6 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event5 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event4 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event3 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event0 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event2 for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/mice for inspectionopen: Permission denied'
[07:11:37][DEBUG] [minitouch_server]'Unable to open device /dev/input/event1 for inspectionUnable to find a suitable touch device'

これの対応に1ステップ必要なので紹介します。

IDE の場合
最新バージョンに更新するのはもちろんですが、 ADB connect のオプションを変える必要があります。

スクリプトの場合
実行する python 環境にインストールされている airtest を更新します。

pip install -U airtest

続いて、スクリプトファイルの auto_setup 後に device の touch_method を ADBTOUCH に変更します。
from airtest.core.api import *
from airtest.core.android import *

auto_setup(__file__)
dev = device()
if isinstance(dev, Android):
    dev.touch_method ="ADBTOUCH"


auto_setup(__file__, ["Android:///?touch_method=ADBTOUCH"])
でも touch_method を指定可能ですが、
IDE のスタートボタンから実行した場合は、auto_setup の時点でデバイスのセットアップ済みのため、
auto_setup で指定した touch_method に切り替わりません。
なので、接続中のデバイスが「Android」だったら touch_method を上書きするようにしています。
この書き方であればスクリプト単体実行と IDE からの実行両方で動作します。


公式ドキュメントだと微妙に名前が違ったりしてハマりましたが、ソースコード解析してなんとか解決できました。。
今回は以上です。では。

2019年4月9日火曜日

Slack のステータス(障害情報)を通知する

ついこの間 Slack の障害が発生し、メッセージが正しく届かなかったり、スタンプが押せなかったりなどの影響がありましたね。
Slack の状態はステータスページで確認できます。また、Twitter アカウントもあります。


あとは、Atom feed と RSS も用意されているので、お好きな方法で状況を確認できます。


ただ、ステータスページを都度都度見るのはめんどくさいですし、twitter もタイムラインをずっと見てるわけじゃないので気づかなそう。RSS や Atom feed はリーダーを使ってない。。。

RPA で任意のツールに通知する
というわけで、RPA 組みました。
今回使ったのは Integromat です。最近のお気に入りです。

出来上がったシナリオは3オペレーションになりました。(こだわらなければ2ステップでできます)


Trigger は RSS で、Slack Status の RSS url をセットします。


間にある Text Parser はステータスからアイコンのファイル名を摘出するためのステップです。
アイコン画像にこだわらなければ、このステップは不要です。


最後は通知するステップです。Slack で通知してますが、ここはなんでも良いです。お好きなもので通知してください。
接続設定(slack ならスペースとチャンネル)をしたら、本文をセットしましょう。
RSS で取得した内容が使えるので、その内容を流しています。(特に決まりはないので、ここもお好きに編集してください。)


Slack ではアイコンを指定できるので、Text Parser で取得したステータスからアイコンの url をセットしました。



最後に、Slack Status は 30 分更新のようなので、Trigger の Interval も 30 分にします。


これで完成です。
シナリオを有効にしたら、以下のように通知が飛んできます。


最後に
Integromat はシナリオの Export/Import が可能です。
今回紹介したシナリオの blueprint を Gist で公開しているので、こちらを Import して始めることもできます。
Integromat 便利なので是非使ってみてください。では~


2019年1月29日火曜日

Integromat で役目を終えたシナリオを自動的に停止させる

Integromat はシナリオでエラーが起こると、実行をしばらくポーズします。
ポーズしている間に、エラーを直しましょう。ということだと思いますが、
エラーのままにしておいて、一定回数ポーズをするとシナリオは Disable にされます。


(だんだんとポーズ時間が延びていき、6回目でシナリオが無効になりました。)

今回はこの挙動を利用して、役目を果たしたシナリオが自動的に Disable になるようにしてみました。

やり方
まず、役目を果たしたことをシナリオが認知しなければいけません。
その点はシナリオによって変わってくるので、ここでは説明しません。
今回は、すでに役目を果たしたことをシナリオで検出できており、そのノードが出来上がっている前提とします。

以下が、そのシナリオです。
Slack 通知が2つあると思いますが上が正常ノード。下は期間終了後のノードで、赤い丸をつけたところが、今回のポイントです。


この HTTP GET オペレーションは、存在しない適当なアドレスに GET リクエストをします。
このオペレーションは失敗します。が、これで OK です。


簡単にいうと、わざと失敗させています。
失敗すればなんでもいいので、正常ケースのオペレーションが、役目を果たしたあとの場合に異常ケースで失敗してしまう、でも(今回の目的では)問題ないです。

なぜこんなことが必要なのか


Free プランで使っているのですが、ちょっとリッチなシナリオを書いたり、一日に何回もトリガーする cron 設定にしたりすると、すぐに 1,000 operations 消費してしまってシナリオ実行ができなくなってしまって困ってました。
Operation の数を削減することもできるのですが、30分毎にトリガーすると 2 x 24 x 30 = 1440 で、仮に 1 operation でも全然足りません。

ただ、今回の場合、30分毎にトリガーする必要はあるものの、1ヶ月間ずっと必要ではなく1週間程度で良かったので、必要なときだけシナリオを有効にすれば OK でした。







自動化したいじゃないですが!

というわけで今回は、「自動で無効にする」ができました。
次は、「自動で有効にする」ができたら報告したいと思います。
(有効化は設定を書き換える必要があったりするので少し手間取りそうですが・・・)

では。

2014年4月14日月曜日

[Jenkins] アップグレードのスケジューリング

Jenkins の管理者の方々は Jenkins 自体のアップグレードやプラグインのアップグレードなど、メンテナンス業務があると思います。
それを少し楽にしたって話です。少しです、少し。

何をしたかというと、「Jenkins を SafeRestart させるジョブ」を作っただけです。
SafeRestart は実行(ビルド)中のジョブがなければ、Jenkins を再起動させる機能です。

どう楽になったか
アップグレードをする場合、Jenkins を止める必要があります。この作業はできるだけ開発メンバーが作業中でない方が良いです。そうなると、アップグレードは夜中とか休日とかなることが多いと思います。
また、大きいプロジェクトや1ビルドがなが~いテストを持つ Jenkins の場合、止めるのにも時間がかかったりします。(強制中断という手もありますが・・・)

それだと、管理者は大変ですよね?

今回、「Jenkins を SafeRestart させるジョブ」を作ったことで、「SafeRestart のスケジューリング」ができるようになり、Jenkins の再起動を予約できるようになりました。
つまり、金曜に Jenkins の更新をダウンロード&インストールしておき(再起動はしてないので、アップグレード自体は未完)、開発メンバーがいない土曜深夜に SafeRestart を仕掛けておけば、日曜日には再起動がかかって無事アップグレードが完了。
そして月曜日にはいつもどおり CI が回せるというわけです。

これで管理者である私は休日出勤しなくて済むようになりました。
SafeRestart させるジョブの作り方
いろいろ方法があると思います。
SafeRestart 自体は、Jenkins の URL + /safeRestart(http://~/safeRestart)を開くだけでもできますし、SafeRestart Plugin ってのもあります。

今回は、みんな大好き Groovy postbuild Plugin を使った方法を紹介します。

1. プロジェクトを作る
2. 「ビルド後の処理の追加」から「Groovy Postbuild」を追加
3. 以下のスクリプトを入力
def jenkins = hudson.model.Hudson.instance
jenkins.doSafeRestart()
4. ビルド・トリガに再起動させたい日時を設定する(ビルド中であることも考慮して早めに設定しておくといいかも)

設定は以上です。これで Jenkins の管理が楽になりますね。

※ Windows の場合、サービスで実行してないとダメなようです。(その他の OS は確認してません)

2013年4月16日火曜日

[Jenkins] スレーブマシンの再起動をするジョブ(その2)

ブログズミ - [Jenkins] スレーブマシンの再起動をするジョブ で紹介したスクリプトをパワーアップさせました。

前回は、再起動したいスレーブでジョブを実行してマシンを再起動させていました。
今回は、再起動したいスレーブとは別のスレーブでジョブを実行し、
ターゲットスレーブのビルドが終わるのを待ってから、再起動させるようにしました。

import hudson.slaves.OfflineCause.SimpleOfflineCause
import hudson.util.RemotingDiagnostics

def jenkins = hudson.model.Hudson.instance

class OfflineMessage extends org.jvnet.localizer.Localizable {
  def message
  OfflineMessage() {
    super(null, null, [])
    def timestr = new Date().format("HH:mm dd/MM/yy z", TimeZone.getTimeZone("UTC"))
    this.message = "automated reboot at end of test at " + timestr
  }
  String toString() {
    this.message
  }
  String toString(java.util.Locale l) {
    toString()
  }
}

def cause = SimpleOfflineCause.create(new OfflineMessage())
def target_name = manager.build.buildVariables.get("REBOOT_SLAVE")

if ( target_name == null ) {
    manager.listener.logger.println("ERROR!! REBOOT_SLAVE is null.")
}

// 同一 PC 上のスレーブをオフライン
def slaves = jenkins.slaves
slaves.each {
    def com = it.toComputer()
    def name = com.getEnvironment().get("COMPUTERNAME","")
    if( name.compareToIgnoreCase(target_name) == 0 ) {
        if( com.isOnline() ) {
            // スレーブをオフラインにしてアイドル待ち
            com.setTemporarilyOffline(true, SimpleOfflineCause.create(new OfflineMessage()))
            // 実際にアイドル待ちするのは、全部オフラインにしてから
        }
    }
}

slaves.each {
    def com = it.toComputer()
    def name = com.getEnvironment().get("COMPUTERNAME","")
    def node_name = it.getNodeName()
    if( name.compareToIgnoreCase(target_name) == 0 ) {
        if( !com.isIdle() ) {
            manager.listener.logger.println("Wait ${node_name} Slave Task...")
            while( !com.isIdle() ) {
                Thread.sleep(3000)
            }
        }
    }
}

// reboot
def script = """

    if (Functions.isWindows()) {
      'cmd /c "shutdown /f /r /t 10 -m \\\\\\\\${target_name} /c \"Restarting after Jenkins test completed\""'.execute()
    }

"""

def computer = manager.build.getBuiltOn().toComputer()
def channel = computer.getChannel()
manager.listener.logger.println(script)
RemotingDiagnostics.executeGroovy( script, channel )

// 再起動待ち
Thread.sleep(5*60*1000)

// 再接続
slaves.each {
    def com = it.toComputer()
    def name = com.getEnvironment().get("COMPUTERNAME","")
    if( name.compareToIgnoreCase(target_name) == 0 ) {
        com.setTemporarilyOffline(false, com.getOfflineCause())
    }
}

こちらのコードは github にもアップしています。

2012年10月18日木曜日

[Jenkins] スレーブマシンの再起動をするジョブ

Groovy postbuild plugin はとりあえずインストールしとけ
で、Groovy postbuild plugin を紹介しました。

今回は、Groovy postbuild plugin を使ってスレーブマシンの再起動する例を見つけたので紹介します。

ネタ元はこちら > https://bugreports.qt-project.org/browse/QTQAINFRA-558

以下に紹介されているコードを示します。
import hudson.slaves.OfflineCause.SimpleOfflineCause
import hudson.util.RemotingDiagnostics

/* FIXME: why cannot we import jenkins.util.NonLocalizable ? */
class OfflineMessage extends org.jvnet.localizer.Localizable {
  def message
  OfflineMessage() {
    super(null, null, [])
    def timestr = new Date().format("HH:mm dd/MM/yy z", TimeZone.getTimeZone("UTC"))
    this.message = "automated reboot at end of test at " + timestr
  }
  String toString() {
    this.message
  }
  String toString(java.util.Locale l) {
    toString()
  }
}

def computer = manager.build.getBuiltOn().toComputer()
def channel = computer.getChannel()
computer.setTemporarilyOffline(true, SimpleOfflineCause.create(new OfflineMessage()))
RemotingDiagnostics.executeGroovy( """

    if (Functions.isWindows()) {
      'shutdown /r /t 10 /c "Restarting after Jenkins test completed"'.execute()
    } else {
      "sudo reboot".execute()
    }

""", channel )

何が嬉しいか
クリーンな環境でテストをしたいと思った場合、
仮想マシンや Windows SteadyState(古い?) を使う方法があります。

そういった場合、クリーンな状態に戻すときに再起動する必要があるので、
このスクリプトを使って自動化できると助かるのではないでしょうか。
(Windows の場合 shutdown コマンドに /f オプションも付けたほうがいいかも)

本当に、Groovy postbuild plugin って便利ですね!