minishift V1.28.0でnginx+gunicorn+Django2を動かす。あっcreatesuperuser忘れてた(笑)

# いままでのおさらい

前回まででnginx+gunicorn+Django2をminishiftで動作させることには成功したわけですが…
Django2プロジェクトにおける大事な要素である`createsuperuser`を忘れていました(笑)

- [Win10環境でDjango2のREST APIを試してみる](https://qiita.com/imp555sti/items/cbe579fbbfa3837075f3)
- [minishift V1.28.0でDjango2を動かす①：テンプレート確認](https://qiita.com/imp555sti/items/7fcb6d507c4e0eae5b3a)
- [minishift V1.28.0でDjango2を動かす②：テンプレート＆s2iソースの作成](https://qiita.com/imp555sti/items/728e774cd54e5781884b)
- [minishift V1.28.0でDjango2を動かす③：s2iソースの修正＆ビルド](https://qiita.com/imp555sti/items/f6ea232c1935f7c9042c)
- [minishift V1.28.0でDjango2を動かす④：残課題](https://qiita.com/imp555sti/items/ac7839d2a846f69a2bc1)
- [minishift V1.28.0でnginx+gunicorn+Django2を動かす](https://qiita.com/imp555sti/items/7733b48f41fc37ddda24)
- [minishift V1.28.0でnginx+gunicorn+Django2を動かす。あっcreatesuperuser忘れてた(笑)](https://qiita.com/imp555sti/items/e4ce4524fe8535313616)
- [openshiftに対応するためのDjango2コーディング時に気を付けるべき点](https://qiita.com/imp555sti/items/e9b37f0d5430220da690)


# SecretにDjango2のsuperuserの情報を追加する
SecretにDjango2のsuperuserの情報を追加します。
これはテンプレートファイルを修正することになります。

まずは"kind": "Secret"に項目を追加します。
修正前

```json:openshift/templates/django2-nginx.json
    :
    {
      "kind": "Secret",
      "apiVersion": "v1",
      "metadata": {
        "name": "${NAME}"
      },
      "stringData" : {
        "django-secret-key" : "${DJANGO_SECRET_KEY}"
      }
    },
    :
```

修正後

```json:openshift/templates/django2-nginx.json
    :
    {
      "kind": "Secret",
      "apiVersion": "v1",
      "metadata": {
        "name": "${NAME}"
      },
      "stringData" : {
        "django-secret-key" : "${DJANGO_SECRET_KEY}",
        "django-admin-user" : "${DJANGO_ADMIN_USER}",
        "django-admin-email" : "${DJANGO_ADMIN_EMAIL}",
        "django-admin-password" : "${DJANGO_ADMIN_PASSWORD}"
      }
    },
    :
```

次にテンプレートのフォームから値を入力できるようパラメータを定義します。
具体的には"parameters"に項目を追加します。

修正前

```json:openshift/templates/django2-nginx.json
  "parameters": [
    :
    {
      "name": "APP_CONFIG",
      "displayName": "Application Configuration File Path",
      "description": "Relative path to Gunicorn configuration file (optional).",
      "value": "conf/gunicorn.py"
    },
    {
      "name": "DJANGO_SECRET_KEY",
      "displayName": "Django Secret Key",
      "description": "Set this to a long random string.",
      "generate": "expression",
      "from": "[\\w]{50}"
    },
    :
  ]
```

修正後

```json:openshift/templates/django2-nginx.json
  "parameters": [
    :
    {
      "name": "APP_CONFIG",
      "displayName": "Application Configuration File Path",
      "description": "Relative path to Gunicorn configuration file (optional).",
      "value": "conf/gunicorn.py"
    },
    {
      "name": "DJANGO_ADMIN_USER",
      "displayName": "Django Admin User Name",
      "required": true,
      "value": "admin"
    },
    {
      "name": "DJANGO_ADMIN_EMAIL",
      "displayName": "Django Admin User's E-Mail",
      "required": true,
      "value": "admin@localhost"
    },
    {
      "name": "DJANGO_ADMIN_PASSWORD",
      "displayName": "Django Admin User's Password",
      "generate": "expression",
      "from": "[a-zA-Z0-9]{16}"
    },
    {
      "name": "DJANGO_SECRET_KEY",
      "displayName": "Django Secret Key",
      "description": "Set this to a long random string.",
      "generate": "expression",
      "from": "[\\w]{50}"
    },
    :
  ]
```

パスワード`DJANGO_ADMIN_PASSWORD`は自動生成もできるようにしておきました。

# Secret情報をDeploy時に参照する
Secretに項目を追加したので、その環境変数が必要になるフェーズ(今回はDeploy時)のセクションに`env`として参照設定を追加します。
これもテンプレートファイルを修正することになります。
ちなみにBuild時にも参照したい場合、`"kind": "BuildConfig"`にも追記します。

"kind": "DeploymentConfig"の中の`"spec": {"containers": [`内に定義されている`env`に追加します。

修正前

```json:openshift/templates/django2-nginx.json
    :
    {
      "kind": "DeploymentConfig",
        :
        "template": {
          "metadata": {
            "name": "${NAME}",
            "labels": {
              "name": "${NAME}"
            }
          },
          "spec": {
            "containers": [
              {
                "name": "${NAME}",
                "image": "${NAME}:latest",
                "ports": [
                  {
                    "containerPort": 8000,
                    "protocol": "TCP"
                  }
                ],
                "env": [
                  {
                    "name": "APP_CONFIG",
                    "value": "${APP_CONFIG}"
                  },
                  {
                    "name": "DJANGO_SECRET_KEY",
                    "valueFrom": {
                      "secretKeyRef" : {
                        "name" : "${NAME}",
                        "key" : "django-secret-key"
                      }
                    }
                  }
                ],
              ：
```

修正後

```json:openshift/templates/django2-nginx.json
    :
    {
      "kind": "DeploymentConfig",
        :
        "template": {
          "metadata": {
            "name": "${NAME}",
            "labels": {
              "name": "${NAME}"
            }
          },
          "spec": {
            "containers": [
              {
                "name": "${NAME}",
                "image": "${NAME}:latest",
                "ports": [
                  {
                    "containerPort": 8000,
                    "protocol": "TCP"
                  }
                ],
                "env": [
                  {
                    "name": "APP_CONFIG",
                    "value": "${APP_CONFIG}"
                  },
                  {
                    "name": "DJANGO_ADMIN_USER",
                    "valueFrom": {
                      "secretKeyRef" : {
                        "name" : "${NAME}",
                        "key" : "django-admin-user"
                      }
                    }
                  },
                  {
                    "name": "DJANGO_ADMIN_EMAIL",
                    "valueFrom": {
                      "secretKeyRef" : {
                        "name" : "${NAME}",
                        "key" : "django-admin-email"
                      }
                    }
                  },
                  {
                    "name": "DJANGO_ADMIN_PASSWORD",
                    "valueFrom": {
                      "secretKeyRef" : {
                        "name" : "${NAME}",
                        "key" : "django-admin-password"
                      }
                    }
                  },
                  {
                    "name": "DJANGO_SECRET_KEY",
                    "valueFrom": {
                      "secretKeyRef" : {
                        "name" : "${NAME}",
                        "key" : "django-secret-key"
                      }
                    }
                  }
                ],
              ：
```

# openshift(minishift)のs2iでcreatesuperuserする
実は一番苦労しました(笑)
`python manage.py migrate`が記載されているs2iスクリプト`s2i/bin/run`の後ろの処理として記載するのですが、podをスケールアップする、podが再起動する、リビルドする等した場合、またそのpodで`s2i/bin/run`が呼ばれます。
今回のDjango2のような実質Adminを使っていないプロジェクトやAdminを使っていてもDBがローカル(pod内の)sqliteのDBファイルを使っている場合は問題ありませんが、persistentなDBを持つプロジェクト(実際にサービスインするならこれしかないですよね)の場合は、2度目の実行で既にsuperuserが登録されており`s2i/bin/run`がエラー停止してDeployが失敗します。
なので、`createsuperuser`する前にユーザが既に登録されているか確認し、登録されていなければ登録するという流れにしました。

また、`migrate`の前に`makemigrationis`を行わないとユーザ独自のModelが認識され内容でしたので、追加しました。

修正前

```bash:s2i/bin/run
:
if should_migrate; then
  if [[ -f "$manage_file" ]]; then
    echo "---> Migrating database ..."
    python "$manage_file" migrate --noinput
  else
    echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
    echo "Skipped 'python manage.py migrate'."
  fi
fi
:
```

修正後

```bash:s2i/bin/run
:
function should_createsuperuser() {
  should_migrate
}
:
if should_migrate; then
  if [[ -f "$manage_file" ]]; then
    echo "---> Migrating database ..."
    python "$manage_file" makemigrations --noinput
    python "$manage_file" migrate --noinput
  else
    echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
    echo "Skipped 'python manage.py migrate'."
  fi
fi

if should_createsuperuser; then
  if [[ -f "$manage_file" ]]; then
   echo "---> createing super user ..."
   python "$manage_file" shell <<EOF
from django.contrib.auth.models import User
if not User.objects.filter(username='$DJANGO_ADMIN_USER'):
    User.objects.create_superuser('$DJANGO_ADMIN_USER', '$DJANGO_ADMIN_EMAIL', '$DJANGO_ADMIN_PASSWORD')
    print('    create super user: $DJANGO_ADMIN_USER')
else:
    print('    user: $DJANGO_ADMIN_USER already exists, nothing to do')
EOF
  else
   echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
   echo "Skipped 'create super user'."
  fi
fi
:
```

# 自動生成したSecretsの確認方法
minishift(Openshift)のWeb-Consoleから
Resources > Secrets から Nameがテンプレート名になっているものをクリックします。
表示される環境変数一覧の上にあるリンク`Reveal Secret`をクリックすると値が見えます。


# 今回のGit
一応、何かあれば対応するつもりではいますが、そのスピード感は？です(笑)
- `python3.6-nginx:latest` … [https://gitlab.com/imp555/python3.6-nginx.git](https://gitlab.com/imp555/python3.6-nginx.git)
- `django2-nginx-ex:latest` … [https://gitlab.com/imp555/django2-nginx.git](https://gitlab.com/imp555/django2-nginx.git)