stack.sh が御三家以外のプロジェクトをインストールする仕組み

# はじめに

devstack を使った Openstack のインストールは御三家（keystone, nova, placement, glance, neutron, horizon）だけでなく、それ以外のプロジェクトも以下のように local.conf の `[[local|localrc]]` に記述する（例：Heat）ことでインストールできる。

```text
#Enable heat services
enable_service h-eng h-api h-api-cfn h-api-cw

#Enable heat plugin
enable_plugin heat https://git.openstack.org/openstack/heat
```

しかし、どのような仕組みで御三家以外のプロジェクトのインストールが実行されるのかが分かっていなかった。
stack.sh のコードを読み勧めていく中で、この仕組みが分かったため忘備録として残す。

# 対象者

* devstack で御三家以外のプロジェクトのインストールがしたい人

# 仕組み

## localrc の enable_plugin を実行

これによりプラグイン名（リポジトリ）を環境変数`DEVSTACK_PLUGINS`に追加する。

```bash
function enable_plugin {
    local name=$1
    local url=$2
    local branch=${3:-master}
    if is_plugin_enabled $name; then
        die $LINENO "Plugin attempted to be enabled twice: ${name} ${url} ${branch}"
    fi
    DEVSTACK_PLUGINS+=",$name"
    GITREPO[$name]=$url
    GITDIR[$name]=$DEST/$name
    GITBRANCH[$name]=$branch
}
```
https://github.com/openstack-dev/devstack/blob/2810e95f9eae0cab92e68e2666514f22b7d80381/functions-common#L1565-L1576

## Configure Projects フェーズの fetch_plugins でリポジトリのクローン

fetch_plugins は、環境変数`DEVSTACK_PLUGINS`に入っているリポジトリをクローンする。

```bash
function fetch_plugins {
    local plugins="${DEVSTACK_PLUGINS}"
    local plugin

    # short circuit if nothing to do
    if [[ -z $plugins ]]; then
        return
    fi

    echo "Fetching DevStack plugins"
    for plugin in ${plugins//,/ }; do
        git_clone_by_name $plugin
    done
}
```
https://github.com/openstack-dev/devstack/blob/2810e95f9eae0cab92e68e2666514f22b7d80381/functions-common#L1594-L1607

```bash
function git_clone_by_name {
    local name=$1
    local repo=${GITREPO[$name]}
    local dir=${GITDIR[$name]}
    local branch=${GITBRANCH[$name]}
    git_clone $repo $dir $branch
}
```
https://github.com/openstack-dev/devstack/blob/2810e95f9eae0cab92e68e2666514f22b7d80381/functions-common#L571-L577

## Extras Install フェーズで stack.sh は run_phase stack install を実行

```bash
# Extras Install
# --------------

# Phase: install
run_phase stack install
```
https://github.com/openstack-dev/devstack/blob/2810e95f9eae0cab92e68e2666514f22b7d80381/stack.sh#L938-L942

## run_phase は run_plugins を実行

```bash
function run_phase {
    local mode=$1
    local phase=$2
<略>
    else
        run_plugins $mode $phase
    fi
}
```
https://github.com/openstack-dev/devstack/blob/2810e95f9eae0cab92e68e2666514f22b7d80381/functions-common#L1703-L1705

## run_plugins はクローンしたディレクトリ全てを対象に devstack/plugin.sh を実行

```bash
function run_plugins {
    local mode=$1
    local phase=$2

    local plugins="${DEVSTACK_PLUGINS}"
    local plugin
    for plugin in ${plugins//,/ }; do
        local dir=${GITDIR[$plugin]}
        if [[ -f $dir/devstack/plugin.sh ]]; then
            source $dir/devstack/plugin.sh $mode $phase
        fi
    done
}
```
https://github.com/openstack-dev/devstack/blob/2810e95f9eae0cab92e68e2666514f22b7d80381/functions-common#L1662-L1674

## plugin.sh は引数に従いインストール処理を実行

```bash
    if [[ "$1" == "stack" && "$2" == "install" ]]; then
        echo_summary "Installing heat"
        # Use stack_install_service here to account for virtualenv
        stack_install_service heat
        echo_summary "Installing heatclient"
        install_heatclient
```
https://github.com/openstack/heat/blob/6f0f14a3a04fb780312076335283f32806929179/devstack/plugin.sh#L12-L17

# 結論

* enable_plugin で指定しないと、そもそもリポジトリがクローンされない。
* stack.sh の Extras Install フェーズでそれぞれのリポジトリ以下の devstack/plugin.sh が実行される。
* 御三家のインストールの処理は、devstack に内蔵されているため plugin が不要。

# おわりに

ツッコミがあればコメントくだし。