はじめに
ストレージ業界団体SNIAが提供するストレージ管理I/Fの標準仕様SwordfishのAPI Emulator(Swordfish-API-Emulator)のコンテナイメージを用意したため、これの実行方法を紹介します。
なお、SwordfishのAPI Emulatorは、Swordfishの母体となるDMTFが提供するシステム管理I/Fの標準仕様[Redfish]のAPI Emulator(Redfish-Interface-Emulator)を活用しているため、本コンテナイメージには両API Emulatorが入っています。
Dockerでの実行方法
以下のコマンドでコンテナにてSwordfish-API-Emulatorを起動します。
$ docker run -p 5000:5000 --name swordfish ysakashita/swordfish-api-emulator:latest
Webブラウザでhttp://localhost:5000/
にアクセスします。
以下の画面が出てきたら、"here for a GPI Redfish browser." の here
をクリックします。
(Swordfish-API-Emulatorはストレージ関連のリソースのみであり、エミュレータ本体はRedfish-Interface-Emulatorを利用するため、GUIではRedfishの画面となります)
すると以下のようにAPI Emulatorで用意されているリソースにアクセスできます。
Namespaceは/redfish/v1
となります。
なお、curlでのアクセスを試したい方は、後述の補足に例を記載していますので、それらをご参照ください。
Kubernetesでの実行方法
Kubernetes上で起動させる場合は、以下のManifestを使いデプロイします。
なお、今回はminikubeでIngressをaddonで有効にした環境で試しています。
minikubeでのaddonを使ったIngressの有効化の方法
``` $ minikube start $ minikube addons enable ingress ```- deploy-swordfish-api-emulator.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: swordfish
spec:
replicas: 1
selector:
matchLabels:
app: swordfish
template:
metadata:
labels:
app: swordfish
spec:
containers:
- name: swordfish
image: ysakashita/swordfish-api-emulator:latest
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 5000
- svc-swordfish-api-emulator.yaml
apiVersion: v1
kind: Service
metadata:
name: swordfish
spec:
selector:
app: swordfish
ports:
- port: 5000
targetPort: 5000
今回は、Ingressも用意します。
Ingressのhostは環境にあわせて設定してください。
- ing-swordfish-api-emurator.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: swordfish
labels:
name: swordfish
spec:
rules:
- host: swordfish.192.168.99.137.nip.io # Please update much as your env.
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: swordfish
port:
number: 5000
上記3つのManifestをデプロイします。
$ kubectl apply -f deploy-swordfish-api-emulator.yaml -f svc-swordfish-api-emulator.yaml -f ing-swordfish-api-emurator.yaml
実行を確認します。
$ kubectl get ing,svc,pod
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/swordfish <none> swordfish.192.168.99.137.nip.io 192.168.99.137 80 41s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 112d
service/swordfish ClusterIP 10.110.217.188 <none> 5000/TCP 41s
NAME READY STATUS RESTARTS AGE
pod/swordfish-7cdf5f6bc9-qm56p 1/1 Running 0 41s
以上で起動完了です。
Dockerの場合と同じくWebブラウザでアクセスします。
URLはIngressで作成したホストです(URL: http://swordfish.192.168.99.137.nip.io/
)。
補足
2022/1/6時点のSwordfish-API-Emulatorでは、Staticなリソースとして/redfish/v1/Storage
配下にIPAttachedDrive
として、SSDのドライブが1つだけと少し寂しいものとなっています。
- curlでの取得例 (コンテナイメージ
ysakashita/swordfish-api-emulator:latest
)
$ curl -X GET http://swordfish.192.168.99.137.nip.io/redfish/v1/Storage |jq
...
{
"@odata.id": "/redfish/v1/Storage",
"@odata.type": "#StorageCollection.StorageCollection",
"Members": [
{
"@odata.id": "/redfish/v1/Storage/IPAttachedDrive"
}
],
"Members@odata.count": 1,
"Name": "Storage Collection"
}
$ curl -X GET http://swordfish.192.168.99.137.nip.io/redfish/v1/Storage/IPAttachedDrive | jq
...
{
"@odata.id": "/redfish/v1/Storage/IPAttachedDrive",
"@odata.type": "#Storage.v1_10_0.Storage",
"Controllers": {
"@odata.id": "/redfish/v1/Storage/IPAttachedDrive/Controllers"
},
"Description": "An NVM Express Subsystem is an NVMe device that contains one or more NVM Express controllers and may contain one or more namespaces.",
"Drives": [
{
"@odata.id": "/redfish/v1/Chassis/IPAttachedDrive/Drives/IPAttachedDrive"
}
],
"Id": "1",
"Identifiers": [
{
"DurableName": "nqn.2014-08.org.nvmexpress:uuid:6c5fe566-10e6-4fb6-aad4-8b4159f50245",
"DurableNameFormat": "NQN"
}
],
"Links": {
"Enclosures": [
{
"@odata.id": "/redfish/v1/Chassis/IPAttachedDrive"
}
]
},
"Name": "NVMe IP Attached Drive Configuration",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"Volumes": {
"@odata.id": "/redfish/v1/Storage/IPAttachedDrive/Volumes"
}
}
$ curl -X GET http://swordfish.192.168.99.137.nip.io/redfish/v1/Chassis/IPAttachedDrive/Drives/IPAttachedDrive | jq
...
{
"@odata.id": "/redfish/v1/Chassis/IPAttachedDrive/Drives/IPAttachedDrive",
"@odata.type": "#Drive.v1_12_0.Drive",
"Actions": {
"#Drive.Reset": {
"target": "/redfish/v1/Chassis/IPAttachedDrive/Drives/IPAttachedDrive/Actions/Drive.Reset"
},
"#Drive.SecureErase": {
"target": "/redfish/v1/Chassis/IPAttachedDrive/Drives/IPAttachedDrive/Actions/Drive.SecureErase"
}
},
"BlockSizeBytes": 512,
"CapableSpeedGbs": 12,
"CapacityBytes": 899527000000,
"Description": "IP Attached drive.",
"EncryptionAbility": "None",
"FailurePredicted": false,
"Id": "IPAttachedDrive",
"Identifiers": [
{
"DurableName": "500003942810D13A",
"DurableNameFormat": "NAA"
}
],
"Links": {
"Volumes": [
{
"@odata.id": "/redfish/v1/Storage/IPAttachedDrive/Volumes/SimpleNamespace"
}
]
},
"LocationIndicatorActive": true,
"Manufacturer": "Contoso",
"MediaType": "SSD",
"Model": "ST9146802SS",
"Name": "NVMe IPAttachedDrive Drive",
"NegotiatedSpeedGbs": 12,
"PartNumber": "SG0GP8811253178M02GJA00",
"PhysicalLocation": {
"PartLocation": {
"LocationType": "Slot"
}
},
"PredictedMediaLifeLeftPercent": 86,
"Protocol": "NVMe",
"Revision": "S20A",
"SKU": "N/A",
"SerialNumber": "72D0A037FRD26",
"Status": {
"Health": "OK",
"State": "Enabled"
},
"StatusIndicator": "OK",
"WriteCacheEnabled": true
}
そこで、少し古くはなりますが、2つのストレージのリソースが用意されていた2018/08時点のもののコンテナイメージ(ysakashita/swordfish-api-emulator:20180801
)も用意しました。Docker or Kubernetesで実行するコンテナイメージのタグに20180801
を指定してください。
- curlでの取得例 (コンテナイメージ
ysakashita/swordfish-api-emulator:20180801
)
$ curl -X GET http://swordfish.192.168.99.137.nip.io/redfish/v1/StorageServices |jq
...
{
"@Redfish.Copyright": "Copyright 2015-2016 SNIA. All rights reserved.",
"@odata.context": "/redfish/v1/$metadata#StorageService.StorageService",
"@odata.id": "/redfish/v1/StorageServices",
"@odata.type": "#StorageServiceCollection.1.0.0.StorageServiceCollection",
"Members": [
{
"@odata.id": "/redfish/v1/StorageServices/1"
},
{
"@odata.id": "/redfish/v1/StorageServices/2"
}
],
"Members@odata.count": 2,
"Name": "Storage Service Collection"
}
$ curl -X GET http://swordfish.192.168.99.137.nip.io/redfish/v1/StorageServices/1 |jq
...
{
"@Redfish.Copyright": "Copyright 2014-2016 SNIA. All rights reserved.",
"@odata.context": "/redfish/v1/$metadata#StorageServices/1",
"@odata.id": "/redfish/v1/StorageServices/1",
"@odata.type": "#StorageService.1.0.0.StorageService",
"ClassesOfService": {
"@odata.id": "/redfish/v1/StorageServices/1/ClassesOfService"
},
"ClientEndpointGroups": {
"@odata.id": "/redfish/v1/StorageServices/1/ClientEndpointGroups"
},
"Description": "Description of storage",
"Drives": {
"@odata.id": "/redfish/v1/StorageServices/1/Drives"
},
"Endpoints": {
"@odata.id": "/redfish/v1/StorageServices/1/Endpoints"
},
"Id": "1",
"Links": {
"DataProtectionLoSCapabilities": {
"@odata.id": "/redfish/v1/StorageServices/1/DataProtectionLoSCapabilities"
},
"DataSecurityLoSCapabilities": {
"@odata.id": "/redfish/v1/StorageServices/1/DataSecurityLoSCapabilities"
},
"DataStorageLoSCapabilities": {
"@odata.id": "/redfish/v1/StorageServices/1/DataStorageLoSCapabilities"
},
"Enclosures": {
"@odata.id": "/redfish/v1/Chassis/1"
},
"HostingSystem": {
"@odata.id": "/redfish/v1/Systems/Complex"
},
"IOConnectivityLoSCapabilities": {
"@odata.id": "/redfish/v1/StorageServices/1/IOConnectivityLoSCapabilities"
},
"IOPerformanceLoSCapabilities": {
"@odata.id": "/redfish/v1/StorageServices/1/IOPerformanceLoSCapabilities"
}
},
"Name": "My Storage Service",
"Oem": {},
"ServerEndpointGroups": {
"@odata.id": "/redfish/v1/StorageServices/1/ServerEndpointGroups"
},
"Status": {
"Health": "OK",
"State": "Enabled"
},
"StorageGroups": {
"@odata.id": "/redfish/v1/StorageServices/1/StorageGroups"
},
"StoragePools": {
"@odata.id": "/redfish/v1/StorageServices/1/StoragePools"
},
"StorageSubsystems": {
"@odata.id": "/redfish/v1/StorageServices/1/StorageSubsystems"
},
"Volumes": {
"Members": [
{
"@odata.id": "/redfish/v1/StorageServices/1/Volumes"
}
]
}
}
$ curl -X GET http://swordfish.192.168.99.137.nip.io/redfish/v1/StorageServices/1/Volumes |jq
...
{
"@Redfish.Copyright": "Copyright 2014-2016 SNIA. All rights reserved.",
"@odata.context": "/redfish/v1/$metadata#VolumeCollection.VolumeCollection",
"@odata.id": "/redfish/v1/StorageServices/1/Volumes",
"@odata.type": "#VolumeCollection_1_0_0.VolumeCollection",
"Members": [
{
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/61001234876545676100123487654567"
},
{
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/65456765456761001234876100123487"
},
{
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/3"
},
{
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/4"
},
{
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/5"
},
{
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/6"
}
],
"Members@odata.count": 6,
"Name": "Volumes",
"Permissions": [
{
"Read": "True"
},
{
"Write": "True"
}
]
}
$ curl -X GET http://swordfish.192.168.99.137.nip.io/redfish/v1/StorageServices/1/Volumes/61001234876545676100123487654567 |jq
...
{
"@Redfish.Copyright": "Copyright 2014-2016 SNIA. All rights reserved.",
"@odata.context": "/redfish/v1/$metadata#Volume.Volume",
"@odata.id": "/redfish/v1/StorageServices/1/Volumes/61001234876545676100123487654567",
"@odata.type": "#Volume_1_0_0.Volume",
"AccessCapabilities": [
"Read",
"Write"
],
"BlockSizeBytes": 512,
"Capacity": {
"Data": {
"AllocatedBytes": 10737418240,
"ConsumedBytes": 0,
"GuaranteedBytes": 536870912,
"ProvisionedBytes": 1099511627776
},
"Metadata": {
"AllocatedBytes": 536870912,
"ConsumedBytes": 536870912,
"GuaranteedBytes": 536870912,
"ProvisionedBytes": 2199023255552
},
"Snapshot": {
"AllocatedBytes": 21474836480,
"ConsumedBytes": 0,
"GuaranteedBytes": 536870912,
"ProvisionedBytes": 2199023255552
}
},
"CapacitySources": [
{
"Links": {
"ClassOfService": {
"@odata.id": "/redfish/v1/StorageServices/1/ClassesOfService/GoldBoston"
},
"ProvidingPool": {
"Members": [
{
"@odata.id": "/redfish/v1/StorageServices/1/StoragePools/BasePool"
}
]
},
"ProvidingVolume": null
},
"ProvidedCapacity": {
"AllocatedBytes": 140759500062720,
"ConsumedBytes": 70390755885056,
"GuaranteedBytes": 17592722915328,
"ProvisionedBytes": 565148976676864
}
}
],
"Description": "Bob's Pizza Recipe",
"Id": "61001234876545676100123487654567",
"Identifiers": [
{
"DurableName": "61001234876545676100123487654567",
"DurableNameFormat": "NAA6"
}
],
"LowSpaceWarningThresholdPercent": [
70,
80,
90,
null,
null
],
"Manufacturer": "SuperDuperStorageProvider",
"Model": "Drive Model string",
"Name": "Volume 1",
"Status": {
"Health": "Warning",
"State": "Enabled"
}
}
感想
今回は、SNIA日本支部の活動で、Swordfishを紹介する機会があったため、これにあわせてコンテナイメージを用意しました。Swordfish-API-Emulatorのドキュメントでは、Windowsの場合のセットアップしか記載がなくPythonのパッケージもセットアップが必要だったため、PCの環境を汚さないためにコンテナイメージを作りました。これによりWindows以外のOSを利用されている方や事前セットアップが面倒な方などでも、手軽にSwordfish-API-Emulatorが試せるかと思いますので、興味のある方は触ってみてください。