go1.18を使ったときに、golangci-lintのtypecheckのエラーが出たり、go generateがこけた
golangci-lintのtypecheckのエラー
go.mod
で、go1.16
が指定されているプロジェクトで、手元のgoのバージョンを1.18.2
にしてgolangci-lint
を実行したときに、今まで出ていなかったエラーが発生しました。こんな感じ
...net/http/httptest (-: could not load export data: no export data for "net/http/httptest") (typecheck) "net/http/httptest" ^ k8sapiserver/k8sapiserver.go:23:13: could not import...load export data: no export data for "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes") (typecheck) authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" ^... ...
go1.16.15
やgo.17.10
では、上記のエラーは発生していませんでした。
対処
golangci-lint
のバージョンを最新に上げました。(ちょうど別件でgo.mod
に記載のバージョンも上げたので念のため記載しておきます。)
# go.mod - go 1.16 + go 1.17 - github.com/golangci/golangci-lint v1.41.1 + github.com/golangci/golangci-lint v1.46.2
上記の対応により、手元のgoバージョンgo1.18.2
で、先のエラーは発生しなくなりました。
go generateがこけた
上記の続きで、go1.18.2
を使ったときにgo generate
を実行したときに以下のエラーが発生しました。
go generate ./... prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules' prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/export: go.mod file not found in current directory or any parent directory; see 'go help modules' 2022/07/10 14:41:06 Loading input failed: exit status 1 export/export.go:3: running "mockgen": exit status 1 prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules' prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/node: go.mod file not found in current directory or any parent directory; see 'go help modules' 2022/07/10 14:41:07 Loading input failed: exit status 1 node/node.go:3: running "mockgen": exit status 1 prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules' prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/replicateexistingcluster: go.mod file not found in current directory or any parent directory; see 'go help modules' 2022/07/10 14:41:08 Loading input failed: exit status 1 replicateexistingcluster/replicateexistingcluster.go:3: running "mockgen": exit status 1 prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in: /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model Please reference the steps in the README to fix this error: https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules' prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/scheduler/plugin: go.mod file not found in current directory or any parent directory; see 'go help modules' 2022/07/10 14:41:09 Loading input failed: exit status 1 scheduler/plugin/wrappedplugin.go:13: running "mockgen": exit status 1 make: *** [Makefile:3: generate] Error 1
go1.16.15
を使用していたときは発生していませんでしたが、こちらgo1.18.2
を使用し始めたときに発生するようになりました。
対処
ここにある2つのうちのどちらかで対処可能です。
例えば以下のように修正します。
- //go:generate mockgen -destination=./mock_$GOPACKAGE/pod.go . PodService + //go:generate mockgen --build_flags=--mod=mod -destination=./mock_$GOPACKAGE/pod.go . PodService
k8s resource watchする
あらまし
PodとかNodeとかリソースの更新を監視したかったです。 (消すコードをぱぱっと持ってきたのでもしかしたら変な部分があるかもしれません。雰囲気でも伝われば幸いです)
雑にやったこと
Server push
ってやつで、クライアント側ではfetchで呼び出してデータを受け取る感じです。(stream
ってやつかと)
まず、echo
を使っていてこのメソッドをハンドラとして公開するイメージです。
func (h *WatcherHandler) WatchResources(c echo.Context) error { ctx := c.Request().Context() c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON) c.Response().WriteHeader(http.StatusOK) // Start to watch and do server push err := h.service.WatchResources(ctx, c.Response()) if err != nil { klog.Errorf("closed to watch resources: %+v", err) return echo.NewHTTPError(http.StatusInternalServerError) } return nil }
肝心のwatchする部分はこんな感じ。もう消すコードだったのでちょっと雑に貼ります、、
type ResponseStream interface { io.Writer http.Flusher } func (s *Service) WatchResources(ctx context.Context, stream ResponseStream) error { podsWatcher := cache.NewListWatchFromClient(s.client.CoreV1().RESTClient(), string(Pods), corev1.NamespaceAll, fields.Everything()) _, podsController := cache.NewInformer(podsWatcher, &corev1.Pod{}, 0, createResourceEventHandlerFuncs(watchEventQ, Pods)) go podsController.Run(ctx.Done()) <-ctx.Done() return xerrors.Errorf("terminated to watch: %v", ctx.Err()) } func createResourceEventHandlerFuncs(weq *watchEventQueue, r resourceKind) cache.ResourceEventHandlerFuncs { return cache.ResourceEventHandlerFuncs{ AddFunc: AddedEventHandler(weq, r), UpdateFunc: ModifiedEventHandler(weq, r), DeleteFunc: DeletedEventHandler(weq, r), } } func AddedEventHandler(weq *watchEventQueue, r resourceKind) func(obj interface{}) { return func(obj interface{}) { // ここで受け取ったイベントを処理する } } ...
server push
する部分はこんな感じ
func watchAndFlushQueue(obj interface{}, stream ResponseStream) error { enc := json.NewEncoder(stream) for { if weq.IsEmpty() { continue } if err := enc.Encode(obj); err != nil { return xerrors.Errorf("encode a WatchEvent in the queue: %w", err) } stream.Flush() // これでクライアントにpushされる } }
このコードを使わなかった訳
cache.NewInformer
の部分では「list呼び出し→watch監視開始」と実行されます。これは、resourceVersion
フィールドの値をlistで取得してwatchでそれを使うことで、無駄な昔の情報をwatchで取得しないようにとかに使います。またこのメソッドで生成されるやつは、watch接続が途切れた場合に、自動で復帰もしてくれる(はず)の優しいやつです。
それが故に、この一連の動作を再度呼び出した時に再度listから実行してしまうことが予想されます。これは今回の私の目的にあっていませんでした。また、resourceVersion
フィールドは外側から指定することができず完全に隠されているので、クライアント側からresourceVersion
を指定して、好きな位置から情報取得をすることができません。
これらにより、便利ではあるんですが、今回は上記の実装は諦めました。
Nuxt.js runtimeConfigの値がundefinedになる
あらまし
コンテナ化して、docker-compose
でnuxtjs
製のアプリケーションを実行しようとしています。
その際、nuxtjs
の機能であるruntimeConfig
を使用して、ランタイムで環境変数を渡そうとした時に、上手く値が渡せずundefined
が渡されていました。
症状
例えば、以下のように環境変数を読ませようとします。
# nuxt.config.js publicRuntimeConfig: { baseURL: process.env.BASE_URL || "https://localhost:3000" },
これをどうにか呼び出した時にundefined
が返ってきます。
const baseURL = context.$config.baseURL ## => undefined
Dockerfile
はこんな感じ
FROM node:16-alpine AS deps RUN apk update && \ apk upgrade && \ apk add --no-cache make gcc g++ py-pip WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile FROM node:16-alpine AS builder WORKDIR /app COPY . . COPY --from=deps /app/node_modules ./node_modules RUN yarn build && yarn install --production --ignore-scripts --prefer-offline FROM node:16-alpine AS runner WORKDIR /app ENV NODE_ENV production ENV NUXT_TELEMETRY_DISABLED 1 ENV HOST_ENV production ENV BASE_URL http://localhost:1212 ENV KUBE_API_SERVER_URL http://localhost:3131 RUN addgroup -g 1001 -S nodejs RUN adduser -S nuxtjs -u 1001 COPY --from=builder ./app/package.json ./ COPY --from=builder ./app/node_modules ./node_modules/ COPY --from=builder ./app/.nuxt ./.nuxt/ COPY --from=builder ./app/static ./static/ USER nuxtjs EXPOSE 3000 CMD ["yarn", "start"]
原因:実行環境にnuxt.config.js
をコピーしていない
上記のDockerfile
はビルドと実行を別環境で行なっています。実行環境にビルドしたものを移す際に、nuxt.config.js
を移していませんでした。おそらく、runtimeConfig
は実行時にnuxt.config.js
を参照してよしなにするのだと思います。
次のようにnuxt.config.js
をコピーする操作を追加して解決します。
... COPY --from=builder /app/nuxt.config.js ./ ## Add COPY --from=builder ./app/package.json ./ COPY --from=builder ./app/node_modules ./node_modules/ COPY --from=builder ./app/.nuxt ./.nuxt/ COPY --from=builder ./app/static ./static/ USER nuxtjs EXPOSE 3000 CMD ["yarn", "start"]
よく考えると、環境変数が上手く読み込めていないのであれば、undefined
ではなく、デフォルト値として設定したhttps://localhost:3000
が入っているはずなので、この辺りで気がつけるといいかも。
参考
これに助けられました。
nuxtjs
のruntimeConfig
について
原因の元となったファイル
kubernetes ScalarResources
v.1.23
で確認
ScalarResources
このScalarResources
ってなんなのって思いました。
// pkg/scheduler/framework/types.go#L410-L419より type Resource struct { MilliCPU int64 Memory int64 EphemeralStorage int64 // We store allowedPodNumber (which is Node.Status.Allocatable.Pods().Value()) // explicitly as int, to avoid conversions and improve performance. AllowedPodNumber int // ScalarResources ScalarResources map[v1.ResourceName]int64 }
k8sのdocsでもあまりヒットしなかったので、僕の調べた結果の予想をちょろっと書いておきます。
結果的には構造体に定義されたCPU
、Memory
、EphemeralStorage
以外のリソースを指すんじゃないかと思います。どういうことかというと、例えばメモリの場合こんな感じで書きます。(メモリリソース割り当てページより)
apiVersion: v1 kind: Pod metadata: name: memory-demo namespace: mem-example spec: containers: - name: memory-demo-ctr image: polinux/stress resources: limits: memory: "200Mi" requests: memory: "100Mi" command: ["stress"] args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
この、resources.requests
やresources.limits
に映えてるmemory
の値が、Resource
構造体のMemory
に格納されるんじゃないかと思います。例えばEphemeralStorage
ならこんな感じ?
じゃあ、ScalarResources
はというと、例えば拡張リソース
apiVersion: v1 kind: Pod metadata: name: extended-resource-demo spec: containers: - name: extended-resource-demo-ctr image: nginx resources: requests: example.com/dongle: 3 limits: example.com/dongle: 3
リソース名にexample.com/dongle
といった感じで各自のドメイン名が入るので、memory
のように単一で表記できない。Huge pageもおそらく名前が可変(定義する名前が変わる)なので、ScalarResources
に格納しておくといった感じかと思う。
pkg/scheduler/util/utils.goに、IsScalarResourceName
という関数があり、そこでリソース名から判定を行える。この実装を見てみると、上記の拡張リソースとHuge pageは、ScalarResources
に含まれると考えられる。
Scalar
という単語に馴染みがなかったので不安ですが、言葉の定義として文字列
が含まれるようなので、ScalarResources
という名前も一応腑に落ちた気がします。
合っているか分からないので、マサカリ歓迎します。
CTF MySQLとか「''-sleep(1)」に関して
あらまし
ここのwriteupで次のようなSQL文がある。
select * from login where username=''-sleep(1);
https://blog.bi0s.in/2019/10/16/Web/inctfi19-web-writeups/
この結果、login
テーブルの内容が全て取得できているロジックがいまいちわからなくて調べた。
準備
create table Test(id integer, title varchar(100)); insert into Test(id, title) values(1, "Hello"); insert into Test(id, title) values(2, "foo"); insert into Test(id, title) values(3, "bar");
-
は何
演算子としての-
と正規表現中に出現する-
がある。任意の文字がマッチするようになるのかと思ったけれど、恐らく演算している。
select * from Test where title='false' // 結果なし select * from Test where title=''-false; // テーブル出力 select * from Test where title=''-true; // 結果なし select * from Test where title=''-0; // テーブル出力 select * from Test where title='aaaa'-false; // テーブル出力
sleep
は0
が帰ってくるはず。上の結果から、booleanの値が関係してそう。
false 0 減算など
SELECT '' IS false; // 1 SELECT 0 IS false; // 1 SELECT 0 IS true; // 0 SELECT ''-0 IS false; // 1 SELECT 'aaa'-false IS false; // 1 SELECT 'aaa'-0 IS false; // 1
上の結果から、多分演算が型の違いか何かで失敗してfalse
が返ってることがわかる。
where username=false;
?
select * from Test where title=false; // テーブル出力 select * from Test where title=true; // 結果なし
''-sleep(1)
は演算失敗してfalse
が返ってくることで、全テーブルが得られていたと推測できる。また、先にsleep(1)
が評価されて、sleep
が実行されてるのも面白いですね。