NextCloudのカレンダーに自動でvCenterの証明書期限を登録してみる


# 概要

現在私はvCenterなどの証明書の期限をNextCloudのカレンダー上で現在管理しています。
ただし、都度手動で追加の運用をしていますが、中々手間な部分もあります。
そこで今回はNextCloudのカレンダーを操作できるCalDAVがあるのでそれを利用して自動化してみようと思います。

## 本記事の対象

- NextCloudのカレンダー操作をプログラムから実行したい方

## 構成する環境

今回は以下のようなイメージを構成してみます。  
NextCloudのカレンダーを操作するためのAPIをFlaskで構成してDocker上で常に動作させておきます。

そして証明書を取得してAPIに登録処理を促すスクリプトをコンテナとしてCronで都度起動させる形にします。
なお今回はある程度汎用性を持たせるように、APIやスクリプトの中身は作成しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406495/f3fc4bcd-92fd-c801-bcb9-604b814092c2.png)

## 実施順番

以下順番で実施していきます。

- NextCloudのカレンダー操作用APIの作成
- Docker上でAPIを起動
- API呼び出し用Python スクリプトの作成
- Cronの設定

# カレンダー操作用APIの作成

まず対象のカレンダーの仕組みを確認します。

NextCloudではカレンダーにイベントとして以下画像のようにスケジュールが登録されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406495/9e1ef862-123a-c52b-3331-d35205ebbb78.png)

上記のイベントの情報はWebDAVでは以下のようなiCalendarフォーマットとして扱われます。

```yaml
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
VERSION:2.0
PRODID:-//IDN nextcloud.com//Calendar app 5.0.0//EN
BEGIN:VEVENT
CREATED:20241002T124846Z
DTSTAMP:20241002T124954Z
LAST-MODIFIED:20241002T124954Z
SEQUENCE:3
UID:8f9c219f-34c7-440c-acba-95e27d093808
DTSTART;TZID=Asia/Tokyo:20241004T000000
DTEND;TZID=Asia/Tokyo:20241004T010000
STATUS:CONFIRMED
SUMMARY:example_123
DESCRIPTION:test_123
CATEGORIES:system_created
END:VEVENT
BEGIN:VTIMEZONE
TZID:Asia/Tokyo
BEGIN:STANDARD
TZOFFSETFROM:+0900
TZOFFSETTO:+0900
TZNAME:JST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
END:VCALENDAR
```

今回はパラメータの対象を絞って、以下を設定するようにします。
一部必須で一部任意のパラメータを想定しています。

| 項目           | APIパラメータの受取          |
|--------------|----------------------|
| UID          | 自動生成                 |
| DTSTAMP      | 自動生成                 |
| DTSTART;TZID | 必須                   |
| DTEND;TZD    | 必須                   |
| SUMMARY      | 必須                   |
| DESCRIPTION  | 任意                   |
| TZID         | 任意 (デフォルトAsia/Tokyo) |

今回APIに必要なものとしては、上記のパラメータを用いて以下2つの処理ができれば、問題はないかという感じです。

- カレンダーにイベントを追加
- カレンダーにイベントがすでにあるか

  
上記の内容をもとにNextCloudのカレンダー操作用のAPIをFlaskベースで用意しました。
細かいコードの説明は省きますが、 `/add_event`というAPIでイベントを追加、 `/event_exists`というAPIでイベントの存在確認を行ったりするようにしています。
（汎用性のため他にもAPIは作成しています）

https://github.com/murajo/NextcloudCalenderManage


例えば以下のようなリクエストでイベントを追加できます。

```bash
curl -X POST "http://localhost:5000/add_event" \
     -H "Content-Type: application/json" \
     -d '{
          "calendar_name": "System",
          "start_time": "2024-10-05T09:00:00",
          "end_time": "2024-10-05T10:00:00",
          "summary": "test",
          "description": "Hello"
         }'
```

一旦これでAPIのコードの準備は出来たため、Docker展開して起動させます。

# Docker上でAPIを起動

ここはすごくシンプルで、先程のコードをコンテナとして起動するだけとなります。

Dockerが実行できるマシンに`git clone`します。

```bash
git clone https://github.com/murajo/NextcloudCalenderManage.git
```

そしてDockerfileの準備を行います。
今回はAPI側は環境変数としてNextCloudの認証情報を受取るようにしています。
そのため、コンテナ側に環境変数をもたせる必要があるため、ENVのところは環境に合わせて書き換えます。
（コンテナ起動時にパラメータで指定することも可）

```Dockerfile
FROM python:3.12

ENV NEXTCLOUD_URL='https://<your_nextcloud_domain>/remote.php/dav'
ENV NEXTCLOUD_USERNAME='<your_nextcloud_username>'
ENV NEXTCLOUD_PASSWORD='<your_nextcloud_password>'
ENV VERIFY_SSL='False' 

WORKDIR /app

COPY . .

RUN pip install --no-cache-dir -r requirements.txt

CMD ["python", "app.py"]
```

続いてDockerfileを用いて`build`します。

```bash
docker build -t nextcloud-calendar-api .
```

docker imagesでイメージが作成されたことを確認します。

```bash
docker images

## 出力
REPOSITORY               TAG       IMAGE ID       CREATED          SIZE
nextcloud-calendar-api   latest    d65149633b0c   29 seconds ago   1.04GB
```

最後に以下で起動します。
今回は5000のポート番号を使って起動しています。
（-eを用いることで、ここで環境変数の指定もできます）
```bash
docker run -d -p 5000:5000 --name nextcloud-calendar-api nextcloud-calendar-api:latest
```

docker psで起動されていることを確認します。
```bash
docker ps

## 出力
CONTAINER ID   IMAGE                           COMMAND           CREATED          STATUS          PORTS                                       NAMES
53d094321788   nextcloud-calendar-api:latest   "python app.py"   25 seconds ago   Up 25 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   nextcloud-calendar-api
```

一応curlを飛ばして、動作していることも確認できます。

```bash
curl -X POST "http://192.168.0.115:5000/add_event" \
     -H "Content-Type: application/json" \
     -d '{
          "calendar_name": "System",
          "start_time": "2024-10-05T09:00:00",
          "end_time": "2024-10-05T10:00:00",
          "summary": "test_event",
          "description": "Hello-world"
         }'

## 出力
{"message":"Event added to System"}
```

カレンダー上にも無事に追加されていました。
![image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406495/587353d4-f1a4-a7ac-b608-fdd984e85dd4.png)

以上でAPIの準備は完了です。

# API呼び出し用Pythonスクリプトの作成

続いて先程のAPIを呼び出して、証明書のスケジュールを登録するスクリプトの準備を行います。

今回はお試しでvCenterのSSL証明書を登録するようにします。
（一応ドメインを指定するだけなので、何でも大丈夫）

登録するイベントとしては以下のような構成にします。
summaryを証明書ごとに一意とするため、証明書のCNに証明書の発行日を加えるようにします。
- start_time: 証明書の期限の0時
- end_time: 証明書の期限の0時
- summary: 証明書のCN+証明書の発行日
- description: "SSL Certificate valid from" + 証明書の発行日 + "to" + 証明書の期限

続いて用意すべき処理としては大きく以下3つとなります

- 証明書の情報の取得
- イベントが登録済みかのチェック
- イベントの追加実施


こちらも細かいコードの説明は省きますが、上記を元にスクリプトを作成しておきました。
今回の目的はvCenterだけではありましたが、複数ドメインに対して確認できるよう汎用性を持たせています。

https://github.com/murajo/certificate-expiration-date-to-nextcloud-calendar

各設定はconfig.yamlに入れておくようにして、ここを変えれば使えるようにしています。
```yaml
nextcloud:
  api_url: "http://<your-nextcloud-calendar-mangae-api-url>:<port>"
  calendar_name: "<your-calendar-name>"
domains:
  - example.com
  - example.org
```

試しにvCenterのドメインを入れて実行してみて、
以下のようにカレンダーに追加されることが確認できました。
![image (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406495/92fd3dcf-0423-f738-2052-e704d8b68e34.png)


ここまでで処理としては全て完成となります。

最後にこのスクリプトをCronからDockerコンテナとして定期的に実行させようと思います。

# Cronの設定

今回は先程のスクリプトをコンテナとして実行させる予定です。
ただし、コンテナはCronにて都度起動させて、処理を終えたら削除させるようにします。

まずDocker環境に先程のスクリプトを持っていきます。
```bash
git clone https://github.com/murajo/certificate-expiration-date-to-nextcloud-calendar
```

Dockerfileも一緒に格納されているので、そのままbuildします。

```bash
docker build -t ssl-certificate-add-to-calendar .
```

続いてドメイン情報等を持っている`config.yaml`の作成を行っておきます。

パラメータの変更を追従できるように、コンテナイメージには持たせず、都度コンテナにマウントさせて起動するようにしておきます。

実行コマンドは以下で、`-rm`で実行完了後削除されるようにしています。
```bash
docker run --rm -v <作成したconfig.yamlの置いてあるパス>/config.yaml:/app/config.yaml ssl-certificate-add-to-calendar
```

それでは最後に上記のコマンドをCronに入れます
まず以下コマンドでcronジョブの編集画面に移ります。
```bash
crontab -e
```

そして開かれた画面に行を追加します。
例えば今回は毎日0時に実行するように設定しておきます。

```conf
0 0 * * * docker run --rm -v /path/to/config_my.yaml:/app/config.yaml ssl-certificate-add-to-calendar
```

これでcronにて都度コンテナが起動して、カレンダーに証明書の期限を入れてくれるようになりました。

# まとめ

今回はNextCloudのカレンダーへの自動イベント追加を行ってみました。
普段わりと手動でやってしまいがちですが、マシン数も増えてきて管理する証明書が多くなってきたのでちょうど良かったです。
なお、あとから記事書きながら思ったこととして、対象とするドメインを今回`config.yaml`に追記する形ですが、DNSサーバーの設定から取れるようにしたほうがより自動化になるなって感じですね。

## 参考にした記事

https://qiita.com/masaki12-s/items/905365c9d5f68b7efcd8

https://qiita.com/yuzo_____/items/1b8af6e04ffa2baa1cab