github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubernetes/debugging/transform_jvm_test.go (about) 1 /* 2 Copyright 2021 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package debugging 18 19 import ( 20 "testing" 21 22 appsv1 "k8s.io/api/apps/v1" 23 batchv1 "k8s.io/api/batch/v1" 24 v1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime" 27 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug/types" 30 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/debugging/adapter" 31 "github.com/GoogleContainerTools/skaffold/testutil" 32 ) 33 34 func TestJdwpTransformerApply(t *testing.T) { 35 tests := []struct { 36 description string 37 containerSpec v1.Container 38 configuration debug.ImageConfiguration 39 result v1.Container 40 debugConfig types.ContainerDebugConfiguration 41 image string 42 }{ 43 { 44 description: "empty", 45 containerSpec: v1.Container{}, 46 configuration: debug.ImageConfiguration{}, 47 result: v1.Container{ 48 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 49 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 50 }, 51 debugConfig: types.ContainerDebugConfiguration{Runtime: "jvm", Ports: map[string]uint32{"jdwp": 5005}}, 52 }, 53 { 54 description: "existing port", 55 containerSpec: v1.Container{ 56 Ports: []v1.ContainerPort{{Name: "http-server", ContainerPort: 8080}}, 57 }, 58 configuration: debug.ImageConfiguration{}, 59 result: v1.Container{ 60 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 61 Ports: []v1.ContainerPort{{Name: "http-server", ContainerPort: 8080}, {Name: "jdwp", ContainerPort: 5005}}, 62 }, 63 debugConfig: types.ContainerDebugConfiguration{Runtime: "jvm", Ports: map[string]uint32{"jdwp": 5005}}, 64 }, 65 { 66 description: "existing jdwp spec", 67 containerSpec: v1.Container{ 68 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n,quiet=y"}}, 69 Ports: []v1.ContainerPort{{ContainerPort: 5005}}, 70 }, 71 configuration: debug.ImageConfiguration{Env: map[string]string{"JAVA_TOOL_OPTIONS": "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n,quiet=y"}}, 72 result: v1.Container{ 73 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=n,quiet=y"}}, 74 Ports: []v1.ContainerPort{{ContainerPort: 5005}, {Name: "jdwp", ContainerPort: 8000}}, 75 }, 76 debugConfig: types.ContainerDebugConfiguration{Runtime: "jvm", Ports: map[string]uint32{"jdwp": 8000}}, 77 }, 78 { 79 description: "existing jdwp port and JAVA_TOOL_OPTIONS", 80 containerSpec: v1.Container{ 81 Env: []v1.EnvVar{{Name: "FOO", Value: "BAR"}}, 82 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 8000}}, 83 }, 84 configuration: debug.ImageConfiguration{Env: map[string]string{"JAVA_TOOL_OPTIONS": "-Xms1g"}}, 85 result: v1.Container{ 86 Env: []v1.EnvVar{{Name: "FOO", Value: "BAR"}, {Name: "JAVA_TOOL_OPTIONS", Value: "-Xms1g -agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 87 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 88 }, 89 debugConfig: types.ContainerDebugConfiguration{Runtime: "jvm", Ports: map[string]uint32{"jdwp": 5005}}, 90 }, 91 } 92 var identity debug.PortAllocator = func(port int32) int32 { 93 return port 94 } 95 for _, test := range tests { 96 testutil.Run(t, test.description, func(t *testutil.T) { 97 adapter := adapter.NewAdapter(&test.containerSpec) 98 config, image, err := debug.NewJDWPTransformer().Apply(adapter, test.configuration, identity, nil) 99 adapter.Apply() 100 101 // Apply never fails since there's always the option to set JAVA_TOOL_OPTIONS 102 t.CheckNil(err) 103 t.CheckDeepEqual(test.result, test.containerSpec) 104 t.CheckDeepEqual(test.debugConfig, config) 105 t.CheckDeepEqual(test.image, image) 106 }) 107 } 108 } 109 110 func TestTransformManifestJVM(t *testing.T) { 111 int32p := func(x int32) *int32 { return &x } 112 tests := []struct { 113 description string 114 in runtime.Object 115 transformed bool 116 out runtime.Object 117 }{ 118 { 119 "Pod with no transformable container", 120 &v1.Pod{ 121 Spec: v1.PodSpec{Containers: []v1.Container{ 122 { 123 Name: "test", 124 Command: []string{"echo", "Hello World"}, 125 }, 126 }}}, 127 false, 128 &v1.Pod{ 129 Spec: v1.PodSpec{Containers: []v1.Container{ 130 { 131 Name: "test", 132 Command: []string{"echo", "Hello World"}, 133 }, 134 }}}, 135 }, 136 { 137 "Pod with Java container", 138 &v1.Pod{ 139 Spec: v1.PodSpec{Containers: []v1.Container{ 140 { 141 Name: "test", 142 Command: []string{"java", "-jar", "foo.jar"}, 143 }, 144 }}}, 145 true, 146 &v1.Pod{ 147 ObjectMeta: metav1.ObjectMeta{ 148 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 149 }, 150 Spec: v1.PodSpec{Containers: []v1.Container{ 151 { 152 Name: "test", 153 Command: []string{"java", "-jar", "foo.jar"}, 154 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 155 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 156 }, 157 }}}, 158 }, 159 { 160 "Deployment with Java container", 161 &appsv1.Deployment{ 162 Spec: appsv1.DeploymentSpec{ 163 Replicas: int32p(2), 164 Template: v1.PodTemplateSpec{ 165 Spec: v1.PodSpec{Containers: []v1.Container{ 166 { 167 Name: "test", 168 Command: []string{"java", "-jar", "foo.jar"}, 169 }, 170 }}}}}, 171 true, 172 &appsv1.Deployment{ 173 // ObjectMeta: metav1.ObjectMeta{ 174 // Labels: map[string]string{"debug.cloud.google.com/enabled": `yes`}, 175 // }, 176 Spec: appsv1.DeploymentSpec{ 177 Replicas: int32p(1), 178 Template: v1.PodTemplateSpec{ 179 ObjectMeta: metav1.ObjectMeta{ 180 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 181 }, 182 Spec: v1.PodSpec{Containers: []v1.Container{ 183 { 184 Name: "test", 185 Command: []string{"java", "-jar", "foo.jar"}, 186 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 187 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 188 }, 189 }}}}}, 190 }, 191 { 192 "ReplicaSet with Java container", 193 &appsv1.ReplicaSet{ 194 Spec: appsv1.ReplicaSetSpec{ 195 Replicas: int32p(2), 196 Template: v1.PodTemplateSpec{ 197 Spec: v1.PodSpec{Containers: []v1.Container{ 198 { 199 Name: "test", 200 Command: []string{"java", "-jar", "foo.jar"}, 201 }, 202 }}}}}, 203 true, 204 &appsv1.ReplicaSet{ 205 // ObjectMeta: metav1.ObjectMeta{ 206 // Labels: map[string]string{"debug.cloud.google.com/enabled": `yes`}, 207 // }, 208 Spec: appsv1.ReplicaSetSpec{ 209 Replicas: int32p(1), 210 Template: v1.PodTemplateSpec{ 211 ObjectMeta: metav1.ObjectMeta{ 212 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 213 }, 214 Spec: v1.PodSpec{Containers: []v1.Container{ 215 { 216 Name: "test", 217 Command: []string{"java", "-jar", "foo.jar"}, 218 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 219 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 220 }, 221 }}}}}, 222 }, 223 { 224 "StatefulSet with Java container", 225 &appsv1.StatefulSet{ 226 Spec: appsv1.StatefulSetSpec{ 227 Replicas: int32p(2), 228 Template: v1.PodTemplateSpec{ 229 Spec: v1.PodSpec{Containers: []v1.Container{ 230 { 231 Name: "test", 232 Command: []string{"java", "-jar", "foo.jar"}, 233 }, 234 }}}}}, 235 true, 236 &appsv1.StatefulSet{ 237 // ObjectMeta: metav1.ObjectMeta{ 238 // Labels: map[string]string{"debug.cloud.google.com/enabled": `yes`}, 239 // }, 240 Spec: appsv1.StatefulSetSpec{ 241 Replicas: int32p(1), 242 Template: v1.PodTemplateSpec{ 243 ObjectMeta: metav1.ObjectMeta{ 244 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 245 }, 246 Spec: v1.PodSpec{Containers: []v1.Container{ 247 { 248 Name: "test", 249 Command: []string{"java", "-jar", "foo.jar"}, 250 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 251 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 252 }, 253 }}}}}, 254 }, 255 { 256 "DaemonSet with Java container", 257 &appsv1.DaemonSet{ 258 Spec: appsv1.DaemonSetSpec{ 259 Template: v1.PodTemplateSpec{ 260 Spec: v1.PodSpec{Containers: []v1.Container{ 261 { 262 Name: "test", 263 Command: []string{"java", "-jar", "foo.jar"}, 264 }, 265 }}}}}, 266 true, 267 &appsv1.DaemonSet{ 268 // ObjectMeta: metav1.ObjectMeta{ 269 // Labels: map[string]string{"debug.cloud.google.com/enabled": `yes`}, 270 // }, 271 Spec: appsv1.DaemonSetSpec{ 272 Template: v1.PodTemplateSpec{ 273 ObjectMeta: metav1.ObjectMeta{ 274 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 275 }, 276 Spec: v1.PodSpec{Containers: []v1.Container{ 277 { 278 Name: "test", 279 Command: []string{"java", "-jar", "foo.jar"}, 280 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 281 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 282 }, 283 }}}}}, 284 }, 285 { 286 "Job with Java container", 287 &batchv1.Job{ 288 Spec: batchv1.JobSpec{ 289 Template: v1.PodTemplateSpec{ 290 Spec: v1.PodSpec{Containers: []v1.Container{ 291 { 292 Name: "test", 293 Command: []string{"java", "-jar", "foo.jar"}, 294 }, 295 }}}}}, 296 true, 297 &batchv1.Job{ 298 // ObjectMeta: metav1.ObjectMeta{ 299 // Labels: map[string]string{"debug.cloud.google.com/enabled": `yes`}, 300 // }, 301 Spec: batchv1.JobSpec{ 302 Template: v1.PodTemplateSpec{ 303 ObjectMeta: metav1.ObjectMeta{ 304 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 305 }, 306 Spec: v1.PodSpec{Containers: []v1.Container{ 307 { 308 Name: "test", 309 Command: []string{"java", "-jar", "foo.jar"}, 310 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 311 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 312 }, 313 }}}}}, 314 }, 315 { 316 "ReplicationController with Java container", 317 &v1.ReplicationController{ 318 Spec: v1.ReplicationControllerSpec{ 319 Replicas: int32p(2), 320 Template: &v1.PodTemplateSpec{ 321 Spec: v1.PodSpec{Containers: []v1.Container{ 322 { 323 Name: "test", 324 Command: []string{"java", "-jar", "foo.jar"}, 325 }, 326 }}}}}, 327 true, 328 &v1.ReplicationController{ 329 // ObjectMeta: metav1.ObjectMeta{ 330 // Labels: map[string]string{"debug.cloud.google.com/enabled": `yes`}, 331 // }, 332 Spec: v1.ReplicationControllerSpec{ 333 Replicas: int32p(1), 334 Template: &v1.PodTemplateSpec{ 335 ObjectMeta: metav1.ObjectMeta{ 336 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 337 }, 338 Spec: v1.PodSpec{Containers: []v1.Container{ 339 { 340 Name: "test", 341 Command: []string{"java", "-jar", "foo.jar"}, 342 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 343 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 344 }, 345 }}}}}, 346 }, 347 { 348 "PodList with Java and non-Java container", 349 &v1.PodList{ 350 Items: []v1.Pod{ 351 { 352 Spec: v1.PodSpec{Containers: []v1.Container{ 353 { 354 Name: "echo", 355 Command: []string{"echo", "Hello World"}, 356 }, 357 }}}, 358 { 359 Spec: v1.PodSpec{Containers: []v1.Container{ 360 { 361 Name: "test", 362 Command: []string{"java", "-jar", "foo.jar"}, 363 }, 364 }}}, 365 }}, 366 true, 367 &v1.PodList{ 368 Items: []v1.Pod{ 369 { 370 Spec: v1.PodSpec{Containers: []v1.Container{ 371 { 372 Name: "echo", 373 Command: []string{"echo", "Hello World"}, 374 }, 375 }}}, 376 { 377 ObjectMeta: metav1.ObjectMeta{ 378 Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","ports":{"jdwp":5005}}}`}, 379 }, 380 Spec: v1.PodSpec{Containers: []v1.Container{ 381 { 382 Name: "test", 383 Command: []string{"java", "-jar", "foo.jar"}, 384 Env: []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}}, 385 Ports: []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}}, 386 }, 387 }}}, 388 }}, 389 }, 390 } 391 for _, test := range tests { 392 testutil.Run(t, test.description, func(t *testutil.T) { 393 value := test.in.DeepCopyObject() 394 395 retriever := func(image string) (debug.ImageConfiguration, error) { 396 return debug.ImageConfiguration{}, nil 397 } 398 result := transformManifest(value, retriever, "HELPERS") 399 400 t.CheckDeepEqual(test.transformed, result) 401 t.CheckDeepEqual(test.out, value) 402 }) 403 } 404 }