SplunkのKV StoreをRESTで操作

# はじめに

Splunkはルックアップ機能が強力で色々なシーンで活用できます。
例）AD情報をルックアップファイルとして用意しておき、ユーザIDから従業員情報をルックアップ

そんなルックアップファイルをREST経由で管理できたら便利だろうなと思い方法を調べました。
ルックアップファイルにはCSVとKV Storeの2種類があり、KV StoreだとRESTでCRUDできることが分かりました。
REST API仕様は[こちら](https://docs.splunk.com/Documentation/Splunk/latest/RESTREF/RESTkvstore)です。

Pythonで一通り確認できたのでメモです。


# 環境

* Splunk Enterprise or Splunk Cloud
* [Lookup File Editor](https://splunkbase.splunk.com/app/1724/) ※Web UIでKV Storeを管理するには必須
* Python

# KV Store Collection作成

まずはKV Store Collectionが必要です。
これはDBで言うテーブルみたいなもので、各レコードに含まれるフィールドを定義できます。

本来は`collections.conf`と`transforms.conf`の作成が必要なのですがLookup File EditorあればWeb UIで完結します。
（細かいチューニングはできないけど）

それじゃ作っていきます。

Lookup File Editorを開き、Create a New Lookup > KV Store lookup

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1218403/b4783907-aa56-5d33-11e9-257f33ee7ae2.png)

Name: 適当な名前
App: 適当なApp
Key-value collection schema: このコレクションで使用するフィールド。とりあえず`id`と`value`をstring形式で用意します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1218403/7c2b3b26-f93e-0a1e-ed95-a73725f18c1e.png)

できました。各フィールドダブルクリックで値を入力できます。
行追加する場合は右クリック。
`_key`フィールドが自動生成されています。ここには各レコードを識別するためのユニーク値が自動生成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1218403/ad5058e1-4c85-065f-faf0-f21f1c9678ec.png)

[Open in Search] をクリックすると、lookup用のtransform作りますねと言ってくれるので、ありがたく作ってもらいましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1218403/a85c2b3d-8a3d-5b89-6b70-5e24f16a0bed.png)

後は普通にlookupとして使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1218403/6b1c1cd8-d919-7b21-b263-d692de577261.png)


作成したKV Store Collectionの権限を変えておきましょう。

Lookup File Editorでさっき作成したのを検索して [Edit Permissions] をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1218403/4d26f72f-399a-04c2-6340-548f23b6530c.png)

「すべてのApp (システム)」に変更。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1218403/39f1e250-956e-7e8c-a5a0-7dc35d47004f.png)

準備おしまい。


# RESTで操作

作成できたKV Store CollectionをRESTで操作してみます。
まずアクセス情報など共通部分です。

```python:共通
import requests
import json

# アクセス情報
host = "xxx"
port = "8089" # management port。デフォルト値は8089。
userid = "xxx"
userpw = "xxx"

# KVストア情報
app = "search" # 作成したcollectionのApp名
kvcol = "kvstore_rest_test" # 作成したcollection名

# URL
url = "https://" + host + ":" + port + "/servicesNS/nobody/" + app + "/storage/collections/data/" + kvcol

```

## 全レコードを取得

```python
res = requests.get(url, verify=False, auth=(userid, userpw))
print(res.json())
```

```python:結果
[{'id': '1', 'value': 'hoge', 'wait': True, '_user': 'nobody', '_key': '6069c7c32962ee4fb9621ebd'}, {'id': 
'2', 'value': 'foo', 'wait': True, '_user': 'nobody', '_key': '6069c8202962ee4fb9621ebe'}, {'id': '3', 'value': '', 'wait': True, '_user': 'nobody', '_key': '6069c8262962ee4fb9621ebf'}]
```

## 条件指定してレコードを取得

使えるオペレーターは[こちら](https://docs.splunk.com/Documentation/Splunk/latest/RESTREF/RESTkvstore#App_KV_Store_REST_API_features)。

```python
params = {"query":"{\"value\":{\"$ne\":\"\"}}"} # valueは空ではない
res = requests.get(url, params=params, verify=False, auth=(userid, userpw))
print(res.json())
```

```python:結果
[{'id': '1', 'value': 'hoge', 'wait': True, '_user': 'nobody', '_key': '6069c7c32962ee4fb9621ebd'}, {'id': 
'2', 'value': 'foo', 'wait': True, '_user': 'nobody', '_key': '6069c8202962ee4fb9621ebe'}]
```

## レコードの追加

```python
headers = {'Content-Type': 'application/json'}
payload = {"id": "4", "value": "hoge"}
res = requests.post(url, headers=headers, data=json.dumps(payload), verify=False, auth=(userid, userpw))
print(res.json())
```

```python:結果
{'_key': '6069ccb42962ee4fb9621ec0'}
```

## レコードの削除

```python
params = {"query":"{\"value\":\"hoge\"}"} # valueがhogeのレコード削除
res = requests.delete(url, params=params, verify=False, auth=(userid, userpw))
```

```python:結果
なし
```

## _keyを元にレコード取得

```python
key = "6069c8202962ee4fb9621ebe"
res = requests.get(url + "/" + key, verify=False, auth=(userid, userpw))
print(res.json())
```

```python:結果
{'id': '2', 'value': 'foo', 'wait': True, '_user': 'nobody', '_key': '6069c8202962ee4fb9621ebe'}
```


## _keyを元にレコード更新

```python
key = "6069c8202962ee4fb9621ebe"
headers = {'Content-Type': 'application/json'}
payload = {"id": "2", "value": "foo2"} # 全てのkeyにvalueを設定しないと設定されていないkeyは空白になる
res = requests.post(url + "/" + key, headers=headers, data=json.dumps(payload), verify=False, auth=(userid, userpw))
print(res.json())
```

```python:結果
{'_key': '6069c8202962ee4fb9621ebe'}
```

## _keyを元にレコード削除

```python
key = "6069c8202962ee4fb9621ebe"
res = requests.delete(url + "/" + key, verify=False, auth=(userid, userpw))
```

```python:結果
なし
```

# まとめ

KV StoreはRESTでCRUDできることが分かりました。
色々使い勝手がありそうです。