diff --git a/.idea/kubekarma.iml b/.idea/kubekarma.iml new file mode 100644 index 0000000..0702e6d --- /dev/null +++ b/.idea/kubekarma.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 3622d32..78837c3 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ - - + \ No newline at end of file diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 0000000..415db03 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,11 @@ +version: v1 +plugins: + - plugin: buf.build/grpc/python:v1.61.0 + out: . + # dependencies + - plugin: buf.build/protocolbuffers/python + out: . + - plugin: buf.build/community/nipunn1313-mypy:v3.5.0 + out: . + - plugin: buf.build/community/nipunn1313-mypy-grpc:v3.5.0 + out: . \ No newline at end of file diff --git a/charts/kubekarma/crds/NetworkTestSuite.yaml b/charts/kubekarma/crds/NetworkTestSuite.yaml index 1c11213..30f7e5d 100644 --- a/charts/kubekarma/crds/NetworkTestSuite.yaml +++ b/charts/kubekarma/crds/NetworkTestSuite.yaml @@ -31,7 +31,7 @@ spec: description: The frequency at which the test suite should be run default: "* * * * *" pattern: "^[*] ([*]|[0-5]?[0-9]) ([*]|[0-5]?[0-9]) ([*]|[0-9]|[0-2]?[0-9]) ([*]|[0-9]|[0-6]?[0-9])$" - testCases: + networkValidations: type: array items: type: object @@ -123,7 +123,7 @@ spec: default: false required: - name - - testCases + - networkValidations status: type: object # Required to allow patch status with KOPF :/ @@ -146,8 +146,8 @@ spec: - Succeeding # The test suite is running and all the test cases are passing - Failing # The test suite is running and at least one test case is failing - # @status.testCases is an array with information about each test case - testCases: + # @status.networkValidations is an array with information about each test case + networkValidations: type: array default: [] items: @@ -187,7 +187,7 @@ spec: description: The number of test cases that passed (Succeeded/Total) required: - phase - - testCases + - networkValidations additionalPrinterColumns: - name: Phase type: string diff --git a/dev/values.yaml b/dev/values.yaml index 1d35cb4..c42e15a 100644 --- a/dev/values.yaml +++ b/dev/values.yaml @@ -1,5 +1,5 @@ workerImage: pullPolicy: IfNotPresent - tag: "v0.0.1-3-g252361d-dirty" + tag: "v0.0.1-1-1-g367d205-dirty" controller: logLevel: "debug" diff --git a/docs/development.md b/docs/development.md index 7ad497f..e3b155e 100644 --- a/docs/development.md +++ b/docs/development.md @@ -14,3 +14,19 @@ minikube start -p custom skaffold dev --port-forward kubectl apply -f examples/NetworkTestSuite/test_with_all_asserts.yaml ``` + +## Generate CRD manifests + +https://book.kubebuilder.io/getting-started +**NOTE** Please export `GO111MODULE=on` and the binary would be installed at `$GOPATH/bin`. +```shell + go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 + +``` + + + + +curl -L -o kubebuilder "https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)" +chmod +x kubebuilder && mv kubebuilder /usr/local/bin/ + diff --git a/examples/NetworkTestSuite/test_with_all_asserts.yaml b/examples/NetworkTestSuite/test_with_all_asserts.yaml index 5773c8d..85cda74 100644 --- a/examples/NetworkTestSuite/test_with_all_asserts.yaml +++ b/examples/NetworkTestSuite/test_with_all_asserts.yaml @@ -5,7 +5,7 @@ metadata: spec: name: A test suite test schedule: "* * * * *" - testCases: + networkValidations: - name: web-server-access testExactDestination: destinationIP: 192.168.1.100 diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ba26d8a --- /dev/null +++ b/go.mod @@ -0,0 +1,37 @@ +module github.com/cristiansteib/kubekarma + +go 1.21.6 + +require k8s.io/apimachinery v0.29.2 + +require ( + github.com/fatih/color v1.16.0 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/gobuffalo/flect v1.0.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.16.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.0 // indirect + k8s.io/apiextensions-apiserver v0.29.0 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + sigs.k8s.io/controller-tools v0.14.0 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..af97641 --- /dev/null +++ b/go.sum @@ -0,0 +1,119 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= +github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= +k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= +k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= +k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= +k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= +k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-tools v0.14.0 h1:rnNoCC5wSXlrNoBKKzL70LNJKIQKEzT6lloG6/LF73A= +sigs.k8s.io/controller-tools v0.14.0/go.mod h1:TV7uOtNNnnR72SpzhStvPkoS/U5ir0nMudrkrC4M9Sc= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/kubekarma/controlleroperator/core/testsuite/resultsreportsubscriber.py b/kubekarma/controlleroperator/core/testsuite/resultsreportsubscriber.py index 9a60733..559c29a 100644 --- a/kubekarma/controlleroperator/core/testsuite/resultsreportsubscriber.py +++ b/kubekarma/controlleroperator/core/testsuite/resultsreportsubscriber.py @@ -12,11 +12,11 @@ from kubekarma.controlleroperator.core.testsuite.statustracker import \ TestSuiteStatusTracker from kubekarma.controlleroperator.core.testsuite.types import TestCaseStatusType +from kubekarma.grpcgen.collectors.v1 import controller_pb2 from kubekarma.shared.crd.genericcrd import ( CRDTestExecutionStatus, - TestCaseStatus + AssertValidationStatus ) -from kubekarma.shared.pb2 import controller_pb2 import logging logger = logging.getLogger(__name__) @@ -55,7 +55,7 @@ def update( and used to set the status of the CRD. """ # Define the status that are considered as bad - bad_status = (TestCaseStatus.Failed, TestCaseStatus.Error) + bad_status = (AssertValidationStatus.Failed, AssertValidationStatus.Error) # prepare the patch to be applied to the CRD to report the results test_cases: List[TestCaseStatusType] = [] @@ -64,7 +64,7 @@ def update( failed_test = [] for result in results.test_case_results: - test_status = TestCaseStatus.from_pb2_test_status(result.status) + test_status = AssertValidationStatus.from_pb2_test_status(result.status) specific_test_case_status: TestCaseStatusType = { # The unique name of the test case, we can consider this # as the ID of the test case. @@ -80,7 +80,7 @@ def update( failed_test.append(result.name) # If the test case failed due to an error, # add the error message to the status. - if test_status == TestCaseStatus.Error: + if test_status == AssertValidationStatus.Error: specific_test_case_status["error"] = result.error_message test_cases.append(specific_test_case_status) diff --git a/kubekarma/controlleroperator/core/testsuite/statustracker.py b/kubekarma/controlleroperator/core/testsuite/statustracker.py index 55bb74a..0a2b99d 100644 --- a/kubekarma/controlleroperator/core/testsuite/statustracker.py +++ b/kubekarma/controlleroperator/core/testsuite/statustracker.py @@ -4,7 +4,7 @@ from kubekarma.controlleroperator.core.testsuite.types import TestSuiteStatusType from kubekarma.shared.crd.genericcrd import CRDTestExecutionStatus, \ - TestCaseStatus + AssertValidationStatus logger = logging.getLogger(__name__) @@ -35,7 +35,7 @@ def calculate_current_test_suite_status( failed_test_cases = [ test_case for test_case in test_cases if test_case["status"] in ( - TestCaseStatus.Failed.value, TestCaseStatus.Error.value + AssertValidationStatus.Failed.value, AssertValidationStatus.Error.value ) ] diff --git a/kubekarma/controlleroperator/grpcsrv/__init__.py b/kubekarma/controlleroperator/grpcservicers/__init__.py similarity index 100% rename from kubekarma/controlleroperator/grpcsrv/__init__.py rename to kubekarma/controlleroperator/grpcservicers/__init__.py diff --git a/kubekarma/controlleroperator/grpcsrv/controller.py b/kubekarma/controlleroperator/grpcservicers/controller.py similarity index 88% rename from kubekarma/controlleroperator/grpcsrv/controller.py rename to kubekarma/controlleroperator/grpcservicers/controller.py index 659665a..82b16e7 100644 --- a/kubekarma/controlleroperator/grpcsrv/controller.py +++ b/kubekarma/controlleroperator/grpcservicers/controller.py @@ -2,7 +2,8 @@ from kubekarma.controlleroperator.core.abc.resultspublisher import \ ITestResultsPublisher -from kubekarma.shared.pb2 import controller_pb2_grpc, controller_pb2 +from kubekarma.grpcgen.collectors.v1 import controller_pb2, \ + controller_pb2_grpc class ControllerServiceServicer(controller_pb2_grpc.ControllerServiceServicer): diff --git a/kubekarma/controlleroperator/grpcsrv/health.py b/kubekarma/controlleroperator/grpcservicers/health.py similarity index 77% rename from kubekarma/controlleroperator/grpcsrv/health.py rename to kubekarma/controlleroperator/grpcservicers/health.py index 7497749..ec36bef 100644 --- a/kubekarma/controlleroperator/grpcsrv/health.py +++ b/kubekarma/controlleroperator/grpcservicers/health.py @@ -1,10 +1,8 @@ -from kubekarma.controlleroperator.grpcsrv.pb2 import health_pb2_grpc -from kubekarma.controlleroperator.grpcsrv.pb2.health_pb2 import ( - HealthCheckResponse -) - import logging +from kubekarma.grpcgen.health.v1 import health_pb2_grpc +from kubekarma.grpcgen.health.v1.health_pb2 import HealthCheckResponse + logger = logging.getLogger(__name__) diff --git a/kubekarma/controlleroperator/grpcservicers/server.py b/kubekarma/controlleroperator/grpcservicers/server.py new file mode 100644 index 0000000..64d112f --- /dev/null +++ b/kubekarma/controlleroperator/grpcservicers/server.py @@ -0,0 +1,17 @@ +import grpc +from concurrent import futures + +from kubekarma.controlleroperator.core.controllerengine import ControllerEngine +from kubekarma.controlleroperator.grpcservicers.utils import \ + add_all_servicers_to_server + + +def build_grpc_server( + server_address, + controller_engine: ControllerEngine +) -> grpc.Server: + """Return the gRPC server for the Master service.""" + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + add_all_servicers_to_server(server, controller_engine) + server.add_insecure_port(server_address) + return server diff --git a/kubekarma/controlleroperator/grpcservicers/utils.py b/kubekarma/controlleroperator/grpcservicers/utils.py new file mode 100644 index 0000000..d4a1dd4 --- /dev/null +++ b/kubekarma/controlleroperator/grpcservicers/utils.py @@ -0,0 +1,25 @@ +import grpc +from kubekarma.controlleroperator.core.controllerengine import ControllerEngine +from kubekarma.controlleroperator.grpcservicers.controller import \ + ControllerServiceServicer +from kubekarma.controlleroperator.grpcservicers.health import HealthServicer +from kubekarma.grpcgen.collectors.v1 import controller_pb2_grpc +from kubekarma.grpcgen.health.v1 import health_pb2_grpc + + +def add_all_servicers_to_server( + server, + controller_engine: ControllerEngine +) -> grpc.Server: + """Add all servicers into the server.""" + health_pb2_grpc.add_HealthServicer_to_server( + HealthServicer(), + server + ) + controller_pb2_grpc.add_ControllerServiceServicer_to_server( + ControllerServiceServicer( + result_publisher=controller_engine.get_results_publisher() + ), + server + ) + return server diff --git a/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2.py b/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2.py deleted file mode 100644 index a3be2b5..0000000 --- a/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: kubekarma/controlleroperator/grpcsrv/pb2/health.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n5kubekarma/controlleroperator/grpcsrv/pb2/health.proto\x12\x0egrpc.health.v1\"%\n\x12HealthCheckRequest\x12\x0f\n\x07service\x18\x01 \x01(\t\"\xa9\x01\n\x13HealthCheckResponse\x12\x41\n\x06status\x18\x01 \x01(\x0e\x32\x31.grpc.health.v1.HealthCheckResponse.ServingStatus\"O\n\rServingStatus\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0b\n\x07SERVING\x10\x01\x12\x0f\n\x0bNOT_SERVING\x10\x02\x12\x13\n\x0fSERVICE_UNKNOWN\x10\x03\x32\xae\x01\n\x06Health\x12P\n\x05\x43heck\x12\".grpc.health.v1.HealthCheckRequest\x1a#.grpc.health.v1.HealthCheckResponse\x12R\n\x05Watch\x12\".grpc.health.v1.HealthCheckRequest\x1a#.grpc.health.v1.HealthCheckResponse0\x01\x62\x06proto3') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'kubekarma.controlleroperator.grpcsrv.pb2.health_pb2', _globals) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _globals['_HEALTHCHECKREQUEST']._serialized_start=73 - _globals['_HEALTHCHECKREQUEST']._serialized_end=110 - _globals['_HEALTHCHECKRESPONSE']._serialized_start=113 - _globals['_HEALTHCHECKRESPONSE']._serialized_end=282 - _globals['_HEALTHCHECKRESPONSE_SERVINGSTATUS']._serialized_start=203 - _globals['_HEALTHCHECKRESPONSE_SERVINGSTATUS']._serialized_end=282 - _globals['_HEALTH']._serialized_start=285 - _globals['_HEALTH']._serialized_end=459 -# @@protoc_insertion_point(module_scope) diff --git a/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2.pyi b/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2.pyi deleted file mode 100644 index 36df8fa..0000000 --- a/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2.pyi +++ /dev/null @@ -1,28 +0,0 @@ -from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union - -DESCRIPTOR: _descriptor.FileDescriptor - -class HealthCheckRequest(_message.Message): - __slots__ = ["service"] - SERVICE_FIELD_NUMBER: _ClassVar[int] - service: str - def __init__(self, service: _Optional[str] = ...) -> None: ... - -class HealthCheckResponse(_message.Message): - __slots__ = ["status"] - class ServingStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - UNKNOWN: _ClassVar[HealthCheckResponse.ServingStatus] - SERVING: _ClassVar[HealthCheckResponse.ServingStatus] - NOT_SERVING: _ClassVar[HealthCheckResponse.ServingStatus] - SERVICE_UNKNOWN: _ClassVar[HealthCheckResponse.ServingStatus] - UNKNOWN: HealthCheckResponse.ServingStatus - SERVING: HealthCheckResponse.ServingStatus - NOT_SERVING: HealthCheckResponse.ServingStatus - SERVICE_UNKNOWN: HealthCheckResponse.ServingStatus - STATUS_FIELD_NUMBER: _ClassVar[int] - status: HealthCheckResponse.ServingStatus - def __init__(self, status: _Optional[_Union[HealthCheckResponse.ServingStatus, str]] = ...) -> None: ... diff --git a/kubekarma/controlleroperator/grpcsrv/server.py b/kubekarma/controlleroperator/grpcsrv/server.py deleted file mode 100644 index 2ab81c9..0000000 --- a/kubekarma/controlleroperator/grpcsrv/server.py +++ /dev/null @@ -1,29 +0,0 @@ -from concurrent import futures - -import grpc - -from kubekarma.controlleroperator.core.controllerengine import ControllerEngine -from kubekarma.controlleroperator.grpcsrv.health import HealthServicer -from kubekarma.controlleroperator.grpcsrv.controller import ControllerServiceServicer -from kubekarma.shared.pb2 import controller_pb2_grpc -from kubekarma.controlleroperator.grpcsrv.pb2 import health_pb2_grpc - - -def build_grpc_server( - server_address, - controller_engine: ControllerEngine -) -> grpc.Server: - """Return the gRPC server for the Master service.""" - server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) - health_pb2_grpc.add_HealthServicer_to_server( - HealthServicer(), - server - ) - controller_pb2_grpc.add_ControllerServiceServicer_to_server( - ControllerServiceServicer( - result_publisher=controller_engine.get_results_publisher() - ), - server - ) - server.add_insecure_port(server_address) - return server diff --git a/kubekarma/controlleroperator/kopfmain.py b/kubekarma/controlleroperator/kopfmain.py index b71622b..f700b0e 100644 --- a/kubekarma/controlleroperator/kopfmain.py +++ b/kubekarma/controlleroperator/kopfmain.py @@ -1,4 +1,3 @@ -import random from datetime import datetime from typing import Any @@ -11,7 +10,7 @@ from kubekarma.controlleroperator.config import config from kubekarma.controlleroperator.core.testsuite.lifecyclehandler import \ ControllerCRDLifecycleHandler -from kubekarma.controlleroperator.grpcsrv.server import build_grpc_server +from kubekarma.controlleroperator.grpcservicers.server import build_grpc_server from kubekarma.controlleroperator.kinds.networktestsuite import \ NetworkTestSuite from kubekarma.controlleroperator.httpserver import get_threaded_server diff --git a/kubekarma/grpcgen/collectors/v1/controller_pb2.py b/kubekarma/grpcgen/collectors/v1/controller_pb2.py new file mode 100644 index 0000000..44bcd2a --- /dev/null +++ b/kubekarma/grpcgen/collectors/v1/controller_pb2.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: kubekarma/grpcgen/collectors/v1/controller.proto +# Protobuf Python Version: 4.25.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n0kubekarma/grpcgen/collectors/v1/controller.proto\x12\x17kubekarma.collectors.v1\"\xbf\x02\n\x0eTestCaseResult\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12J\n\x06status\x18\x02 \x01(\x0e\x32\x32.kubekarma.collectors.v1.TestCaseResult.TestStatusR\x06status\x12-\n\x12\x65xecution_duration\x18\x03 \x01(\tR\x11\x65xecutionDuration\x12\x30\n\x14\x65xecution_start_time\x18\x04 \x01(\tR\x12\x65xecutionStartTime\x12#\n\rerror_message\x18\x05 \x01(\tR\x0c\x65rrorMessage\"G\n\nTestStatus\x12\t\n\x05\x45RROR\x10\x00\x12\r\n\tSUCCEEDED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x12\x13\n\x0fNOT_IMPLEMENTED\x10\x03\"\xc7\x01\n\x1eProcessTestSuiteResultsRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12&\n\x0fstarted_at_time\x18\x02 \x01(\tR\rstartedAtTime\x12S\n\x11test_case_results\x18\x03 \x03(\x0b\x32\'.kubekarma.collectors.v1.TestCaseResultR\x0ftestCaseResults\x12\x14\n\x05token\x18\x04 \x01(\tR\x05token\";\n\x1fProcessTestSuiteResultsResponse\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message2\xa4\x01\n\x11\x43ontrollerService\x12\x8e\x01\n\x17ProcessTestSuiteResults\x12\x37.kubekarma.collectors.v1.ProcessTestSuiteResultsRequest\x1a\x38.kubekarma.collectors.v1.ProcessTestSuiteResultsResponse\"\x00\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'kubekarma.grpcgen.collectors.v1.controller_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_TESTCASERESULT']._serialized_start=78 + _globals['_TESTCASERESULT']._serialized_end=397 + _globals['_TESTCASERESULT_TESTSTATUS']._serialized_start=326 + _globals['_TESTCASERESULT_TESTSTATUS']._serialized_end=397 + _globals['_PROCESSTESTSUITERESULTSREQUEST']._serialized_start=400 + _globals['_PROCESSTESTSUITERESULTSREQUEST']._serialized_end=599 + _globals['_PROCESSTESTSUITERESULTSRESPONSE']._serialized_start=601 + _globals['_PROCESSTESTSUITERESULTSRESPONSE']._serialized_end=660 + _globals['_CONTROLLERSERVICE']._serialized_start=663 + _globals['_CONTROLLERSERVICE']._serialized_end=827 +# @@protoc_insertion_point(module_scope) diff --git a/kubekarma/grpcgen/collectors/v1/controller_pb2.pyi b/kubekarma/grpcgen/collectors/v1/controller_pb2.pyi new file mode 100644 index 0000000..e637b18 --- /dev/null +++ b/kubekarma/grpcgen/collectors/v1/controller_pb2.pyi @@ -0,0 +1,130 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class TestCaseResult(google.protobuf.message.Message): + """* + TestCaseResult represents and individual test case result + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + class _TestStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _TestStatusEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[TestCaseResult._TestStatus.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + ERROR: TestCaseResult._TestStatus.ValueType # 0 + """ERROR: when some exception was raised during the execution of the test case""" + SUCCEEDED: TestCaseResult._TestStatus.ValueType # 1 + """SUCCEEDED: when the test case was executed successfully""" + FAILED: TestCaseResult._TestStatus.ValueType # 2 + """FAILED: when the test case was executed but the assertion failed""" + NOT_IMPLEMENTED: TestCaseResult._TestStatus.ValueType # 3 + """NOTIMPLEMENTED: when the test case code is not implemented yet""" + + class TestStatus(_TestStatus, metaclass=_TestStatusEnumTypeWrapper): ... + ERROR: TestCaseResult.TestStatus.ValueType # 0 + """ERROR: when some exception was raised during the execution of the test case""" + SUCCEEDED: TestCaseResult.TestStatus.ValueType # 1 + """SUCCEEDED: when the test case was executed successfully""" + FAILED: TestCaseResult.TestStatus.ValueType # 2 + """FAILED: when the test case was executed but the assertion failed""" + NOT_IMPLEMENTED: TestCaseResult.TestStatus.ValueType # 3 + """NOTIMPLEMENTED: when the test case code is not implemented yet""" + + NAME_FIELD_NUMBER: builtins.int + STATUS_FIELD_NUMBER: builtins.int + EXECUTION_DURATION_FIELD_NUMBER: builtins.int + EXECUTION_START_TIME_FIELD_NUMBER: builtins.int + ERROR_MESSAGE_FIELD_NUMBER: builtins.int + name: builtins.str + """The specific name of the test case""" + status: global___TestCaseResult.TestStatus.ValueType + execution_duration: builtins.str + """How long it took to execute the test case""" + execution_start_time: builtins.str + """When the test case started executing""" + error_message: builtins.str + """errorMessage is only set when the status is ERROR and it contains the + exception message and stack trace + """ + def __init__( + self, + *, + name: builtins.str = ..., + status: global___TestCaseResult.TestStatus.ValueType = ..., + execution_duration: builtins.str = ..., + execution_start_time: builtins.str = ..., + error_message: builtins.str = ..., + ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["error_message", b"error_message", "execution_duration", b"execution_duration", "execution_start_time", b"execution_start_time", "name", b"name", "status", b"status"]) -> None: ... + +global___TestCaseResult = TestCaseResult + +@typing_extensions.final +class ProcessTestSuiteResultsRequest(google.protobuf.message.Message): + """* + TestSuiteResult represents the result of a whole test suite execution + """ + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + NAME_FIELD_NUMBER: builtins.int + STARTED_AT_TIME_FIELD_NUMBER: builtins.int + TEST_CASE_RESULTS_FIELD_NUMBER: builtins.int + TOKEN_FIELD_NUMBER: builtins.int + name: builtins.str + """name: is the name of the test suite""" + started_at_time: builtins.str + """the time when the test suite started executing + it should be in ISO 8601 format + """ + @property + def test_case_results(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___TestCaseResult]: ... + token: builtins.str + """token: is used to identify the test suite execution""" + def __init__( + self, + *, + name: builtins.str = ..., + started_at_time: builtins.str = ..., + test_case_results: collections.abc.Iterable[global___TestCaseResult] | None = ..., + token: builtins.str = ..., + ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["name", b"name", "started_at_time", b"started_at_time", "test_case_results", b"test_case_results", "token", b"token"]) -> None: ... + +global___ProcessTestSuiteResultsRequest = ProcessTestSuiteResultsRequest + +@typing_extensions.final +class ProcessTestSuiteResultsResponse(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + MESSAGE_FIELD_NUMBER: builtins.int + message: builtins.str + def __init__( + self, + *, + message: builtins.str = ..., + ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["message", b"message"]) -> None: ... + +global___ProcessTestSuiteResultsResponse = ProcessTestSuiteResultsResponse diff --git a/kubekarma/shared/pb2/controller_pb2_grpc.py b/kubekarma/grpcgen/collectors/v1/controller_pb2_grpc.py similarity index 61% rename from kubekarma/shared/pb2/controller_pb2_grpc.py rename to kubekarma/grpcgen/collectors/v1/controller_pb2_grpc.py index 8d361ed..168e86a 100644 --- a/kubekarma/shared/pb2/controller_pb2_grpc.py +++ b/kubekarma/grpcgen/collectors/v1/controller_pb2_grpc.py @@ -2,7 +2,7 @@ """Client and server classes corresponding to protobuf-defined services.""" import grpc -from kubekarma.shared.pb2 import controller_pb2 as kubekarma_dot_shared_dot_pb2_dot_controller__pb2 +from kubekarma.grpcgen.collectors.v1 import controller_pb2 as kubekarma_dot_grpcgen_dot_collectors_dot_v1_dot_controller__pb2 class ControllerServiceStub(object): @@ -15,9 +15,9 @@ def __init__(self, channel): channel: A grpc.Channel. """ self.ProcessTestSuiteResults = channel.unary_unary( - '/ControllerService/ProcessTestSuiteResults', - request_serializer=kubekarma_dot_shared_dot_pb2_dot_controller__pb2.ProcessTestSuiteResultsRequest.SerializeToString, - response_deserializer=kubekarma_dot_shared_dot_pb2_dot_controller__pb2.ProcessTestSuiteResultsResponse.FromString, + '/kubekarma.collectors.v1.ControllerService/ProcessTestSuiteResults', + request_serializer=kubekarma_dot_grpcgen_dot_collectors_dot_v1_dot_controller__pb2.ProcessTestSuiteResultsRequest.SerializeToString, + response_deserializer=kubekarma_dot_grpcgen_dot_collectors_dot_v1_dot_controller__pb2.ProcessTestSuiteResultsResponse.FromString, ) @@ -36,12 +36,12 @@ def add_ControllerServiceServicer_to_server(servicer, server): rpc_method_handlers = { 'ProcessTestSuiteResults': grpc.unary_unary_rpc_method_handler( servicer.ProcessTestSuiteResults, - request_deserializer=kubekarma_dot_shared_dot_pb2_dot_controller__pb2.ProcessTestSuiteResultsRequest.FromString, - response_serializer=kubekarma_dot_shared_dot_pb2_dot_controller__pb2.ProcessTestSuiteResultsResponse.SerializeToString, + request_deserializer=kubekarma_dot_grpcgen_dot_collectors_dot_v1_dot_controller__pb2.ProcessTestSuiteResultsRequest.FromString, + response_serializer=kubekarma_dot_grpcgen_dot_collectors_dot_v1_dot_controller__pb2.ProcessTestSuiteResultsResponse.SerializeToString, ), } generic_handler = grpc.method_handlers_generic_handler( - 'ControllerService', rpc_method_handlers) + 'kubekarma.collectors.v1.ControllerService', rpc_method_handlers) server.add_generic_rpc_handlers((generic_handler,)) @@ -60,8 +60,8 @@ def ProcessTestSuiteResults(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/ControllerService/ProcessTestSuiteResults', - kubekarma_dot_shared_dot_pb2_dot_controller__pb2.ProcessTestSuiteResultsRequest.SerializeToString, - kubekarma_dot_shared_dot_pb2_dot_controller__pb2.ProcessTestSuiteResultsResponse.FromString, + return grpc.experimental.unary_unary(request, target, '/kubekarma.collectors.v1.ControllerService/ProcessTestSuiteResults', + kubekarma_dot_grpcgen_dot_collectors_dot_v1_dot_controller__pb2.ProcessTestSuiteResultsRequest.SerializeToString, + kubekarma_dot_grpcgen_dot_collectors_dot_v1_dot_controller__pb2.ProcessTestSuiteResultsResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/kubekarma/grpcgen/collectors/v1/controller_pb2_grpc.pyi b/kubekarma/grpcgen/collectors/v1/controller_pb2_grpc.pyi new file mode 100644 index 0000000..734a243 --- /dev/null +++ b/kubekarma/grpcgen/collectors/v1/controller_pb2_grpc.pyi @@ -0,0 +1,44 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import abc +import collections.abc +import grpc +import grpc.aio +import kubekarma.grpcgen.collectors.v1.controller_pb2 +import typing + +_T = typing.TypeVar('_T') + +class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): + ... + +class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore + ... + +class ControllerServiceStub: + def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... + ProcessTestSuiteResults: grpc.UnaryUnaryMultiCallable[ + kubekarma.grpcgen.collectors.v1.controller_pb2.ProcessTestSuiteResultsRequest, + kubekarma.grpcgen.collectors.v1.controller_pb2.ProcessTestSuiteResultsResponse, + ] + """ProcessTestSuiteResults is called by the test runner to report the results of the execution""" + +class ControllerServiceAsyncStub: + ProcessTestSuiteResults: grpc.aio.UnaryUnaryMultiCallable[ + kubekarma.grpcgen.collectors.v1.controller_pb2.ProcessTestSuiteResultsRequest, + kubekarma.grpcgen.collectors.v1.controller_pb2.ProcessTestSuiteResultsResponse, + ] + """ProcessTestSuiteResults is called by the test runner to report the results of the execution""" + +class ControllerServiceServicer(metaclass=abc.ABCMeta): + @abc.abstractmethod + def ProcessTestSuiteResults( + self, + request: kubekarma.grpcgen.collectors.v1.controller_pb2.ProcessTestSuiteResultsRequest, + context: _ServicerContext, + ) -> typing.Union[kubekarma.grpcgen.collectors.v1.controller_pb2.ProcessTestSuiteResultsResponse, collections.abc.Awaitable[kubekarma.grpcgen.collectors.v1.controller_pb2.ProcessTestSuiteResultsResponse]]: + """ProcessTestSuiteResults is called by the test runner to report the results of the execution""" + +def add_ControllerServiceServicer_to_server(servicer: ControllerServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... diff --git a/kubekarma/grpcgen/health/v1/health_pb2.py b/kubekarma/grpcgen/health/v1/health_pb2.py new file mode 100644 index 0000000..90700da --- /dev/null +++ b/kubekarma/grpcgen/health/v1/health_pb2.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: kubekarma/grpcgen/health/v1/health.proto +# Protobuf Python Version: 4.25.3 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n(kubekarma/grpcgen/health/v1/health.proto\x12\x0egrpc.health.v1\".\n\x12HealthCheckRequest\x12\x18\n\x07service\x18\x01 \x01(\tR\x07service\"\xb1\x01\n\x13HealthCheckResponse\x12I\n\x06status\x18\x01 \x01(\x0e\x32\x31.grpc.health.v1.HealthCheckResponse.ServingStatusR\x06status\"O\n\rServingStatus\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0b\n\x07SERVING\x10\x01\x12\x0f\n\x0bNOT_SERVING\x10\x02\x12\x13\n\x0fSERVICE_UNKNOWN\x10\x03\x32\xae\x01\n\x06Health\x12P\n\x05\x43heck\x12\".grpc.health.v1.HealthCheckRequest\x1a#.grpc.health.v1.HealthCheckResponse\x12R\n\x05Watch\x12\".grpc.health.v1.HealthCheckRequest\x1a#.grpc.health.v1.HealthCheckResponse0\x01\x62\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'kubekarma.grpcgen.health.v1.health_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _globals['_HEALTHCHECKREQUEST']._serialized_start=60 + _globals['_HEALTHCHECKREQUEST']._serialized_end=106 + _globals['_HEALTHCHECKRESPONSE']._serialized_start=109 + _globals['_HEALTHCHECKRESPONSE']._serialized_end=286 + _globals['_HEALTHCHECKRESPONSE_SERVINGSTATUS']._serialized_start=207 + _globals['_HEALTHCHECKRESPONSE_SERVINGSTATUS']._serialized_end=286 + _globals['_HEALTH']._serialized_start=289 + _globals['_HEALTH']._serialized_end=463 +# @@protoc_insertion_point(module_scope) diff --git a/kubekarma/grpcgen/health/v1/health_pb2.pyi b/kubekarma/grpcgen/health/v1/health_pb2.pyi new file mode 100644 index 0000000..d3cd90f --- /dev/null +++ b/kubekarma/grpcgen/health/v1/health_pb2.pyi @@ -0,0 +1,66 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +Source https://github.com/grpc/grpc/blob/master/doc/health-checking.md""" +import builtins +import google.protobuf.descriptor +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +@typing_extensions.final +class HealthCheckRequest(google.protobuf.message.Message): + """buf:lint:ignore""" + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + SERVICE_FIELD_NUMBER: builtins.int + service: builtins.str + def __init__( + self, + *, + service: builtins.str = ..., + ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["service", b"service"]) -> None: ... + +global___HealthCheckRequest = HealthCheckRequest + +@typing_extensions.final +class HealthCheckResponse(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + class _ServingStatus: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + + class _ServingStatusEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[HealthCheckResponse._ServingStatus.ValueType], builtins.type): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + UNKNOWN: HealthCheckResponse._ServingStatus.ValueType # 0 + SERVING: HealthCheckResponse._ServingStatus.ValueType # 1 + NOT_SERVING: HealthCheckResponse._ServingStatus.ValueType # 2 + SERVICE_UNKNOWN: HealthCheckResponse._ServingStatus.ValueType # 3 + + class ServingStatus(_ServingStatus, metaclass=_ServingStatusEnumTypeWrapper): ... + UNKNOWN: HealthCheckResponse.ServingStatus.ValueType # 0 + SERVING: HealthCheckResponse.ServingStatus.ValueType # 1 + NOT_SERVING: HealthCheckResponse.ServingStatus.ValueType # 2 + SERVICE_UNKNOWN: HealthCheckResponse.ServingStatus.ValueType # 3 + + STATUS_FIELD_NUMBER: builtins.int + status: global___HealthCheckResponse.ServingStatus.ValueType + def __init__( + self, + *, + status: global___HealthCheckResponse.ServingStatus.ValueType = ..., + ) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["status", b"status"]) -> None: ... + +global___HealthCheckResponse = HealthCheckResponse diff --git a/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2_grpc.py b/kubekarma/grpcgen/health/v1/health_pb2_grpc.py similarity index 62% rename from kubekarma/controlleroperator/grpcsrv/pb2/health_pb2_grpc.py rename to kubekarma/grpcgen/health/v1/health_pb2_grpc.py index 79ef815..8963eda 100644 --- a/kubekarma/controlleroperator/grpcsrv/pb2/health_pb2_grpc.py +++ b/kubekarma/grpcgen/health/v1/health_pb2_grpc.py @@ -2,7 +2,7 @@ """Client and server classes corresponding to protobuf-defined services.""" import grpc -from kubekarma.controlleroperator.grpcsrv.pb2 import health_pb2 as kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2 +from kubekarma.grpcgen.health.v1 import health_pb2 as kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2 class HealthStub(object): @@ -16,13 +16,13 @@ def __init__(self, channel): """ self.Check = channel.unary_unary( '/grpc.health.v1.Health/Check', - request_serializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckRequest.SerializeToString, - response_deserializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckResponse.FromString, + request_serializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckRequest.SerializeToString, + response_deserializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckResponse.FromString, ) self.Watch = channel.unary_stream( '/grpc.health.v1.Health/Watch', - request_serializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckRequest.SerializeToString, - response_deserializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckResponse.FromString, + request_serializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckRequest.SerializeToString, + response_deserializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckResponse.FromString, ) @@ -46,13 +46,13 @@ def add_HealthServicer_to_server(servicer, server): rpc_method_handlers = { 'Check': grpc.unary_unary_rpc_method_handler( servicer.Check, - request_deserializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckRequest.FromString, - response_serializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckResponse.SerializeToString, + request_deserializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckRequest.FromString, + response_serializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckResponse.SerializeToString, ), 'Watch': grpc.unary_stream_rpc_method_handler( servicer.Watch, - request_deserializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckRequest.FromString, - response_serializer=kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckResponse.SerializeToString, + request_deserializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckRequest.FromString, + response_serializer=kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckResponse.SerializeToString, ), } generic_handler = grpc.method_handlers_generic_handler( @@ -76,8 +76,8 @@ def Check(request, timeout=None, metadata=None): return grpc.experimental.unary_unary(request, target, '/grpc.health.v1.Health/Check', - kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckRequest.SerializeToString, - kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckResponse.FromString, + kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckRequest.SerializeToString, + kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) @@ -93,7 +93,7 @@ def Watch(request, timeout=None, metadata=None): return grpc.experimental.unary_stream(request, target, '/grpc.health.v1.Health/Watch', - kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckRequest.SerializeToString, - kubekarma_dot_controlleroperator_dot_grpcsrv_dot_pb2_dot_health__pb2.HealthCheckResponse.FromString, + kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckRequest.SerializeToString, + kubekarma_dot_grpcgen_dot_health_dot_v1_dot_health__pb2.HealthCheckResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/kubekarma/grpcgen/health/v1/health_pb2_grpc.pyi b/kubekarma/grpcgen/health/v1/health_pb2_grpc.pyi new file mode 100644 index 0000000..da2f2b9 --- /dev/null +++ b/kubekarma/grpcgen/health/v1/health_pb2_grpc.pyi @@ -0,0 +1,55 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +Source https://github.com/grpc/grpc/blob/master/doc/health-checking.md""" +import abc +import collections.abc +import grpc +import grpc.aio +import kubekarma.grpcgen.health.v1.health_pb2 +import typing + +_T = typing.TypeVar('_T') + +class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): + ... + +class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore + ... + +class HealthStub: + def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... + Check: grpc.UnaryUnaryMultiCallable[ + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckRequest, + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse, + ] + Watch: grpc.UnaryStreamMultiCallable[ + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckRequest, + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse, + ] + +class HealthAsyncStub: + Check: grpc.aio.UnaryUnaryMultiCallable[ + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckRequest, + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse, + ] + Watch: grpc.aio.UnaryStreamMultiCallable[ + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckRequest, + kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse, + ] + +class HealthServicer(metaclass=abc.ABCMeta): + @abc.abstractmethod + def Check( + self, + request: kubekarma.grpcgen.health.v1.health_pb2.HealthCheckRequest, + context: _ServicerContext, + ) -> typing.Union[kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse, collections.abc.Awaitable[kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse]]: ... + @abc.abstractmethod + def Watch( + self, + request: kubekarma.grpcgen.health.v1.health_pb2.HealthCheckRequest, + context: _ServicerContext, + ) -> typing.Union[collections.abc.Iterator[kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse], collections.abc.AsyncIterator[kubekarma.grpcgen.health.v1.health_pb2.HealthCheckResponse]]: ... + +def add_HealthServicer_to_server(servicer: HealthServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... diff --git a/kubekarma/shared/crd/genericcrd.py b/kubekarma/shared/crd/genericcrd.py index 1760e8b..31f56c4 100644 --- a/kubekarma/shared/crd/genericcrd.py +++ b/kubekarma/shared/crd/genericcrd.py @@ -1,7 +1,7 @@ """A module to represent the generic CRD object status.""" import enum -from kubekarma.shared.pb2 import controller_pb2 +from kubekarma.grpcgen.collectors.v1 import controller_pb2 class CRDTestPhase(enum.Enum): @@ -19,7 +19,7 @@ class CRDTestExecutionStatus(enum.Enum): Failing = "Failing" -class TestCaseStatus(enum.Enum): +class AssertValidationStatus(enum.Enum): """The status of a specific test case assert.""" Failed = "Failed" Succeeded = "Succeeded" @@ -29,20 +29,20 @@ class TestCaseStatus(enum.Enum): @classmethod def from_pb2_test_status( cls, - status: controller_pb2.TestStatus - ) -> 'TestCaseStatus': + status: controller_pb2.TestCaseResult.TestStatus + ) -> 'AssertValidationStatus': """Return the test case status defined by the CRD. This method converts the status transmitted by worker to the controller to the status defined by the CRD. """ - if status == controller_pb2.TestStatus.SUCCEEDED: - return TestCaseStatus.Succeeded - elif status == controller_pb2.TestStatus.FAILED: - return TestCaseStatus.Failed - elif status == controller_pb2.TestStatus.NOTIMPLEMENTED: - return TestCaseStatus.NotImplemented - elif status == controller_pb2.TestStatus.ERROR: - return TestCaseStatus.Error + if status == controller_pb2.TestCaseResult.TestStatus.SUCCEEDED: + return AssertValidationStatus.Succeeded + elif status == controller_pb2.TestCaseResult.TestStatus.FAILED: + return AssertValidationStatus.Failed + elif status == controller_pb2.TestCaseResult.TestStatus.NOTIMPLEMENTED: + return AssertValidationStatus.NotImplemented + elif status == controller_pb2.TestCaseResult.TestStatus.ERROR: + return AssertValidationStatus.Error else: raise Exception(f"Unknown status: {status}") diff --git a/kubekarma/shared/pb2/controller_pb2.py b/kubekarma/shared/pb2/controller_pb2.py deleted file mode 100644 index 9b9c566..0000000 --- a/kubekarma/shared/pb2/controller_pb2.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: kubekarma/shared/pb2/controller.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%kubekarma/shared/pb2/controller.proto\"\x8c\x01\n\x0eTestCaseResult\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x1b\n\x06status\x18\x02 \x01(\x0e\x32\x0b.TestStatus\x12\x1a\n\x12\x65xecution_duration\x18\x03 \x01(\t\x12\x1c\n\x14\x65xecution_start_time\x18\x04 \x01(\t\x12\x15\n\rerror_message\x18\x05 \x01(\t\"\x82\x01\n\x1eProcessTestSuiteResultsRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x17\n\x0fstarted_at_time\x18\x02 \x01(\t\x12*\n\x11test_case_results\x18\x03 \x03(\x0b\x32\x0f.TestCaseResult\x12\r\n\x05token\x18\x04 \x01(\t\"2\n\x1fProcessTestSuiteResultsResponse\x12\x0f\n\x07message\x18\x01 \x01(\t*F\n\nTestStatus\x12\t\n\x05\x45RROR\x10\x00\x12\r\n\tSUCCEEDED\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x12\x12\n\x0eNOTIMPLEMENTED\x10\x03\x32s\n\x11\x43ontrollerService\x12^\n\x17ProcessTestSuiteResults\x12\x1f.ProcessTestSuiteResultsRequest\x1a .ProcessTestSuiteResultsResponse\"\x00\x62\x06proto3') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'kubekarma.shared.pb2.controller_pb2', _globals) -if _descriptor._USE_C_DESCRIPTORS == False: - DESCRIPTOR._options = None - _globals['_TESTSTATUS']._serialized_start=369 - _globals['_TESTSTATUS']._serialized_end=439 - _globals['_TESTCASERESULT']._serialized_start=42 - _globals['_TESTCASERESULT']._serialized_end=182 - _globals['_PROCESSTESTSUITERESULTSREQUEST']._serialized_start=185 - _globals['_PROCESSTESTSUITERESULTSREQUEST']._serialized_end=315 - _globals['_PROCESSTESTSUITERESULTSRESPONSE']._serialized_start=317 - _globals['_PROCESSTESTSUITERESULTSRESPONSE']._serialized_end=367 - _globals['_CONTROLLERSERVICE']._serialized_start=441 - _globals['_CONTROLLERSERVICE']._serialized_end=556 -# @@protoc_insertion_point(module_scope) diff --git a/kubekarma/shared/pb2/controller_pb2.pyi b/kubekarma/shared/pb2/controller_pb2.pyi deleted file mode 100644 index f5726b1..0000000 --- a/kubekarma/shared/pb2/controller_pb2.pyi +++ /dev/null @@ -1,50 +0,0 @@ -from google.protobuf.internal import containers as _containers -from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union - -DESCRIPTOR: _descriptor.FileDescriptor - -class TestStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - ERROR: _ClassVar[TestStatus] - SUCCEEDED: _ClassVar[TestStatus] - FAILED: _ClassVar[TestStatus] - NOTIMPLEMENTED: _ClassVar[TestStatus] -ERROR: TestStatus -SUCCEEDED: TestStatus -FAILED: TestStatus -NOTIMPLEMENTED: TestStatus - -class TestCaseResult(_message.Message): - __slots__ = ["name", "status", "execution_duration", "execution_start_time", "error_message"] - NAME_FIELD_NUMBER: _ClassVar[int] - STATUS_FIELD_NUMBER: _ClassVar[int] - EXECUTION_DURATION_FIELD_NUMBER: _ClassVar[int] - EXECUTION_START_TIME_FIELD_NUMBER: _ClassVar[int] - ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int] - name: str - status: TestStatus - execution_duration: str - execution_start_time: str - error_message: str - def __init__(self, name: _Optional[str] = ..., status: _Optional[_Union[TestStatus, str]] = ..., execution_duration: _Optional[str] = ..., execution_start_time: _Optional[str] = ..., error_message: _Optional[str] = ...) -> None: ... - -class ProcessTestSuiteResultsRequest(_message.Message): - __slots__ = ["name", "started_at_time", "test_case_results", "token"] - NAME_FIELD_NUMBER: _ClassVar[int] - STARTED_AT_TIME_FIELD_NUMBER: _ClassVar[int] - TEST_CASE_RESULTS_FIELD_NUMBER: _ClassVar[int] - TOKEN_FIELD_NUMBER: _ClassVar[int] - name: str - started_at_time: str - test_case_results: _containers.RepeatedCompositeFieldContainer[TestCaseResult] - token: str - def __init__(self, name: _Optional[str] = ..., started_at_time: _Optional[str] = ..., test_case_results: _Optional[_Iterable[_Union[TestCaseResult, _Mapping]]] = ..., token: _Optional[str] = ...) -> None: ... - -class ProcessTestSuiteResultsResponse(_message.Message): - __slots__ = ["message"] - MESSAGE_FIELD_NUMBER: _ClassVar[int] - message: str - def __init__(self, message: _Optional[str] = ...) -> None: ... diff --git a/kubekarma/tests/controlleroperator/core/test_resultsreportpublisher.py b/kubekarma/tests/controlleroperator/core/test_resultsreportpublisher.py index 0c56ee4..156ae34 100644 --- a/kubekarma/tests/controlleroperator/core/test_resultsreportpublisher.py +++ b/kubekarma/tests/controlleroperator/core/test_resultsreportpublisher.py @@ -1,9 +1,10 @@ import unittest from unittest.mock import Mock -from kubekarma.controlleroperator import ResultsReportPublisher from kubekarma.controlleroperator.core.abc.resultspublisher import \ IResultsSubscriber +from kubekarma.controlleroperator.core.resultsreportpublisher import \ + ResultsReportPublisher class ResultsReportPublisherTest(unittest.TestCase): diff --git a/kubekarma/tests/controlleroperator/kinds/test_cronjob_helper.py b/kubekarma/tests/controlleroperator/kinds/test_cronjob_helper.py index 944b5c2..f30921d 100644 --- a/kubekarma/tests/controlleroperator/kinds/test_cronjob_helper.py +++ b/kubekarma/tests/controlleroperator/kinds/test_cronjob_helper.py @@ -21,7 +21,7 @@ def test_create_cronjob(self): schedule="* * * * *", task_execution_config={ "name": "test-suite-1", - "testCases": [ + "networkValidations": [ { "testExactDestination": { "destinationIp": "1.1.1.1", @@ -34,7 +34,8 @@ def test_create_cronjob(self): kind="NetworkTestSuite", config=Config( controller_server_host="http://localhost:5000", - worker_image="kubekarma/worker:latest" + worker_image="kubekarma/worker:latest", + log_level=1 ) ) self.assertIsInstance(cron, V1CronJob) diff --git a/kubekarma/tests/worker/test_np_test_suite.py b/kubekarma/tests/worker/test_np_test_suite.py index df5cd0e..aa5aaac 100644 --- a/kubekarma/tests/worker/test_np_test_suite.py +++ b/kubekarma/tests/worker/test_np_test_suite.py @@ -26,5 +26,5 @@ def test_process_a_spec(self): ) as _run_test_mock: test_suite = NetworkTestSuite(test_config["spec"]) test_suite.run() - test_suite._parse_test_case(test_config["spec"]["testCases"][3]) + test_suite._parse_test_case(test_config["spec"]["networkValidations"][3]) self.assertEqual(_run_test_mock.call_count, 4) diff --git a/kubekarma/worker/networksuite/testsuite.py b/kubekarma/worker/networksuite/testsuite.py index 33136f9..b6525ff 100644 --- a/kubekarma/worker/networksuite/testsuite.py +++ b/kubekarma/worker/networksuite/testsuite.py @@ -4,11 +4,11 @@ import logging +from kubekarma.grpcgen.collectors.v1 import controller_pb2 +from kubekarma.grpcgen.collectors.v1.controller_pb2 import TestCaseResult from kubekarma.worker import utils from kubekarma.worker.abs.exception import AssertionFailure, InvalidDefinition from kubekarma.worker.networksuite.dnsresolutionassertion import DNSResolutionAssertion -from kubekarma.shared.pb2.controller_pb2 import TestCaseResult -from kubekarma.shared.pb2 import controller_pb2 from kubekarma.worker.networksuite.exactdestionationassertion import \ ExactDestinationAssertion @@ -40,7 +40,7 @@ def __init__(self, config_spec: dict): config_spec examples: { "name": "test-suite-1", - "testCases": [ + "networkValidations": [ { "testExactDestination": { "destinationIp": "1.1.1.1", @@ -61,19 +61,19 @@ def _parse_test_case(self, test_case_spec: dict) -> TestCase: # TODO: improve this method keys = set(_test_case.keys()) if "name" not in keys: - raise InvalidDefinition("testCases[] items must have a .name") + raise InvalidDefinition("networkValidations[] items must have a .name") test_name = _test_case.pop("name") # remove this value to only keep the assertion type _test_case.pop("allowedToFail", None) keys = set(_test_case.keys()) if len(keys) != 1: raise InvalidDefinition( - f"testCases[{test_name}] must have exactly one assertion type." + f"networkValidations[{test_name}] must have exactly one assertion type." ) assertion_type, assertion_config = _test_case.popitem() if assertion_type not in self.DEFINED_ASSERTIONS: raise InvalidDefinition( - f"testCases <{test_name}> has an unsupported assertion type: " + f"networkValidations <{test_name}> has an unsupported assertion type: " f"<{assertion_type}>" ) return self.TestCase( @@ -101,30 +101,30 @@ def run(self) -> List[TestCaseResult]: self.config_spec["name"] ) results = [] - for test in self.config_spec["testCases"]: + for test in self.config_spec["networkValidations"]: start_time = time.perf_counter() # Create a partial result item, the rest of the values # will be filled by the controller operator. test_result = TestCaseResult( name=test["name"], - status=controller_pb2.TestStatus.FAILED, + status=controller_pb2.TestCaseResult.TestStatus.FAILED, execution_duration="-", execution_start_time=str(time.time()), ) try: self._run_test(test) - test_result.status = controller_pb2.TestStatus.SUCCEEDED + test_result.status = controller_pb2.TestCaseResult.TestStatus.SUCCEEDED logger.info("[%s] ... PASSED", test['name']) except AssertionFailure: logger.info("[%s] ... FAILED", test['name']) except NotImplementedError: - test_result.status = controller_pb2.TestStatus.NOTIMPLEMENTED + test_result.status = controller_pb2.TestCaseResult.TestStatus.NOTIMPLEMENTED logger.info("[%s] ... SKIPPED", test['name']) except Exception as e: logger.exception( "[%s] ... ERROR", test['name'] ) - test_result.status = controller_pb2.TestStatus.ERROR + test_result.status = controller_pb2.TestCaseResult.TestStatus.ERROR test_result.error_message = utils.stringify_exception(e) finally: end_time = time.perf_counter() diff --git a/operator.Dockerfile b/operator.Dockerfile index 01594a1..2ef889d 100644 --- a/operator.Dockerfile +++ b/operator.Dockerfile @@ -8,20 +8,29 @@ ENV LANG=C.UTF-8 ENV PYTHONDONTWRITEBYTECODE=1 # Seems to speed things up ENV PYTHONUNBUFFERED=1 +RUN python -m pip install hatch +COPY readme.md . +COPY pyproject.toml . + +RUN hatch dep show requirements --all > requirements.txt -COPY requirements.controller.txt ./ RUN --mount=type=cache,target=/root/.cache/pip \ - pip wheel --no-deps --wheel-dir /usr/src/app/wheels \ - -r requirements.controller.txt + pip wheel --no-deps --wheel-dir /wheels \ + -r requirements.txt + +COPY . . +RUN --mount=type=cache,target=/root/.cache/pip \ + pip wheel --no-deps --wheel-dir /wheels . -FROM python:3.11-slim AS app +FROM python:3.11-slim AS application LABEL org.opencontainers.image.authors="Cristian Steib" ENV PYTHONPATH="${PYTHONPATH}:/app" -COPY --from=builder /usr/src/app/wheels /wheels +COPY --from=builder /wheels /wheels RUN pip install --no-cache /wheels/* && rm -rf /wheels -WORKDIR /app -COPY kubekarma/controlleroperator kubekarma/controlleroperator -COPY kubekarma/shared kubekarma/shared +WORKDIR /app/kubekarma +COPY kubekarma/controlleroperator controlleroperator +COPY kubekarma/shared shared +COPY kubekarma/grpcgen grpcgen LABEL org.opencontainers.image.version="0.0.1" @@ -30,4 +39,4 @@ ENV OPERATOR_NAMESPACE="default" ENTRYPOINT ["kopf"] # --all-namespaces is required to watch all namespaces in order # to watch all CRDs of kubekarma.io -CMD ["run", "kubekarma/controlleroperator/kopfmain.py", "--all-namespaces"] +CMD ["run", "/app/kubekarma/controlleroperator/kopfmain.py", "--all-namespaces"] diff --git a/protobuf/buf.yaml b/protobuf/buf.yaml new file mode 100644 index 0000000..60c053f --- /dev/null +++ b/protobuf/buf.yaml @@ -0,0 +1,12 @@ +version: v1 +lint: + use: + - DEFAULT + ignore: + - kubekarma/health/v1/health.proto + enum_zero_value_suffix: _UNSPECIFIED + rpc_allow_same_request_response: false + rpc_allow_google_protobuf_empty_requests: false + rpc_allow_google_protobuf_empty_responses: false + service_suffix: Service + allow_comment_ignores: true diff --git a/protos/kubekarma/shared/pb2/controller.proto b/protobuf/kubekarma/grpcgen/collectors/v1/controller.proto similarity index 74% rename from protos/kubekarma/shared/pb2/controller.proto rename to protobuf/kubekarma/grpcgen/collectors/v1/controller.proto index 99dc8e5..ba6a5c8 100644 --- a/protos/kubekarma/shared/pb2/controller.proto +++ b/protobuf/kubekarma/grpcgen/collectors/v1/controller.proto @@ -1,20 +1,22 @@ syntax = "proto3"; -enum TestStatus { - // ERROR: when some exception was raised during the execution of the test case - ERROR = 0; - // SUCCEEDED: when the test case was executed successfully - SUCCEEDED = 1; - // FAILED: when the test case was executed but the assertion failed - FAILED = 2; - // NOTIMPLEMENTED: when the test case code is not implemented yet - NOTIMPLEMENTED = 3; -} +package kubekarma.collectors.v1; /** TestCaseResult represents and individual test case result */ message TestCaseResult { + enum TestStatus { + // ERROR: when some exception was raised during the execution of the test case + ERROR = 0; + // SUCCEEDED: when the test case was executed successfully + SUCCEEDED = 1; + // FAILED: when the test case was executed but the assertion failed + FAILED = 2; + // NOTIMPLEMENTED: when the test case code is not implemented yet + NOT_IMPLEMENTED = 3; + } + // The specific name of the test case string name = 1; diff --git a/protos/kubekarma/controlleroperator/grpcsrv/pb2/health.proto b/protobuf/kubekarma/grpcgen/health/v1/health.proto similarity index 69% rename from protos/kubekarma/controlleroperator/grpcsrv/pb2/health.proto rename to protobuf/kubekarma/grpcgen/health/v1/health.proto index d9445b7..0e224f8 100644 --- a/protos/kubekarma/controlleroperator/grpcsrv/pb2/health.proto +++ b/protobuf/kubekarma/grpcgen/health/v1/health.proto @@ -1,12 +1,9 @@ -// https://github.com/grpc/grpc/blob/master/doc/health-checking.md - -/* - This service is for kubernetes probes. -**/ +// Source https://github.com/grpc/grpc/blob/master/doc/health-checking.md syntax = "proto3"; package grpc.health.v1; +// buf:lint:ignore message HealthCheckRequest { string service = 1; } @@ -16,7 +13,7 @@ message HealthCheckResponse { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; - SERVICE_UNKNOWN = 3; // Used only by the Watch method. + SERVICE_UNKNOWN = 3; } ServingStatus status = 1; } diff --git a/protos/readme.md b/protobuf/readme.md similarity index 88% rename from protos/readme.md rename to protobuf/readme.md index 30a4a18..0b21552 100644 --- a/protos/readme.md +++ b/protobuf/readme.md @@ -10,4 +10,8 @@ Usage example: python3 -m grpc_tools.protoc -I protos --python_out=. --pyi_out=. --grpc_python_out=. ./protos/kubekarma/shared/pb2/*.proto ``` -This will generate the files under the path `kubekarma/controlleroperator/grpc/pb2/*` \ No newline at end of file +This will generate the files under the path `kubekarma/controlleroperator/grpc/pb2/*` + +```shell +buf generate protobuf/ +``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e68e6d3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,79 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "kubekarma" +description = "A Kubernetes operator to ensure environment quality for applications." +readme.content-type = "text/markdown" +readme.file = "readme.md" +maintainers = [ + { name = "Cristian Steib", email = "cristiansteib@gmail.com" }, +] +authors = [ + { name = "Cristian Steib", email = "cristiansteib@gmail.com" }, +] +requires-python = ">=3.11" +dynamic = [ + "version" +] +classifiers = [ + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +dependencies = [] + +optional-dependencies.controller = [ + "kopf[full-auth]", + "kubernetes", + "fastapi", + "uvicorn", + "grpcio", + "protobuf", + "croniter" +] + +optional-dependencies.worker = [ + "dnspython==2.4.2", + "urllib3", # This package could conflict with the kubernetes version + "PyYAML==6.0.1", + "protobuf", + "grpcio" +] + + +optional-dependencies.dev = [ + "grpcio-tools", + "import-linter" +] + + +optional-dependencies.testing = [ + "coverage>=4.0.3", + "flake8", + "tox", + "mypy" +] + + + +[project.scripts] +collector-server = "reportreceiver.grpc.server:main" + +[tool.hatch.version] +#path = "src/__init__.py" +source = "vcs" + +[build.hooks.vcs] +version-file = "_version.py" + +[tool.hatch.build.targets.wheel] +packages = [ + "app/", + "app/cluster", + "app/reportreceiver", + "app/operations", + "app/ui", +] \ No newline at end of file diff --git a/requirements.controller.txt b/requirements.controller.txt deleted file mode 100644 index b227062..0000000 --- a/requirements.controller.txt +++ /dev/null @@ -1,7 +0,0 @@ -kopf[full-auth]==1.36.2 -kubernetes==28.1.0 -fastapi -uvicorn -grpcio -protobuf -croniter \ No newline at end of file diff --git a/requirements.dev.txt b/requirements.dev.txt deleted file mode 100644 index 6cf7f34..0000000 --- a/requirements.dev.txt +++ /dev/null @@ -1,2 +0,0 @@ -grpcio-tools -import-linter \ No newline at end of file diff --git a/requirements.test.txt b/requirements.test.txt deleted file mode 100644 index c8f62ab..0000000 --- a/requirements.test.txt +++ /dev/null @@ -1,4 +0,0 @@ -coverage>=4.0.3 -flake8 -tox -mypy \ No newline at end of file diff --git a/requirements.worker.txt b/requirements.worker.txt deleted file mode 100644 index d2673f5..0000000 --- a/requirements.worker.txt +++ /dev/null @@ -1,6 +0,0 @@ -dnspython==2.4.2 -# This version conflicts with the kubernetes version -urllib3 -PyYAML==6.0.1 -protobuf -grpcio \ No newline at end of file diff --git a/worker.Dockerfile b/worker.Dockerfile index fcf117a..74c366c 100644 --- a/worker.Dockerfile +++ b/worker.Dockerfile @@ -8,11 +8,14 @@ ENV LANG=C.UTF-8 ENV PYTHONDONTWRITEBYTECODE=1 # Seems to speed things up ENV PYTHONUNBUFFERED=1 +RUN python -m pip install hatch +COPY readme.md . +COPY pyproject.toml . -COPY requirements.worker.txt ./ +RUN hatch dep show requirements --all > requirements.txt RUN --mount=type=cache,target=/root/.cache/pip \ pip wheel --no-deps --wheel-dir /usr/src/app/wheels \ - -r requirements.worker.txt + -r requirements.txt FROM python:3.11-slim AS app LABEL org.opencontainers.image.authors="Cristian Steib"