github.com/GoogleContainerTools/skaffold/v2@v2.13.2/integration/debug_test.go (about) 1 /* 2 Copyright 2019 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 integration 18 19 import ( 20 "context" 21 "encoding/json" 22 "strings" 23 "testing" 24 "time" 25 26 dockertypes "github.com/docker/docker/api/types" 27 28 "github.com/GoogleContainerTools/skaffold/v2/integration/skaffold" 29 "github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/debug/types" 30 "github.com/GoogleContainerTools/skaffold/v2/proto/v1" 31 "github.com/GoogleContainerTools/skaffold/v2/testutil" 32 ) 33 34 func TestDebug(t *testing.T) { 35 tests := []struct { 36 description string 37 dir string 38 config string 39 args []string 40 deployments []string 41 pods []string 42 ignoreWorkdir bool 43 }{ 44 { 45 description: "kubectl", 46 dir: "testdata/debug", 47 deployments: []string{"java"}, 48 pods: []string{"nodejs", "npm" /*, "python3"*/, "go" /*, "netcore"*/}, 49 }, 50 { 51 description: "kustomize", 52 dir: "testdata/debug", 53 args: []string{"--profile", "kustomize"}, 54 deployments: []string{"java"}, 55 pods: []string{"nodejs", "npm" /*, "python3"*/, "go" /*, "netcore"*/}, 56 }, 57 { 58 description: "specified-runtime-nodejs", 59 dir: "testdata/debug", 60 args: []string{"--profile", "specified-runtime", "--check-cluster-node-platforms=false"}, 61 pods: []string{"nodejs"}, 62 }, 63 // TODO(#8811): Enable this test when issue is solve. 64 // { 65 // description: "buildpacks", 66 // dir: "testdata/debug", 67 // args: []string{"--profile", "buildpacks"}, 68 // deployments: []string{"java"}, 69 // pods: []string{"nodejs", "npm" /*, "python3"*/, "go" /*, "netcore"*/}, 70 // }, 71 { 72 description: "helm", 73 dir: "examples/helm-deployment", 74 deployments: []string{"skaffold-helm"}, 75 ignoreWorkdir: true, // dockerfile doesn't have a workdir 76 }, 77 { 78 description: "modules", 79 dir: "examples/multi-config-microservices", 80 deployments: []string{"leeroy-web", "leeroy-app"}, 81 ignoreWorkdir: true, // dockerfile doesn't have a workdir 82 }, 83 } 84 for _, test := range tests { 85 t.Run(test.description, func(t *testing.T) { 86 MarkIntegrationTest(t, CanRunWithoutGcp) 87 // Run skaffold build first to fail quickly on a build failure 88 skaffold.Build(test.args...).InDir(test.dir).RunOrFail(t) 89 90 ns, client := SetupNamespace(t) 91 92 skaffold.Debug(test.args...).InDir(test.dir).InNs(ns.Name).RunBackground(t) 93 94 verifyDebugAnnotations := func(annotations map[string]string) { 95 var configs map[string]types.ContainerDebugConfiguration 96 if anno, found := annotations["debug.cloud.google.com/config"]; !found { 97 t.Errorf("deployment missing debug annotation: %v", annotations) 98 } else if err := json.Unmarshal([]byte(anno), &configs); err != nil { 99 t.Errorf("error unmarshalling debug annotation: %v: %v", anno, err) 100 } else { 101 for k, config := range configs { 102 if !test.ignoreWorkdir && config.WorkingDir == "" { 103 t.Errorf("debug config for %q missing WorkingDir: %v: %v", k, anno, config) 104 } 105 if config.Runtime == "" { 106 t.Errorf("debug config for %q missing Runtime: %v: %v", k, anno, config) 107 } 108 } 109 } 110 } 111 112 for _, podName := range test.pods { 113 pod := client.GetPod(podName) 114 115 annotations := pod.Annotations 116 verifyDebugAnnotations(annotations) 117 } 118 119 for _, depName := range test.deployments { 120 deploy := client.GetDeployment(depName) 121 122 annotations := deploy.Spec.Template.GetAnnotations() 123 verifyDebugAnnotations(annotations) 124 } 125 }) 126 } 127 } 128 129 func TestDockerDebug(t *testing.T) { 130 t.Run("debug docker deployment", func(t *testing.T) { 131 MarkIntegrationTest(t, CanRunWithoutGcp) 132 skaffold.Build("-p", "docker").InDir("testdata/debug").RunOrFail(t) 133 134 skaffold.Debug("-p", "docker").InDir("testdata/debug").RunBackground(t) 135 defer skaffold.Delete("-p", "docker").InDir("testdata/debug").RunBackground(t) 136 137 // use docker client to verify container has been created properly 138 // check this container and verify entrypoint has been rewritten 139 client := SetupDockerClient(t) 140 var ( 141 verifyEntrypointRewrite bool 142 verifySupportContainer bool 143 tries = 0 144 sleepTime = 2 * time.Second // retrieve containers every two seconds 145 maxTries = 15 // try for 30 seconds max 146 ) 147 for { 148 containers, err := client.ContainerList(context.Background(), dockertypes.ContainerListOptions{All: true}) 149 if err != nil { 150 t.Fail() 151 } 152 time.Sleep(sleepTime) 153 if len(containers) == 0 { 154 continue 155 } 156 157 checkEntrypointRewrite(containers, &verifyEntrypointRewrite) 158 checkSupportContainer(containers, &verifySupportContainer) 159 160 if verifyEntrypointRewrite && verifySupportContainer { 161 break 162 } 163 tries++ 164 if tries == maxTries { 165 break 166 } 167 } 168 169 if !verifyEntrypointRewrite { 170 t.Error("couldn't verify rewritten container") 171 } 172 if !verifySupportContainer { 173 t.Error("couldn't verify support container was created") 174 } 175 }) 176 } 177 178 func checkEntrypointRewrite(containers []dockertypes.Container, found *bool) { 179 if *found { 180 return 181 } 182 for _, c := range containers { 183 if strings.Contains(c.Command, "docker-entrypoint.sh") { 184 *found = true 185 } 186 } 187 } 188 189 func checkSupportContainer(containers []dockertypes.Container, found *bool) { 190 if *found { 191 return 192 } 193 for _, c := range containers { 194 if strings.Contains(c.Image, "gcr.io/k8s-skaffold/skaffold-debug-support") { 195 *found = true 196 } 197 } 198 } 199 200 func TestFilterWithDebugging(t *testing.T) { 201 MarkIntegrationTest(t, CanRunWithoutGcp) 202 // `filter` currently expects to receive a digested yaml 203 renderedOutput := skaffold.Render("--digest-source=local").InDir("examples/getting-started").RunOrFailOutput(t) 204 205 testutil.Run(t, "no --build-artifacts should transform all images", func(t *testutil.T) { 206 transformedOutput := skaffold.Filter("--debugging").InDir("examples/getting-started").WithStdin(renderedOutput).RunOrFailOutput(t.T) 207 transformedYaml := string(transformedOutput) 208 if !strings.Contains(transformedYaml, "/dbg/go/bin/dlv") { 209 t.Error("transformed yaml seems to be missing debugging details", transformedYaml) 210 } 211 }) 212 213 testutil.Run(t, "--build-artifacts=file should result in specific transforms", func(t *testutil.T) { 214 buildFile := t.TempFile("build.txt", []byte(`{"builds":[{"imageName":"doesnotexist","tag":"doesnotexist:notag"}]}`)) 215 transformedOutput := skaffold.Filter("--debugging", "--build-artifacts="+buildFile).InDir("examples/getting-started").WithStdin(renderedOutput).RunOrFailOutput(t.T) 216 transformedYaml := string(transformedOutput) 217 if strings.Contains(transformedYaml, "/dbg/go/bin/dlv") { 218 t.Error("transformed yaml should not include debugging details", transformedYaml) 219 } 220 }) 221 } 222 223 func TestDebugEventsRPC_StatusCheck(t *testing.T) { 224 t.Skipf("Disable the test dues to flakyness. https://github.com/GoogleContainerTools/skaffold/issues/7405") 225 MarkIntegrationTest(t, CanRunWithoutGcp) 226 227 // Run skaffold build first to fail quickly on a build failure 228 skaffold.Build().InDir("testdata/jib").RunOrFail(t) 229 230 ns, client := SetupNamespace(t) 231 232 rpcAddr := randomPort() 233 skaffold.Debug("--rpc-port", rpcAddr).InDir("testdata/jib").InNs(ns.Name).RunBackground(t) 234 235 waitForDebugEvent(t, client, rpcAddr) 236 } 237 238 func TestDebugEventsRPC_NoStatusCheck(t *testing.T) { 239 t.Skipf("Disable the test dues to flakyness. https://github.com/GoogleContainerTools/skaffold/issues/7405") 240 MarkIntegrationTest(t, CanRunWithoutGcp) 241 242 // Run skaffold build first to fail quickly on a build failure 243 skaffold.Build().InDir("testdata/jib").RunOrFail(t) 244 245 ns, client := SetupNamespace(t) 246 247 rpcAddr := randomPort() 248 skaffold.Debug("--rpc-port", rpcAddr, "--status-check=false").InDir("testdata/jib").InNs(ns.Name).RunBackground(t) 249 250 waitForDebugEvent(t, client, rpcAddr) 251 } 252 253 // nolint add lint back after https://github.com/GoogleContainerTools/skaffold/issues/7405 254 func waitForDebugEvent(t *testing.T, client *NSKubernetesClient, rpcAddr string) { 255 client.WaitForPodsReady() 256 257 _, entries := apiEvents(t, rpcAddr) 258 259 timeout := time.After(1 * time.Minute) 260 for { 261 select { 262 case <-timeout: 263 t.Fatalf("timed out waiting for debugging event") 264 case entry := <-entries: 265 switch entry.Event.GetEventType().(type) { 266 case *proto.Event_DebuggingContainerEvent: 267 // success! 268 return 269 default: 270 } 271 } 272 } 273 }