1
16
17 package benchmark
18
19 import (
20 "context"
21 "fmt"
22 "time"
23
24 apierrors "k8s.io/apimachinery/pkg/api/errors"
25 "k8s.io/apimachinery/pkg/api/meta"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28 "k8s.io/apimachinery/pkg/runtime/schema"
29 "k8s.io/client-go/discovery/cached/memory"
30 "k8s.io/client-go/restmapper"
31 "k8s.io/klog/v2"
32 "k8s.io/kubernetes/test/utils/ktesting"
33 )
34
35
36
37 type createAny struct {
38
39 Opcode operationCode
40
41 Namespace string
42
43 TemplatePath string
44 }
45
46 var _ runnableOp = &createAny{}
47
48 func (c *createAny) isValid(allowParameterization bool) error {
49 if c.Opcode != createAnyOpcode {
50 return fmt.Errorf("invalid opcode %q; expected %q", c.Opcode, createAnyOpcode)
51 }
52 if c.TemplatePath == "" {
53 return fmt.Errorf("TemplatePath must be set")
54 }
55
56
57 return nil
58 }
59
60 func (c *createAny) collectsMetrics() bool {
61 return false
62 }
63
64 func (c *createAny) patchParams(w *workload) (realOp, error) {
65 return c, c.isValid(false)
66 }
67
68 func (c *createAny) requiredNamespaces() []string {
69 if c.Namespace == "" {
70 return nil
71 }
72 return []string{c.Namespace}
73 }
74
75 func (c *createAny) run(tCtx ktesting.TContext) {
76 var obj *unstructured.Unstructured
77 if err := getSpecFromFile(&c.TemplatePath, &obj); err != nil {
78 tCtx.Fatalf("%s: parsing failed: %v", c.TemplatePath, err)
79 }
80
81
82
83 discoveryCache := memory.NewMemCacheClient(tCtx.Client().Discovery())
84 restMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryCache)
85 gv, err := schema.ParseGroupVersion(obj.GetAPIVersion())
86 if err != nil {
87 tCtx.Fatalf("%s: extract group+version from object %q: %v", c.TemplatePath, klog.KObj(obj), err)
88 }
89 gk := schema.GroupKind{Group: gv.Group, Kind: obj.GetKind()}
90
91 create := func() error {
92 mapping, err := restMapper.RESTMapping(gk, gv.Version)
93 if err != nil {
94
95 restMapper.Reset()
96 return fmt.Errorf("map %q to resource: %v", gk, err)
97 }
98 resourceClient := tCtx.Dynamic().Resource(mapping.Resource)
99 options := metav1.CreateOptions{
100
101
102
103
104 FieldValidation: "Strict",
105 }
106 if c.Namespace != "" {
107 if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
108 return fmt.Errorf("namespace %q set for %q, but %q has scope %q", c.Namespace, c.TemplatePath, gk, mapping.Scope.Name())
109 }
110 _, err = resourceClient.Namespace(c.Namespace).Create(tCtx, obj, options)
111 } else {
112 if mapping.Scope.Name() != meta.RESTScopeNameRoot {
113 return fmt.Errorf("namespace not set for %q, but %q has scope %q", c.TemplatePath, gk, mapping.Scope.Name())
114 }
115 _, err = resourceClient.Create(tCtx, obj, options)
116 }
117 if err == nil && shouldCleanup(tCtx) {
118 tCtx.CleanupCtx(func(tCtx ktesting.TContext) {
119 del := resourceClient.Delete
120 if mapping.Scope.Name() != meta.RESTScopeNameNamespace {
121 del = resourceClient.Namespace(c.Namespace).Delete
122 }
123 err := del(tCtx, obj.GetName(), metav1.DeleteOptions{})
124 if !apierrors.IsNotFound(err) {
125 tCtx.ExpectNoError(err, fmt.Sprintf("deleting %s.%s %s", obj.GetKind(), obj.GetAPIVersion(), klog.KObj(obj)))
126 }
127 })
128 }
129 return err
130 }
131
132 ctx, cancel := context.WithTimeout(tCtx, 20*time.Second)
133 defer cancel()
134 for {
135 err := create()
136 if err == nil {
137 return
138 }
139 select {
140 case <-ctx.Done():
141 tCtx.Fatalf("%s: timed out (%q) while creating %q, last error was: %v", c.TemplatePath, context.Cause(ctx), klog.KObj(obj), err)
142 case <-time.After(time.Second):
143 }
144 }
145 }
146
View as plain text