1
16
17 package monitoring
18
19 import (
20 "fmt"
21 "os/exec"
22 "strings"
23
24 appsv1 "k8s.io/api/apps/v1"
25 v1 "k8s.io/api/core/v1"
26 rbacv1 "k8s.io/api/rbac/v1"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/kubernetes/test/e2e/framework"
29 e2edeployment "k8s.io/kubernetes/test/e2e/framework/deployment"
30 e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"
31 imageutils "k8s.io/kubernetes/test/utils/image"
32
33 gcm "google.golang.org/api/monitoring/v3"
34 )
35
36 var (
37
38 CustomMetricName = "foo"
39
40 UnusedMetricName = "unused"
41
42 CustomMetricValue = int64(448)
43
44 UnusedMetricValue = int64(446)
45
46 StackdriverExporter = "stackdriver-exporter"
47
48
49 HPAPermissions = &rbacv1.ClusterRoleBinding{
50 ObjectMeta: metav1.ObjectMeta{
51 Name: "custom-metrics-reader",
52 },
53 RoleRef: rbacv1.RoleRef{
54 APIGroup: "rbac.authorization.k8s.io",
55 Kind: "ClusterRole",
56 Name: "system:controller:horizontal-pod-autoscaler",
57 },
58 Subjects: []rbacv1.Subject{
59 {
60 APIGroup: "rbac.authorization.k8s.io",
61 Kind: "Group",
62 Name: "system:unauthenticated",
63 },
64 },
65 }
66
67 StagingDeploymentsLocation = "https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/staging/"
68
69 AdapterForOldResourceModel = "adapter_old_resource_model.yaml"
70
71 AdapterForNewResourceModel = "adapter_new_resource_model.yaml"
72
73 AdapterDefault = AdapterForOldResourceModel
74
75 ClusterAdminBinding = "e2e-test-cluster-admin-binding"
76 )
77
78
79
80 type CustomMetricContainerSpec struct {
81 Name string
82 MetricName string
83 MetricValue int64
84 }
85
86
87
88 func SimpleStackdriverExporterDeployment(name, namespace string, replicas int32, metricValue int64) *appsv1.Deployment {
89 return StackdriverExporterDeployment(name, namespace, replicas,
90 []CustomMetricContainerSpec{
91 {
92 Name: StackdriverExporter,
93 MetricName: CustomMetricName,
94 MetricValue: metricValue,
95 },
96 })
97 }
98
99
100
101
102
103 func StackdriverExporterDeployment(name, namespace string, replicas int32, containers []CustomMetricContainerSpec) *appsv1.Deployment {
104 podSpec := v1.PodSpec{Containers: []v1.Container{}}
105 for _, containerSpec := range containers {
106 podSpec.Containers = append(podSpec.Containers, stackdriverExporterContainerSpec(containerSpec.Name, namespace, containerSpec.MetricName, containerSpec.MetricValue))
107 }
108
109 d := e2edeployment.NewDeployment(name, replicas, map[string]string{"name": name}, "", "", appsv1.RollingUpdateDeploymentStrategyType)
110 d.ObjectMeta.Namespace = namespace
111 d.Spec.Template.Spec = podSpec
112 return d
113 }
114
115
116
117 func StackdriverExporterPod(podName, namespace, podLabel, metricName string, metricValue int64) *v1.Pod {
118 return &v1.Pod{
119 ObjectMeta: metav1.ObjectMeta{
120 Name: podName,
121 Namespace: namespace,
122 Labels: map[string]string{
123 "name": podLabel,
124 },
125 },
126 Spec: v1.PodSpec{
127 Containers: []v1.Container{stackdriverExporterContainerSpec(StackdriverExporter, namespace, metricName, metricValue)},
128 },
129 }
130 }
131
132 func stackdriverExporterContainerSpec(name string, namespace string, metricName string, metricValue int64) v1.Container {
133 return v1.Container{
134 Name: name,
135 Image: imageutils.GetE2EImage(imageutils.SdDummyExporter),
136 ImagePullPolicy: v1.PullPolicy("Always"),
137 Command: []string{
138 "/bin/sh",
139 "-c",
140 strings.Join([]string{
141 "./sd_dummy_exporter",
142 "--pod-id=$(POD_ID)",
143 "--pod-name=$(POD_NAME)",
144 "--namespace=" + namespace,
145 "--metric-name=" + metricName,
146 fmt.Sprintf("--metric-value=%v", metricValue),
147 "--use-old-resource-model",
148 "--use-new-resource-model",
149 }, " "),
150 },
151 Env: []v1.EnvVar{
152 {
153 Name: "POD_ID",
154 ValueFrom: &v1.EnvVarSource{
155 FieldRef: &v1.ObjectFieldSelector{
156 FieldPath: "metadata.uid",
157 },
158 },
159 },
160 {
161 Name: "POD_NAME",
162 ValueFrom: &v1.EnvVarSource{
163 FieldRef: &v1.ObjectFieldSelector{
164 FieldPath: "metadata.name",
165 },
166 },
167 },
168 },
169 Ports: []v1.ContainerPort{{ContainerPort: 80}},
170 }
171 }
172
173
174
175
176 func PrometheusExporterDeployment(name, namespace string, replicas int32, metricValue int64) *appsv1.Deployment {
177 d := e2edeployment.NewDeployment(name, replicas, map[string]string{"name": name}, "", "", appsv1.RollingUpdateDeploymentStrategyType)
178 d.ObjectMeta.Namespace = namespace
179 d.Spec.Template.Spec = prometheusExporterPodSpec(CustomMetricName, metricValue, 8080)
180 return d
181 }
182
183 func prometheusExporterPodSpec(metricName string, metricValue int64, port int32) v1.PodSpec {
184 return v1.PodSpec{
185 Containers: []v1.Container{
186 {
187 Name: "prometheus-exporter",
188 Image: imageutils.GetE2EImage(imageutils.PrometheusDummyExporter),
189 ImagePullPolicy: v1.PullPolicy("Always"),
190 Command: []string{"/prometheus_dummy_exporter", "--metric-name=" + metricName,
191 fmt.Sprintf("--metric-value=%v", metricValue), fmt.Sprintf("=--port=%d", port)},
192 Ports: []v1.ContainerPort{{ContainerPort: port}},
193 },
194 {
195 Name: "prometheus-to-sd",
196 Image: imageutils.GetE2EImage(imageutils.PrometheusToSd),
197 ImagePullPolicy: v1.PullPolicy("Always"),
198 Command: []string{"/monitor", fmt.Sprintf("--source=:http://localhost:%d", port),
199 "--stackdriver-prefix=custom.googleapis.com", "--pod-id=$(POD_ID)", "--namespace-id=$(POD_NAMESPACE)"},
200 Env: []v1.EnvVar{
201 {
202 Name: "POD_ID",
203 ValueFrom: &v1.EnvVarSource{
204 FieldRef: &v1.ObjectFieldSelector{
205 FieldPath: "metadata.uid",
206 },
207 },
208 },
209 {
210 Name: "POD_NAMESPACE",
211 ValueFrom: &v1.EnvVarSource{
212 FieldRef: &v1.ObjectFieldSelector{
213 FieldPath: "metadata.namespace",
214 },
215 },
216 },
217 },
218 },
219 },
220 }
221 }
222
223
224
225 func CreateAdapter(adapterDeploymentFile string) error {
226
227
228
229 err := createClusterAdminBinding()
230 if err != nil {
231 return err
232 }
233 adapterURL := StagingDeploymentsLocation + adapterDeploymentFile
234 err = exec.Command("wget", adapterURL).Run()
235 if err != nil {
236 return err
237 }
238 stat, err := e2ekubectl.RunKubectl("", "apply", "-f", adapterURL)
239 framework.Logf(stat)
240 return err
241 }
242
243 func createClusterAdminBinding() error {
244 stdout, stderr, err := framework.RunCmd("gcloud", "config", "get-value", "core/account")
245 if err != nil {
246 framework.Logf(stderr)
247 return err
248 }
249 serviceAccount := strings.TrimSpace(stdout)
250 framework.Logf("current service account: %q", serviceAccount)
251 stat, err := e2ekubectl.RunKubectl("", "create", "clusterrolebinding", ClusterAdminBinding, "--clusterrole=cluster-admin", "--user="+serviceAccount)
252 framework.Logf(stat)
253 return err
254 }
255
256
257 func CreateDescriptors(service *gcm.Service, projectID string) error {
258 _, err := service.Projects.MetricDescriptors.Create(fmt.Sprintf("projects/%s", projectID), &gcm.MetricDescriptor{
259 Name: CustomMetricName,
260 ValueType: "INT64",
261 Type: "custom.googleapis.com/" + CustomMetricName,
262 MetricKind: "GAUGE",
263 }).Do()
264 if err != nil {
265 return err
266 }
267 _, err = service.Projects.MetricDescriptors.Create(fmt.Sprintf("projects/%s", projectID), &gcm.MetricDescriptor{
268 Name: UnusedMetricName,
269 ValueType: "INT64",
270 Type: "custom.googleapis.com/" + UnusedMetricName,
271 MetricKind: "GAUGE",
272 }).Do()
273 return err
274 }
275
276
277
278 func CleanupDescriptors(service *gcm.Service, projectID string) {
279 _, err := service.Projects.MetricDescriptors.Delete(fmt.Sprintf("projects/%s/metricDescriptors/custom.googleapis.com/%s", projectID, CustomMetricName)).Do()
280 if err != nil {
281 framework.Logf("Failed to delete descriptor for metric '%s': %v", CustomMetricName, err)
282 }
283 _, err = service.Projects.MetricDescriptors.Delete(fmt.Sprintf("projects/%s/metricDescriptors/custom.googleapis.com/%s", projectID, UnusedMetricName)).Do()
284 if err != nil {
285 framework.Logf("Failed to delete descriptor for metric '%s': %v", CustomMetricName, err)
286 }
287 }
288
289
290 func CleanupAdapter(adapterDeploymentFile string) {
291 stat, err := e2ekubectl.RunKubectl("", "delete", "-f", adapterDeploymentFile)
292 framework.Logf(stat)
293 if err != nil {
294 framework.Logf("Failed to delete adapter deployments: %s", err)
295 }
296 err = exec.Command("rm", adapterDeploymentFile).Run()
297 if err != nil {
298 framework.Logf("Failed to delete adapter deployment file: %s", err)
299 }
300 cleanupClusterAdminBinding()
301 }
302
303 func cleanupClusterAdminBinding() {
304 stat, err := e2ekubectl.RunKubectl("", "delete", "clusterrolebinding", ClusterAdminBinding)
305 framework.Logf(stat)
306 if err != nil {
307 framework.Logf("Failed to delete cluster admin binding: %s", err)
308 }
309 }
310
View as plain text