6.2. Validation サービスのカスタムルールの作成

Validation サービスは Open Policy Agent (OPA) ポリシールールを使用して、移行に対する各仮想マシン (VM) の適合性を確認します。Validation サービスは、各 VM の concerns 一覧を生成します。これは、Provider Inventory サービスに VM 属性として保存されます。Web コンソールには、プロバイダーインベントリー内の各 VM の concerns が表示されます。

カスタムルールを作成して、Validation サービスのデフォルトルールセットを拡張することができます。たとえば、VM に複数のディスクがあるかどうかを確認するルールを作成できます。

6.2.1. Rego ファイルについて

検証ルールは、Open Policy Agent (OPA) のネイティブクエリー言語である Rego で記述されます。ルールは、Validation Pod の /usr/share/opa/policies/io/konveyor/forklift/<provider> ディレクトリーに .rego ファイルとして保存されます。

各検証ルールは、個別の .rego ファイルに定義され、特定の条件をテストします。条件が true と評価された場合、ルールは {“category", “label", “assessment"} ハッシュを concerns に追加します。concerns のコンテンツは、VM のインベントリーレコードの concerns キーに追加されます。Web コンソールには、プロバイダーインベントリー内の各 VM の concerns キーのコンテンツが表示されます。

次の .rego ファイルの例では、VMware VM のクラスターで有効になっている分散リソーススケジューリングを確認します。

drs_enabled.rego の例

package io.konveyor.forklift.vmware 1

has_drs_enabled {
    input.host.cluster.drsEnabled 2
}

concerns[flag] {
    has_drs_enabled
    flag := {
        "category": "Information",
        "label": "VM running in a DRS-enabled cluster",
        "assessment": "Distributed resource scheduling is not currently supported by OpenShift Virtualization. The VM can be migrated but it will not have this feature in the target environment."
    }
}

1
各検証ルールはパッケージ内で定義されます。パッケージの名前空間は、VMware の場合は io.konveyor.forklift.vmware、Red Hat Virtualization の場合は io.konveyor.forklift.ovirt です。
2
クエリーパラメーターは、Validation サービス JSON の input キーに基づいています。

6.2.2. デフォルトの検証ルールの確認

カスタムルールを作成する前に、Validation サービスのデフォルトルールを確認して、既存のデフォルト値を再定義するルールを作成しないようにする必要があります。

例: デフォルトのルールに default valid_input = false の行が含まれていて、default valid_input = true の行が含まれるカスタムルールを作成した場合、Validation サービスは起動しません。

手順

  1. Validation Pod のターミナルに接続します。

    $ oc rsh <validation_pod>
  2. プロバイダーの OPA ポリシーディレクトリーに移動します。

    $ cd /usr/share/opa/policies/io/konveyor/forklift/<provider> 1
    1
    vmware または ovirt を指定します。
  3. デフォルトポリシーを検索します。

    $ grep -R "default" *

6.2.3. Inventory サービス JSON の取得

Inventory サービスクエリーを仮想マシン (VM) に送信して Inventory サービス JSON を取得します。出力には "input" キーが含まれます。このキーには、Validation サービスルールによってクエリーされるインベントリー属性が含まれます。

検証ルールは、"input" キーの任意の属性に基づいて作成できます (例: input.snapshot.kind)。

手順

  1. Inventory サービスルートを取得します。

    $ oc get route <inventory_service> -n openshift-mtv
  2. プロバイダーの UUID を取得します。

    $ GET https://<inventory_service_route>/providers/<provider> 1
    1
    プロバイダーで使用できる値は vsphere および ovirt です。
  3. プロバイダーの VM を取得します。

    $ GET https://<inventory_service_route>/providers/<provider>/<UUID>/vms
  4. VM の詳細を取得します。

    $ GET https://<inventory_service_route>/providers/<provider>/<UUID>/workloads/<vm>

    出力例

    {
        "input": {
            "selfLink": "providers/vsphere/c872d364-d62b-46f0-bd42-16799f40324e/workloads/vm-431",
            "id": "vm-431",
            "parent": {
                "kind": "Folder",
                "id": "group-v22"
            },
            "revision": 1,
            "name": "iscsi-target",
            "revisionValidated": 1,
            "isTemplate": false,
            "networks": [
                {
                    "kind": "Network",
                    "id": "network-31"
                },
                {
                    "kind": "Network",
                    "id": "network-33"
                }
            ],
            "disks": [
                {
                    "key": 2000,
                    "file": "[iSCSI_Datastore] iscsi-target/iscsi-target-000001.vmdk",
                    "datastore": {
                        "kind": "Datastore",
                        "id": "datastore-63"
                    },
                    "capacity": 17179869184,
                    "shared": false,
                    "rdm": false
                },
                {
                    "key": 2001,
                    "file": "[iSCSI_Datastore] iscsi-target/iscsi-target_1-000001.vmdk",
                    "datastore": {
                        "kind": "Datastore",
                        "id": "datastore-63"
                    },
                    "capacity": 10737418240,
                    "shared": false,
                    "rdm": false
                }
            ],
            "concerns": [],
            "policyVersion": 5,
            "uuid": "42256329-8c3a-2a82-54fd-01d845a8bf49",
            "firmware": "bios",
            "powerState": "poweredOn",
            "connectionState": "connected",
            "snapshot": {
                "kind": "VirtualMachineSnapshot",
                "id": "snapshot-3034"
            },
            "changeTrackingEnabled": false,
            "cpuAffinity": [
                0,
                2
            ],
            "cpuHotAddEnabled": true,
            "cpuHotRemoveEnabled": false,
            "memoryHotAddEnabled": false,
            "faultToleranceEnabled": false,
            "cpuCount": 2,
            "coresPerSocket": 1,
            "memoryMB": 2048,
            "guestName": "Red Hat Enterprise Linux 7 (64-bit)",
            "balloonedMemory": 0,
            "ipAddress": "10.19.2.96",
            "storageUsed": 30436770129,
            "numaNodeAffinity": [
                "0",
                "1"
            ],
            "devices": [
                {
                    "kind": "RealUSBController"
                }
            ],
            "host": {
                "id": "host-29",
                "parent": {
                    "kind": "Cluster",
                    "id": "domain-c26"
                },
                "revision": 1,
                "name": "IP address or host name of the vCenter host or RHV Engine host",
                "selfLink": "providers/vsphere/c872d364-d62b-46f0-bd42-16799f40324e/hosts/host-29",
                "status": "green",
                "inMaintenance": false,
                "managementServerIp": "10.19.2.96",
                "thumbprint": <thumbprint>,
                "timezone": "UTC",
                "cpuSockets": 2,
                "cpuCores": 16,
                "productName": "VMware ESXi",
                "productVersion": "6.5.0",
                "networking": {
                    "pNICs": [
                        {
                            "key": "key-vim.host.PhysicalNic-vmnic0",
                            "linkSpeed": 10000
                        },
                        {
                            "key": "key-vim.host.PhysicalNic-vmnic1",
                            "linkSpeed": 10000
                        },
                        {
                            "key": "key-vim.host.PhysicalNic-vmnic2",
                            "linkSpeed": 10000
                        },
                        {
                            "key": "key-vim.host.PhysicalNic-vmnic3",
                            "linkSpeed": 10000
                        }
                    ],
                    "vNICs": [
                        {
                            "key": "key-vim.host.VirtualNic-vmk2",
                            "portGroup": "VM_Migration",
                            "dPortGroup": "",
                            "ipAddress": "192.168.79.13",
                            "subnetMask": "255.255.255.0",
                            "mtu": 9000
                        },
                        {
                            "key": "key-vim.host.VirtualNic-vmk0",
                            "portGroup": "Management Network",
                            "dPortGroup": "",
                            "ipAddress": "10.19.2.13",
                            "subnetMask": "255.255.255.128",
                            "mtu": 1500
                        },
                        {
                            "key": "key-vim.host.VirtualNic-vmk1",
                            "portGroup": "Storage Network",
                            "dPortGroup": "",
                            "ipAddress": "172.31.2.13",
                            "subnetMask": "255.255.0.0",
                            "mtu": 1500
                        },
                        {
                            "key": "key-vim.host.VirtualNic-vmk3",
                            "portGroup": "",
                            "dPortGroup": "dvportgroup-48",
                            "ipAddress": "192.168.61.13",
                            "subnetMask": "255.255.255.0",
                            "mtu": 1500
                        },
                        {
                            "key": "key-vim.host.VirtualNic-vmk4",
                            "portGroup": "VM_DHCP_Network",
                            "dPortGroup": "",
                            "ipAddress": "10.19.2.231",
                            "subnetMask": "255.255.255.128",
                            "mtu": 1500
                        }
                    ],
                    "portGroups": [
                        {
                            "key": "key-vim.host.PortGroup-VM Network",
                            "name": "VM Network",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch0"
                        },
                        {
                            "key": "key-vim.host.PortGroup-Management Network",
                            "name": "Management Network",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch0"
                        },
                        {
                            "key": "key-vim.host.PortGroup-VM_10G_Network",
                            "name": "VM_10G_Network",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1"
                        },
                        {
                            "key": "key-vim.host.PortGroup-VM_Storage",
                            "name": "VM_Storage",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1"
                        },
                        {
                            "key": "key-vim.host.PortGroup-VM_DHCP_Network",
                            "name": "VM_DHCP_Network",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1"
                        },
                        {
                            "key": "key-vim.host.PortGroup-Storage Network",
                            "name": "Storage Network",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch1"
                        },
                        {
                            "key": "key-vim.host.PortGroup-VM_Isolated_67",
                            "name": "VM_Isolated_67",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch2"
                        },
                        {
                            "key": "key-vim.host.PortGroup-VM_Migration",
                            "name": "VM_Migration",
                            "vSwitch": "key-vim.host.VirtualSwitch-vSwitch2"
                        }
                    ],
                    "switches": [
                        {
                            "key": "key-vim.host.VirtualSwitch-vSwitch0",
                            "name": "vSwitch0",
                            "portGroups": [
                                "key-vim.host.PortGroup-VM Network",
                                "key-vim.host.PortGroup-Management Network"
                            ],
                            "pNICs": [
                                "key-vim.host.PhysicalNic-vmnic4"
                            ]
                        },
                        {
                            "key": "key-vim.host.VirtualSwitch-vSwitch1",
                            "name": "vSwitch1",
                            "portGroups": [
                                "key-vim.host.PortGroup-VM_10G_Network",
                                "key-vim.host.PortGroup-VM_Storage",
                                "key-vim.host.PortGroup-VM_DHCP_Network",
                                "key-vim.host.PortGroup-Storage Network"
                            ],
                            "pNICs": [
                                "key-vim.host.PhysicalNic-vmnic2",
                                "key-vim.host.PhysicalNic-vmnic0"
                            ]
                        },
                        {
                            "key": "key-vim.host.VirtualSwitch-vSwitch2",
                            "name": "vSwitch2",
                            "portGroups": [
                                "key-vim.host.PortGroup-VM_Isolated_67",
                                "key-vim.host.PortGroup-VM_Migration"
                            ],
                            "pNICs": [
                                "key-vim.host.PhysicalNic-vmnic3",
                                "key-vim.host.PhysicalNic-vmnic1"
                            ]
                        }
                    ]
                },
                "networks": [
                    {
                        "kind": "Network",
                        "id": "network-31"
                    },
                    {
                        "kind": "Network",
                        "id": "network-34"
                    },
                    {
                        "kind": "Network",
                        "id": "network-57"
                    },
                    {
                        "kind": "Network",
                        "id": "network-33"
                    },
                    {
                        "kind": "Network",
                        "id": "dvportgroup-47"
                    }
                ],
                "datastores": [
                    {
                        "kind": "Datastore",
                        "id": "datastore-35"
                    },
                    {
                        "kind": "Datastore",
                        "id": "datastore-63"
                    }
                ],
                "vms": null,
                "networkAdapters": [],
                "cluster": {
                    "id": "domain-c26",
                    "parent": {
                        "kind": "Folder",
                        "id": "group-h23"
                    },
                    "revision": 1,
                    "name": "mycluster",
                    "selfLink": "providers/vsphere/c872d364-d62b-46f0-bd42-16799f40324e/clusters/domain-c26",
                    "folder": "group-h23",
                    "networks": [
                        {
                            "kind": "Network",
                            "id": "network-31"
                        },
                        {
                            "kind": "Network",
                            "id": "network-34"
                        },
                        {
                            "kind": "Network",
                            "id": "network-57"
                        },
                        {
                            "kind": "Network",
                            "id": "network-33"
                        },
                        {
                            "kind": "Network",
                            "id": "dvportgroup-47"
                        }
                    ],
                    "datastores": [
                        {
                            "kind": "Datastore",
                            "id": "datastore-35"
                        },
                        {
                            "kind": "Datastore",
                            "id": "datastore-63"
                        }
                    ],
                    "hosts": [
                        {
                            "kind": "Host",
                            "id": "host-44"
                        },
                        {
                            "kind": "Host",
                            "id": "host-29"
                        }
                    ],
                    "dasEnabled": false,
                    "dasVms": [],
                    "drsEnabled": true,
                    "drsBehavior": "fullyAutomated",
                    "drsVms": [],
                    "datacenter": null
                }
            }
        }
    }

6.2.4. 検証ルールの作成

ルールを含む設定マップカスタムリソース (CR) を Validation サービスに適用して、検証ルールを作成します。

重要
  • 既存のルールと同じ名前でルールを作成すると、Validation サービスは、それらのルールで OR 操作を実行します。
  • デフォルトのルールと矛盾するルールを作成すると、Validation サービスは開始されません。

検証ルールの例

検証ルールは、Provider Inventory サービスが収集する仮想マシン (VM) 属性に基づいています。

たとえば、VMware API はこのパス (MOR:Virtual Machine.config.extra Config["numa.node Affinity"]) を使用して、VMware VM に NUMA ノードアフィニティーが設定されているかどうかを確認します。

Provider Inventory サービスは、この設定を簡素化し、リスト値を持つテスト可能な属性を返します。

"numaNodeAffinity": [
    "0",
    "1"
],

この属性に基づいて Rego クエリーを作成し、それを forklift-validation-config 設定マップに追加します。

`count(input.numaNodeAffinity) != 0`

手順

  1. 以下の例に従って設定マップ CR を作成します。

    $ cat << EOF | oc apply -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: <forklift-validation-config>
      namespace: openshift-mtv
    data:
      vmware_multiple_disks.rego: |-
        package <provider_package> 1
    
        has_multiple_disks { 2
          count(input.disks) > 1
        }
    
        concerns[flag] {
          has_multiple_disks 3
            flag := {
              "category": "<Information>", 4
              "label": "Multiple disks detected",
              "assessment": "Multiple disks detected on this VM."
            }
        }
    EOF
    1
    プロバイダーパッケージ名を指定します。使用できる値は、VMware の場合は io.konveyor.forklift.vmware、Red Hat Virtualization の場合は io.konveyor.forklift.ovirt です。
    2
    concerns の名前と Rego クエリーを指定します。
    3
    concerns の名前と flag パラメーターの値を指定します。
    4
    使用できる値は CriticalWarning、および Information です。
  2. forklift-controller デプロイメントを 0 にスケーリングして、Validation Pod を停止します。

    $ oc scale -n openshift-mtv --replicas=0 deployment/forklift-controller
  3. forklift-controller デプロイメントを 1 にスケーリングして、Validation Pod を起動します。

    $ oc scale -n openshift-mtv --replicas=1 deployment/forklift-controller
  4. Validation Pod ログをチェックして、Pod が起動したことを確認します。

    $ oc logs -f <validation_pod>

    カスタムルールがデフォルトのルールと競合する場合、Validation Pod は起動しません。

  5. ソースプロバイダーを削除します。

    $ oc delete provider <provider> -n openshift-mtv
  6. ソースプロバイダーを追加して、新規ルールを適用します。

    $ cat << EOF | oc apply -f -
    apiVersion: forklift.konveyor.io/v1beta1
    kind: Provider
    metadata:
      name: <provider>
      namespace: openshift-mtv
    spec:
      type: <provider_type> 1
      url: <api_end_point> 2
      secret:
        name: <secret> 3
        namespace: openshift-mtv
    EOF
    1
    使用できる値は ovirt および vsphere です。
    2
    API エンドポイント URL を指定します (例: vSphere の場合は https://<vCenter_host>/sdk、RHV の場合は https://<engine_host>/ovirt-engine/api/)。
    3
    プロバイダーの Secret CR の名前を指定します。

カスタムルールを作成した後、ルールのバージョンを更新して、Inventory サービスが変更を検出し、VM を検証できるようにする必要があります。

6.2.5. インベントリールールバージョンの更新

Provider Inventory サービスが変更を検出して Validation サービスをトリガーするように、ルールを更新するたびにインベントリールールのバージョンを更新する必要があります。

ルールバージョンは、各プロバイダーの rules_version.rego ファイルに記録されます。

手順

  1. 現在のルールバージョンを取得します。

    $ GET https://forklift-validation/v1/data/io/konveyor/forklift/<provider>/rules_version 1

    出力例

    {
       "result": {
           "rules_version": 5
       }
    }

  2. Validation Pod のターミナルに接続します。

    $ oc rsh <validation_pod>
  3. /usr/share/opa/policies/io/konveyor/forklift/<provider>/rules_version.rego ファイルでルールバージョンを更新します。
  4. Validation Pod ターミナルからログアウトします。
  5. 更新されたルールバージョンを検証します。

    $ GET https://forklift-validation/v1/data/io/konveyor/forklift/<provider>/rules_version 1

    出力例

    {
       "result": {
           "rules_version": 6
       }
    }