Playwrightを使ってServiceNowインスタンスを自動で叩き起こす

業務の中でServiceNow開発者インスタンスを利用する方はそれなりにいらっしゃいますよね。
そんな皆様が日々「嫌だなー」と感じることは大きく分けて以下の２つがあると思います。

- ServiceNow開発者インスタンスは起動時間がそこそこかかる
- ServiceNow開発者インスタンスは10日間使われていないと削除される

そこで今回は、いつでも自分が使いたいタイミングでServiceNow開発者インスタンスを使えるようにするために、月曜〜金曜の朝5時に自動的にServiceNow開発者インスタンスを起こす仕組みを作成していきましょう。

# 筆者の環境

- macOS Monterey 12.0.1
- Docker Desktop for Mac 4.1.0

# ディレクトリ構造

```
.
├── Dockerfile           # コンテナイメージを管理するためのファイル
├── docker-compose.yml   # アプリケーションを定義するためのファイル
├── snow.py              # ServiceNow開発者インスタンス起動スクリプト
└── login.png            # ServiceNow開発者インスタンス起動確認用スクリーンショット
```

# ServiceNow開発者インスタンスの準備

本稿では、起動したいServiceNow開発者インスタンスがすでにあることを前提としています。
ServiceNow開発者インスタンスの作成方法については、すでに素晴らしい記事が存在しているので「[ServiceNow開発者インスタンスの作成](https://qiita.com/htshozawa/items/e23a39926b876ccb0a42)」のような記事を参考にしてください。

# 自動化したい手順の図解

[ServiceNow開発者用サイト](https://developer.servicenow.com/dev.do)にアクセスして、「Sign In」を押下する。

<img width="400" alt="サインインボタンを押す.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2262262/33e894c0-cdbd-25da-d40b-06854c9924b0.png">

登録しているメールアドレスを入力して、「Next」を押下する。

<img width="250" alt="メール入力.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2262262/75e81541-b936-bc80-46bb-f25d05c20c78.png">

パスワードを入力して、「Sign in」を押下する。

<img width="250" alt="パスワード入力.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2262262/2df1291c-47ff-664d-b4dd-211570bdca70.png">

ページ遷移後に、「Start Building」を押下する。

<img width="400" alt="インスタンス起動.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2262262/afd818a9-2ea6-17af-5721-9e45e6d2376a.png">

別タブにて以下のような画面が開かれてることにより、インスタンスが起動していることを確認する。

<img width="400" alt="インスタンス画面.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2262262/ebeebb3e-c2e9-afda-abc5-4cc84bf5fc1f.png">



# 自動化したい手順をPlaywrightで実現したコードサンプル

コード中の`<メールアドレス>`、`<パスワード>`、`<インスタンスID>`はお使いのServiceNow開発者インスタンスに合わせて変更して使ってください。

```python:snow.py
from playwright.sync_api import sync_playwright

def run(playwright):
    browser = playwright.chromium.launch(headless=True)
    context = browser.new_context()

    page = context.new_page()
    # ServiceNow開発者用サイトにアクセス
    page.goto("https://developer.servicenow.com/dev.do")

    # Sign Inボタンをクリック
    with page.expect_navigation():
        page.click("button:has-text(\"Sign In\")")

    # メールアドレスを入力
    page.fill("[placeholder=\"Email\"]", <メールアドレス>)
    # Nextボタンをクリック
    page.click("text=Next")

    # パスワードを入力
    page.fill("[placeholder=\"Password\"]", <パスワード>)

    # Sign Inボタンをクリック
    with page.expect_navigation():
        page.click("button:has-text(\"Sign in\")")
    
    # Start Buildingボタンをクリック
    with page.expect_popup() as popup_info:
        page.click("button:has-text(\"Start Building\")")
    page1 = popup_info.value

    # ServiceNow開発者インスタンスにアクセス
    page1.goto("https://<インスタンスID>.service-now.com")
    # ServiceNow開発者インスタンスが起動したことを確認するスクショを撮影
    page1.screenshot(path="login.png")
    page1.close()

    page.close()

    context.close()
    browser.close()

with sync_playwright() as playwright:
    run(playwright)
```

# Playwright実行環境の構築

本稿では、Docker環境がすでにお使いのPCに導入されていることを前提としています。
インストールされていない方は[Docker公式サイト](https://www.docker.com/)からDocker環境を準備しておいてください。

[Playwright](https://playwright.dev/)は、Microsoftが中心になって開発するブラウザを操作するためのライブラリです。
今回は、このPlaywrightを使ってブラウザ操作をエミュレートすることで、ServiceNow開発者インスタンスを叩き起こしていきます。

まず、以下のようなDockerfileを作成してください。

```Dockerfile:Dockerfile
FROM mcr.microsoft.com/playwright:focal
RUN pip install playwright
```

今回は、docker-composeを用いてDockerfileをビルドしPlaywright実行環境を作成した上で、ServiceNow開発者インスタンス起動スクリプトを実行することを考えます。
以下のようなdocker-compose.ymlを作成してください。

```yml:docker-compose.yml
version: '3.8'
services:
  playwright:
    build: 
      context: .
    volumes:
        - .:/usr/src/app/
    entrypoint: >
      sh -c "
        cd /usr/src/app/ &&
        python snow.py
      "
```

# 動作確認

ここまでに作成したもので、実際にServiceNow開発者インスタンスが起きてくれるかの動作確認をします。
「[ディレクトリ構造](#ディレクトリ構造)」のルートにあたる位置で、以下のコマンドを実行してください。

```terminal:terminal
$ docker-compose up -d
```

その後、以下のコマンドを実行しスクリプトの実行が完了されたことを確認します。

```terminal:terminal
$ docker ps -a
```

このとき、今回用いたPlaywright環境コンテナのStatusがExited (0)となっていれば、同ディレクトリ内に`login.png`が作成されているので、そちらを開くとインスタンス起動画面を見ることができます。

※ Playwright環境コンテナのStatusがUpとなっている場合は、スクリプトの実行中ですので少し待った後、再び確認してください。

# cronで作成したコードを定時実行

cronは、Unix系OSにおいてコマンドの定時実行のスケジュール管理を行うために用いられます。
今回はこれを利用して、作成したスクリプトを自動実行するようにしていきます。

まず、以下のコマンドを実行してください。

```terminal:terminal
$ crontab -e
```

すると、crontabが起動されるので以下のように入力してください。

```vim:crontab
0 5 * * 1-5 /usr/local/bin/docker-compose up -d
```

上記は月〜金の朝5時にServiceNow開発者インスタンスを起動することを意味しています。

※ 起動されるテキストエディタはvimですので、vimの使い方がわからない方は、「[Vim初心者に捧ぐ実践的入門](https://qiita.com/okamos/items/c97970ab34ff55ff3167)」のような記事を参考にしてください。
※ docker-composeの絶対パスはお使いの環境に合わせて適宜変更してください。

# おわりに

皆様のServiceNow開発者インスタンスが自動で叩き起こされる平和な日々を願っています。

# オマケ - Macユーザ向け -

オマケとして、ServiceNow開発者インスタンスを起こすためだけに常に起動しているサーバを用意したくない方向けの解決案を共有しておきます。

Macを用いることを考えます。
しかし、Macではスリープ状態の際にcronがきちんと動作しないため、cronでスクリプトを自動実行するためにスリープ状態を解除してあげる必要があります。
そこで今回は、ServiceNow開発者インスタンス起動スクリプトを月〜金の朝5時に実行するために、システム環境設定>バッテリー>スケジュールを開いて、「起動またはスリープ解除」にチェックを入れた上で、スリープ解除の曜日・時間を月〜金の朝5時に設定します。
すると月〜金の朝5時にスリープが解除され、cronによりServiceNow開発者インスタンス起動スクリプトが実行され、お使いのServiceNow開発者インスタンスが起きるようになります。