半農半エンジニアの記録

関西在住エンジニア。個人で勉強・開発したこと、その他趣味のことを書いてます。農業してます。

k8sのPHPクライアントライブラリのエラーを修正した

先日の課題が解決です。

www.m24te28.com

tl;dr

mergeしてもらったプルリクエストです。

github.com

振り返り

k8sのAPIクライアントは各言語向けに公式のものが用意されていますが、PHPは公式ではなく有志のものが紹介されています。

Client Libraries - Kubernetes

2つ紹介されていますが、私が使わせてもらったのはこちら。

※ネコ好きだからとかでは決してない!

github.com

で使ってる時にエラーが出てたので調べました。

調べる

エラーメッセージ

前回曖昧にしてたので、改めてエラーメッセージはこんな感じ。

"Deployment in version \"v1\" cannot be handled as a Deployment: v1.Deployment.Spec: v1.DeploymentSpec.Template: v1.PodTemplateSpec.Spec: v1.PodSpec.Volumes: v1.Volume: v1.Volume.VolumeSource: EmptyDir: readObjectStart: expect { or n, but found [, error found in #10 byte of ...|ptyDir\": \n |..., bigger context ...|\": \"shared\",\n \"emptyDir\": []\n }\n ]\n |...

expect { or n, but found [

がポイントっぽい。

マニフェストファイル

処理としては.ymlファイルを読み込ませてarrayに変換し、ライブラリのpods()->createメソッド呼んでるだけ。 先に.ymlの確認。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

実際のファイルでは無いですが、これで十分なので公式で公開されているマニフェストを参考にします。

emptyDir: {}

とあるのがエラーメッセージとかなり関係してそう。

ちなみにこのファイルで kubectl apply -f pod.yml とかすると正常にPodができます。

ソースコード

さてついにソースコードです。 create()の中を追っていきます。

Repository.phpという抽象クラスに集約されています。

抜粋)

 /**
     * Send a request.
     *
     * @param  string  $method
     * @param  string  $uri
     * @param  array   $query
     * @param  mixed   $body
     * @param  boolean $namespace
     * @return array
     */
    protected function sendRequest($method, $uri, $query = [], $body = [], $namespace = true)
    {
        $apiVersion = $this->getApiVersion();
        if ($apiVersion == 'v1') {
            $apiVersion = null;
        }
        return $this->client->sendRequest($method, $uri, $query, $body, $namespace, $apiVersion);
    }
...
    /**
     * Create a new model.
     *
     * @param  \Maclof\Kubernetes\Models\Model $model
     * @return array
     */
    public function create(Model $model)
    {
        return $this->sendRequest('POST', '/' . $this->uri, null, $model->getSchema(), $this->namespace);
    }

$modelに読み込んだマニフェストのarrayを渡しています。

呼び出し先はClient.php

 public function sendRequest($method, $uri, $query = [], $body = [], $namespace = true, $apiVersion = null)
    {
        $baseUri = $apiVersion ? 'apis/' . $apiVersion : 'api/' . $this->apiVersion;
        if ($namespace) {
            $baseUri .= '/namespaces/' . $this->namespace;
        }
        $requestUri = $baseUri . $uri;
        $requestOptions = [];
        if (is_array($query) && !empty($query)) {
            $requestOptions['query'] = $query;
        }
        if ($body !== null) {
            $requestOptions['body'] = is_array($body) ? json_encode($body) : $body;
        }
...
    }

ここの$bodyが渡された$model->getSchema()です。json_encodeしている。ここでしょう。

結論

expect { or n, but found [

ということなので、空の配列として認識されてるっぽい。

json_encodeにはオプションが指定できるらしい。使えそうなのを見つける。

JSON_FORCE_OBJECT (integer)

非連想配列を使用した場合に、配列ではなくオブジェクトを出力します。 出力を受け取る側がオブジェクトを期待しており、配列が空っぽである場合などに特に便利です。 この定数は PHP 5.3.0 以降で使用可能です。

これかな?

というわけで修正して実行!成功です!

あとは先の通りプルリクエスト出して、数時間後に無事マージしていただきました。

感想

オープンソースにコミットするのが初めてでしたが、ゲームやってるみたいで楽しいですね。

これからもっとやっていきます。