kubectl apply -f ~/cncf/apisnoop/deployment/k8s/raiinbow.yaml
We can query a few tables, this is a simple core api query for get APIs that do not hit volumes.
SELECT
operation_id,
k8s_action,
path,
description
FROM untested_stable_core_endpoints
where path not like '%volume%'
and operation_id like '%PodTemplate%'
ORDER BY operation_id desc
LIMIT 25
;
operation_id | k8s_action | path | description
---------------------------------------------+------------------+----------------------------------------------------+--------------------------------------------
replaceCoreV1NamespacedPodTemplate | put | /api/v1/namespaces/{namespace}/podtemplates/{name} | replace the specified PodTemplate
readCoreV1NamespacedPodTemplate | get | /api/v1/namespaces/{namespace}/podtemplates/{name} | read the specified PodTemplate
patchCoreV1NamespacedPodTemplate | patch | /api/v1/namespaces/{namespace}/podtemplates/{name} | partially update the specified PodTemplate
listCoreV1PodTemplateForAllNamespaces | list | /api/v1/podtemplates | list or watch objects of kind PodTemplate
deleteCoreV1CollectionNamespacedPodTemplate | deletecollection | /api/v1/namespaces/{namespace}/podtemplates | delete collection of PodTemplate
(5 rows)
You can iterate over a query until you have a set of endpoints you’d like to write a test for, usually by adjusting the columns you view or by extending the where clause to filter more specifically.
Finding documentation for this API
This is where the test code goes. It is useful to seperate it into blocks which can be evaluted independently.
You can write tests in a variety of languages, outlined in “Client Libraries” on k8s reference page.
Whichever language you choose, you want to make sure to set the useragent to something starting with live-test
. This ensures apisnoop’s queries around testing work correctly.
We’ve included sample tests in Go and Javascript.
go get -v -u k8s.io/apimachinery/pkg/apis/meta/v1
go get -v -u k8s.io/client-go/kubernetes
go get -v -u k8s.io/client-go/tools/clientcmd
package main
import (
"fmt"
"flag"
"os"
//"encoding/json"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/apimachinery/pkg/types"
)
func main() {
// uses the current context in kubeconfig
kubeconfig := flag.String("kubeconfig", fmt.Sprintf("%v/%v/%v", os.Getenv("HOME"), ".kube", "config"), "(optional) absolute path to the kubeconfig file")
flag.Parse()
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
fmt.Println(err)
return
}
// make our work easier to find in the audit_event queries
config.UserAgent = "live-test-writing"
// creates the clientset
clientset, _ := kubernetes.NewForConfig(config)
podTemplateName := "nginx-pod-template"
// get a list of PodTemplates
podTemplateList, err := clientset.CoreV1().PodTemplates("").List(metav1.ListOptions{})
if err != nil {
fmt.Println("[error]", err)
return
}
if len(podTemplateList.Items) > 0 {
fmt.Println("[error] templates should not be populated")
return
}
fmt.Println("[status] no PodTemplates found")
// create a PodTemplate
_, err = clientset.CoreV1().PodTemplates("default").Create(&v1.PodTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: podTemplateName,
},
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{
{Name: "nginx", Image: "nginx"},
},
},
},
})
if err != nil {
fmt.Println("[error]", err)
return
}
fmt.Println("[status] PodTemplate created")
// get template
podTemplateRead, err := clientset.CoreV1().PodTemplates("default").Get(podTemplateName, metav1.GetOptions{})
if err != nil {
fmt.Println("[error]", err)
return
}
if podTemplateRead.ObjectMeta.Name != podTemplateName {
fmt.Println("[error] PodTemplate name doesn't match")
return
}
fmt.Println("[status] found created PodTemplate")
// patch template
PodTemplatePatch := fmt.Sprintf(`{"metadata":{"labels":{"a":"1"}}}`)
_, err = clientset.CoreV1().PodTemplates("default").Patch(podTemplateName, types.StrategicMergePatchType, []byte(PodTemplatePatch))
if err != nil {
fmt.Println("[error]", err)
return
}
fmt.Println("[status] patched PodTemplate with label a=1")
// get template (ensure label is there)
podTemplateRead, err = clientset.CoreV1().PodTemplates("default").Get(podTemplateName, metav1.GetOptions{})
if err != nil {
fmt.Println("[error]", err)
return
}
if podTemplateRead.ObjectMeta.Labels["a"] != "1" {
fmt.Println("[error] template doesn't contain the label a=1")
return
}
fmt.Println("[status] found label on PodTemplate")
// list PodTemplates on all namespaces by label a=1
podTemplateListWithLabel, err := clientset.CoreV1().PodTemplates("").List(metav1.ListOptions{
LabelSelector: "a=1",
})
if err != nil {
fmt.Println("[error]", err)
return
}
foundPodTemplateWithLabel := false
for _, podTemplate := range podTemplateListWithLabel.Items {
if podTemplate.ObjectMeta.Name == podTemplateName && podTemplate.ObjectMeta.Labels["a"] == "1" {
foundPodTemplateWithLabel = true
}
}
if foundPodTemplateWithLabel == false || len(podTemplateListWithLabel.Items) == 0 {
fmt.Println("[error] PodTemplate doesn't contain the label")
return
}
fmt.Println("[status] found PodTemplate by label")
err = clientset.CoreV1().PodTemplates("default").Delete(podTemplateName, &metav1.DeleteOptions{})
if err != nil {
fmt.Println("[error]", err)
return
}
fmt.Println("[status] deleted PodTemplate")
podTemplateListWithLabel, err = clientset.CoreV1().PodTemplates("").List(metav1.ListOptions{
LabelSelector: "a=1",
})
if err != nil {
fmt.Println("[error]", err)
return
}
if len(podTemplateListWithLabel.Items) > 0 {
fmt.Println("[error] list returned a PodTemplate matching the requested labels")
return
}
fmt.Println("[status] no PodTemplates found")
fmt.Println("[status] complete")
}
select distinct useragent from audit_event where bucket='apisnoop' and useragent not like 'kube%' and useragent not like 'coredns%' and useragent not like 'kindnetd%';
-- select * from endpoints_hit_by_new_test where useragent like 'Swagger%' or useragent like 'live-%';
--select * from endpoints_hit_by_new_test where useragent like 'Swagger%';
-- select * from endpoints_hit_by_new_test where useragent like 'live%';
useragent
-------------------
live-test-writing
(1 row)
NOTE: for the projected change in coverage, your test functions must be configured with a useragent that starts with live-test
, otherwise endpoints hit by that test won’t be counted as part of new coverage.
select * from endpoints_hit_by_new_test where useragent like 'live%';
select * from projected_change_in_coverage;
category | total_endpoints | old_coverage | new_coverage | change_in_number
---------------+-----------------+--------------+--------------+------------------
test_coverage | 438 | 183 | 186 | 3
(1 row)
select kind, sub_kind, field_path, test_hits, distance from full_podspec_field_coverage where job != 'live';
[[file:results.txt]]