SOLIDWORKS PDMの完全なバックアップを自動でおこなう

# はじめに

ロボットのモデルをつくるときみなさんはなにを使っているでしょうか？わたしのプロジェクトでは、[SOLIDWORKS 3D CAD](https://www.solidworks.com/ja/category/3d-cad)を使用しています。今回は、SOLIDWORKSを使うときにバージョン管理を行う[SOLIDWORKS PDM](https://www.solidworks.com/ja/product/solidworks-pdm)のシステムを自前で運用した時に手間のかかる作業となる完全なバックアップの自動化をまとめました。

# 前提知識

[インストレーションガイドSOLIDWORKS PDM 2019/SOLIDWORKS Manage 2019](https://files.solidworks.com/Supportfiles/PDMWorks_Ent_Installation/2019/Japanese/Installation%20Guide.pdf)を読み、完全に理解している人を対象にしています。

# 環境

| 環境 | バージョン |
|:-:|:-:|
| Server | Windows 10 Professional |
| SOLIDWORKS | 2019 SP3 |
| PDM | Standard |
| SQL Server | 2014 Express |

# バックアップの保存先について

今回は取得したバックアップの保存先をS3にしています。またAWSの設定は、CircleCIを用いてTerraformで自動化してありますので、今回は例としてその設定ファイルを示します。

## IAMの設定

IAMの設定をする例を示します。`{バケット名}`には、自分のバケット名称を記述してください。

```iam.tf
resource "aws_iam_user" "solidworks_aws_iam_user" {
  name          = "${var.solidworks_aws_iam_user}"
  path          = "/"
  force_destroy = true
  tags = {
    group = "solidworks"
  }
}
resource "aws_iam_access_key" "solidworks_iam_access_key" {
  user    = "${var.solidworks_aws_iam_user}"
  pgp_key = "${var.pgp_key}"
}
resource "aws_iam_group" "solidworks_iam_group" {
  name  = "${var.solidworks_aws_iam_group}"
}
resource "aws_iam_policy" "solidworks_backup_policy" {
  name        = "solidworks_backup"
  path        = "/"
  description = "My test policy"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "ListObjectsInBucket",
          "Effect": "Allow",
          "Action": ["s3:ListBucket"],
          "Resource": ["arn:aws:s3:::{バケット名}"]
      },
      {
          "Sid": "AllObjectActions",
          "Effect": "Allow",
          "Action": "s3:*Object",
          "Resource": ["arn:aws:s3:::{バケット名}/*"]
      }
  ]
}
EOF
}
resource "aws_iam_group_policy_attachment" "solidworks-group-s3fullaccess" {
  group      = "${var.solidworks_aws_iam_group}"
  policy_arn = "${aws_iam_policy.solidworks_backup_policy.arn}"
}
resource "aws_iam_group_membership" "solidworks_group_membership" {
  name  = "solidworks_group"
  users = [
    "${var.solidworks_aws_iam_user}"
  ]
  group = "${var.solidworks_aws_iam_group}"
}
```

## S3バケットの設定

S3バケットの設定例を示します。

```s3backup.tf
resource "aws_s3_bucket" "s3solidworks" {
  bucket = "{バケット名}"
  region = "ap-northeast-1"

  lifecycle_rule {
    id      = "backup"
    enabled = true

    prefix = "backup/"
    expiration {
      days = 20
    }
  }
}

resource "aws_s3_bucket_public_access_block" "s3solidworks_access_block" {
  bucket = "${aws_s3_bucket.s3solidworks.id}"

  block_public_acls   = true
  block_public_policy = true
  ignore_public_acls = true
  restrict_public_buckets = true
}
```

## 変数の設定

変数を設定します。pgp_keyについては、わたしの場合、keybaseで生成したものを使用しています。各自のキーを設定してください。

```variable.tf
variable "solidworks_aws_iam_user" {
  type = "string"
  default = "solidworks.backup"
}
variable "solidworks_aws_iam_group" {
  type = "string"
  default = "solidworks"
}
variable "pgp_key" {
  type = "string"
  default = "{keybaseで生成したもの}"
}
```

## 出力の設定

出力設定を示します。ここで`encrypted_secret`は、暗号化され出力されますので、それを自前のキーで復号化して`aws configure --profile`で設定します。

```output.tf
output "encrypted_secret" {
  value = "${aws_iam_access_key.solidworks_iam_access_key.encrypted_secret}"
}
output "solidworks_iam_access_key_id" {
  value = "${aws_iam_access_key.solidworks_iam_access_key.id}"
}
output "solidworks_iam_access_key_user" {
  value = "${aws_iam_access_key.solidworks_iam_access_key.user}"
}
```

これでPUSHしたコミットがCircleCIでTerraform Planを実行し、`approval`されると権限が作成されます。

# バックアップ先のディレクトリ構成

今回は、わかりやすくデスクトップに下記の画像のような構成をしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559128/264b4795-beac-50c9-47f2-8b64ead2afba.png)

# アーカイブサーバのバックアップ設定

## アーカイブサーバのコンフィグレーションについて

アーカイブサーバのコンフィグレーションバックアップを設定します。これは、インストレーションマニュアル通りGUIから設定するだけなので省略します。バックアップは、毎日AM1:00にし、バックアップ先は、今回`C:\Users\wnwn\Desktop\SolidworksBackup\backup\Backup.dat`に設定しています。

## アーカイブサーバのデータについて

アーカイブサーバのデータ領域については、自動でバックアップをする機能はありません。ここでは、powershellを使い、`compress-archive`コマンドでバックアップを作成します。

```
powershell compress-archive -Path C:\Users\wnwn\Desktop\SolidworksArchive -DestinationPath C:\Users\wnwn\Desktop\SolidworksBackup\backup\ArchiveServer.zip
```

# SQL Serverのバックアップ

SQL Server Expressは、製品版と違い自動バックアップ機能がありません。しかしSQLからバックアップを取得することができるため、まず必要なSQLを作成します。今回バックアップするVolt名称は、`test`です。[ConisioMasterDb](https://forum.solidworks.com/thread/101149)も同様にバックアップが必要なためバックアップします。

```backup.sql
BACKUP DATABASE [test] TO  DISK = N'C:\Users\wnwn\Desktop\SolidworksBackup\backup\test.bak' WITH NOFORMAT, INIT,  NAME = N'test-完全 データベース バックアップ', SKIP, NOREWIND, NOUNLOAD,  STATS = 10
GO
BACKUP DATABASE [ConisioMasterDb] TO  DISK = N'C:\Users\wnwn\Desktop\SolidworksBackup\backup\ConisioMasterDb.bak' WITH NOFORMAT, INIT,  NAME = N'ConisioMasterDb-完全 データベース バックアップ', SKIP, NOREWIND, NOUNLOAD,  STATS = 10
GO
```
このファイルを`C:\Users\wnwn\Desktop\SolidworksBackup\sql`に配置します。これで必要な設定が終わりました。

# バックアップシェルを作成する

それでは、SQL Serverのバックアップ・アーカイブサーバのバックアップをとり、それをS3にアップロードして、合否をslackに通知するバッチの例を下記に示します。

```backup.cmd
echo %date% %time%

del C:\Users\wnwn\Desktop\SolidworksBackup\backup\*.bak
del C:\Users\wnwn\Desktop\SolidworksBackup\backup\*.zip

sqlcmd -S {SQL Serverのホスト}\SWPDM -U sa -P {パスワード} -i C:\Users\wnwn\Desktop\SolidworksBackup\sql\backup.sql
powershell compress-archive -Path C:\Users\wnwn\Desktop\SolidworksArchive -DestinationPath C:\Users\wnwn\Desktop\SolidworksBackup\backup\ArchiveServer.zip

CHDIR C:\Users\wnwn\Desktop\SolidworksBackup\backup

set count=0
for %%A in (*.bak *.zip *.dat) do set /a count+=1

aws s3 mv C:\Users\wnwn\Desktop\SolidworksBackup\backup\test.bak s3://{バケット名}/backup/%date:~0,4%%date:~5,2%%date:~8,2%/
aws s3 mv C:\Users\wnwn\Desktop\SolidworksBackup\backup\ConisioMasterDb.bak s3://{バケット名}/backup/%date:~0,4%%date:~5,2%%date:~8,2%/
aws s3 mv C:\Users\wnwn\Desktop\SolidworksBackup\backup\ArchiveServer.zip s3://{バケット名}/backup/%date:~0,4%%date:~5,2%%date:~8,2%/
aws s3 mv C:\Users\wnwn\Desktop\SolidworksBackup\backup\Backup.dat s3://{バケット名}/backup/%date:~0,4%%date:~5,2%%date:~8,2%/

if %count% equ 4 (
    SET SLACK_TEXT=[Solidworks PDM] backup batch was completed. [num:%count%]
) else (
    SET SLACK_TEXT=[Solidworks PDM] backup batch was failed. [num:%count%]
)

SET SLACK_CHANNEL=#{チャンネル名}
SET SLACK_BOTNAME=Backup Notification
SET SLACK_WEBHOOKURL="{Webhook URL}"
curl -X POST --data-urlencode payload="{\"channel\":\"%SLACK_CHANNEL%\", \"username\": \"%SLACK_BOTNAME%\", \"text\":\"%SLACK_TEXT%\"}" %SLACK_WEBHOOKURL%
```

これでバッチは完成です。

# タスクスケジューラに登録する

下記の内容でAM6:00に設定します。

```
C:\Users\wnwn\Desktop\SolidworksBackup\batch\backup.cmd > C:\Users\wnwn\Desktop\SolidworksBackup\log\%date:~0,4%%date:~5,2%%date:~8,2%.log
```

無事実行された場合は、slackに下記のような通知がきます。

```
[Solidworks PDM] backup batch was complited. [num:4]
```

# データの復元について

## 誤ってVoltを削除してしまった場合

テスト用のVoltを削除すると下記のようなエラーが発生します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559128/2bb24425-922f-1571-ad32-240969e8a103.png)

## バックアップデータの取得

バックアップのある日にちを確認し、データを取得します。

```
$ chdir C:¥solidworks_backup
$ aws s3 cp s3://{バケット名}/backup/20190628/ . --recursive
```

## データベースの復元

Microsoft SQL Server Management Studioを立ち上げてDBを復元します。デバイスから復元するを選択し、前述で取得したデータからVolt名が`test`より`test.bak`を選択します。OKでデータベースが復元します。

## アーカイブサーバのデータの復元

前述で取得したファイルより`ArchiveServer.zip`をダブルクリックして圧縮ファイルを展開します。Voltを削除してから別の更新がある場合、それが上書きされてしまうため注意が必要です。

## アーカイブコンフィグレーションの復元

これはインストレーションマニュアルにあるとおり、GUIから設定できるので省略します。これで、誤って削除してしまったVoltを復元できました。

# PDMを管理しているPCを変更する

サーバが物理的に故障した場合などで別サーバにセットアップする場合、再度`SOLIDWORKS PDM`の及び`SQL Server Express`をセットアップします。データの復元は、前述と同じ作業ですが、SQL ServerにConisioMasterDbも復旧する必要があります。全ての作業が終わったら、データが復旧したことを確認し、最後に同じようにバックアップ設定を行います。これでサーバが万が一にも故障しても、PDMデータが復元できることが確認できました。

# まとめ

* SOLIDWORKS PDMの完全なバックアップの自動化と復元ができることを確認できた
* ロボット開発者は、自動化できるものは自動化することを確認できた